比特币与区块链

(一):什么是区块链?

1、比特币的背景知识

随着信息技术的发展,人们的生活逐渐网络化,数字化。人类社会因此发生着深刻的变化。对数字货币的探索,就是在这样的背景下应运而生的。其实相关的研究在上世纪八九十年代,就开始了。

 

在数字货币的探索实践中,比特币是目前表现最好的一个。说到比特币的缘起,就不得不谈到一个略显神秘的团体:密码朋克(CypherPunk)。这个团体是密码天才们的松散联盟。在比特币的创新中,大量借鉴了密码朋克成员的贡献。

亚当·贝克(Adam Back)是一位英国的密码学家,1997年,他发明了哈希现金(hashcash)[i],其中用到了工作量证明机制(proof of work)。这个机制的原型是用于解决互联网垃圾信息问题的[ii]。工作量证明机制后来成为比特币的核心要素之一。密码朋克本身就是数字货币最早的传播者,在其电子邮件组中,常见关于数字货币的讨论,并有一些想法付诸实践。在比特币之前,有很多失败的尝试。在这里我们简要列举一些之前探路者。

  • 哈伯和斯托尼塔(Haber and Stornetta)在1997年提出了一个用时间戳的方法保证数字文件安全的协议[iii],这个协议成为比特币区块链协议的原型。
  • 戴伟(W Dai)是一位兴趣广泛的密码学专家,他在1998年发明了B-money[iv],B-money强调点对点的交易和不可更改的交易记录。不过在B-money中,每台计算机各自单独书写交易记录,这很容易造成系统被账本的不一致。戴伟为此设计了复杂的奖惩机制以防止作弊,但是并没有能从根本上解决问题。中本聪发明比特币的时候,借鉴了很多戴伟的设计,并和戴伟有很多邮件交流。
  • 哈尔·芬尼(Hal Finney))是PGP公司的一位顶级开发人员,也是密码朋克运动早期和重要的成员。2004年,芬尼推出了自己版本的电子货币,在其中采用了可重复使用的工作量证明机制(RPOW)。哈尔·芬尼是第一笔比特币转账的接受者,在比特币发展的早期与中本聪有大量互动与交流。由于身患绝症,哈尔·芬尼已于2014年去世。

2、比特币的诞生

2008年9月,以雷曼兄弟的倒闭为开端,金融危机在美国爆发并向全世界蔓延。为应对危机,各国政府采取量化宽松等措施,救助由于自身过失、陷入危机的大型金融机构。这些措施带来了广泛的质疑,并一度引发了“占领华尔街”运动。

2008年10月31日纽约时间下午2点10分,在一个普通的密码学邮件列表中,几百个成员均收到了自称是中本聪的人的电子邮件[v],“我一直在研究一个新的电子现金系统,这完全是点对点的,无需任何可信的第三方”,然后他将他们引向一个九页的白皮书,其中描述了一个新的货币体系。同年11月16日,中本聪放出了比特币代码的先行版本[vi]。

2009年1月3日,中本聪在位于芬兰赫尔辛基的一个小型服务器上挖出了比特币的第一个区块——创世区块(Genesis Block),并获得了首矿”奖励——50个比特币。在创世区块中,中本聪写下这样一句话:

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

“财政大臣站在第二次救助银行的边缘”

这句话是当天泰晤士报头版的标题。中本聪将它写进创世区块,不但清晰地展示着比特币的诞生时间,还表达着对旧体系的嘲讽。

如今,比特币已经成为数字货币领域的翘楚,拥有数十亿美元的市值,但中本聪却于2010年选择隐退。中本聪是谁,对每一个开始了解比特币的人,都是感兴趣的话题。从《纽约客》到《新闻周刊》,媒体们找到了数个自称是中本聪,或者被认为是中本聪的人。但无一例外,这些发现都因为可信度不足,遭到了读者甚至是中本聪本人的否定。中本聪是谁?也许我们永远不得而知。 

3、比特币与区块链

比特币已经在争议中走过了7年多的历程。在历史上,很少有这样一种东西,人们对待它的态度如此泾渭分明,支持者认为它将改变世界,反对者认为它毫无价值。望文生义,很容易得出后一个结论。“币”这个词虽然准确的描述了其金融属性,但由于过于形象,使得大多数人对于它如何能与完全虚拟的“比特”关联起来而大惑不解。 

其实,在比特币的系统中,最重要的并不是“币”的概念,而是一个没有中心存储机构的“账本”的概念。“币”只是在这个账本上使用的记账单位。可以这么说,比特币本质就是一个基于互联网的去中心化账本,而区块链就是这个账本的名字。这里我们可以做一个形象的类比,假如区块链是一个实物账本,一个区块就相当于账本中的一页,区块中承载的信息,就是这一页上记载的交易内容。

区块链是比特币的核心与基础架构,是一个去中心化的账本系统。

既然区块链是个账本,这个账本和我们传统的账本有什么不同?我们知道,账本上的内容必须是唯一的,这导致记账天然是中心化的行为。在通讯手段不发达的时代如此,在现今的信息时代也是如此。然而,中心化的记账却有一些显而易见的弱点:一旦这个中心出现问题,如被篡改、被损坏,整个系统就会面临危机乃至崩溃。

那么问题来了——我们能不能构建一个去中心化的不依赖任何第三方的但却可信的记账系统呢?去中心记账可以克服中心化账本的弱点,但是想实现这样的账本系统绝非易事。

在数字时代,负责记账的自然是计算机。这里,我们把记账系统中接入的每一台计算机称为“节点”。去中心化就是没有中心,也就是说参与到这个系统中的每个节点都是中心。从设计账本系统的角度,就是需要每个节点都保存一份完整的账本。然而,由于一致性的要求,每个节点却不能同时记账。因为节点所处的环境不同,接收到的信息自然不同,如果同时记账的话,必然会导致账本的不一致,造成混乱。

既然节点不能同时记账,那我们就不得不选择哪个节点拥有记账的权力。但是,如果指定某些特殊节点拥有记账的权力,势必又会与我们去中心化的初衷相违背。

这似乎成了不可能解决的问题。

竞争记账和激励机制

中本聪设计的比特币区块链通过竞争记账的方式解决了去中心化的记账系统的一致性问题。

前面提到,节点可以理解为接入系统中的计算机,而所谓的竞争记账,就是以每个节点的计算能力即“算力”来竞争记账权的一种机制。在比特币系统中,大约每十分钟进行一轮算力竞赛(算力大小会决定赢得一轮竞争的概率,算力高的节点赢得算力竞争的概率更大),竞赛的胜利者,就获得一次记账的权力,这样,一定时间内,只有竞争的胜利者才能记账并向其他节点同步新增账本信息。

那么,在一个去中心化的系统中,谁有权判定竞争的结果呢?比特币系统是通过一个称为“工作量证明”(proof of work, POW)的机制完成的。举个简单的例子,比如说要生产一些玩具,早上起来我给你一些零件,晚上回来,看到需要的玩具摆在桌上,虽然我没有从早到晚盯着你做玩具的过程,我也能确定你确实做了这么多工作。这就是工作量证明简单的理解——通过一个(人人都可以验证的)特定的结果就能确认(竞争的)参与者完成了相应的工作量。(关于POW的机制与实现细节,会在接下来的文章中详述)

算力竞争是要付出成本的,没有激励,节点就没有进行竞争的动力。在中本聪的设计里,每轮竞争胜出并完成记账的节点,将可以获得系统给予的一定数量的比特币奖励[vii]。而这个奖励的过程,同时也是比特币的发行过程。这种设计相当巧妙 —— 它将竞争的激励机制与货币的发行完美结合到一起,在引入竞争的同时,解决了去中心化货币系统中发行的难题。

在这个系统中,每一个节点只需要根据自身利益行事。出于“自私”的目的进行的竞争,最终造就了保护系统安全的庞大算力基础。在这样精巧的安排下,比特币获得了越来越多的信任,和越来越高的价值,进而又吸引了更多的资源投入其中,成为一个正向循环的经济系统。

正因为比特币通过区块链的机制造就了这样一个正向循环的经济系统,才会在没有强大的中心化机构推动的情况下,自然的生长出来并发展壮大。

读到这里,显然我们会发现,虽然区块链脱胎于比特币,但区块链无论作为一个系统还是作为一项技术,它的应用领域及发展潜力,将远不止货币。之后的文章,我们会通过更加深入的分析与讲解,带您深入到区块链的原理与实现细节。

作者介绍

张健,火币网技术副总裁,火币网数字货币与区块链研究中心负责人,国内首家区块链查询网站“区块”创始人,国内首个基于多重签名技术的比特币钱包“快钱包”创始人,火币网(Huobi.com)是全球领先的数字货币交易平台与服务提供商。区块(Qukuai.com)是国内最大的区块链查询及数据服务平台。

参考文档与备注

i] http://www.hashcash.org/papers/announce.txt

[ii] Dwork, CynthiaNaor, Moni (1993). “Pricing via Processing, Or, Combatting Junk Mail, Advances in Cryptology”CRYPTO’92: Lecture Notes in Computer Science No. 740 (Springer): 139–147.

[iii] S. Haber, W.S. Stornetta, “Secure names for bit-strings,” In Proceedings of the 4th ACM Conference on Computer and Communications Security, pages 28-35, April 1997. on Computer and Communications Security, pages 28-35, April 1997.

[iv] W Dai,a scheme for a group of untraceable digital pseudonyms to pay each other with money and to enforce contracts amongst themselves without outside help “B-money”,http://www.weidai.com/bmoney.txt, 1998

[v] http://www.mail-archive.com/[email protected]/msg09959.html

[vi] http://www.mail-archive.com/[email protected]/msg10142.html

[vii]记账奖励包括一个数量的比特币和该区块包含的所有交易的手续费。系统发放的记账奖励每四年进行一次减半。最开始为50币/区块,目前为25币/区块,以此类推,直到系统中的总币数达到2100万的上限。



(二):什么是工作量证明?



1. 起源

工作量证明(Proof Of Work,简称POW),简单理解就是一份证明,用来确认你做过一定量的工作。监测工作的整个过程通常是极为低效的,而通过对工作的结果进行认证来证明完成了相应的工作量,则是一种非常高效的方式。比如现实生活中的毕业证、驾驶证等等,也是通过检验结果的方式(通过相关的考试)所取得的证明。

工作量证明系统(或者说协议、函数),是一种应对拒绝服务攻击和其他服务滥用的经济对策。它要求发起者进行一定量的运算,也就意味着需要消耗计算机一定的时间。这个概念由Cynthia Dwork 和Moni Naor 1993年在学术论文中首次提出。而工作量证明(POW)这个名词,则是在1999年 Markus Jakobsson 和Ari Juels的文章中才被真正提出。

哈希现金是一种工作量证明机制,它是亚当·贝克(Adam Back)在1997年发明的,用于抵抗邮件的拒绝服务攻击及垃圾邮件网关滥用。在比特币之前,哈希现金被用于垃圾邮件的过滤,也被微软用于hotmail/exchange/outlook等产品中(微软使用一种与哈希现金不兼容的格式并将之命名为电子邮戳)。


