本文翻译自 13 年一篇关于比特币协议的深度解析文章

成千上万篇文章为了解释比特币这一线上、点对点的货币而撰写。大多数文章对于其底层加密协议都只给出一些简短的解释,却忽略了很多细节。甚至那些文章常常掩盖重点进行更深入的研究。我这篇文章的目的是以一种清晰、容易理解的方式解释隐藏在比特币协议后面的主要思想。我们将从第一原则开始,对于比特币如何工作建立一个广义的理论上的理解,然后再深挖其细节,检查比特币交易的原始数据。

以细节的方式理解协议是一项困难的工作。人们转而接受比特币,并从事投机关于如何通过比特币致富、比特币吧是否泡沫,比特币是否意味着税收结束的一天等等。这很有趣,但是严重限制你理解它。理解比特币的协议细节打开了难以进入的远景。特别是,理解比特币内建脚本语言的基础会使得使用比特币创造新的金融工具成为可能,比如智能合同。反过来,新的金融工具可以被用来创造新的市场并缔造人类行为新的集合形式。聊聊这些趣事吧!

我会在后面的文章中描述比特币脚本和一些概念,比如智能合同。这篇文章集中解释比特币协议的核心。理解这篇文章你需要对公钥加密以及与其紧密关联的数字签名概念比较熟悉。我将同样假定你对加密散列概念熟悉。以上这些都没有特别难理解的。基本概念都会在大学的大一数学课程或者计算机课程中教授。这些概念很优雅,所以如果你对于他们不是很熟悉,我建议你先花一点时间熟悉一下。

也许看上去比较神奇,比特币的基础是密码学。比特币不是一种货币?不是一种发送秘密信息的方式?事实上,比特币需要解决的事情大部分是安全事务——确保人们不能互相窃取,或者伪造等等。在原子世界我们通过一些设备,例如锁、保险箱、签名、银行金库实现安全。在比特世界我们通过加密实现安全。这也是为什么比特币的核心是加密协议。

我在这篇文章中的策略是分阶段建立起比特币。我会通过解释一种非常简单的数字货币开始,所基于的思想几乎显而易见。我们将称其信息货币(Infocoin),以区分于比特币。当然,我们第一个版本的信息币会有很多不足,然后我们会经过多个迭代,每个迭代介绍仅仅一或两个新的想法。经过多个迭代后,我们将达到完整的比特币协议。我们将重新发明了比特币。

这种策略比起我一次性解释整个比特币协议要慢。但是当你通过这样一次性解释的方式理解了比特币机制时,再去理解比特币为什么这样设计就会很困难。这种通过慢迭代的解释方式优势在于可以让你对于比特币每一个元素理解得更加犀利。

最后,我应该提及对于比特币我也是个新手。我从 2011 年开始松散地关注(在 20 世纪 90 年代末开始关注加密数字货币),但直到今年早些时候才着重关注比特币协议的细节。所以我将非常感激对于我误解部分的指正。另外在本篇文章中我还包含了很多“留给读者的问题”——在我写作过程中对于新冒出的问题的一些笔记。你会发现这很有趣,但你也可以把它们全部跳过以免丢失全文的线索。

第一步:签名意图信

所以我们该如何设计一个数字货币呢?

从表面上来看,数字货币听起来是不可能的。假设某个人,让我们称其 Alice,她有一些电子钱想花掉。如果 Alice 想使用一串比特字符作为钱,我们如何才能阻止她反复使用相同的比特字符串呢?否则将意味着会产生无穷无尽的钱。或者假如我们可以通过某种方式解决这个问题,但我们如何才能防止其他人伪造这样一串比特字符并用来偷取 Alice 的钱呢?

这些只是众多问题中的两个,必须被克服以为了使用信息作为货币。

作为信息币的第一个版本,让我们找到一个方法使得 Alice 可以使用一串字符(非常原始和不完整)作为货币的形式,以某种至少保证她的货币不会被伪造的方式。假设 Alice 想给 Bob 一个信息币。为了这么做,Alice 写下一行字符串“我,爱丽丝,给 Bob 一个信息币”。然后她用私钥给这条信息做了数字签名,并告知全世界 这段签过名的字符串。

