首页 >>
三、时间戳服务与存在证明
发布时间:2019-09-17 10:57:16 来源:Anggame电竞官方-手机app客户端软件点击:63

  简介:“比特币技术进阶”由知名比特币技术专家Kevin原创的三篇文章《比特币交易构成》、《时间戳服务与存在证明》、《工作证明与挖矿》组成,对于那些想要探究比特币工作原理却又不想费力分析源代码的朋友,这篇文章是您或不可缺的进阶指南。

  工作证明(Proof Of Work,简称POW),顾名思义,即工作量的证明。通常来说只能从结果证明,因为监测工作过程通常是繁琐与低效的。

  比特币在Block的生成过程中使用了POW机制,一个符合要求的Block Hash由N个前导零构成,零的个数取决于网络的难度值。要得到合理的Block Hash需要经过大量尝试计算,计算时间取决于机器的哈希运算速度。当某个节点提供出一个合理的Block Hash值,说明该节点确实经过了大量的尝试计算,当然,并不能得出计算次数的绝对值,因为寻找合理hash是一个概率事件。当节点拥有占全网n%的算力时,该节点即有n/100的概率找到Block Hash。

  工作证明机制看似很神秘,其实在社会中的应用非常广泛。例如,毕业证、学位证等证书,就是工作证明,拥有证书即表明你在过去投入了学习与工作。生活大部分事情都是通过结果来判断的。

  挖矿即不断接入新的Block延续Block Chain的过程。

  

  挖矿为整个系统的运转提供原动力,是比特币的发动机,没有挖矿就没有比特币。挖矿有三个重要功能:

  发行新的货币(总量达到之前)

  维系货币的支付功能

  通过算力保障系统安全

  金矿消耗资源将黄金注入流通经济,比特币通过“挖矿”完成相同的事情,只不过消耗的是CPU时间与电力。当然,比特币的挖矿意义远大于此。

  Block头部信息的构成:

  字段名

  含义

  大小(字节)

  Version

  版本号

  4

  hashPrevBlock

  上一个block hash值

  32

  hashMerkleRoot

  上一个block产生之后至新block生成此时间内,

  交易数据打包形成的Hash

  32

  Time

  Unix时间戳

  4

  Bits

  目标值,即难度

  4

  Nonce

  随机数

  4

  nHeight+1) % nInterval !=0) {

  // 未达到周期个数,无需调节

  return pindexLast->nBits;

  }

  // Go back by what we want to be 14 days worth of blocks

  const CBlockIndex* pindexFirst=pindexLast;

  for (int i=0; pindexFirst && i < nInterval-1; i++) pindexFirst=pindexFirst->pprev;

  // 计算本次2016个块的实际产生时间

  // Limit adjustment step

  int64 nActualTimespan=pindexLast->GetBlockTime() - pindexFirst->GetBlockTime();

  // 限定幅度,最低为1/4,最高为4倍

  if (nActualTimespan < nTargetTimespan/4) nActualTimespan=nTargetTimespan/4; if (nActualTimespan > nTargetTimespan*4)

  nActualTimespan=nTargetTimespan*4;

  // 根据最近2016个块的时间,重新计算目标难度

  // Retarget

  CBigNum bnNew;

  bnNew.SetCompact(pindexLast->nBits);

  bnNew *=nActualTimespan;

  bnNew /=nTargetTimespan;

  if (bnNew > bnProofOfWorkLimit)

  bnNew=bnProofOfWorkLimit;

  return bnNew.GetCompact();

  Block字段详解

  Version,版本号,很少变动,一般用于软件全网升级时做标识

  hashPrevBlock,前向Block Hash值,该字段强制多个Block之间形成链接

  hashMerkleRoot,交易Hash树的根节点Hash值,起校验作用,保障Block在网络传输过程中的数据一致性,有新交易加入即发生变化

  Time,Unix时间戳,每秒自增一,标记Block的生成时间,同时为block hash探寻引入一个频繁的变动因子

  Bits,可以推算出难度值,用于验证block hash难度是否达标

  Nonce,随机数,在上面数个字段都固定的情况下,不停地更换随机数来探寻

  最为关键的字段是hashPrevBlock,该字段使得Block之间链接起来,形成一个巨大的“链条”。Block本是稀松平常的数据结构,但以链式结构组织起来后却使得它们具有非常深远的意义:

  形成分支博弈,使得算力总是在主分支上角逐

  算力攻击的概率难度呈指数上升(泊松分布)

  每个block都必须指向前一个block,否则无法验证通过。追溯至源头,便是高度为零的创世纪块(Genesis Block),这里是Block Chain的起点,其前向block hash为零,或者说为空。

  下面是一个简单的步骤描述,实际矿池运作会有区别,复杂一些:

  节点监听全网交易,通过验证的交易进入节点的内存池(Tx Mem Pool),并更新交易数据的Merkle Hash值

  更新时间戳

  尝试不同的随机数(Nonce),进行hash计算

  重复该过程至找到合理的hash

  打包block:先装入block meta信息,然后是交易数据

  对外部广播出新block

  其他节点验证通过后,链接至Block Chain,主链高度加一,然后切换至新block后面挖矿

  由于hashPrevBlock字段的存在,使得大家总是在最新的block后面开挖,稍后会分析原因。

  从block hash算法我们知道,合理的block并不是唯一的,同一高度存在多个block的可能性。那么,当同一个高度出现多个时,主链即出现分叉(Fork)。遇到分叉时,网络会根据下列原则选举出Best Chain:

  不同高度的分支,总是接受最高(即最长)的那条分支

  相同高度的,接受难度最大的

  高度相同且难度一致的,接受时间最早的

  若所有均相同,则按照从网络接受的顺序

  等待Block Chain高度增一,则重新选择Best Chain

  

  按照这个规则运作的节点,称为诚实节点(Honest Nodes)。节点可以诚实也可以不诚实。

  我们假设所有的节点:

  都是理性的,追求收益最大化

  都是不诚实的,且不惜任何手段获取利益

  所有节点均独自挖矿不理会其他节点,并将所得收益放入自己口袋,现象就是一个节点挖一个分支。由于机器的配置总是有差别的,那么算力最强的节点挖得的分支必然是最长的,如果一个节点的分支不是最长的,意味其收益存在不被认可的风险(即零收益)。为了降低、逃避此风险,一些节点肯定会联合起来一起挖某个分支,试图成为最长的分支或保持最长分支优势。

  一旦出现有少量的节点联合,那么其他节点必然会效仿,否则他们收益为零的风险会更大。于是,分支迅速合并汇集,所有节点都会选择算力更强的分支,只有这样才能保持收益风险最小。最终,只会存在一个这样的分支,就是主干分支(Best/Main Chain)。

  对于不诚实节点来说,结局是无奈的:能且只能加入主干挖矿。不加入即意味被抛弃,零收益;加入就是老实干活,按占比分成。

  Block hash的计算是随机概率事件,当有节点广播出难度更高的block后,大家便跑到那个分支。在比特币系统运行过程中,算力经常在分支间跳来跳去,此现象称为Hash Dance。一般情况下,分支的高度为1~2,没有大的故障很难出现高于2的分支。

  Hash Dance起名源于Google Dance.

  算力攻击是一个概率问题,这里作简单叙述:

  p=诚实节点挖出block概率

  q=攻击者挖出block概率,q=1 – p

  qz=攻击者从z个block追上的概率

  

  我们假设p>q,否则攻击者掌握了一半以上的算力,那么概率上永远是赢的。该事件(攻击者胜出)的概率是固定,且N次事件之间是相互独立的,那么这一系列随机过程符合泊松分布(Poisson Distribution)。Z个块时,攻击者胜出的期望为lambda:

  

  攻击者在攻击时已经偷偷的计算了k个块,那么这k个块概率符合泊松分布(下图左侧部分),若k<=z,那么追赶上后续z-k个块的概率为(q/p)z-k,即:

  

  展开为如下形式:

  

  计算该过程的C语言代码如下:

  #include double AttackerSuccessProbability(double q, int z)

  {

  double sum=1.0;

  double p=1.0 - q;

  double lambda=z * (q / p);

  int i, k;

  for (k=0; k <=z; k++) {

  double poisson=exp(-lambda);

  for (i=1; i <=k; i++)

  poisson *=lambda / i;

  sum -=poisson * (1 - pow(q / p, z - k));

  }

  return sum;

  }

  我们选取几个值,结果如下:

  

  可以看到,由于block的链式形式,随着块数的上升,攻击者赢得的概率呈指数下降。这是很多应用等待六个甚至六个以上确认的原因,一旦超过N个确认,攻击者得逞的可能微乎其微,概率值快速趋近零。

  当攻击者的算力超过50%时,便可以控制Block Chain,俗称51%攻击。

  攻击者算出block后,block&Txs必须能够通过验证,否则其他节点都会拒掉,攻击便无意义。攻击者无法做出下列行为:

  偷盗他人的币。消费某个地址的币时,需要对应的ECDSA私钥签名,而私钥是无法破解的。

  凭空制造比特币。每个block奖励的币值是统一的规则,篡改奖励币值会导致其他节点会拒绝该block。

  唯一的益处是可以选择性的收录进入block的交易,对自己的币进行多重消费(Double Spending)。

  过程是这样的:假设现在block高度为100,攻击者给商户发了一个交易10BTC,记作交易A,通常这笔交易会被收录进高度101的block中,当商户在101块中看到这笔交易后,就把货物给了攻击者。此时,攻击者便开始构造另一个高度为101的block,但用交易B替换了交易A,交易B中的输入是同一笔,使得发给商户的那笔钱发给他自己。同时,攻击者需要努力计算block,使得他的分支能够赶上主分支,并合并(Merge)被大家接受,一旦接受,便成功地完成了一次Double Spending。

  攻击难度呈指数上升,所以成功的Double Spending通常是一个极小概率事件。

  全网算力的上升对比特币是极其有利的,这是毫无疑问的。但目前大矿池与矿业巨头使得算力高度集中化,这与中本聪所设想的一CPU一票(one-CPU-one-vote)的分散局面背道而驰,或许是他未曾预料的。

  挖矿是一项专业劳动,最后必然会交给最专业的人或团队,因为这样才能实现资源配置最优,效率最高。普通投资人通过购买算力巨头的股票:1. 完成投资;2. 分享算力红利。看似中心化的背后其实依然是分散的:

  矿业公司的背后是无数分散的投资人

  矿池背后是无数分散的个体算力

  既得利益使得算力巨头倾向于维护系统而不是破坏,因其收益均建立在比特币系统之上,既得利益者断然不会搬石头砸自己脚。甚至很多巨头在达到一定算力占比后会主动控制算力增长,使得低于某阈值内。

  本篇几乎都在讲挖矿,因为挖矿对于比特币系统来说实在是太重要了。需要了解:1. block是基于工作量证明的。2. block以链式结构存在时的深远意义。

  交易(Transaction)是比特币系统的信息载体,最小单元。而块(Block)就是将这些基础单元打包装箱,贴上封条,并串联起来。巨大算力保障了块的安全,也就保障了单个交易的安全。

  交易有三种常见类型:产量交易(Generation),合成地址交易(Script Hash),通用地址交易(Pubkey Hash)。该分类并非严格意义的,只是根据交易的输入输出做的简单区分。

  每个Block都对应一个产量交易(Generation TX),该类交易是没有输入交易的,挖出的新币是所有币的源头。

  该类交易目前不是很常见,大部分人可能没有听说过,但是非常有意义。未来应该会在某些场合频繁使用。该类交易的接受地址不是通常意义的地址,而是一个合成地址,以3开头(对,以3开头的也是比特币地址!)。三对公私钥,可以生成一个合成地址。在生成过程时指定n of 3中的n,n范围是[1, 3],若n=1,则仅需一个私钥签名即可花费该地址的币,若n=3,则需要三把私钥依次签名才可以。

  该类是最常见的交易类型,由N个输入、M个输出构成。

  交易中存放的是货币所有权的流转信息,所有权登记在比特币地址上(Public Key)。这些信息是全网公开的,以明文形式存储(比特币系统里的所有数据都是明文的),只有当需要转移货币所有权时,才需要用私钥签名来验证。

  字段大小

  描述

  数据类型

  解释

  4

  version, 版本

  uint32_t

  交易数据结构的版本号

  1+

  tx_in count, 输入数量

  var_int

  输入交易的数量

  41+

  tx_in

  tx_in[]

  输入交易的数组,每个输入>=41字节

  1+

  tx_out count, 输出数量

  var_int

  输出地址的数量

  9+

  tx_out

  tx_out[]

  输入地址的数组,每个输入>=9字节

  4

  lock_time, 锁定时间

  uint32_t

  见下方解释

  lock_time是一个多意字段,表示在某个高度的Block之前或某个时间点之前该交易处于锁定态,无法收录进Block。

  值

  含义

  0

  立即生效

  < 500000000

  含义为Block高度,处于该Block之前为锁定(不生效)

  >=500000000

  含义为Unix时间戳,处于该时刻之前为锁定(不生效)

  若该笔交易的所有输入交易的sequence字段,均为INT32最大值(0xffffffff),则忽略lock_time字段。否则,该交易在未达到Block高度或达到某个时刻之前,是不会被收录进Block中的。

  示例

  为了演示方便,我们读取稍早期的块数据,以高度116219 Block为例。

  # ~ bitcoind getblock 0000000000007c639f2cbb23e4606a1d022fa4206353b9d92e99f5144bd74611?

  {

  "hash" : "0000000000007c639f2cbb23e4606a1d022fa4206353b9d92e99f5144bd74611",

  "confirmations" : 144667,

  "size" : 1536,

  "height" : 116219,

  "version" : 1,

  "merkleroot" : "587fefd748f899f84d0fa1d8a3876fdb406a4bb8f54a31445cb72564701daea6",

  "tx" : [

  "be8f08d7f519eb863a68cf292ca51dbab7c9b49f50a96d13f2db32e432db363e",

  "a387039eca66297ba51ef2da3dcc8a0fc745bcb511e20ed9505cc6762be037bb",

  "2bd83162e264abf59f9124ca517050065f8c8eed2a21fbf85d454ee4e0e4c267",

  "028cfae228f8a4b0caee9c566bd41aed36bcd237cdc0eb18f0331d1e87111743",

  "3a06b6615756dc3363a8567fbfa8fe978ee0ba06eb33fd844886a0f01149ad62"

  ],

  "time" : 1301705313,

  "nonce" : 1826107553,

  "bits" : "1b00f339",

  "difficulty" : 68977.78463021,

  "previousblockhash" : "00000000000010d549135eb39bd3bbb1047df8e1512357216e8a85c57a1efbfb",

  "nextblockhash" : "000000000000e9fcc59a6850f64a94476a30f5fe35d6d8c4b4ce0b1b04103a77"

  }

  该Block里面有5笔交易,第一笔为Generation TX,解析出来看一下具体内容:

  # ~ bitcoind getrawtransaction be8f08d7f519eb863a68cf292ca51dbab7c9b49f50a96d13f2db32e432db363e 1

  {

  "hex" : "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff070439f3001b0134ffffffff014034152a010000004341045b3aaa284d169c5ae2d20d0b0673468ed3506aa8fea5976eacaf1ff304456f6522fbce1a646a24005b8b8e771a671f564ca6c03e484a1c394bf96e2a4ad01dceac00000000",

  "txid" : "be8f08d7f519eb863a68cf292ca51dbab7c9b49f50a96d13f2db32e432db363e",

  "version" : 1,

  "locktime" : 0,

  "vin" : [

  {

  "coinbase" : "0439f3001b0134",

  "sequence" : 4294967295

  }

  ],

  "vout" : [

  {

  "value" : 50.01000000,

  "n" : 0,

  "scriptPubKey" : {

  "asm" : "045b3aaa284d169c5ae2d20d0b0673468ed3506aa8fea5976eacaf1ff304456f6522fbce1a646a24005b8b8e771a671f564ca6c03e484a1c394bf96e2a4ad01dce OP_CHECKSIG",

  "hex" : "41045b3aaa284d169c5ae2d20d0b0673468ed3506aa8fea5976eacaf1ff304456f6522fbce1a646a24005b8b8e771a671f564ca6c03e484a1c394bf96e2a4ad01dceac",

  "reqSigs" : 1,

  "type" : "pubkey",

  "addresses" : [

  "1LgZTvoTJ6quJNCURmBUaJJkWWQZXkQnDn"

  ]

  }

  }

  ],

  "blockhash" : "0000000000007c639f2cbb23e4606a1d022fa4206353b9d92e99f5144bd74611",

  "confirmations" : 145029,

  "time" : 1301705313,

  "blocktime" : 1301705313

  }

  Generation TX的输入不是一个交易,而带有coinbase字段的结构。该字段的值由挖出此Block的人填写,这是一种“特权”:可以把信息写入货币系统(大家很喜欢用系统中的数据结构字段名来命名站点,例如blockchain、coinbase等,这些词的各种后缀域名都被抢注一空)。中本聪在比特币的第一个交易中的写入的coinbase值是:

  "coinbase":"04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73"

  将该段16进制转换为ASCII字符,就是那段著名的创世块留言:

  The Times 03/Jan/2009 Chancellor on brink of second bailout for banks

  接下来展示的是一个三个输入、两个输出的普通交易:

  # ~ bitcoind getrawtransaction 028cfae228f8a4b0caee9c566bd41aed36bcd237cdc0eb18f0331d1e87111743 1

  {

  "hex" : "0100000003c9f3b07ebfca68fd1a6339d0808fbb013c90c6095fc93901ea77410103489ab7000000008a473044022055bac1856ecbc377dd5e869b1a84ed1d5228c987b098c095030c12431a4d5249022055523130a9d0af5fc27828aba43b464ecb1991172ba2a509b5fbd6cac97ff3af0141048aefd78bba80e2d1686225b755dacea890c9ca1be10ec98173d7d5f2fefbbf881a6e918f3b051f8aaaa3fcc18bbf65097ce8d30d5a7e5ef8d1005eaafd4b3fbeffffffffc9f3b07ebfca68fd1a6339d0808fbb013c90c6095fc93901ea77410103489ab7010000008a47304402206b993231adec55e6085e75f7dc5ca6c19e42e744cd60abaff957b1c352b3ef9a022022a22fec37dfa2c646c78d9a0753d56cb4393e8d0b22dc580ef1aa6cccef208d0141042ff65bd6b3ef04253225405ccc3ab2dd926ff2ee48aac210819698440f35d785ec3cec92a51330eb0c76cf49e9e474fb9159ab41653a9c1725c031449d31026affffffffc98620a6c40fc7b3a506ad79af339541762facd1dd80ff0881d773fb72b230da010000008b483045022040a5d957e087ed61e80f1110bcaf4901b5317c257711a6cbc54d6b98b6a8563f02210081e3697031fe82774b8f44dd3660901e61ac5a99bff2d0efc83ad261da5b4f1d014104a7d1a57e650613d3414ebd59e3192229dc09d3613e547bdd1f83435cc4ca0a11c679d96456cae75b1f5563728ec7da1c1f42606db15bf554dbe8a829f3a8fe2fffffffff0200bd0105000000001976a914634228c26cf40a02a05db93f2f98b768a8e0e61b88acc096c7a6030000001976a9147514080ab2fcac0764de3a77d10cb790c71c74c288ac00000000",

  "txid" : "028cfae228f8a4b0caee9c566bd41aed36bcd237cdc0eb18f0331d1e87111743",

  "version" : 1,

  "locktime" : 0,

  "vin" : [

  {

  "txid" : "b79a4803014177ea0139c95f09c6903c01bb8f80d039631afd68cabf7eb0f3c9",

  "vout" : 0,

  "scriptSig" : {

  "asm" : "3044022055bac1856ecbc377dd5e869b1a84ed1d5228c987b098c095030c12431a4d5249022055523130a9d0af5fc27828aba43b464ecb1991172ba2a509b5fbd6cac97ff3af01 048aefd78bba80e2d1686225b755dacea890c9ca1be10ec98173d7d5f2fefbbf881a6e918f3b051f8aaaa3fcc18bbf65097ce8d30d5a7e5ef8d1005eaafd4b3fbe",

  "hex" : "473044022055bac1856ecbc377dd5e869b1a84ed1d5228c987b098c095030c12431a4d5249022055523130a9d0af5fc27828aba43b464ecb1991172ba2a509b5fbd6cac97ff3af0141048aefd78bba80e2d1686225b755dacea890c9ca1be10ec98173d7d5f2fefbbf881a6e918f3b051f8aaaa3fcc18bbf65097ce8d30d5a7e5ef8d1005eaafd4b3fbe"

  },

  "sequence" : 4294967295

  },

  {

  "txid" : "b79a4803014177ea0139c95f09c6903c01bb8f80d039631afd68cabf7eb0f3c9",

  "vout" : 1,

  "scriptSig" : {

  "asm" : "304402206b993231adec55e6085e75f7dc5ca6c19e42e744cd60abaff957b1c352b3ef9a022022a22fec37dfa2c646c78d9a0753d56cb4393e8d0b22dc580ef1aa6cccef208d01 042ff65bd6b3ef04253225405ccc3ab2dd926ff2ee48aac210819698440f35d785ec3cec92a51330eb0c76cf49e9e474fb9159ab41653a9c1725c031449d31026a",

  "hex" : "47304402206b993231adec55e6085e75f7dc5ca6c19e42e744cd60abaff957b1c352b3ef9a022022a22fec37dfa2c646c78d9a0753d56cb4393e8d0b22dc580ef1aa6cccef208d0141042ff65bd6b3ef04253225405ccc3ab2dd926ff2ee48aac210819698440f35d785ec3cec92a51330eb0c76cf49e9e474fb9159ab41653a9c1725c031449d31026a"

  },

  "sequence" : 4294967295

  },

  {

  "txid" : "da30b272fb73d78108ff80ddd1ac2f76419533af79ad06a5b3c70fc4a62086c9",

  "vout" : 1,

  "scriptSig" : {

  "asm" : "3045022040a5d957e087ed61e80f1110bcaf4901b5317c257711a6cbc54d6b98b6a8563f02210081e3697031fe82774b8f44dd3660901e61ac5a99bff2d0efc83ad261da5b4f1d01 04a7d1a57e650613d3414ebd59e3192229dc09d3613e547bdd1f83435cc4ca0a11c679d96456cae75b1f5563728ec7da1c1f42606db15bf554dbe8a829f3a8fe2f",

  "hex" : "483045022040a5d957e087ed61e80f1110bcaf4901b5317c257711a6cbc54d6b98b6a8563f02210081e3697031fe82774b8f44dd3660901e61ac5a99bff2d0efc83ad261da5b4f1d014104a7d1a57e650613d3414ebd59e3192229dc09d3613e547bdd1f83435cc4ca0a11c679d96456cae75b1f5563728ec7da1c1f42606db15bf554dbe8a829f3a8fe2f"

  },

  "sequence" : 4294967295

  }

  ],

  "vout" : [

  {

  "value" : 0.84000000,

  "n" : 0,

  "scriptPubKey" : {

  "asm" : "OP_DUP OP_HASH160 634228c26cf40a02a05db93f2f98b768a8e0e61b OP_EQUALVERIFY OP_CHECKSIG",

  "hex" : "76a914634228c26cf40a02a05db93f2f98b768a8e0e61b88ac",

  "reqSigs" : 1,

  "type" : "pubkeyhash",

  "addresses" : [

  "1A3q9pDtR4h8wpvyb8SVpiNPpT8ZNbHY8h"

  ]

  }

  },

  {

  "value" : 156.83000000,

  "n" : 1,

  "scriptPubKey" : {

  "asm" : "OP_DUP OP_HASH160 7514080ab2fcac0764de3a77d10cb790c71c74c2 OP_EQUALVERIFY OP_CHECKSIG",

  "hex" : "76a9147514080ab2fcac0764de3a77d10cb790c71c74c288ac",

  "reqSigs" : 1,

  "type" : "pubkeyhash",

  "addresses" : [

  "1Bg44FZsoTeYteRykC1XHz8facWYKhGvQ8"

  ]

  }

  }

  ],

  "blockhash" : "0000000000007c639f2cbb23e4606a1d022fa4206353b9d92e99f5144bd74611",

  "confirmations" : 147751,

  "time" : 1301705313,

  "blocktime" : 1301705313

  }

  字段hex记录了所有相关信息,后面显示的是hex解析出来的各类字段信息。下面把逐个分解hex内容(hex可以从上面的直接看到):

  01000000 // 版本号,UINT32

  03 // Tx输入数量,变长INT。3个输入。

  // Tx Hash,固定32字节

  c9f3b07ebfca68fd1a6339d0808fbb013c90c6095fc93901ea77410103489ab7

  00000000 // 消费的Tx位于前向交易输出的第0个,UINT32,固定4字节

  8a // 签名的长度, 0x8A=138字节

  // 138字节长度的签名,含有两个部分:公钥+签名

  47 // 公钥长度,0x47=71字节

  3044022055bac1856ecbc377dd5e869b1a84ed1d5228c987b098c095030c12431a4d5249022055523130a9d0af5fc27828aba43b464ecb1991172ba2a509b5fbd6cac97ff3af01

  41 // 签名长度,0x41=65字节

  048aefd78bba80e2d1686225b755dacea890c9ca1be10ec98173d7d5f2fefbbf881a6e918f3b051f8aaaa3fcc18bbf65097ce8d30d5a7e5ef8d1005eaafd4b3fbe

  ffffffff // sequence,0xffffffff=4294967295, UINT32, 固定4字节

  c9f3b07ebfca68fd1a6339d0808fbb013c90c6095fc93901ea77410103489ab7010000008a47304402206b993231adec55e6085e75f7dc5ca6c19e42e744cd60abaff957b1c352b3ef9a022022a22fec37dfa2c646c78d9a0753d56cb4393e8d0b22dc580ef1aa6cccef208d0141042ff65bd6b3ef04253225405ccc3ab2dd926ff2ee48aac210819698440f35d785ec3cec92a51330eb0c76cf49e9e474fb9159ab41653a9c1725c031449d31026affffffff

  c98620a6c40fc7b3a506ad79af339541762facd1dd80ff0881d773fb72b230da010000008b483045022040a5d957e087ed61e80f1110bcaf4901b5317c257711a6cbc54d6b98b6a8563f02210081e3697031fe82774b8f44dd3660901e61ac5a99bff2d0efc83ad261da5b4f1d014104a7d1a57e650613d3414ebd59e3192229dc09d3613e547bdd1f83435cc4ca0a11c679d96456cae75b1f5563728ec7da1c1f42606db15bf554dbe8a829f3a8fe2fffffffff

  02 // Tx输出数量,变长INT。两个输出。

  00bd010500000000 // 输出的币值,UINT64,8个字节。字节序需翻转,~=0x000000000501bd00=84000000 satoshi

  19 // 输出目的地址字节数, 0x19=25字节,由一些操作码与数值构成

  // 目标地址

  // 0x76 -> OP_DUP(stack ops)

  // 0xa9 -> OP_HASH160(crypto)

  // 0x14 -> 长度,0x14=20字节

  76 a9 14

  // 地址的HASH160值,20字节

  634228c26cf40a02a05db93f2f98b768a8e0e61b

  // 0x88 -> OP_EQUALVERIFY(bit logic)

  // 0xac -> OP_CHECKSIG(crypto)

  88 ac

  c096c7a603000000

  19

  76 a9 14 7514080ab2fcac0764de3a77d10cb790c71c74c2 88 ac

  00000000 // lock_time,UINT32,固定4字节

  Tx Hash,俗称交易ID,由hex得出:Tx Hash=SHA256(SHA256(hex))。由于每个交易只能成为下一个的输入,有且仅有一次,那么不存在输入完全相同的交易,那么就不存在相同的Tx Hash(SHA256碰撞概率极小,所以无需考虑Hash碰撞的问题,就像无需考虑地址私钥被别人撞到一样)。

  即便如此,在系统里依然产生了相同的Tx Hash,是某位矿工兄弟挖出Block后,打包Block时忘记修改Generation Tx coinbase字段的值,币量相同且输出至相同的地址,那么就构造了两个完全一模一样的交易,分别位于两个Block的第一个位置。这个对系统不会产生什么问题,但只要花费其中一笔,另一个也被花费了。相同的Generation Tx相当于覆盖了另一个,白白损失了挖出的币。该交易ID为e3bf3d07d4b0375638d5f1db5255fe07ba2c4cb067cd81b84ee974b6585fb468,第一次出现在#91722,第二次出现在#91880。

  

  签名是对所有权的验证,节点收到交易广播后,会对交易进行验证,通过后则收录进内存、打包进Block,否则,丢弃之。签名就类似传统纸质合同盖章、签字过程,合法转移所有权的保证手段。

  由于一个交易的输入、输出都可能具有多个,那么签名也具有多种类型,目前共三类:SIGHASH_ALL, SIGHASH_NONE, SIGHASH_SINGLE。

  该签名类型为默认类型,也是目前绝大部分交易采用的,顾名思义即签名整单交易。首先,组织所有输出、输入,就像上文分解Hex过程一样,每个输入都对应一个签名,暂时留空,其他包括sequence等字段均须填写,这样就形成了一个完整的交易Hex(只缺签名字段)。然后,每一个输入均需使用私钥对该段数据进行签名,签名完成后各自填入相应的位置,N个输入N个签名。简单理解就是:对于该笔单子,认可且只认可的这些输入、输出,并同意花费我的那笔输入。

  该签名类型是最自由松散的,仅对输入签名,不对输出签名,输出可以任意指定。某人对某笔币签名后交给你,你可以在任意时刻填入任意接受地址,广播出去令其生效。简单理解就是:我同意花费我的那笔钱,至于给谁,我不关心。

  该签名类型其次自由松散,仅对自己的输入、输出签名,并留空sequence字段。其输入的次序对应其输出的次序,比如输入是第3个,那么签名的输出也是第三个。简单理解就是:我同意花费我的那笔钱,且只能花费到我认可的输出,至于单子里的其他输入、输出,我不关心。

  上篇介绍了交易结构、签名等,为了更直观的认识比特币,借助bitcoind演示手动构造并广播交易的完整过程。

  通过命令:listunspent [minconf=1] [maxconf=9999999] ["address",...]列出某个地址未花费的币(交易),minconf/maxconf表示该笔收入交易的确认数范围,如果需要列出还未确认的交易,需将minconf设置为0。

  执行:

  bitcoind listunspent 0 100 '["1Lab618UuWjLmVA1Q64tHZXcLoc4397ZX3"]'

  输出:

  [

  {

  "txid" : "296ea7bf981b44999d689853d17fe0ceb852a8a34e68fcd19f0a41e589132156",

  "vout" : 0,

  "address" : "1Lab618UuWjLmVA1Q64tHZXcLoc4397ZX3",

  "account" : "",

  "scriptPubKey" : "76a914d6c492056f3f99692b56967a42b8ad44ce76b67a88ac",

  "amount" : 0.19900000,

  "confirmations" : 1

  }

  ]

  我们找到该地址的一个未花费交易,位于交易296ea7bf981b4499…9f0a41e589132156的第0个位置。

  创建待发送交易,由命令:createrawtransaction [来完成。我们将 0.1 BTC发送至 1Q8s4qDRbCbFypG5AFNR9tFC57PStkPX1x ,并支付 0.0001 BTC做为矿工费。输入交易的额度为 0.199 ,输出为 0.1 + 0.0001=0.1001 ,那么还剩余: 0.199 – 0.1001=0.0989 ,将此作为找零发回给自己。

  执行:

  bitcoind createrawtransaction \

  '['

  输出:

  010000000156211389e5410a9fd1fc684ea3a852b8cee07fd15398689d99441b98bfa76e290000000000ffffffff0280969800000000001976a914fdc7990956642433ea75cabdcc0a9447c5d2b4ee88acd0e89600000000001976a914d6c492056f3f99692b56967a42b8ad44ce76b67a88ac00000000

  通过命令:decoderawtransaction ,可以将此段十六进制字符串解码。

  执行:

  bitcoind decoderawtransaction '010000000156211389e5410a9fd1fc684ea3a852b8cee07fd15398689d99441b98bfa76e290000000000ffffffff0280969800000000001976a914fdc7990956642433ea75cabdcc0a9447c5d2b4ee88acd0e89600000000001976a914d6c492056f3f99692b56967a42b8ad44ce76b67a88ac00000000'

  输出:

  {

  "txid" : "54f773a3fdf7cb3292fc76b46c97e536348b3a0715886dbfd2f60e115fb3a8f0",

  "version" : 1,

  "locktime" : 0,

  "vin" : [

  {

  "txid" : "296ea7bf981b44999d689853d17fe0ceb852a8a34e68fcd19f0a41e589132156",

  "vout" : 0,

  "scriptSig" : {

  "asm" : "",

  "hex" : ""

  },

  "sequence" : 4294967295

  }

  ],

  "vout" : [

  {

  "value" : 0.10000000,

  "n" : 0,

  "scriptPubKey" : {

  "asm" : "OP_DUP OP_HASH160 fdc7990956642433ea75cabdcc0a9447c5d2b4ee OP_EQUALVERIFY OP_CHECKSIG",

  "hex" : "76a914fdc7990956642433ea75cabdcc0a9447c5d2b4ee88ac",

  "reqSigs" : 1,

  "type" : "pubkeyhash",

  "addresses" : [

  "1Q8s4qDRbCbFypG5AFNR9tFC57PStkPX1x"

  ]

  }

  },

  {

  "value" : 0.09890000,

  "n" : 1,

  "scriptPubKey" : {

  "asm" : "OP_DUP OP_HASH160 d6c492056f3f99692b56967a42b8ad44ce76b67a OP_EQUALVERIFY OP_CHECKSIG",

  "hex" : "76a914d6c492056f3f99692b56967a42b8ad44ce76b67a88ac",

  "reqSigs" : 1,

  "type" : "pubkeyhash",

  "addresses" : [

  "1Lab618UuWjLmVA1Q64tHZXcLoc4397ZX3"

  ]

  }

  }

  ]

  }

  至此,一个“空白交易”就构造好了,尚未使用私钥对交易进行签名,字段scriptSig是留空的,无签名的交易是无效的。此时的Tx ID并不是最终的Tx ID,填入签名后Tx ID会发生变化。

  在手动创建交易时,务必注意输入、输出的值,非常容易犯错的是忘记构造找零输出(如非必要勿手动构造交易)。曾经有人构造交易时忘记找零,发生了支付 200 BTC 的矿工费的人间惨剧,所幸的是收录该笔交易的Block由著名挖矿团队“烤猫(Friedcat)”挖得,该团队非常厚道的退回了多余费用。

  交易签名使用命令:

  signrawtransaction \

  [,...] [,...] \

  [sighashtype="ALL"]

  第一个参数是创建的待签名交易的十六进制字符串;

  第二个参数有点类似创建交易时的参数,不过需要多出一个公钥字段scriptPubKey,其他节点验证交易时是通过公钥和签名来完成的,所以要提供公钥;如果是合成地址,则需要提供redeemScript;

  第三个参数是即将花费的币所在地址的私钥,用来对交易进行签名,如果该地址私钥已经导入至bitcoind中,则无需显式提供;

  最后一个参数表示签名类型,在上一篇里,介绍了三种交易签名类型;

  签名之前需要找到scriptPubKey,提取输入交易信息即可获取(也可以根据其公钥自行计算),由命令:getrawtransaction [verbose=0]完成。

  执行:

  bitcoind getrawtransaction 296ea7bf981b44999d689853d17fe0ceb852a8a34e68fcd19f0a41e589132156 1

  输出:

  {

  "hex" : "01000000010511331f639e974283d3909496787a660583dc88f41598d177e225b5f352314a000000006c493046022100be8c796122ec598295e6dfd6664a20a7e20704a17f76d3d925c9ec421ca60bc1022100cf9f2d7b9f24285f7c119c91f24521e5483f6b141de6ee55658fa70116ee04d4012103cad07f6de0b181891b5291a5bc82b228fe6509699648b0b53556dc0057eeb5a4ffffffff0160a62f01000000001976a914d6c492056f3f99692b56967a42b8ad44ce76b67a88ac00000000",

  "txid" : "296ea7bf981b44999d689853d17fe0ceb852a8a34e68fcd19f0a41e589132156",

  "version" : 1,

  "locktime" : 0,

  "vin" : [

  {

  "txid" : "4a3152f3b525e277d19815f488dc8305667a78969490d38342979e631f331105",

  "vout" : 0,

  "scriptSig" : {

  "asm" : "3046022100be8c796122ec598295e6dfd6664a20a7e20704a17f76d3d925c9ec421ca60bc1022100cf9f2d7b9f24285f7c119c91f24521e5483f6b141de6ee55658fa70116ee04d401 03cad07f6de0b181891b5291a5bc82b228fe6509699648b0b53556dc0057eeb5a4",

  "hex" : "493046022100be8c796122ec598295e6dfd6664a20a7e20704a17f76d3d925c9ec421ca60bc1022100cf9f2d7b9f24285f7c119c91f24521e5483f6b141de6ee55658fa70116ee04d4012103cad07f6de0b181891b5291a5bc82b228fe6509699648b0b53556dc0057eeb5a4"

  },

  "sequence" : 4294967295

  }

  ],

  "vout" : [

  {

  "value" : 0.19900000,

  "n" : 0,

  "scriptPubKey" : {

  "asm" : "OP_DUP OP_HASH160 d6c492056f3f99692b56967a42b8ad44ce76b67a OP_EQUALVERIFY OP_CHECKSIG",

  "hex" : "76a914d6c492056f3f99692b56967a42b8ad44ce76b67a88ac",

  "reqSigs" : 1,

  "type" : "pubkeyhash",

  "addresses" : [

  "1Lab618UuWjLmVA1Q64tHZXcLoc4397ZX3"

  ]

  }

  }

  ],

  "blockhash" : "000000000000000488f18f7659acd85b2bd06a5ed2c4439eea74a8b968d16656",

  "confirmations" : 19,

  "time" : 1383235737,

  "blocktime" : 1383235737

  }

  scriptPubKey位于”vout”[0]–>“scriptPubKey”–>“hex”,即: 76a914d6c492056f3f99692b56967a42b8ad44ce76b67a88ac 。

  签名使用ECDSA算法,对其,“空白交易”签名之,执行:

  bitcoind signrawtransaction \

  "010000000156211389e5410a9fd1fc684ea3a852b8cee07fd15398689d99441b98bfa76e290000000000ffffffff0280969800000000001976a914fdc7990956642433ea75cabdcc0a9447c5d2b4ee88acd0e89600000000001976a914d6c492056f3f99692b56967a42b8ad44ce76b67a88ac00000000" \

  '[]'

  输出:

  {

  "hex" : "010000000156211389e5410a9fd1fc684ea3a852b8cee07fd15398689d99441b98bfa76e29000000008c493046022100f9da4f53a6a4a8317f6e7e9cd9a7b76e0f5e95dcdf70f1b1e2b3548eaa3a6975022100858d48aed79da8873e09b0e41691f7f3e518ce9a88ea3d03f7b32eb818f6068801410477c075474b6798c6e2254d3d06c1ae3b91318ca5cc62d18398697208549f798e28efb6c55971a1de68cca81215dd53686c31ad8155cdc03563bf3f73ce87b4aaffffffff0280969800000000001976a914fdc7990956642433ea75cabdcc0a9447c5d2b4ee88acd0e89600000000001976a914d6c492056f3f99692b56967a42b8ad44ce76b67a88ac00000000",

  "complete" : true

  }

  签名后,签名值会填入上文所述的空字段中,从而得到一个完整的交易。可通过上文介绍的命令decoderawtransaction 解码查看之。

  最后一步,就是将其广播出去,等待网络传播至所有节点,约10~60秒广播至全球节点,取决与你的节点的网络连接状况。稍后一些时刻,就会进入Block中。广播由命令sendrawtransaction 来完成。如果没有运行节点,可以通过公共节点的API进行广播,例如:blockchain.info/pushtx。

  执行:

  bitcoind sendrawtransaction \

  "010000000156211389e5410a9fd1fc684ea3a852b8cee07fd15398689d99441b98bfa76e29000000008c493046022100f9da4f53a6a4a8317f6e7e9cd9a7b76e0f5e95dcdf70f1b1e2b3548eaa3a6975022100858d48aed79da8873e09b0e41691f7f3e518ce9a88ea3d03f7b32eb818f6068801410477c075474b6798c6e2254d3d06c1ae3b91318ca5cc62d18398697208549f798e28efb6c55971a1de68cca81215dd53686c31ad8155cdc03563bf3f73ce87b4aaffffffff0280969800000000001976a914fdc7990956642433ea75cabdcc0a9447c5d2b4ee88acd0e89600000000001976a914d6c492056f3f99692b56967a42b8ad44ce76b67a88ac00000000"

  输出:

  b5f8da1ea9e02ec3cc0765f9600f49945e94ed4b0c88ed0648896bf3e213205d

  返回的是Transaction Hash值,即该交易的ID。至此,交易构造、签名、发送的完整过程完成了。

  合成地址以3开头,可以实现多方管理资产,极大提高安全性,也可以轻松实现基于比特币原生的三方交易担保支付。一个M-of-N的模式:

  m {pubkey}...{pubkey} n OP_CHECKMULTISIG

  M和N需满足:

  1<=N<=3

  1<=M<=N

  可以是1 of 1,1 of 2,2 of 3等组合,通常选择N=3:

  1 of 3,最大程度私钥冗余。防丢私钥损失,3把私钥中任意一把即可签名发币,即使丢失2把都可以保障不受损失;

  2 of 3,提高私钥冗余度的同时解决单点信任问题。3把私钥任意2把私钥可签名发币,三方不完全信任的情形,即中介交易中,非常适用;

  3 of 3,最大程度解决资金信任问题,无私钥冗余。必须3把私钥全部签名才能发币,适用多方共同管理重要资产,但任何一方遗失私钥均造成严重损失;

  合成地址的交易构造、签名、发送过程与普通交易类似,这里只介绍如何创建一个合成地址。大神Gavin Andresen已经演示过,下面内容摘自其gist.

  首先,需要三对公钥、私钥。公钥创建地址、私钥用于签名。

  # No.1

  0491bba2510912a5bd37da1fb5b1673010e43d2c6d812c514e91bfa9f2eb129e1c183329db55bd868e209aac2fbc02cb33d98fe74bf23f0c235d6126b1d8334f86 / 5JaTXbAUmfPYZFRwrYaALK48fN6sFJp4rHqq2QSXs8ucfpE4yQU

  # No.2

  04865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac09ef122b1a986818a7cb624532f062c1d1f8722084861c5c3291ccffef4ec6874 / 5Jb7fCeh1Wtm4yBBg3q3XbT6B525i17kVhy3vMC9AqfR6FH2qGk

  # No.3

  048d2455d2403e08708fc1f556002f1b6cd83f992d085097f9974ab08a28838f07896fbab08f39495e15fa6fad6edbfb1e754e35fa1c7844c41f322a1863d46213 / 5JFjmGo5Fww9p8gvx48qBYDJNAzR9pmH5S389axMtDyPT8ddqmw

  使用命令:createmultisig <'["key","key"]'>来合成,其中key为公钥,创建地址时仅需公钥。创建类型是2 of 3.

  输入:

  bitcoind createmultisig 2 \

  '["0491bba2510912a5bd37da1fb5b1673010e43d2c6d812c514e91bfa9f2eb129e1c183329db55bd868e209aac2fbc02cb33d98fe74bf23f0c235d6126b1d8334f86","04865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac09ef122b1a986818a7cb624532f062c1d1f8722084861c5c3291ccffef4ec6874","048d2455d2403e08708fc1f556002f1b6cd83f992d085097f9974ab08a28838f07896fbab08f39495e15fa6fad6edbfb1e754e35fa1c7844c41f322a1863d46213"]'

  输出:

  {

  "address" : "3QJmV3qfvL9SuYo34YihAf3sRCW3qSinyC",

  "redeemScript" : "52410491bba2510912a5bd37da1fb5b1673010e43d2c6d812c514e91bfa9f2eb129e1c183329db55bd868e209aac2fbc02cb33d98fe74bf23f0c235d6126b1d8334f864104865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac09ef122b1a986818a7cb624532f062c1d1f8722084861c5c3291ccffef4ec687441048d2455d2403e08708fc1f556002f1b6cd83f992d085097f9974ab08a28838f07896fbab08f39495e15fa6fad6edbfb1e754e35fa1c7844c41f322a1863d4621353ae"

  }

  得到的合成地址是:3QJmV3qfvL9SuYo34YihAf3sRCW3qSinyC,该地址没有公钥,仅有redeemScript,作用与公钥相同。后续的构造、签名、发送过程与上文普通地址交易类似,略去。

  存在证明就是向第三方证明某个物品/事件,在过去的某个时刻存在过。

  这是一件很简单的事情,提供票据、通信记录之类的就可以办到。但这些并不严格,因为这些证据都是非常易伪造或销毁。要完成证明,必须依赖强有力的证据链,这个必须是任何人都无法伪造与销毁的,或者说伪造成本极其高昂近乎不可能。

  回忆一下,电影里经常出现的绑匪镜头,他们为了证明在某个时间确实拥有人质,而不是事前拍摄的视频,通常会用当天的发行量很大的报纸来辅助证明。当香港媒体误报“成龙高楼坠亡”时,成龙也不得不拿报纸来证明自己的存在:

  

  报纸之所以能够成为有效的时间证明系统是因为:

  不可伪造性。新闻等信息是无法预测的,尤其是证券大盘数据,报纸上大量充满这样的信息,所以无人能够提前伪造。

  公开且不可销毁。报纸通常拥有很大的发行数量,受众广泛,一旦发布出去就分散到各个角落,很难再次收集齐全并全部销毁。通常图书馆也会存档数十年期限的报纸。

  具有时间特征。报纸具有很强时间特征,版面到处可见的是时间标记。

  借助报纸可以完成某个时间之后的存在证明,但无法完成某个时间之前的。例如,你拿9月1号的报纸拍摄进照片,那么仅能证明其在9月1号之后拍摄,可能是9月1号,也可能是9月15号。

  比特币本质是构造了一个永不停息、无坚不摧的时间戳系统。

  

  然后该系统上添加若干特性后使得具有货币的功能。报纸从另一个角度讲也是一种时间戳服务。

  比特币具有下列优良的特性可以更完美的用于存在证明:

  不可预测/伪造。因block的计算是随机事件,其hash值是一个32字节的随机大数(2256)。想蒙对该数的概率实在是太低了。

  不可销毁/修改。Block Chain拥有巨大的算力在维护与延续,对于N个确认的block,想篡改是不可能的。

  block具有天然时间特性。timestamp是block meta字段之一。

  block可以存储信息。对于block meta信息,是无法控制的。但block会收录交易,而交易是可以”写入”自己的数据。

  简单来说,对一串数据进行Hash运算,得到的Hash值称为数字摘要。除了Hash函数,还有其他方式,如密钥签名等也可以得到。Hash值通常是一个非常巨大的数,例如用SHA256时,Hash值区间非常大:1~2256。数字摘要的计算过程不可逆,那么可以认为:

  欲证明你拥有某个文件,提供该文件的Hash值(及Hash函数)即可。第三方可以轻易验证文件的Hash值来判断之。

  因为block hash的不可伪造性,能提供Block Hash即可证明存在于该Block时刻之后。例如,你在拍照的时候,拿着打印有block hash的纸即可证明:你在该block时刻之后进行的拍摄。

  前向证明需要精心构造一个包含数字摘要的交易,待该交易进入block中。便可以证明你在该block时刻之前拥有该数字摘要。前向证明的关键是能把信息写入时间戳服务载体。

  有时候,仅仅证明时间点之前或之后是不够的,需要能够确认到某一个时刻。将上述方式综合即可完成:

  将block A的hash值添入数据文件,并制作文件数字摘要。(时间点后向证明)

  将摘要信息构造至交易中,广播之。(时间点前向证明)

  当交易被block B收录进去,那么即可证明,该文件于block A与B的时间间隔中存在。

  如果交易给了足够的矿工费(Transaction Fee),具有较高优先级的话,便很有可能被紧随其后的block收录。连续的block约10分钟,那么就在一个相对小的时间内作了证明,可以近似认为是时间点。

  带有数字摘要的交易如何构造呢?下面以32字节的数字摘要为例,提出数个可行方法,其他长度的可变换得出。

  32字节可以分割为16个双字节,每个双字节的数值范围是:0~65535。比特币的现行单位可以分割至小数点后八位,那么我们可以利用最后的5位来存放一个数值,一共需要16个输出(Tx output)即可完成32字节的信息存储。中间涉及比特币最大数量为:

  .00065535 * 16=.0104856 btc

  需要的比特币数量很少,约0.01Btc,且输出依然发回给自己的地址,唯一的代价就是付出矿工费(Tx Fee)。任何人都可以使用之。

  著名站点SatoshiDice就是采用这种方式为其服务端种子文件做时间前向证明的。下面演示一下步骤。服务端的种子文件为hash.keys,我们对其做SHA256运算,得到hash值,32个字节。

  $ sha256sum hash.keys

  # hash of file "hash.keys", in hex:

  9b0d87ac871518cfd8601aa456b58fa74c01194cfeb25e7f3eecf43759d6ccb4 hash.keys

  将该hash转为16个10进制数值:

  9b0d=39693

  87ac=34732

  8715=34581

  18cf=6351

  d860=55392

  1aa4=6820

  56b5=22197

  8fa7=36775

  4c01=19457

  194c=6476

  feb2=65202

  5e7f=24191

  3eec=16108

  f437=62519

  59d6=22998

  ccb4=52404

  将这16个数除以108,作为输出额度,构造交易:

  

  交易被收录,证明完成。

  回顾一下地址的生成算法(下图是一个未压缩公钥生成地址的过程,公钥是否压缩对该证明过程没有影响):

  

  我们用数字摘要的Hash值代替图中红色框中的值,然后得到一个地址,我们把0.00000001 btc打入该地址,形成交易,收录后完成证明。验证时,需要首先得到数字摘要hash值,再生成对应的地址,核对地址是否一致即可。

  这个方法有个缺点,打入该地址的币永远消失了,因为没有其对应的私钥。虽然可以只需1聪,目前价值几乎忽略不计,但毕竟浪费了。该方法可以进一步衍生一些类似的方法。曾有个网站使用之,后来该网站关闭了。

  大小介于1 ~ 0xFFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFE BAAE DCE6 AF48 A03B BFD2 5E8C D036 4141之间的数,都可以认为是一个合法的私钥,其大小为32字节。那么,可以把数字摘要的Hash作私钥,并推算出公钥和地址。

  将任意币值输出至该地址构成交易,交易收录后,通过私钥再转移走即可。这样便在block chain里留下了这个地址。验证时重复该过程,检查地址是否一致即可。

  该方法不会像方法二那样形成浪费,也比较容易操作。我们依然SatoshiDice的种子文件为例,种子数字摘要的Hash为:9b0d87ac871518cfd8601aa456b58fa74c01194cfeb25e7f3eecf43759d6ccb4。

  借助bitaddress.org,输入私钥(种子hash)后:

  

  得到两把公钥,分别对应两个地址。证明时将币打入任何一个地址即可,建议使用未压缩公钥地址,因为并不是所有客户端都对压缩公钥支持良好。然后将该私钥导入任何一个客户端,再把该地址的钱转移到一个安全的地方。最后,公开私钥和对应收录地址的交易。

  方法二浪费,应避免使用。方法一繁琐,需要工具辅助转换。方法三相对容易,门槛低一些,大部分客户端都支持,私钥公钥地址的推导也有很多工具支持。

  就这样比特币系统轻松的完成了存在证明,安全稳固,公信力远胜任何第三方、机构、政府。过程极其简单,使得任何一人都可以轻易地做出存在证明,其意义非常重大。可以预见,未来将比特币作为存在证明会得到广泛的应用。