2. 哈希函数
哈希现金也被哈尔·芬尼以可重复使用的工作量证明(RPOW)的形式用于一种比特币之前的加密货币实验中。另外,戴伟的B-money、尼克·萨博的比特金(Bit-Gold)这些比特币的先行者,都是在哈希现金的框架下进行挖矿的。

哈希函数(Hash Function),也称为散列函数,给定一个输入x,它会算出相应的输出H(x)。哈希函数的主要特征是:

  1. 输入x可以是任意长度的字符串
  2. 输出结果即H(x)的长度是固定的
  3. 计算H(x)的过程是高效的(对于长度为n的字符串x,计算出H(x)的时间复杂度应为O(n))

而对于比特币这种加密系统所使用的哈希函数,它需要另外具备以下的性质:

  1. 免碰撞,即不会出现输入x≠y,但是H(x)=H(y)

    其实这个特点在理论上并不成立,比如,比特币使用的SHA256算法,会有2^256种输出,如果我们进行2^256+1次输入,那么必然会产生一次碰撞;甚至从概率的角度看,进行2^130次输入就会有99%的可能发生一次碰撞。不过我们可以计算一下,假设一台计算机以每秒10000次的速度进行哈希运算,要经过10^27年才能完成2^128次哈希!甚至可以这么说,即便是人类制造的所有计算机自宇宙诞生开始一直运算到今天,发现碰撞的几率也是极其小的。

  2. 隐匿性,也就是说,对于一个给定的输出结果H(x),想要逆推出输入x,在计算上是不可能的。
  3. 不存在比穷举更好的方法,可以使哈希结果H(x)落在特定的范围。

以上特点是比特币的工作量证明系统可以正常运行的基石。

3. 工作量证明的基本原理

工作量证明系统主要特征是客户端需要做一定难度的工作得出一个结果,验证方却很容易通过结果来检查出客户端是不是做了相应的工作。这种方案的一个核心特征是不对称性:工作对于请求方是适中的,对于验证方则是易于验证的。它与验证码不同,验证码的设计出发点是易于被人类解决而不易被计算机解决。

下图表示的是工作量证明的流程:

举个例子,给定的一个基本的字符串”Hello, world!”,我们给出的工作量要求是,可以在这个字符串后面添加一个叫做nonce的整数值,对变更后(添加nonce)的字符串进行SHA256哈希运算,如果得到的哈希结果(以16进制的形式表示)是以”0000”开头的,则验证通过。为了达到这个工作量证明的目标。我们需要不停的递增nonce值,对得到的新字符串进行SHA256哈希运算。按照这个规则,我们需要经过4251次计算才能找到恰好前4位为0的哈希散列。

"Hello, world!0" => 1312af178c253f84028d480a6adc1e25e81caa44c749ec81976192e2ec934c64
"Hello, world!1" => e9afc424b79e4f6ab42d99c81156d3a17228d6e1eef4139be78e948a9332a7d8
"Hello, world!2" => ae37343a357a8297591625e7134cbea22f5928be8ca2a32aa475cf05fd4266b7
...
"Hello, world!4248" => 6e110d98b388e77e9c6f042ac6b497cec46660deef75a55ebc7cfdf65cc0b965
"Hello, world!4249" => c004190b822f1669cac8dc37e761cb73652e7832fb814565702245cf26ebb9e6
"Hello, world!4250" => 0000c3af42fc31103f1fdc0151fa747ff87349a4714df7cc52ea464e12dcd4e9

通过这个示例我们对工作量证明机制有了一个初步的理解。有的人会认为如果工作量证明只是这样的一个过程,那是不是只需要记住nonce为4521计算能通过验证就行了?当然不是的,这只是一个个例。

下面,我们将输入简单的变更为”Hello, world+整数值”,整数值取1到1000,也就是说,将输入变成一个由1000个值组成的数组:”Hello, world!1、Hello, world!2……Hello, world!1000”。然后对数组中的每一个输入依次进行上面例子中要求的工作量证明——找到前导为4个0的哈希散列。

容易算出,预期大概要进行2^16次尝试(哈希值的伪随机特性使得我们可以做概率估算),才能得到4个前导0的哈希散列。而统计一下刚才进行的1000次计算的实际计算结果,我们会发现,进行计算的平均次数为66958次,十分接近2^16(65536)。在这个例子中,数学期望的计算次数,就是我们要求的“工作量”,重复多次进行的工作量证明会是一个符合统计学规律的概率事件。

统计输入的字符串与对应得到目标结果实际使用的计算次数列表如下:

Hello, world!1 => 42153
Hello, world!2 => 2643
Hello, world!3 => 32825
Hello, world!4 => 250
Hello, world!5 => 7300
...
Hello, world!995 => 164819
Hello, world!996 => 178486
Hello, world!997 => 22798
Hello, world!998 => 68868
Hello, world!999 => 46821

比特币体系里的工作量证明机制与上述示例类似,但要比它更复杂一些。

4. 比特币中的工作量证明

比特币网络中任何一个节点,如果想生成一个新的区块并写入区块链,必须解出比特币网络出的工作量证明的迷题。这道题关键的三个要素是工作量证明函数、区块及难度值。工作量证明函数是这道题的计算方法,区块决定了这道题的输入数据,难度值决定了这道题的所需要的计算量。

4.1工作量证明函数

和我们上节例子中用到的哈希函数一样,比特币系统中使用的工作量证明函正是SHA256。

SHA是安全散列算法(Secure Hash Algorithm)的缩写,是一个密码散列函数家族。这一组函数是由美国国家安全局(NSA)设计,美国国家标准与技术研究院(NIST) 发布的,主要适用于数字签名标准。SHA256就是这个函数家族中的一个,是输出值为256位的哈希算法。到目前为止,还没有出现对SHA256算法的有效攻击。

4.2 区块

比特币的区块由区块头及该区块所包含的交易列表组成。区块头的大小为80字节,由4字节的版本号、32字节的上一个区块的散列值、32字节的Merkle Root Hash、4字节的时间缀(当前时间)、4字节的当前难度值、4字节的随机数组成。区块包含的交易列表则附加在区块头后面,其中的第一笔交易是coinbase交易,这是一笔为了让矿工获得奖励及手续费的特殊交易。

区块的大致结构如图所示:

拥有80字节固定长度的区块头,就是用于比特币工作量证明的输入字符串。因此,为了使区块头能体现区块所包含的所有交易,在区块的构造过程中,需要将该区块要包含的交易列表,通过Merkle Tree算法生成Merkle Root Hash,并以此作为交易列表的摘要存到区块头中。其中Merkle Tree的算法图解如下:

4.3难度值

难度值(difficulty)是矿工们在挖矿时候的重要参考指标,它决定了矿工大约需要经过多少次哈希运算才能产生一个合法的区块。比特币的区块大约每10分钟生成一个,如果要在不同的全网算力条件下,新区块的产生保持都基本这个速率,难度值必须根据全网算力的变化进行调整。简单地说,难度值被设定在无论挖矿能力如何,新区块产生速率都保持在10分钟一个。

难度的调整是在每个完整节点中独立自动发生的。每2016个区块,所有节点都会按统一的公式自动调整难度,这个公式是由最新2016个区块的花费时长与期望时长(期望时长为20160分钟即两周,是按每10分钟一个区块的产生速率计算出的总时长)比较得出的,根据实际时长与期望时长的比值,进行相应调整(或变难或变易)。也就是说,如果区块产生的速率比10分钟快则增加难度,比10分钟慢则降低难度。

这个公式可以总结为如下形式:

新难度值 = 旧难度值 * ( 过去2016个区块花费时长 / 20160 分钟 )

工作量证明需要有一个目标值。比特币工作量证明的目标值(Target)的计算公式如下:

目标值 = 最大目标值 / 难度值
其中最大目标值为一个恒定值:
0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF

目标值的大小与难度值成反比。比特币工作量证明的达成就是矿工计算出来的区块哈希值必须小于目标值。

与第3节所举的例子相类比,我们也可以简单理解成,比特币工作量证明的过程,就是通过不停的变换区块头(即尝试不同的nouce值)作为输入进行SHA256哈希运算,找出一个特定格式哈希值的过程(即要求有一定数量的前导0)。而要求的前导0的个数越多,代表难度越大。

4.4 工作量证明的过程

我们可以把比特币矿工解这道工作量证明迷题的步骤大致归纳如下:

  1. 生成Coinbase交易,并与其他所有准备打包进区块的交易组成交易列表,通过Merkle Tree算法生成Merkle Root Hash
  2. 把Merkle Root Hash及其他相关字段组装成区块头,将区块头的80字节数据(Block Header)作为工作量证明的输入
  3. 不停的变更区块头中的随机数即nonce的数值,并对每次变更后的的区块头做双重SHA256运算(即SHA256(SHA256(Block_Header))),将结果值与当前网络的目标值做对比,如果小于目标值,则解题成功,工作量证明完成。

该过程可以用下图表示:

5. 结语

比特币的工作量证明,就是我们俗称“挖矿”所做的主要工作。理解工作量证明机制,将为我们进一步理解比特币区块链的共识机制奠定基础。在之后的文章中,我们将会详细介绍比特币交易和区块的结构及同步过程、最长链机制以及达成共识的原理。



(三):比特币的私钥、公钥与地址

地址、交易、区块、网络是区块链数据里面最基本最重要的概念。地址用来标示一笔交易的支出方和接收方。所有的交易最终需要被记到统一的账本——区块链上,而这个账本是通过区块确认并完成的。每一个新区块,都会被打上时间戳,最终生成依照时间前后排列并加以记录。每个独立节点之间又通过比特币网络来建立联系,这样就为电子交易记录建立了一个去中心化、分布式的时间戳服务器系统。

很复杂,在这一节,我们先讲地址。

1、公钥密码学

讲到地址,我们就不得不先说一说密码学,作为保护信息传输安全的技术手段,密码在人类社会中的应用源远流长,凯撒密码是古典密码的典型代表,它的基本思想是通过字符的代换来实现加解密。因此古典密码的安全性主要依赖加密算法本身的安全性,如果算法泄露了,要加密的信息也就没有秘密可言了。


1949年香农发表了《保密系统的信息理论》,为对称密码系统建立了理论基础,带来了加密传输基于秘钥安全而不是基于加密算法安全的理论和技术变革。这是密码学发展的里程碑,标志着现代密码学时代的来临。
如今密码学相关技术已经深入各个领域,它们的理论共识都遵循由奥古斯特•柯克霍夫在19世纪提出“柯克霍夫原则”—— 密码系统应该即使被所有人知道其运作步骤,仍然是安全的。即算法是公开的,唯一需要保护的是密钥。

公钥密码学兴起之前,对称加密是主流的加密模式,人们基于秘钥来对信息进行加解密,通常情况下,密钥越长,代表着密文被破解的难度越大。由于加密算法和解密算法都是同一模式,只有一把密钥保证加密数据的安全,因此这种加密算法也叫做“对称加密算法”。对称加密有一个最大弱点:甲方必须把密钥告诉乙方,否则乙方无法解密。而保存和传递密钥,就成了最头疼的问题。