(顺便提一下,我使用首字母大写的 Infocoin 表示信息币协议及一般概念,用首字母小写的 infocoin 特指货币面值,类似用法很常见,虽然在比特币的世界不通用)

这并不是一个令人非常影响深刻的数字货币原型。但它的确有一些优点。世界上的任何人(包括 Bob)可以使用 Alice 的公钥去确认 Alice 的确是“我,爱丽丝,给 Bob 一个信息币”这条信息签名的主人。没有其他人可以造出这条比特信息。但反过来,Alice 也可以说“不,我没说要给 Bob 一个信息币”。所以这个协议建立在 Alice 真的想给 Bob 一个信息币。同样的事实——没有其他人可以构造这样一条签名信息——也给予 Alice 一些防止其他人伪造的有限保护。当然,在 Alice 创建她的这条信息后也可能其他人复制了这条信息,这样的话伪造是可能的。但无法从头伪造。这两种属性——Alice 建立企图的部分和防止伪造的有限保护部分,是这个协议值得注意的特征。

我在这个协议中没有(非常)准确地讲数字货币是什么。为了使其明确:特指这条信息本身,例如,这行比特字符串展示了数字货币“我,爱丽丝,给 Bob 一个信息币”。后面的协议类似,我们所有数字货币的形式只是会越来越复杂。

使用序列号来使得货币被唯一标识

第一个版本的信息币的问题在于 Alice 可以一次又一次地继续向 Bob 发送相同的签名消息。假定 Bob 收到了十份“我,爱丽丝,给 Bob 一个信息币”这样的拷贝签名信息。意味着 Alice 向 Bob 发送了十个不同的信息币吗?她的信息是巧合复制出来的吗?可能她只是试图戏弄 Bob 使其相信她给了他十个不同的信息币,当这条信息向全世界证明才表示她真的企图传送一个信息币。

我们想要的是一种使得信息币唯一的方式。它们需要一个标签或者序列号。Alice 将签名“我,爱丽丝,用序列号 8740348 给 Bob 一个信息币”这条信息。然后,随后,Alice 可以签名“我,爱丽丝,用序列号 8770431 给 Bob 一个信息币”消息,然后 Bob(还有其他人)将会知道这是另外一个信息币被传送了。

使得这个方案工作,我们需要一个可信任的序列号源用于信息币。创建这样一个源的方法之一是引用一个银行。这个银行将为信息币提供序列号,并追溯谁拥有了哪一个信息币并确认交易的确合法。

更详细地说,让我们假设 Alice 去银行并说“我想从我的账户提取一个信息币”。银行从她的账户余额中扣减一个信息币,并分配给她一个新的、之前从未使用过的序列号,让我们称其 1234567。然后当 Alice 想把她的信息比转移给 Bob 时,她签名“我,Alice,给 Bob 一个信息币,使用序列号 1234567”这条消息。但 Bob 并没有就这样接受这个信息币。而是联系了银行以确认:(a)这个序列号的信息币是否属于 Alice;(b)Alice 已经支付了这个信息币。如果这两者都是真的,然后 Bob 告诉银行他想接受这个信息币,于是银行更新他们的交易记录并展示这个序列号的信息币现在是 Bob 的财产,并不再属于 Alice。

使每个人都集中于银行

上一个解决方案看上去很有前途。然而,事实证明,我们可以做一些更有野心的事情。我们完全可以消除银行的协议。这在很大程度上改变了货币的本质。这意味着不再有任何单一的组织管控货币。当你想到中央银行的巨大力量——控制着货币的供应量——这将是一个非常巨大的变化。

这个想法是使得每个人(全体地)都是银行。特别是,我们假设每一个人都使用信息币保持着哪些信息币属于哪一个人的完整记录。你可以理解为这是一个展示所有的信息币交易的共享公共平台。我们称这个平台为区块链,因为那就被称为比特币的完整记录,一旦我们得到它。