公钥密码学是现代密码学最重要的进展。公钥密码学可以在不直接传递密钥的情况下,完成密文的解密。加密和解密可以使用不同的规则,只要这两种规则之间存在某种对应关系即可,系统的安全性既不依赖算法的保密,也不用直接传递密钥。基于这种公钥机制的思想,开始出现了一系列非对称加密算法。

1976年Whitfield Diffie & Martin Hellman首次提出了基于数学难题的公钥密码机制,1978年RSA公钥密码机制的出现,成为公钥密码的杰出代表并成为事实标准,在密码学史上创造了又一个新的里程碑。90年代公钥密码学进一步发展,基于椭圆曲线乘法、素数幂等数学函数的公钥算法诞生,使得数字密钥和不可伪造的数字签名成为可能。

数据签名算法的核心在于证明数据的发送方是签名者发出的、不可抵赖,而不是待签名数据的保密性。

下图比较说明非对称加密与对称加密算法的区别:

非对称加密需要两个(一对)密钥:公开密钥(publickey)和私有密钥(privatekey),用公钥对数据进行加密后,只有对应的私钥才能解密;反之如果私钥用于加密,则只有对应的公钥才能解密。通信双方无须交换密钥就可以建立保密通信。

公钥算法用到的是私钥与公钥,他们和比特币体系中常常说到的地址有什么关系?在比特币系统中,私钥由32字节的随机数组成,通过私钥可以算出公钥,公钥经过一系列哈希及编码算法就得到了比特币中的地址。所以地址其实是公钥的另一种表现形式,可以理解为公钥的摘要。

2、相关的加密算法

在私钥、公钥及地址的相关运算中,用到了基于secp256k1椭圆曲线乘法的签名算法、SHA-256、RIPEMD-160,和Base58编码。

2.1椭圆曲线签名算法

椭圆曲线在密码学中的使用是在1985年由Neal Koblitz和Victor Miller分别独立提出的。它的主要优势是在某些情况下它比其他的算法(比如RSA)使用更小的密钥但提供相当的或更高等级的安全性。

比特币使用了基于secp256k1椭圆曲线数学的公钥密码学算法。它包含私钥与公钥,私钥用于对交易进行签名,将签名与原始数据发送给整个比特币网络,公钥则用于整个网络中的节点对交易有效性进行验证。签名算法保证了交易是由拥有对应私钥的人所发出的。

2.2 哈希函数

SHA-256是一种哈希函数,已经在上一节的讲解中做了介绍,这里不再赘述[1]

RIPEMD-160也是在生成地址时用到的一种哈希函数,其输出长度为20字节(160位)。比特币用它减少标识接收方的字节数。

2.3 Base58编码

可读性编码算法,类似古典密码学里的置换算法,理论上并不是密码学理论的核心内容。可读性编码算法不是为了保护数据的安全性,而是为了可读性。以二进制进行传输的信息是不具备可读性的,数字与字母组成的字符串才更容易被识别。可读性编码不改变信息内容,只改变信息内容的表现形式(部分编码算法还加入了容错校验功能,以保证传输过程中数据的准确性和完整性)。

Base64是常见的可读性编码算法,所谓Base64,即是说在编码过程中使用了64种字符:大写A到Z、小写a到z、数字0到9、“+”和“/”。

Base58是Bitcoin中使用的一种编码方式,主要用于产生Bitcoin的钱包地址。相比Base64,Base58不使用数字”0”,字母大写”O”,字母大写”I”,和字母小写”i”,以及”+”和”/”符号。

设计Base58主要的目的是:

  1. 避免混淆。在某些字体下,数字0和字母大写O,以及字母大写I和字母小写l会非常相似。
  2. 不使用”+”和”/”的原因是,非字母或数字的字符串难以作为账号的一部分被接受。
  3. 没有标点符号,通常不会被从中间分行。
  4. 使大部分的软件支持双击选择整个字符串。

比特币中使用Base58算法来对公钥的Hash160及私钥进行编码,以生成以1或3开头的比特币地址及WIF(Wallet import Format)格式的私钥。

3、私钥与公钥

比特币私钥其实是使用SHA-256生成的32字节(256位)的随机数,有效私钥的范围则取决于比特币使用的secp256k1 椭圆曲线数字签名标准。大小介于0x1 到0xFFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFE BAAE DCE6 AF48 A03B BFD2 5E8C D036 4140之间的数几乎都是合法的私钥。

在私钥的前面加上版本号,后面添加压缩标志和附加校验码,(所谓附加校验码,就是对私钥经过2次SHA-256运算,取两次哈希结果的前四字节),然后再对其进行Base58编码,就可以得到我们常见的WIF(Wallet import Format)格式的私钥。

私钥经过椭圆曲线乘法运算,可以得到公钥。公钥是椭圆曲线上的点,并具有x和y坐标。公钥有两种形式:压缩的与非压缩的。早期比特币均使用非压缩公钥,现在大部分客户端默认使用压缩公钥。

由于数学原理,从私钥推算公钥是可行的,从公钥逆推私钥是不可能的。

初识比特币的人常有一种误解,认为比特币公钥就是地址,这是不正确的。从公钥到地址还要经过一些运算。

4、地址的生成

椭圆曲线算法生成的公钥信息比较长,压缩格式的有33字节,非压缩的则有65字节。地址是为了减少接收方所需标识的字节数。比特币地址的生成步骤如下:

  1. 生成私钥与公钥
  2. 将公钥通过SHA256哈希算法处理得到32字节的哈希值
  3. 后对得到的哈希值通过RIPEMD-160算法来得到20字节的哈希值 —— Hash160
  4. 把版本号[2]+Hash160组成的21字节数组进行双次SHA256哈希运算,得到的哈希值的头4个字节作为校验和,放置21字节数组的末尾。
  5. 对组成25位数组进行Base58编码,就得到地址。

下图以非压缩格式的65字节公钥示意上述过程:

由于椭圆曲线乘法以及哈希函数的特性,我们可以从私钥推导出公钥,也可以从公钥推导出地址,而这个过程是不可逆的。也正因如此,在整个比特币系统中,私钥是最关键的部分。私钥泄露也就意味着丢失了一切。

我们要花掉一个地址上的资产,需要构造一笔交易,同时使用这个地址对应的私钥签名。而如果我们要将资产转移到某个地址上,只需要转账给他公开的地址就行了。

在下一节,我们将详细讲述比特币交易是如何构成和实现的。


[1] http://www.infoq.com/cn/articles/bitcoin-and-block-chain-part02

[2] 普通地址P2PKH的版本默认值是0,P2SH类型的地址版本默认值是5


(四):比特币的交易

在比特币区块链中,交易是最核心的内容。通过前面的讲述,我们知道,比特币通过基于密码学的公私钥体系,交易的发起者可以使用自己的私钥对交易进行签名,其他人可以使用其公钥进行验证,这就从数学上保证了用户资金的安全。那么其交易具体是怎么构建的呢?

简化模型

在中本聪的白皮书里,比特币被定义成一个链式的数字签名串。币的拥有者通过对前一次交易和下一次拥有者的公钥签署一个数字签名,并将这个签名附加在这笔交易的当中,来完成一笔转账。而转账的收款人通过对签名进行验证,就能够验证该链条的所有者是不是发送方。

交易的运作图如下:

这样设计的交易体系的问题在于收款人很难校验之前的某位资产拥有者是否进行了双重支付(双花)。通常的解决方案是引入可信的第三方,如银行,来对每一笔交易进行检验,以防止双重支付。而如果想要排除第三方中介机构,那么交易信息就应当被公开,需要整个系统内的所有参与者,都有唯一公认的历史交易序列。收款人需要确保在交易期间绝大多数的节点都认同该交易是首次出现。

账本系统不以“账户”为基础

比特币区块链本质上可以说是一个基于互联网的去中心化的账本系统,而这个账本上记载的,就是一笔笔比特币地址之间的转账交易,一笔具体的交易过程如上面所示,那整个系统该如何构建呢?。


常常有一种简单化的说法,将比特币公钥类比为用户的银行卡号,也即用户的账户。那么最容易想到的交易系统的记录方式是以账户为基础的,简化的示意图类似这样:

这种记账方式是最容易想到的,然而比特币区块链并没有采用这种方式。重要的事情说三遍,比特币的交易系统不是这样的,不是这样的,不是这样的。原因很简单,如果采用这种记账方式的话,每当要进行一笔新交易的时候,系统都不得不回溯该所有交易历史,这样才能确定最新的这笔交易是不是合法,如上图所示,用户C有这些钱吗?当系统庞大、交易数量众多的时候,每次都进行这样的检验无疑是笨重低效的。

那么比特币的交易系统是怎样构建的呢?

UTXO是比特币交易的基本单位

UTXO(Unspent Transaction Outputs)是未花费的交易输出,它是比特币交易生成及验证的一个核心概念。交易构成了一组链式结构,所有合法的比特币交易都可以追溯到前向一个或多个交易的输出,这些链条的源头都是挖矿奖励,末尾则是当前未花费的交易输出。所有的未花费的输出即整个比特币网络的UTXO。

比特币规定每一笔新的交易的输入必须是某笔交易未花费的输出,每一笔输入同时也需要上一笔输出所对应的私钥进行签名,并且每个比特币的节点都会存储当前整个区块链上的UTXO,整个网络上的节点通过UTXO及签名算法来验证新交易的合法性。这样,节点不需要追溯历史就可以验证新交易的合法性。

交易的输入与输出

比特币的交易,并不是通常意义的一手交钱一手交货的交易,而是转账。如果每一笔转账都需要构造一笔交易数据会比较笨拙,为了使得价值易于组合与分割,比特币的交易被设计为可以纳入多个输入和输出。即一笔交易可以转账给多个人。从生成到在网络中传播,再到通过工作量证明、整个网络节点验证,最终记录到比特币的区块链,就是交易的整个生命周期。

交易的本质是一个包含交易发送方、接收方、资产转移等相关信息的数据结构,其数据结构如下:

字段

描述

大小

版本

这笔交易参照的规则

4 字节

输入数量

交易输入列表的数量

1 - 9 字节

输入列表

一个或多个交易输入

不定

输出数量

交易输出列表的数量

1 - 9 字节

输出列表

一个或多个交易输出

不定

锁定时间

锁定时间

4 字节

从整体结构来看,交易主要的两个单元字段就是交易的输入与输出。输入标识着交易的发送方,输出标识着交易的接收方及对于自己的找零,交易的手续费则是输入的总和与输出的总和之差。由于所有的交易输入必然是前面某笔交易的输出,所以交易最核心的字段是交易的输出。

一笔交易的数据结构图如下所示:

比特币的交易输入(TxIn)有三种,分别是Standard TxIn(标准输入)、Spend Coinbase TxOut(花费挖矿奖励)、Coinbase/Generation(产生挖矿奖励),下图分别描述了这三种TxIn的结构:

比特币的交易输出(TxOut Script)有两种,分别是Standard TxOut (标准交易输出)、Coinbase TxOut (挖矿奖励输出),下图分别描述了这两种TxOut的结构:

脚本