现在,假定 Alice 想转移一个信息币给 Bob。她签名了“我,Alice,给 Bob 一个信息币,以序列号 1234567”这条消息并把这条签名消息给了 Bob。Bob 可以用他拷贝的区块链去校验这的确是 Alice 给出的。如果校验成功,然后他把这笔交易中 Alice 发出的消息和他的接收消息广播给整个网络,于是每个人都更新他们的区块链拷贝。

我们仍然有“序列号从哪来”这个问题,但这变得容易解决,所以我将推迟到后面讲解,在讨论比特币的部分。一个更具挑战的问题是,这个协议允许 Alice 通过支付她的信息币双倍来作弊。她发送“我,爱丽丝,给了 Bob 一个信息币,以序列号 1234567”给 Bob,同时发送“我,爱丽丝,给 Charlie 一个信息币,以序列号 1234567”给 Charlie。Bob 和 Charlie 都使用他们拷贝的区块链来检查这个信息币是 Alice 支付的。只要他们是同一时刻做这个验证(在他们有机会彼此听说之前),他们两个都会发现,是的,区块链显示这个信息币的确属于 Alice。于是他们都会接受这笔交易,并广播他们的接受。现在就有了问题,其他人该怎么更新他们的区块链呢?可能没有简单的方法来实现一个一致的共享事务平台。即使每个人都能达成一致的方式去更新他们的区块链,仍会有 Bob 或者 Charlie 将被欺骗的问题。

乍一看 Alice 支付双份的问题难以解决。毕竟,如果 Alice 先向 Bob 发送消息,然后 Bob 可以确认这条消息,并告诉每个在网络内的人(包括 Charlie)去更新他们的区块链。一旦那发生了,Charlie 就不再会被 Alice 欺骗。所以最有可能只有非常短的一段时间内 Alice 可以支付出双份。然而,显然这样的一段时间是不可理喻的。更糟糕的是,有技术可以被 Alice 用来延长这一段时间。她可以,举个例子,利用网络流量分析发现 Bob 和 Charlie 沟通延迟很多的一段时间。或者她可以做些事情来故意破坏他们的通信。如果她能减慢通信甚至一点都将使得她支付双份更加容易。

我们怎样才能解决这个双份支付的问题?明显的解决方法是当 Alice 向 Bob 发送一个信息币的时候,Bob 不应该试图独自确认交易。相反,他应该将可能的交易广播给信息币用户整个网络,并询问他们去判定这笔交易是否合法。如果他们集体决定这笔交易没问题,然后 Bob 可以接受这个信息币,并告诉每个人更新区块链。这种协议可以避免双份支付,因为如果 Alice 试图将她的信息币同时支付给 Bob 和 Charlie,其他人会察觉到,并且网络用户会告诉 Bob 和 Charlie 这笔交易有问题,于是交易将无法通过。

更详细地,让我们假设 Alice 想要给 Bob 一个信息币。像之前那样,她签名“我,爱丽丝,给 Bob 一个信息币,以序列号 1234567”这条消息,并把这条签名消息发送给 Bob。同样如以前那样,Bob 做了一个明智的检查,使用他拷贝的区块链检查,的确,当前这个信息币属于爱丽丝。但在这个点上协议被修改了。Bob 并没有继续接受这笔交易。取而代之的是,他广播 Alice 的这条消息给整个网络。网络上的其他成员检查 Alice 是否拥有这个信息币。如果如此,他们广播消息“是的,Alice 拥有信息币 1234567,现在这条消息可以发送给 Bob”。一旦足够多的人广播这条消息,每个人都更新他们的区块链以显示信息币现在属于 Bob,交易将完成。

目前这个协议有许多不准确的元素。例如,什么是“一旦足够多的人广播了这条消息”?这里的“足够”到底意味着什么?它可以意味着网络里的每一个人,因为我们无法预先知道谁在这个信息币网络里。出于同样的原因,它不能意味着网络内一些固定的用户。我们现在不试着使这些想法变准确。取而代之,在下一个部分我会指出一个严重的问题和方法按照所描述。解决那个问题将同时有良好的副作用可以使得上面的想法更加准确。