脚本是交易里另一个比较重要的技术。每一笔交易的每一项输出严格意义上并不是指向一个地址,而是指向一个脚本。脚本类似一套规则,它约束着接收方怎样才能花掉这个输出上锁定的资产。

交易的合法性验证也依赖于脚本。目前它依赖于两类脚本:锁定脚本与解锁脚本。锁定脚本是基于可变的模式,通过一段脚本语言来实现,位于交易的输出。解锁脚本与锁定脚本相对应,只有按锁定脚本的规则去解,才能花掉这个脚本上对应的资产,位于交易的输入。脚本语言可以表达出无数的条件变种。这也是比特币作为一种“可编程的货币”所拥有的特性。而解释该脚本是通过类似我们编程领域里的“虚拟机”,它分布式运行在比特币网络里的每一个节点。

比特币的脚本目前常用的主要分为两种,一种是普通的类型P2PKH(Pay-to-Public-Key-Hash),即支付给公钥的哈希即地址,接收方只需要使用地址对应的私钥对该输出进行签名,即可花掉该输出。另一种是P2SH(Pay-to-Script-Hash),支付脚本的哈希。拿多重签名来举例,它要求该输出同时要有N把私钥中的M把私钥(M<=N)同时签名才能花掉该资产,它类似于现实生活中需要多把钥匙才能同时打开的保险柜,只是更加灵活。

比如在比特币中,P2PKH的脚本规则如下:

Pubkey script: OP_DUP OP_HASH160 <PubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
Signature script: <sig> <pubkey> 

P2SH的脚本规则如下:

Pubkey script: OP_HASH160 <Hash160(redeemScript)> OP_EQUAL
Signature script: <sig> [sig] [sig...] <redeemScript>

在上述的2种脚本规则里,Pubkey script代表着锁定脚本,Signature script代表着解锁脚本。OP_开头的单词是相关的脚本命令,也是”虚拟机”所能解析的指令。这些命令规则根据Pubkey script的不同来进行划分,它也决定着解锁脚本的规则。

比特币中的脚本机制相对简单,只是一个基于堆栈式的,解释相关OP指令的引擎,能够解析的脚本规则并不是太多,不能实现很复杂的逻辑。但它为区块链可编程提供了一个原型,后续一些可编程区块链项目其实是基于脚本的原理发展起来的,比如以太坊,就是深入强化了脚本机制,脚本机制里不再单单是简单的OP指令,而是支持脚本语言,该脚本语言可以通过”虚拟机”去执行。以太坊实现了一个支持图灵完备脚本语言的区块链平台。

脚本的机制对于区块链来说非常重要,它类似于区块链技术提供的一个扩展接口,任何人都可以基于这个接口,去开发基于区块链技术的应用,比如智能合约的功能。脚本机制也让区块链技术作为一项底层协议成为可能。未来很多基于区块链的颠覆性应用,都有可能是通过区块链的脚本语言来完成的。

以上简述了比特币区块链中交易的过程和相关的重要概念。限于篇幅,在这里省略了一些可以拓展的内容。到目前为止,我们讲述的内容,包括上一节讲述的公私钥,都是与用户的使用直接相关的。关于区块链的共识机制、系统安全等广大读者关心的问题,我们会在之后的文章中为您讲解。


(五):深入理解比特币交易的脚本


本文作者为火币区块链研究中心技术专家廖雪峰,他有十年软件开发经验,精通Java/Python/Ruby/Visual Basic/Objective C/Lisp等编程语言,对开源框架有深入研究,著有《Spring 2.0核心技术与最佳实践》一书,并有多个业余开源项目托管在GitHub。本文中廖雪峰详细地介绍了比特币及比特币区块链的相关知识。

在比特币区块链中,每一个区块都指向上一个区块,这些通过SHA256计算的区块哈希链就是比特币账本不可篡改的基础。

在一个区块中,比特币系统用交易(Transaction)来表示一笔比特币交易。一个区块包含至少一笔交易。这些Transaction的Hash通过Merkle Tree计算出所有交易的Merkle Hash,并被包含至区块Hash中,从而实现交易的不可修改。

如果我们仔细观察每一笔交易,可以发现,除了第一笔交易是矿工的挖矿所得外,每一笔交易都拥有一个或多个输入(TxIn),以及一个或多个输出(TxOut):

第一笔矿工挖矿的收入交易通常被称为Coinbase,它没有输入,所以TxIn的Hash总是被标记为00000000…0000

其他的交易,任何一个TxIn都会唯一追溯到区块链上在本区块之前的某个交易Hash,以及索引:

通过交易Hash和索引(从0开始),即可唯一确定一个未花费的交易输出——UTXO(Unspent Transaction Output)。这样,每一个Tx Input都和之前的某个Tx Output关联了起来。

我们假设在上一笔交易中,Bob给Alice支付了0.15个BTC。

由于比特币并没有账户的概念,这一笔交易的输出并没有写上Alice的名字,也没有写上Alice的公钥。

那么,Alice想要花费这0.15个BTC,她应该如何证明自己拥有这个UTXO,并且,其他人无法假冒Alice来花费这个UTXO呢?

答案是比特币的交易创建的输出其实并非一个简单的公钥地址,而是一个脚本。在Bob给Alice支付0.15个BTC的这个交易中,Bob创建的输出脚本类似:

OP_DUP OP_HASH160 abcd1234...9876 OP_EQUALVERIFY OP_CHECKSIG

其中,abcd1234…9876是Alice的公钥Hash。整个脚本的意思是,谁能够提供一个签名和一个公钥,让这个脚本运行通过,谁就能花费这笔交易的1.5个BTC。

由于创建签名只能使用Alice的私钥,非Alice的私钥创建的签名将无法通过这个脚本的验证,所以,其他人无法假冒Alice来花费这笔输出。

一旦Alice提供了一个签名和自己的公钥,她实际上已经创建了另一笔交易来花费这个输出。

所有人都可以验证Alice创建的这个新交易是否有效。如果有效,该交易就会被矿工打包进新的区块,从而成为区块链上不可更改的一部分。

我们以著名的Pizza Transaction为例,来验证一个交易是否是有效的。

在交易cca75078…4d79中,唯一的TxIn输入提供的sigScript是:

8b4830450221009908144ca6539e09512b9295c8
a27050d478fbb96f8addbc3d075544dc41328702
201aa528be2b907d316d2da068dd9eb1e23243d9
7e444d59290d2fddf25269ee0e0141042e930f39
ba62c6534ee98ed20ca98959d34aa9e057cda01c
fd422c6bab3667b76426529382c23f42b9b08d78
32d4fee1d6b437a8526e59667ce9c4e9dcebcabb

该sigScript实际上由两部分构成:

签名:30450221…ee0e01(71字节+1字节签名类型),实际签名是去掉最后一个字节01的30450221…ee0e,签名类型是SIGHASH_ALL(0x01)。

公钥:042e930f…cabb(65字节)

为了验证该交易是否有效,我们首先要根据TxIn所声明的Previous Output Hash:a1075db5…d48d和索引0找到上一笔交易的输出:

https://webbtc.com/tx/a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d

这笔交易输出的脚本是:

1976a91446af3fb481837fadbb421727f9959c2d32a3682988ac

比特币的脚本由一系列指令和数据构成,每个指令占用一个字节,数据由数据头部的长度决定。上述二进制脚本翻译后的比特币指令如下:

OP_DUP OP_HASH160 46af3fb481837fadbb421727f9959c2d32a36829 OP_EQUALVERIFY OP_CHECKSIG

现在,我们有了签名,公钥和脚本:

sig: 30450221...ee0e01
pubkey: 042e930f...cabb
OP_DUP OP_HASH160 46af3fb4…6829 OP_EQUALVERIFY OP_CHECKSIG

就可以运行这个脚本来验证交易是否有效。

比特币脚本被设计成以栈来运行的虚拟机指令,它只有有限的几种指令,并且故意被设计成没有循环、条件跳转,所以,比特币脚本不是图灵完备的语言。

比特币脚本的执行非常简单。我们首先要准备一个空栈,然后把签名和公钥入栈:

紧接着,我们就可以执行TxOut的脚本:

OP_DUP OP_HASH160 46af3fb481837fadbb421727f9959c2d32a36829 OP_EQUALVERIFY OP_CHECKSIG

首先执行OP_DUP,这条指令把栈顶的元素复制一份,所以结果变成:

紧接着执行OP_HASH160,它对栈顶元素计算SHA256/RipeMD160,实际上是计算公钥Hash,所以运行结果变成:

接下来的指令实际上是一个数据,我们直接把数据入栈:

然后,执行OP_EQUALVERIFY,这条指令会比较栈顶的两个元素是否相等,如果不等,整个脚本就执行失败了,如果相等,脚本会继续执行,所以运行结果变成:

最后,执行指令OP_CHECKSIG,这条指令会验证签名。首先,我们根据签名类型SIGHASH_ALL(0x01)对整个交易进行验证。验证方法是:

把当前Transaction的所有TxIn的scriptSig去掉(红色部分),并把当前TxIn的scriptSig替换为UTXO的script(蓝色部分),调整长度字段(绿色部分):

最后加上小端序4字节的签名类型0x01(灰色部分),计算两次SHA256,我们得到:

c2d48f45…2669

现在,使用ECDSA算法对签名进行验证:

boolean ecdsa_verify_signature(byte[] message, byte[] signature, byte[] pubkey)

根据签名的验证结果,我们即可确认该交易是否有效。

由于引入了脚本,我们可以看到,比特币实际上通过编程脚本实现了一个严格以计算机程序验证为基础的数字货币所有权的转移机制。由于计算机程序的可扩展性,比特币支付其实并不限定在必须支付给某一个公钥地址。利用脚本,我们可以构造出各种支付条件,例如,多重签名验证条件:

2 <public-key1> <public-key2> <public-key3> 3 OP_CHECKMULTISIGN

这种提供多个公钥地址,并且需要多个签名验证的多重签名脚本,允许在M个签名种至少给出N个签名即可使用。上述脚本允许提供3个公钥地址中的任意两个有效签名。

当我们把比特币托管在某个第三方的在线钱包中时,就可以使用多重签名来保证只有自己和第三方钱包共同签名后才可动用输出,这样保证了黑客在攻击了第三方钱包后也无法花掉用户的比特币。

通过OP_CHECKLOCKTIMEVERIFY,我们可以指定一个交易的锁定时间,在此之前,该交易输出无法被花掉。这个指令其实实现了支付宝的7天资金锁定然后再支付给卖家的功能。

还有一些交易并没有指定一个公钥Hash,例如,这个交易的脚本如下:

OP_HASH256 6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000 OP_EQUAL

它的意思是说,谁能够提供一个数据,它的SHA256是6fe28c0a…0000,谁就可以花费这笔交易。

(注:该交易已经被花费了,有人找到了符合条件的数据)

从比特币的脚本,我们可以看到,基于区块链的数字货币支付实际上是数字货币所有权的安全转移。如果我们把金融资产或者实物资产以数字化的形式登记在区块链上,通过脚本就可以安全实现各种条件下的所有权转移,这正是智能合约在区块链上的应用。

出处:火币区块链研究中心。转载需注明来源!


(一):什么是区块链?

1、比特币的背景知识

随着信息技术的发展,人们的生活逐渐网络化,数字化。人类社会因此发生着深刻的变化。对数字货币的探索,就是在这样的背景下应运而生的。其实相关的研究在上世纪八九十年代,就开始了。

 

在数字货币的探索实践中,比特币是目前表现最好的一个。说到比特币的缘起,就不得不谈到一个略显神秘的团体:密码朋克(CypherPunk)。这个团体是密码天才们的松散联盟。在比特币的创新中,大量借鉴了密码朋克成员的贡献。

亚当·贝克(Adam Back)是一位英国的密码学家,1997年,他发明了哈希现金(hashcash)[i],其中用到了工作量证明机制(proof of work)。这个机制的原型是用于解决互联网垃圾信息问题的[ii]。工作量证明机制后来成为比特币的核心要素之一。密码朋克本身就是数字货币最早的传播者,在其电子邮件组中,常见关于数字货币的讨论,并有一些想法付诸实践。在比特币之前,有很多失败的尝试。在这里我们简要列举一些之前探路者。

  • 哈伯和斯托尼塔(Haber and Stornetta)在1997年提出了一个用时间戳的方法保证数字文件安全的协议[iii],这个协议成为比特币区块链协议的原型。
  • 戴伟(W Dai)是一位兴趣广泛的密码学专家,他在1998年发明了B-money[iv],B-money强调点对点的交易和不可更改的交易记录。不过在B-money中,每台计算机各自单独书写交易记录,这很容易造成系统被账本的不一致。戴伟为此设计了复杂的奖惩机制以防止作弊,但是并没有能从根本上解决问题。中本聪发明比特币的时候,借鉴了很多戴伟的设计,并和戴伟有很多邮件交流。
  • 哈尔·芬尼(Hal Finney))是PGP公司的一位顶级开发人员,也是密码朋克运动早期和重要的成员。2004年,芬尼推出了自己版本的电子货币,在其中采用了可重复使用的工作量证明机制(RPOW)。哈尔·芬尼是第一笔比特币转账的接受者,在比特币发展的早期与中本聪有大量互动与交流。由于身患绝症,哈尔·芬尼已于2014年去世。

2、比特币的诞生

2008年9月,以雷曼兄弟的倒闭为开端,金融危机在美国爆发并向全世界蔓延。为应对危机,各国政府采取量化宽松等措施,救助由于自身过失、陷入危机的大型金融机构。这些措施带来了广泛的质疑,并一度引发了“占领华尔街”运动。

2008年10月31日纽约时间下午2点10分,在一个普通的密码学邮件列表中,几百个成员均收到了自称是中本聪的人的电子邮件[v],“我一直在研究一个新的电子现金系统,这完全是点对点的,无需任何可信的第三方”,然后他将他们引向一个九页的白皮书,其中描述了一个新的货币体系。同年11月16日,中本聪放出了比特币代码的先行版本[vi]。

2009年1月3日,中本聪在位于芬兰赫尔辛基的一个小型服务器上挖出了比特币的第一个区块——创世区块(Genesis Block),并获得了首矿”奖励——50个比特币。在创世区块中,中本聪写下这样一句话:

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

“财政大臣站在第二次救助银行的边缘”

这句话是当天泰晤士报头版的标题。中本聪将它写进创世区块,不但清晰地展示着比特币的诞生时间,还表达着对旧体系的嘲讽。

如今,比特币已经成为数字货币领域的翘楚,拥有数十亿美元的市值,但中本聪却于2010年选择隐退。中本聪是谁,对每一个开始了解比特币的人,都是感兴趣的话题。从《纽约客》到《新闻周刊》,媒体们找到了数个自称是中本聪,或者被认为是中本聪的人。但无一例外,这些发现都因为可信度不足,遭到了读者甚至是中本聪本人的否定。中本聪是谁?也许我们永远不得而知。 

3、比特币与区块链

比特币已经在争议中走过了7年多的历程。在历史上,很少有这样一种东西,人们对待它的态度如此泾渭分明,支持者认为它将改变世界,反对者认为它毫无价值。望文生义,很容易得出后一个结论。“币”这个词虽然准确的描述了其金融属性,但由于过于形象,使得大多数人对于它如何能与完全虚拟的“比特”关联起来而大惑不解。 

其实,在比特币的系统中,最重要的并不是“币”的概念,而是一个没有中心存储机构的“账本”的概念。“币”只是在这个账本上使用的记账单位。可以这么说,比特币本质就是一个基于互联网的去中心化账本,而区块链就是这个账本的名字。这里我们可以做一个形象的类比,假如区块链是一个实物账本,一个区块就相当于账本中的一页,区块中承载的信息,就是这一页上记载的交易内容。

区块链是比特币的核心与基础架构,是一个去中心化的账本系统。

既然区块链是个账本,这个账本和我们传统的账本有什么不同?我们知道,账本上的内容必须是唯一的,这导致记账天然是中心化的行为。在通讯手段不发达的时代如此,在现今的信息时代也是如此。然而,中心化的记账却有一些显而易见的弱点:一旦这个中心出现问题,如被篡改、被损坏,整个系统就会面临危机乃至崩溃。

那么问题来了——我们能不能构建一个去中心化的不依赖任何第三方的但却可信的记账系统呢?去中心记账可以克服中心化账本的弱点,但是想实现这样的账本系统绝非易事。

在数字时代,负责记账的自然是计算机。这里,我们把记账系统中接入的每一台计算机称为“节点”。去中心化就是没有中心,也就是说参与到这个系统中的每个节点都是中心。从设计账本系统的角度,就是需要每个节点都保存一份完整的账本。然而,由于一致性的要求,每个节点却不能同时记账。因为节点所处的环境不同,接收到的信息自然不同,如果同时记账的话,必然会导致账本的不一致,造成混乱。

既然节点不能同时记账,那我们就不得不选择哪个节点拥有记账的权力。但是,如果指定某些特殊节点拥有记账的权力,势必又会与我们去中心化的初衷相违背。

这似乎成了不可能解决的问题。

竞争记账和激励机制

中本聪设计的比特币区块链通过竞争记账的方式解决了去中心化的记账系统的一致性问题。

前面提到,节点可以理解为接入系统中的计算机,而所谓的竞争记账,就是以每个节点的计算能力即“算力”来竞争记账权的一种机制。在比特币系统中,大约每十分钟进行一轮算力竞赛(算力大小会决定赢得一轮竞争的概率,算力高的节点赢得算力竞争的概率更大),竞赛的胜利者,就获得一次记账的权力,这样,一定时间内,只有竞争的胜利者才能记账并向其他节点同步新增账本信息。

那么,在一个去中心化的系统中,谁有权判定竞争的结果呢?比特币系统是通过一个称为“工作量证明”(proof of work, POW)的机制完成的。举个简单的例子,比如说要生产一些玩具,早上起来我给你一些零件,晚上回来,看到需要的玩具摆在桌上,虽然我没有从早到晚盯着你做玩具的过程,我也能确定你确实做了这么多工作。这就是工作量证明简单的理解——通过一个(人人都可以验证的)特定的结果就能确认(竞争的)参与者完成了相应的工作量。(关于POW的机制与实现细节,会在接下来的文章中详述)

算力竞争是要付出成本的,没有激励,节点就没有进行竞争的动力。在中本聪的设计里,每轮竞争胜出并完成记账的节点,将可以获得系统给予的一定数量的比特币奖励[vii]。而这个奖励的过程,同时也是比特币的发行过程。这种设计相当巧妙 —— 它将竞争的激励机制与货币的发行完美结合到一起,在引入竞争的同时,解决了去中心化货币系统中发行的难题。

在这个系统中,每一个节点只需要根据自身利益行事。出于“自私”的目的进行的竞争,最终造就了保护系统安全的庞大算力基础。在这样精巧的安排下,比特币获得了越来越多的信任,和越来越高的价值,进而又吸引了更多的资源投入其中,成为一个正向循环的经济系统。

正因为比特币通过区块链的机制造就了这样一个正向循环的经济系统,才会在没有强大的中心化机构推动的情况下,自然的生长出来并发展壮大。

读到这里,显然我们会发现,虽然区块链脱胎于比特币,但区块链无论作为一个系统还是作为一项技术,它的应用领域及发展潜力,将远不止货币。之后的文章,我们会通过更加深入的分析与讲解,带您深入到区块链的原理与实现细节。

作者介绍

张健,火币网技术副总裁,火币网数字货币与区块链研究中心负责人,国内首家区块链查询网站“区块”创始人,国内首个基于多重签名技术的比特币钱包“快钱包”创始人,火币网(Huobi.com)是全球领先的数字货币交易平台与服务提供商。区块(Qukuai.com)是国内最大的区块链查询及数据服务平台。

参考文档与备注

i] http://www.hashcash.org/papers/announce.txt

[ii] Dwork, CynthiaNaor, Moni (1993). “Pricing via Processing, Or, Combatting Junk Mail, Advances in Cryptology”CRYPTO’92: Lecture Notes in Computer Science No. 740 (Springer): 139–147.

[iii] S. Haber, W.S. Stornetta, “Secure names for bit-strings,” In Proceedings of the 4th ACM Conference on Computer and Communications Security, pages 28-35, April 1997. on Computer and Communications Security, pages 28-35, April 1997.

[iv] W Dai,a scheme for a group of untraceable digital pseudonyms to pay each other with money and to enforce contracts amongst themselves without outside help “B-money”,http://www.weidai.com/bmoney.txt, 1998

[v] http://www.mail-archive.com/[email protected]/msg09959.html

[vi] http://www.mail-archive.com/[email protected]/msg10142.html

[vii]记账奖励包括一个数量的比特币和该区块包含的所有交易的手续费。系统发放的记账奖励每四年进行一次减半。最开始为50币/区块,目前为25币/区块,以此类推,直到系统中的总币数达到2100万的上限。



(二):什么是工作量证明?



1. 起源

工作量证明(Proof Of Work,简称POW),简单理解就是一份证明,用来确认你做过一定量的工作。监测工作的整个过程通常是极为低效的,而通过对工作的结果进行认证来证明完成了相应的工作量,则是一种非常高效的方式。比如现实生活中的毕业证、驾驶证等等,也是通过检验结果的方式(通过相关的考试)所取得的证明。

工作量证明系统(或者说协议、函数),是一种应对拒绝服务攻击和其他服务滥用的经济对策。它要求发起者进行一定量的运算,也就意味着需要消耗计算机一定的时间。这个概念由Cynthia Dwork 和Moni Naor 1993年在学术论文中首次提出。而工作量证明(POW)这个名词,则是在1999年 Markus Jakobsson 和Ari Juels的文章中才被真正提出。

哈希现金是一种工作量证明机制,它是亚当·贝克(Adam Back)在1997年发明的,用于抵抗邮件的拒绝服务攻击及垃圾邮件网关滥用。在比特币之前,哈希现金被用于垃圾邮件的过滤,也被微软用于hotmail/exchange/outlook等产品中(微软使用一种与哈希现金不兼容的格式并将之命名为电子邮戳)。