工作证据(Proof-of-work)

假设 Alice 想要支付双份,以我刚描述的基于网络的协议。她可以通过接管信息币网络来这么做。让我们假设她使用了一个自动化系统建立了非常大量的独立身份,让我假设是十亿个,在信息币网络上。正如此前,她想支付双份,同时将一个信息币发送给 Bob 和 Charlie。但是当 Bob 和 Charlie 询问网络以验证他们对于交易的观点,Alice 的傀儡身份在网络中向 Bob 声称他们验证了这笔交易,并告诉 Charlie 他们验证了这笔交易,可能同时愚弄一个或二者同时去接受这笔交易。

有一个聪明的方法可以避免这个问题,使用一个被称为工作证据的想法。这个想法是违反直觉的并且设计到两个概念的结合:(1)去(人工)使得对于网络用户验证交易变得从计算角度花费很大(昂贵)(原文:to (artificially) make it computationally costly for network users to validate transactions);(2) 奖励那些试图帮助验证交易的人。奖励被使用,这样网络上的用户就会努力去帮忙验证交易。虽然那样会导致一个计算非常昂贵的过程。使得验证交易变得昂贵的收益是不再会受网络身份的某些人控制的影响,而只有通过总的计算力量才能施加在验证上(原文:The benefit of making it costly to validate transactions is that validation can no longer be influenced by the number of network identities someone controls, but only by the total computational power they can bring to bear on validation.)我们会看到,用一些聪明的设计我们可以让骗子欺骗需要巨大的计算资源,使得其不切实际。

这是 Proof-of-work 的要点。但要真正理解其,我们需要深究细节。

假定 Alice 向网络广播一条消息“我,爱丽丝,给 Bob 一个信息币,以序列号 1234567”。

当别人在网络上听到这条消息,每个人将其添加进一个他们被告知的交易等待队列,但他们还尚未被网络所批准。举个例子,另一个网络用户名叫 David 可能有以下交易等待队列:

我,Tom,给 Sue 一个信息币,以序列号 1201174 我,Sydney,给 Cynthia 一个信息币,以序列号 1295618 我,Alice,给 Bob 一个信息币,以序列号 1234567

David 检查自己的区块链,并可以看到每一笔交易都是有效的。他想通过广播整个网络这个有效性来帮忙。

然而,在此之前,作为验证协议的一部分,David 被要求去解决一个困难的计算难题——the proof-of-work。没有对于这个难题的解决,网络的其他人不会接受他对于这笔交易的验证。

David 需要解决的是一个怎样的难题呢?为了解释它,让 h 作为一个固定的散列函数,被网络内的每一个人所知道——被建立在协议内。比特币使用著名的 SHA-256 散列函数,但是任何加密安全散列函数都可以。让我们给 David 的交易等待队列一个标签 l,这样它有了名字可以被用来谈及。假设 David 为 l 附上一个数字 x(称为 nonce)并为其组合求哈希。举个例子,如果我们使用 l=“Hello,world!"(显然这不是一个交易清单,只是一个用于演示目的的字符串)和临时值(nonce)x=0(输出是一个十六进制)

h("Hello,world!0") =
	1312af178c253f84028d480a6adc1e25e81caa44c749ec81976192e2ec934c64

David 需要解决的难题是——the proof-of-work——去找到一个临时值(nonce)x,这样当我们将 x 附加于 l 并求其组合的散列值,输出的哈希值以很长一段 0 开头。这里的困难可以被变得更加困难或更加简单通过改变解决这个困难所需要的 0 的数量。一个较为简单的 proof-of-work 难题可能在哈希值的头部只需要 3 个或 4 个 0,然而一个较为困难的 proof-of-work 难题可能需要更长的一串 0,比如 15 个连续的 0。在任何一种情况,上述找到合适的临时值尝试,用 x=0,都是一个失败,因为输出的开头根本就不含任何的 0。尝试用 x=1 也没有效果。