2. 哈希函数
哈希现金也被哈尔·芬尼以可重复使用的工作量证明(RPOW)的形式用于一种比特币之前的加密货币实验中。另外,戴伟的B-money、尼克·萨博的比特金(Bit-Gold)这些比特币的先行者,都是在哈希现金的框架下进行挖矿的。

哈希函数(Hash Function),也称为散列函数,给定一个输入x,它会算出相应的输出H(x)。哈希函数的主要特征是:

  1. 输入x可以是任意长度的字符串
  2. 输出结果即H(x)的长度是固定的
  3. 计算H(x)的过程是高效的(对于长度为n的字符串x,计算出H(x)的时间复杂度应为O(n))

而对于比特币这种加密系统所使用的哈希函数,它需要另外具备以下的性质:

  1. 免碰撞,即不会出现输入x≠y,但是H(x)=H(y)

    其实这个特点在理论上并不成立,比如,比特币使用的SHA256算法,会有2^256种输出,如果我们进行2^256+1次输入,那么必然会产生一次碰撞;甚至从概率的角度看,进行2^130次输入就会有99%的可能发生一次碰撞。不过我们可以计算一下,假设一台计算机以每秒10000次的速度进行哈希运算,要经过10^27年才能完成2^128次哈希!甚至可以这么说,即便是人类制造的所有计算机自宇宙诞生开始一直运算到今天,发现碰撞的几率也是极其小的。

  2. 隐匿性,也就是说,对于一个给定的输出结果H(x),想要逆推出输入x,在计算上是不可能的。
  3. 不存在比穷举更好的方法,可以使哈希结果H(x)落在特定的范围。

以上特点是比特币的工作量证明系统可以正常运行的基石。

3. 工作量证明的基本原理

工作量证明系统主要特征是客户端需要做一定难度的工作得出一个结果,验证方却很容易通过结果来检查出客户端是不是做了相应的工作。这种方案的一个核心特征是不对称性:工作对于请求方是适中的,对于验证方则是易于验证的。它与验证码不同,验证码的设计出发点是易于被人类解决而不易被计算机解决。

下图表示的是工作量证明的流程:

举个例子,给定的一个基本的字符串”Hello, world!”,我们给出的工作量要求是,可以在这个字符串后面添加一个叫做nonce的整数值,对变更后(添加nonce)的字符串进行SHA256哈希运算,如果得到的哈希结果(以16进制的形式表示)是以”0000”开头的,则验证通过。为了达到这个工作量证明的目标。我们需要不停的递增nonce值,对得到的新字符串进行SHA256哈希运算。按照这个规则,我们需要经过4251次计算才能找到恰好前4位为0的哈希散列。

"Hello, world!0" => 1312af178c253f84028d480a6adc1e25e81caa44c749ec81976192e2ec934c64
"Hello, world!1" => e9afc424b79e4f6ab42d99c81156d3a17228d6e1eef4139be78e948a9332a7d8
"Hello, world!2" => ae37343a357a8297591625e7134cbea22f5928be8ca2a32aa475cf05fd4266b7
...
"Hello, world!4248" => 6e110d98b388e77e9c6f042ac6b497cec46660deef75a55ebc7cfdf65cc0b965
"Hello, world!4249" => c004190b822f1669cac8dc37e761cb73652e7832fb814565702245cf26ebb9e6
"Hello, world!4250" => 0000c3af42fc31103f1fdc0151fa747ff87349a4714df7cc52ea464e12dcd4e9

通过这个示例我们对工作量证明机制有了一个初步的理解。有的人会认为如果工作量证明只是这样的一个过程,那是不是只需要记住nonce为4521计算能通过验证就行了?当然不是的,这只是一个个例。

下面,我们将输入简单的变更为”Hello, world+整数值”,整数值取1到1000,也就是说,将输入变成一个由1000个值组成的数组:”Hello, world!1、Hello, world!2……Hello, world!1000”。然后对数组中的每一个输入依次进行上面例子中要求的工作量证明——找到前导为4个0的哈希散列。

容易算出,预期大概要进行2^16次尝试(哈希值的伪随机特性使得我们可以做概率估算),才能得到4个前导0的哈希散列。而统计一下刚才进行的1000次计算的实际计算结果,我们会发现,进行计算的平均次数为66958次,十分接近2^16(65536)。在这个例子中,数学期望的计算次数,就是我们要求的“工作量”,重复多次进行的工作量证明会是一个符合统计学规律的概率事件。

统计输入的字符串与对应得到目标结果实际使用的计算次数列表如下:

Hello, world!1 => 42153
Hello, world!2 => 2643
Hello, world!3 => 32825
Hello, world!4 => 250
Hello, world!5 => 7300
...
Hello, world!995 => 164819
Hello, world!996 => 178486
Hello, world!997 => 22798
Hello, world!998 => 68868
Hello, world!999 => 46821

比特币体系里的工作量证明机制与上述示例类似,但要比它更复杂一些。

4. 比特币中的工作量证明

比特币网络中任何一个节点,如果想生成一个新的区块并写入区块链,必须解出比特币网络出的工作量证明的迷题。这道题关键的三个要素是工作量证明函数、区块及难度值。工作量证明函数是这道题的计算方法,区块决定了这道题的输入数据,难度值决定了这道题的所需要的计算量。

4.1工作量证明函数

和我们上节例子中用到的哈希函数一样,比特币系统中使用的工作量证明函正是SHA256。

SHA是安全散列算法(Secure Hash Algorithm)的缩写,是一个密码散列函数家族。这一组函数是由美国国家安全局(NSA)设计,美国国家标准与技术研究院(NIST) 发布的,主要适用于数字签名标准。SHA256就是这个函数家族中的一个,是输出值为256位的哈希算法。到目前为止,还没有出现对SHA256算法的有效攻击。

4.2 区块

比特币的区块由区块头及该区块所包含的交易列表组成。区块头的大小为80字节,由4字节的版本号、32字节的上一个区块的散列值、32字节的Merkle Root Hash、4字节的时间缀(当前时间)、4字节的当前难度值、4字节的随机数组成。区块包含的交易列表则附加在区块头后面,其中的第一笔交易是coinbase交易,这是一笔为了让矿工获得奖励及手续费的特殊交易。

区块的大致结构如图所示:

拥有80字节固定长度的区块头,就是用于比特币工作量证明的输入字符串。因此,为了使区块头能体现区块所包含的所有交易,在区块的构造过程中,需要将该区块要包含的交易列表,通过Merkle Tree算法生成Merkle Root Hash,并以此作为交易列表的摘要存到区块头中。其中Merkle Tree的算法图解如下:

4.3难度值

难度值(difficulty)是矿工们在挖矿时候的重要参考指标,它决定了矿工大约需要经过多少次哈希运算才能产生一个合法的区块。比特币的区块大约每10分钟生成一个,如果要在不同的全网算力条件下,新区块的产生保持都基本这个速率,难度值必须根据全网算力的变化进行调整。简单地说,难度值被设定在无论挖矿能力如何,新区块产生速率都保持在10分钟一个。

难度的调整是在每个完整节点中独立自动发生的。每2016个区块,所有节点都会按统一的公式自动调整难度,这个公式是由最新2016个区块的花费时长与期望时长(期望时长为20160分钟即两周,是按每10分钟一个区块的产生速率计算出的总时长)比较得出的,根据实际时长与期望时长的比值,进行相应调整(或变难或变易)。也就是说,如果区块产生的速率比10分钟快则增加难度,比10分钟慢则降低难度。

这个公式可以总结为如下形式:

新难度值 = 旧难度值 * ( 过去2016个区块花费时长 / 20160 分钟 )

工作量证明需要有一个目标值。比特币工作量证明的目标值(Target)的计算公式如下:

目标值 = 最大目标值 / 难度值
其中最大目标值为一个恒定值:
0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF

目标值的大小与难度值成反比。比特币工作量证明的达成就是矿工计算出来的区块哈希值必须小于目标值。

与第3节所举的例子相类比,我们也可以简单理解成,比特币工作量证明的过程,就是通过不停的变换区块头(即尝试不同的nouce值)作为输入进行SHA256哈希运算,找出一个特定格式哈希值的过程(即要求有一定数量的前导0)。而要求的前导0的个数越多,代表难度越大。

4.4 工作量证明的过程

我们可以把比特币矿工解这道工作量证明迷题的步骤大致归纳如下:

  1. 生成Coinbase交易,并与其他所有准备打包进区块的交易组成交易列表,通过Merkle Tree算法生成Merkle Root Hash
  2. 把Merkle Root Hash及其他相关字段组装成区块头,将区块头的80字节数据(Block Header)作为工作量证明的输入
  3. 不停的变更区块头中的随机数即nonce的数值,并对每次变更后的的区块头做双重SHA256运算(即SHA256(SHA256(Block_Header))),将结果值与当前网络的目标值做对比,如果小于目标值,则解题成功,工作量证明完成。

该过程可以用下图表示:

5. 结语

比特币的工作量证明,就是我们俗称“挖矿”所做的主要工作。理解工作量证明机制,将为我们进一步理解比特币区块链的共识机制奠定基础。在之后的文章中,我们将会详细介绍比特币交易和区块的结构及同步过程、最长链机制以及达成共识的原理。



(三):比特币的私钥、公钥与地址

地址、交易、区块、网络是区块链数据里面最基本最重要的概念。地址用来标示一笔交易的支出方和接收方。所有的交易最终需要被记到统一的账本——区块链上,而这个账本是通过区块确认并完成的。每一个新区块,都会被打上时间戳,最终生成依照时间前后排列并加以记录。每个独立节点之间又通过比特币网络来建立联系,这样就为电子交易记录建立了一个去中心化、分布式的时间戳服务器系统。

很复杂,在这一节,我们先讲地址。

1、公钥密码学

讲到地址,我们就不得不先说一说密码学,作为保护信息传输安全的技术手段,密码在人类社会中的应用源远流长,凯撒密码是古典密码的典型代表,它的基本思想是通过字符的代换来实现加解密。因此古典密码的安全性主要依赖加密算法本身的安全性,如果算法泄露了,要加密的信息也就没有秘密可言了。


1949年香农发表了《保密系统的信息理论》,为对称密码系统建立了理论基础,带来了加密传输基于秘钥安全而不是基于加密算法安全的理论和技术变革。这是密码学发展的里程碑,标志着现代密码学时代的来临。
如今密码学相关技术已经深入各个领域,它们的理论共识都遵循由奥古斯特•柯克霍夫在19世纪提出“柯克霍夫原则”—— 密码系统应该即使被所有人知道其运作步骤,仍然是安全的。即算法是公开的,唯一需要保护的是密钥。

公钥密码学兴起之前,对称加密是主流的加密模式,人们基于秘钥来对信息进行加解密,通常情况下,密钥越长,代表着密文被破解的难度越大。由于加密算法和解密算法都是同一模式,只有一把密钥保证加密数据的安全,因此这种加密算法也叫做“对称加密算法”。对称加密有一个最大弱点:甲方必须把密钥告诉乙方,否则乙方无法解密。而保存和传递密钥,就成了最头疼的问题。

公钥密码学是现代密码学最重要的进展。公钥密码学可以在不直接传递密钥的情况下,完成密文的解密。加密和解密可以使用不同的规则,只要这两种规则之间存在某种对应关系即可,系统的安全性既不依赖算法的保密,也不用直接传递密钥。基于这种公钥机制的思想,开始出现了一系列非对称加密算法。

1976年Whitfield Diffie & Martin Hellman首次提出了基于数学难题的公钥密码机制,1978年RSA公钥密码机制的出现,成为公钥密码的杰出代表并成为事实标准,在密码学史上创造了又一个新的里程碑。90年代公钥密码学进一步发展,基于椭圆曲线乘法、素数幂等数学函数的公钥算法诞生,使得数字密钥和不可伪造的数字签名成为可能。

数据签名算法的核心在于证明数据的发送方是签名者发出的、不可抵赖,而不是待签名数据的保密性。

下图比较说明非对称加密与对称加密算法的区别:

非对称加密需要两个(一对)密钥:公开密钥(publickey)和私有密钥(privatekey),用公钥对数据进行加密后,只有对应的私钥才能解密;反之如果私钥用于加密,则只有对应的公钥才能解密。通信双方无须交换密钥就可以建立保密通信。

公钥算法用到的是私钥与公钥,他们和比特币体系中常常说到的地址有什么关系?在比特币系统中,私钥由32字节的随机数组成,通过私钥可以算出公钥,公钥经过一系列哈希及编码算法就得到了比特币中的地址。所以地址其实是公钥的另一种表现形式,可以理解为公钥的摘要。

2、相关的加密算法

在私钥、公钥及地址的相关运算中,用到了基于secp256k1椭圆曲线乘法的签名算法、SHA-256、RIPEMD-160,和Base58编码。

2.1椭圆曲线签名算法

椭圆曲线在密码学中的使用是在1985年由Neal Koblitz和Victor Miller分别独立提出的。它的主要优势是在某些情况下它比其他的算法(比如RSA)使用更小的密钥但提供相当的或更高等级的安全性。

比特币使用了基于secp256k1椭圆曲线数学的公钥密码学算法。它包含私钥与公钥,私钥用于对交易进行签名,将签名与原始数据发送给整个比特币网络,公钥则用于整个网络中的节点对交易有效性进行验证。签名算法保证了交易是由拥有对应私钥的人所发出的。

2.2 哈希函数

SHA-256是一种哈希函数,已经在上一节的讲解中做了介绍,这里不再赘述[1]

RIPEMD-160也是在生成地址时用到的一种哈希函数,其输出长度为20字节(160位)。比特币用它减少标识接收方的字节数。

2.3 Base58编码

可读性编码算法,类似古典密码学里的置换算法,理论上并不是密码学理论的核心内容。可读性编码算法不是为了保护数据的安全性,而是为了可读性。以二进制进行传输的信息是不具备可读性的,数字与字母组成的字符串才更容易被识别。可读性编码不改变信息内容,只改变信息内容的表现形式(部分编码算法还加入了容错校验功能,以保证传输过程中数据的准确性和完整性)。

Base64是常见的可读性编码算法,所谓Base64,即是说在编码过程中使用了64种字符:大写A到Z、小写a到z、数字0到9、“+”和“/”。

Base58是Bitcoin中使用的一种编码方式,主要用于产生Bitcoin的钱包地址。相比Base64,Base58不使用数字”0”,字母大写”O”,字母大写”I”,和字母小写”i”,以及”+”和”/”符号。

设计Base58主要的目的是:

  1. 避免混淆。在某些字体下,数字0和字母大写O,以及字母大写I和字母小写l会非常相似。
  2. 不使用”+”和”/”的原因是,非字母或数字的字符串难以作为账号的一部分被接受。
  3. 没有标点符号,通常不会被从中间分行。
  4. 使大部分的软件支持双击选择整个字符串。

比特币中使用Base58算法来对公钥的Hash160及私钥进行编码,以生成以1或3开头的比特币地址及WIF(Wallet import Format)格式的私钥。

3、私钥与公钥

比特币私钥其实是使用SHA-256生成的32字节(256位)的随机数,有效私钥的范围则取决于比特币使用的secp256k1 椭圆曲线数字签名标准。大小介于0x1 到0xFFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFE BAAE DCE6 AF48 A03B BFD2 5E8C D036 4140之间的数几乎都是合法的私钥。

在私钥的前面加上版本号,后面添加压缩标志和附加校验码,(所谓附加校验码,就是对私钥经过2次SHA-256运算,取两次哈希结果的前四字节),然后再对其进行Base58编码,就可以得到我们常见的WIF(Wallet import Format)格式的私钥。

私钥经过椭圆曲线乘法运算,可以得到公钥。公钥是椭圆曲线上的点,并具有x和y坐标。公钥有两种形式:压缩的与非压缩的。早期比特币均使用非压缩公钥,现在大部分客户端默认使用压缩公钥。

由于数学原理,从私钥推算公钥是可行的,从公钥逆推私钥是不可能的。

初识比特币的人常有一种误解,认为比特币公钥就是地址,这是不正确的。从公钥到地址还要经过一些运算。

4、地址的生成

椭圆曲线算法生成的公钥信息比较长,压缩格式的有33字节,非压缩的则有65字节。地址是为了减少接收方所需标识的字节数。比特币地址的生成步骤如下:

  1. 生成私钥与公钥
  2. 将公钥通过SHA256哈希算法处理得到32字节的哈希值
  3. 后对得到的哈希值通过RIPEMD-160算法来得到20字节的哈希值 —— Hash160
  4. 把版本号[2]+Hash160组成的21字节数组进行双次SHA256哈希运算,得到的哈希值的头4个字节作为校验和,放置21字节数组的末尾。
  5. 对组成25位数组进行Base58编码,就得到地址。

下图以非压缩格式的65字节公钥示意上述过程:

由于椭圆曲线乘法以及哈希函数的特性,我们可以从私钥推导出公钥,也可以从公钥推导出地址,而这个过程是不可逆的。也正因如此,在整个比特币系统中,私钥是最关键的部分。私钥泄露也就意味着丢失了一切。

我们要花掉一个地址上的资产,需要构造一笔交易,同时使用这个地址对应的私钥签名。而如果我们要将资产转移到某个地址上,只需要转账给他公开的地址就行了。

在下一节,我们将详细讲述比特币交易是如何构成和实现的。


[1] http://www.infoq.com/cn/articles/bitcoin-and-block-chain-part02

[2] 普通地址P2PKH的版本默认值是0,P2SH类型的地址版本默认值是5


(四):比特币的交易

在比特币区块链中,交易是最核心的内容。通过前面的讲述,我们知道,比特币通过基于密码学的公私钥体系,交易的发起者可以使用自己的私钥对交易进行签名,其他人可以使用其公钥进行验证,这就从数学上保证了用户资金的安全。那么其交易具体是怎么构建的呢?

简化模型

在中本聪的白皮书里,比特币被定义成一个链式的数字签名串。币的拥有者通过对前一次交易和下一次拥有者的公钥签署一个数字签名,并将这个签名附加在这笔交易的当中,来完成一笔转账。而转账的收款人通过对签名进行验证,就能够验证该链条的所有者是不是发送方。

交易的运作图如下:

这样设计的交易体系的问题在于收款人很难校验之前的某位资产拥有者是否进行了双重支付(双花)。通常的解决方案是引入可信的第三方,如银行,来对每一笔交易进行检验,以防止双重支付。而如果想要排除第三方中介机构,那么交易信息就应当被公开,需要整个系统内的所有参与者,都有唯一公认的历史交易序列。收款人需要确保在交易期间绝大多数的节点都认同该交易是首次出现。

账本系统不以“账户”为基础

比特币区块链本质上可以说是一个基于互联网的去中心化的账本系统,而这个账本上记载的,就是一笔笔比特币地址之间的转账交易,一笔具体的交易过程如上面所示,那整个系统该如何构建呢?。


常常有一种简单化的说法,将比特币公钥类比为用户的银行卡号,也即用户的账户。那么最容易想到的交易系统的记录方式是以账户为基础的,简化的示意图类似这样:

这种记账方式是最容易想到的,然而比特币区块链并没有采用这种方式。重要的事情说三遍,比特币的交易系统不是这样的,不是这样的,不是这样的。原因很简单,如果采用这种记账方式的话,每当要进行一笔新交易的时候,系统都不得不回溯该所有交易历史,这样才能确定最新的这笔交易是不是合法,如上图所示,用户C有这些钱吗?当系统庞大、交易数量众多的时候,每次都进行这样的检验无疑是笨重低效的。

那么比特币的交易系统是怎样构建的呢?

UTXO是比特币交易的基本单位

UTXO(Unspent Transaction Outputs)是未花费的交易输出,它是比特币交易生成及验证的一个核心概念。交易构成了一组链式结构,所有合法的比特币交易都可以追溯到前向一个或多个交易的输出,这些链条的源头都是挖矿奖励,末尾则是当前未花费的交易输出。所有的未花费的输出即整个比特币网络的UTXO。

比特币规定每一笔新的交易的输入必须是某笔交易未花费的输出,每一笔输入同时也需要上一笔输出所对应的私钥进行签名,并且每个比特币的节点都会存储当前整个区块链上的UTXO,整个网络上的节点通过UTXO及签名算法来验证新交易的合法性。这样,节点不需要追溯历史就可以验证新交易的合法性。

交易的输入与输出

比特币的交易,并不是通常意义的一手交钱一手交货的交易,而是转账。如果每一笔转账都需要构造一笔交易数据会比较笨拙,为了使得价值易于组合与分割,比特币的交易被设计为可以纳入多个输入和输出。即一笔交易可以转账给多个人。从生成到在网络中传播,再到通过工作量证明、整个网络节点验证,最终记录到比特币的区块链,就是交易的整个生命周期。

交易的本质是一个包含交易发送方、接收方、资产转移等相关信息的数据结构,其数据结构如下:

字段

描述

大小

版本

这笔交易参照的规则

4 字节

输入数量

交易输入列表的数量

1 - 9 字节

输入列表

一个或多个交易输入

不定

输出数量

交易输出列表的数量

1 - 9 字节

输出列表

一个或多个交易输出

不定

锁定时间

锁定时间

4 字节

从整体结构来看,交易主要的两个单元字段就是交易的输入与输出。输入标识着交易的发送方,输出标识着交易的接收方及对于自己的找零,交易的手续费则是输入的总和与输出的总和之差。由于所有的交易输入必然是前面某笔交易的输出,所以交易最核心的字段是交易的输出。

一笔交易的数据结构图如下所示:

比特币的交易输入(TxIn)有三种,分别是Standard TxIn(标准输入)、Spend Coinbase TxOut(花费挖矿奖励)、Coinbase/Generation(产生挖矿奖励),下图分别描述了这三种TxIn的结构:

比特币的交易输出(TxOut Script)有两种,分别是Standard TxOut (标准交易输出)、Coinbase TxOut (挖矿奖励输出),下图分别描述了这两种TxOut的结构:

脚本

脚本是交易里另一个比较重要的技术。每一笔交易的每一项输出严格意义上并不是指向一个地址,而是指向一个脚本。脚本类似一套规则,它约束着接收方怎样才能花掉这个输出上锁定的资产。

交易的合法性验证也依赖于脚本。目前它依赖于两类脚本:锁定脚本与解锁脚本。锁定脚本是基于可变的模式,通过一段脚本语言来实现,位于交易的输出。解锁脚本与锁定脚本相对应,只有按锁定脚本的规则去解,才能花掉这个脚本上对应的资产,位于交易的输入。脚本语言可以表达出无数的条件变种。这也是比特币作为一种“可编程的货币”所拥有的特性。而解释该脚本是通过类似我们编程领域里的“虚拟机”,它分布式运行在比特币网络里的每一个节点。

比特币的脚本目前常用的主要分为两种,一种是普通的类型P2PKH(Pay-to-Public-Key-Hash),即支付给公钥的哈希即地址,接收方只需要使用地址对应的私钥对该输出进行签名,即可花掉该输出。另一种是P2SH(Pay-to-Script-Hash),支付脚本的哈希。拿多重签名来举例,它要求该输出同时要有N把私钥中的M把私钥(M<=N)同时签名才能花掉该资产,它类似于现实生活中需要多把钥匙才能同时打开的保险柜,只是更加灵活。

比如在比特币中,P2PKH的脚本规则如下:

Pubkey script: OP_DUP OP_HASH160 <PubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
Signature script: <sig> <pubkey> 

P2SH的脚本规则如下:

Pubkey script: OP_HASH160 <Hash160(redeemScript)> OP_EQUAL
Signature script: <sig> [sig] [sig...] <redeemScript>

在上述的2种脚本规则里,Pubkey script代表着锁定脚本,Signature script代表着解锁脚本。OP_开头的单词是相关的脚本命令,也是”虚拟机”所能解析的指令。这些命令规则根据Pubkey script的不同来进行划分,它也决定着解锁脚本的规则。

比特币中的脚本机制相对简单,只是一个基于堆栈式的,解释相关OP指令的引擎,能够解析的脚本规则并不是太多,不能实现很复杂的逻辑。但它为区块链可编程提供了一个原型,后续一些可编程区块链项目其实是基于脚本的原理发展起来的,比如以太坊,就是深入强化了脚本机制,脚本机制里不再单单是简单的OP指令,而是支持脚本语言,该脚本语言可以通过”虚拟机”去执行。以太坊实现了一个支持图灵完备脚本语言的区块链平台。

脚本的机制对于区块链来说非常重要,它类似于区块链技术提供的一个扩展接口,任何人都可以基于这个接口,去开发基于区块链技术的应用,比如智能合约的功能。脚本机制也让区块链技术作为一项底层协议成为可能。未来很多基于区块链的颠覆性应用,都有可能是通过区块链的脚本语言来完成的。

以上简述了比特币区块链中交易的过程和相关的重要概念。限于篇幅,在这里省略了一些可以拓展的内容。到目前为止,我们讲述的内容,包括上一节讲述的公私钥,都是与用户的使用直接相关的。关于区块链的共识机制、系统安全等广大读者关心的问题,我们会在之后的文章中为您讲解。


(五):深入理解比特币交易的脚本


本文作者为火币区块链研究中心技术专家廖雪峰,他有十年软件开发经验,精通Java/Python/Ruby/Visual Basic/Objective C/Lisp等编程语言,对开源框架有深入研究,著有《Spring 2.0核心技术与最佳实践》一书,并有多个业余开源项目托管在GitHub。本文中廖雪峰详细地介绍了比特币及比特币区块链的相关知识。

在比特币区块链中,每一个区块都指向上一个区块,这些通过SHA256计算的区块哈希链就是比特币账本不可篡改的基础。

在一个区块中,比特币系统用交易(Transaction)来表示一笔比特币交易。一个区块包含至少一笔交易。这些Transaction的Hash通过Merkle Tree计算出所有交易的Merkle Hash,并被包含至区块Hash中,从而实现交易的不可修改。

如果我们仔细观察每一笔交易,可以发现,除了第一笔交易是矿工的挖矿所得外,每一笔交易都拥有一个或多个输入(TxIn),以及一个或多个输出(TxOut):

第一笔矿工挖矿的收入交易通常被称为Coinbase,它没有输入,所以TxIn的Hash总是被标记为00000000…0000

其他的交易,任何一个TxIn都会唯一追溯到区块链上在本区块之前的某个交易Hash,以及索引:

通过交易Hash和索引(从0开始),即可唯一确定一个未花费的交易输出——UTXO(Unspent Transaction Output)。这样,每一个Tx Input都和之前的某个Tx Output关联了起来。

我们假设在上一笔交易中,Bob给Alice支付了0.15个BTC。

由于比特币并没有账户的概念,这一笔交易的输出并没有写上Alice的名字,也没有写上Alice的公钥。

那么,Alice想要花费这0.15个BTC,她应该如何证明自己拥有这个UTXO,并且,其他人无法假冒Alice来花费这个UTXO呢?

答案是比特币的交易创建的输出其实并非一个简单的公钥地址,而是一个脚本。在Bob给Alice支付0.15个BTC的这个交易中,Bob创建的输出脚本类似:

OP_DUP OP_HASH160 abcd1234...9876 OP_EQUALVERIFY OP_CHECKSIG

其中,abcd1234…9876是Alice的公钥Hash。整个脚本的意思是,谁能够提供一个签名和一个公钥,让这个脚本运行通过,谁就能花费这笔交易的1.5个BTC。

由于创建签名只能使用Alice的私钥,非Alice的私钥创建的签名将无法通过这个脚本的验证,所以,其他人无法假冒Alice来花费这笔输出。

一旦Alice提供了一个签名和自己的公钥,她实际上已经创建了另一笔交易来花费这个输出。

所有人都可以验证Alice创建的这个新交易是否有效。如果有效,该交易就会被矿工打包进新的区块,从而成为区块链上不可更改的一部分。

我们以著名的Pizza Transaction为例,来验证一个交易是否是有效的。

在交易cca75078…4d79中,唯一的TxIn输入提供的sigScript是:

8b4830450221009908144ca6539e09512b9295c8
a27050d478fbb96f8addbc3d075544dc41328702
201aa528be2b907d316d2da068dd9eb1e23243d9
7e444d59290d2fddf25269ee0e0141042e930f39
ba62c6534ee98ed20ca98959d34aa9e057cda01c
fd422c6bab3667b76426529382c23f42b9b08d78
32d4fee1d6b437a8526e59667ce9c4e9dcebcabb

该sigScript实际上由两部分构成:

签名:30450221…ee0e01(71字节+1字节签名类型),实际签名是去掉最后一个字节01的30450221…ee0e,签名类型是SIGHASH_ALL(0x01)。

公钥:042e930f…cabb(65字节)

为了验证该交易是否有效,我们首先要根据TxIn所声明的Previous Output Hash:a1075db5…d48d和索引0找到上一笔交易的输出:

https://webbtc.com/tx/a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d

这笔交易输出的脚本是:

1976a91446af3fb481837fadbb421727f9959c2d32a3682988ac

比特币的脚本由一系列指令和数据构成,每个指令占用一个字节,数据由数据头部的长度决定。上述二进制脚本翻译后的比特币指令如下:

OP_DUP OP_HASH160 46af3fb481837fadbb421727f9959c2d32a36829 OP_EQUALVERIFY OP_CHECKSIG

现在,我们有了签名,公钥和脚本:

sig: 30450221...ee0e01
pubkey: 042e930f...cabb
OP_DUP OP_HASH160 46af3fb4…6829 OP_EQUALVERIFY OP_CHECKSIG

就可以运行这个脚本来验证交易是否有效。

比特币脚本被设计成以栈来运行的虚拟机指令,它只有有限的几种指令,并且故意被设计成没有循环、条件跳转,所以,比特币脚本不是图灵完备的语言。

比特币脚本的执行非常简单。我们首先要准备一个空栈,然后把签名和公钥入栈:

紧接着,我们就可以执行TxOut的脚本:

OP_DUP OP_HASH160 46af3fb481837fadbb421727f9959c2d32a36829 OP_EQUALVERIFY OP_CHECKSIG

首先执行OP_DUP,这条指令把栈顶的元素复制一份,所以结果变成:

紧接着执行OP_HASH160,它对栈顶元素计算SHA256/RipeMD160,实际上是计算公钥Hash,所以运行结果变成:

接下来的指令实际上是一个数据,我们直接把数据入栈:

然后,执行OP_EQUALVERIFY,这条指令会比较栈顶的两个元素是否相等,如果不等,整个脚本就执行失败了,如果相等,脚本会继续执行,所以运行结果变成:

最后,执行指令OP_CHECKSIG,这条指令会验证签名。首先,我们根据签名类型SIGHASH_ALL(0x01)对整个交易进行验证。验证方法是:

把当前Transaction的所有TxIn的scriptSig去掉(红色部分),并把当前TxIn的scriptSig替换为UTXO的script(蓝色部分),调整长度字段(绿色部分):

最后加上小端序4字节的签名类型0x01(灰色部分),计算两次SHA256,我们得到:

c2d48f45…2669

现在,使用ECDSA算法对签名进行验证:

boolean ecdsa_verify_signature(byte[] message, byte[] signature, byte[] pubkey)

根据签名的验证结果,我们即可确认该交易是否有效。

由于引入了脚本,我们可以看到,比特币实际上通过编程脚本实现了一个严格以计算机程序验证为基础的数字货币所有权的转移机制。由于计算机程序的可扩展性,比特币支付其实并不限定在必须支付给某一个公钥地址。利用脚本,我们可以构造出各种支付条件,例如,多重签名验证条件:

2 <public-key1> <public-key2> <public-key3> 3 OP_CHECKMULTISIGN

这种提供多个公钥地址,并且需要多个签名验证的多重签名脚本,允许在M个签名种至少给出N个签名即可使用。上述脚本允许提供3个公钥地址中的任意两个有效签名。

当我们把比特币托管在某个第三方的在线钱包中时,就可以使用多重签名来保证只有自己和第三方钱包共同签名后才可动用输出,这样保证了黑客在攻击了第三方钱包后也无法花掉用户的比特币。

通过OP_CHECKLOCKTIMEVERIFY,我们可以指定一个交易的锁定时间,在此之前,该交易输出无法被花掉。这个指令其实实现了支付宝的7天资金锁定然后再支付给卖家的功能。

还有一些交易并没有指定一个公钥Hash,例如,这个交易的脚本如下:

OP_HASH256 6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000 OP_EQUAL

它的意思是说,谁能够提供一个数据,它的SHA256是6fe28c0a…0000,谁就可以花费这笔交易。

(注:该交易已经被花费了,有人找到了符合条件的数据)

从比特币的脚本,我们可以看到,基于区块链的数字货币支付实际上是数字货币所有权的安全转移。如果我们把金融资产或者实物资产以数字化的形式登记在区块链上,通过脚本就可以安全实现各种条件下的所有权转移,这正是智能合约在区块链上的应用。

出处:火币区块链研究中心。转载需注明来源!


猜你喜欢

转载自blog.csdn.net/whatisthespring/article/details/79037064