比特币:一种点对点电子现金系统
中本聪 satoshin@gmx.com www.bitcoin.org
抽象
一种纯粹的点对点电子现金版本将允许在线支付直接从一方发送到另一方,而无需通过金融机构。数字签名提供了解决方案的一部分,但如果仍然需要可信的第三方来防止双重支付,主要好处就会丧失。我们提出了一种使用点对点网络解决双重支付问题的方案。该网络通过将交易哈希到一个持续的基于哈希的工作量证明链中来时间戳交易,形成一个无法在不重新进行工作量证明的情况下更改的记录。最长的链不仅作为目击事件顺序的证明,还证明它来自最大的 CPU 算力池。只要大多数 CPU 算力由不合作攻击网络的节点控制,他们就会生成最长的链并超越攻击者。网络本身需要的结构最小。消息以尽力而为的方式广播,节点可以随意离开和重新加入网络,接受最长的工作量证明链作为他们离开期间发生的事情的证明。
1. 介绍
互联网商业几乎完全依赖金融机构作为可信的第三方来处理电子支付。虽然这个系统对大多数交易来说运作良好,但仍然存在信任模型固有的弱点。完全不可逆的交易实际上是不可能的,因为金融机构无法避免调解争议。调解的成本增加了交易成本,限制了最低实际交易规模,并切断了小额随意交易的可能性,同时在无法进行不可逆支付的非可逆服务方面也造成了更广泛的成本。由于存在可逆的可能性,信任的需求也随之增加。商家必须对客户保持警惕,要求他们提供比通常需要的更多信息。一定比例的欺诈被视为不可避免。这些成本和支付不确定性可以通过使用实物货币在面对面交易中避免,但没有机制可以在没有可信方的情况下通过通信渠道进行支付。
所需的是一种基于密码学证明而非信任的电子支付系统,使任何两个愿意的交易方能够直接进行交易,而无需可信的第三方。那些计算上不切实际的逆转交易将保护卖家免受欺诈,而常规的托管机制可以轻松实施以保护买家。在本文中,我们提出了一种使用点对点分布式时间戳服务器解决双重支付问题的方案,以生成交易时间顺序的计算证明。只要诚实节点共同控制的 CPU 算力超过任何合作攻击者节点组,该系统就是安全的。
2. 交易
我们将电子货币定义为一串数字签名。每个拥有者通过数字签名前一个交易的哈希值和下一个拥有者的公钥,将硬币转移给下一个拥有者,并将这些添加到硬币的末尾。收款人可以验证签名以确认所有权链。
当然,问题在于收款人无法验证其中一位所有者是否没有重复花费这枚硬币。一个常见的解决方案是引入一个可信的中央权威或铸币厂,检查每笔交易是否存在重复花费。在每笔交易后,硬币必须返回铸币厂以发行新硬币,只有直接从铸币厂发行的硬币才被信任不会重复花费。这个解决方案的问题在于,整个货币系统的命运依赖于运营铸币厂的公司,每笔交易都必须通过他们,就像银行一样。
我们需要一种方式让收款人知道之前的所有者没有签署任何早期交易。对我们来说,最早的交易才是重要的,所以我们不关心后来的双重支付尝试。确认没有交易的唯一方法是了解所有交易。在基于铸币的模型中,铸币知道所有交易并决定哪个先到。为了在没有可信方的情况下实现这一点,交易必须公开宣布[1],我们需要一个系统让参与者就它们被接收的顺序达成一致的单一历史。收款人需要证明,在每笔交易时,大多数节点都同意它是第一笔接收的交易。
3. 时间戳服务器
我们提出的解决方案始于一个时间戳服务器。时间戳服务器通过对一组待时间戳的项目进行哈希处理,并广泛发布该哈希(例如在报纸或 Usenet 帖子中)来工作[2-5]。时间戳证明数据必须在那个时间存在,显然,才能进入哈希。每个时间戳在其哈希中包含前一个时间戳,形成一个链条,每个额外的时间戳都加强之前的时间戳。
4. 工作量证明
要在点对点基础上实现分布式时间戳服务器,我们需要使用类似于亚当·巴克的 Hashcash 的工作量证明系统,而不是报纸或 Usenet 帖子。工作量证明涉及扫描一个值,当其被哈希时,例如使用 SHA-256,哈希以若干个零位开头。所需的平均工作量与所需的零位数量呈指数关系,并且可以通过执行单个哈希来验证。
对于我们的时间戳网络,我们通过在区块中递增一个随机数来实现工作量证明,直到找到一个值,使得区块的哈希具有所需的零位。一旦 CPU 的努力被用来使其满足工作量证明,该区块就无法更改,除非重新进行工作。由于后续区块是依赖于它的,改变该区块的工作将包括重新做所有后面的区块。
工作量证明还解决了在多数决策中确定代表性的问题。如果多数是基于一个 IP 地址一票,那么任何能够分配多个 IP 的人都可以颠覆这一点。工作量证明本质上是一个 CPU 一票。多数决策由最长链表示,该链投入了最大的工作量证明努力。如果大多数 CPU 算力由诚实节点控制,诚实链将以最快的速度增长,超越任何竞争链。要修改过去的区块,攻击者必须重新进行该区块及其后所有区块的工作量证明,然后赶上并超越诚实节点的工作。我们稍后将展示,随着后续区块的增加,较慢攻击者赶上的概率呈指数级下降。
为了补偿硬件速度的提高和运行节点兴趣的变化,工作量证明的难度是通过一个移动平均值来确定的,目标是每小时生成一定数量的区块。如果生成速度过快,难度就会增加。
5. 网络
运行网络的步骤如下:
新交易会广播到所有节点。
每个节点将新交易收集到一个区块中。
每个节点都在为其区块寻找一个困难的工作量证明。
当一个节点找到工作量证明时,它会将区块广播给所有节点。
节点仅在区块中的所有交易有效且未被花费时才接受该区块。
节点通过使用已接受区块的哈希作为前一个哈希,来创建链中的下一个区块,从而表达对该区块的接受。
节点总是认为最长的链是正确的,并会继续努力扩展它。如果两个节点同时广播下一个区块的不同版本,一些节点可能会先接收到其中一个。在这种情况下,它们会处理第一个接收到的版本,但会保存另一个分支以防它变得更长。当下一个工作量证明被找到并且一个分支变得更长时,平局将被打破;那些在另一个分支上工作的节点将切换到更长的分支。
新的交易广播不一定需要到达所有节点。只要它们到达许多节点,就会很快进入一个区块。区块广播也能容忍丢失的信息。如果一个节点没有收到一个区块,它会在收到下一个区块时请求它,并意识到自己错过了一个。
6. 激励
根据惯例,区块中的第一笔交易是一个特殊交易,它启动了由区块创建者拥有的新币。这为节点支持网络提供了激励,并提供了一种将币初步分发到流通中的方式,因为没有中央权威来发行它们。不断增加固定数量的新币类似于金矿工人花费资源将黄金投入流通。在我们的情况下,消耗的是 CPU 时间和电力。
激励也可以通过交易费用来资助。如果交易的输出值低于其输入值,差额就是交易费用,这会被添加到包含该交易的区块的激励值中。一旦预定数量的币进入流通,激励可以完全转向交易费用,完全无通货膨胀。
激励可能有助于鼓励节点保持诚实。如果一个贪婪的攻击者能够集结比所有诚实节点更多的 CPU 算力,他将不得不在用它来欺诈人们以窃取回他的支付,或用它来生成新币之间做出选择。他应该会发现,遵循规则更有利可图,这些规则使他获得的新币比其他所有人加起来都多,而不是破坏系统和他自己财富的有效性。
7. 重新获取磁盘空间
一旦某个币的最新交易被足够的区块埋藏,就可以丢弃之前的已花费交易以节省磁盘空间。为了在不破坏区块哈希的情况下实现这一点,交易在梅克尔树中进行哈希处理,只有根被包含在区块的哈希中。然后,可以通过去掉树的分支来压缩旧区块。内部哈希不需要存储。
在梅克尔树中哈希的交易
从区块中修剪 Tx0-2 后
一个没有交易的区块头大约是 80 字节。如果我们假设每 10 分钟生成一个区块,那么每年就是 80 字节
∗
6
∗
24
∗
365
=
4.2
MB
∗
6
∗
24
∗
365
=
4.2
MB
**6**24**365=4.2MB * 6 * 24 * 365=4.2 \mathrm{MB} 。截至 2008 年,计算机系统通常配备 2GB 的 RAM,而摩尔定律预测每年增长 1.2GB,因此即使区块头必须保存在内存中,存储也不应该是问题。
8. 简化支付验证
可以在不运行完整网络节点的情况下验证支付。用户只需保留最长工作量证明链的区块头副本,可以通过查询网络节点直到确认自己拥有最长链,并获取将交易链接到其时间戳所在区块的梅克尔分支。他无法自己检查交易,但通过将其链接到链中的某个位置,可以看到网络节点已接受该交易,之后添加的区块进一步确认网络已接受它。
因此,只要诚实的节点控制网络,验证就是可靠的,但如果网络被攻击者控制,就更容易受到攻击。虽然网络节点可以自行验证交易,但简化的方法可能会被攻击者伪造的交易欺骗,只要攻击者能够继续控制网络。一种保护措施是,当网络节点检测到无效区块时,接受警报,促使用户的软件下载完整区块和警报交易以确认不一致。频繁收款的企业可能仍然希望运行自己的节点,以获得更独立的安全性和更快的验证。
9. 组合与拆分价值
虽然可以单独处理硬币,但为每一分钱的转账进行单独交易会很麻烦。为了允许价值的拆分和合并,交易包含多个输入和输出。通常会有一个来自较大先前交易的单一输入,或者多个输入合并较小的金额,最多有两个输出:一个用于支付,另一个如果有的话则将找零返回给发送者。
需要注意的是,扇出,即一个交易依赖于多个交易,而这些交易又依赖于更多交易,在这里并不是问题。永远不需要提取交易历史的完整独立副本。
10. 隐私
传统银行模型通过限制信息访问仅限于相关方和可信第三方来实现一定程度的隐私。公开宣布所有交易的必要性排除了这种方法,但仍然可以通过在其他地方打破信息流来保持隐私:保持公钥匿名。公众可以看到某人向其他人发送了一定金额,但没有信息将交易与任何人关联。这类似于证券交易所发布的信息水平,个别交易的时间和规模,即“带子”,是公开的,但没有透露交易方是谁。
作为额外的防火墙,每笔交易应使用一对新的密钥,以防止它们与共同的所有者关联。多输入交易仍然不可避免地会有一些关联,因为它们的输入必然显示由同一所有者拥有。风险在于,如果密钥的所有者被揭示,关联可能会揭示属于同一所有者的其他交易。
11. 计算
我们考虑攻击者试图比诚实链更快地生成替代链的情况。即使成功了,也不会让系统开放给任意更改,比如凭空创造价值或拿走从未属于攻击者的钱。节点不会接受无效交易作为支付,诚实节点永远不会接受包含这些交易的区块。攻击者只能尝试更改自己的一笔交易,以收回他最近花费的钱。
诚实链与攻击者链之间的竞争可以被描述为二项随机游走。成功事件是诚实链增加一个区块,领先优势增加 +1,失败事件是攻击者链增加一个区块,差距减少 -1。
攻击者从给定的劣势追赶上来的概率类似于赌徒破产问题。假设一个拥有无限信用的赌徒从劣势开始,并进行潜在无限次的尝试以试图达到收支平衡。我们可以计算他是否能达到收支平衡的概率,或者攻击者是否能追赶上诚实链的概率,如下所示[8]:
p
=
p
=
p= p= 诚实节点找到下一个区块的概率
q
=
q
=
q= q= 攻击者找到下一个区块的概率
q
z
=
q
z
=
q_(z)= q_{z}= 攻击者从
z
z
z z 个区块落后永远追上的概率
q
z
=
{
1
if
p
≤
q
(
q
/
p
)
z
if
p
>
q
}
q
z
=
1
if
p
≤
q
(
q
/
p
)
z
if
p
>
q
q_(z)={[1," if "p <= q],[(q//p)^(z)," if "p > q]} q_{z}=\left\{\begin{array}{cc}
1 & \text { if } p \leq q \\
(q / p)^{z} & \text { if } p>q
\end{array}\right\}
考虑到我们假设的
p
>
q
p
>
q
p > q p>q ,随着攻击者需要追赶的区块数量增加,概率呈指数下降。在不利的情况下,如果他没有在早期幸运地向前冲一把,他的机会会随着他进一步落后而变得微乎其微。
我们现在考虑新交易的接收者需要等待多久,才能足够确定发送者无法更改交易。我们假设发送者是一个攻击者,他想让接收者相信他已经支付了,然后在一段时间后再切换回自己。接收者在发生这种情况时会被警告,但发送者希望那时已经太晚了。
接收方生成一对新密钥,并在签名前不久将公钥提供给发送方。这防止了发送方提前准备一系列区块,通过不断工作直到足够幸运地领先,然后在那个时刻执行交易。一旦交易被发送,不诚实的发送方就开始秘密工作,创建一个包含其交易替代版本的平行链。
接收者会等到交易被添加到一个区块中,并且在它之后链接了
z
z
z z 个区块。他不知道攻击者的确切进展,但假设诚实区块的处理时间是每个区块的平均预期时间,攻击者的潜在进展将是一个期望值为的泊松分布:
λ
=
z
q
p
λ
=
z
q
p
lambda=z(q)/(p) \lambda=z \frac{q}{p}
为了计算攻击者现在仍然能够追上的概率,我们将他可能取得的每一进展量的泊松密度与他从那个点追上的概率相乘:
∑
k
=
0
∞
λ
k
e
−
λ
k
!
⋅
{
(
q
/
p
)
(
z
−
k
)
if
k
≤
z
1
if
k
>
z
}
∑
k
=
0
∞
λ
k
e
−
λ
k
!
⋅
(
q
/
p
)
(
z
−
k
)
if
k
≤
z
1
if
k
>
z
sum_(k=0)^(oo)(lambda^(k)e^(-lambda))/(k!)*{[(q//p)^((z-k))," if "k <= z],[1," if "k > z]} \sum_{k=0}^{\infty} \frac{\lambda^{k} e^{-\lambda}}{k!} \cdot\left\{\begin{array}{cc}
(q / p)^{(z-k)} & \text { if } k \leq z \\
1 & \text { if } k>z
\end{array}\right\}
重新排列以避免对分布的无限尾部求和……
1
−
∑
k
=
0
z
λ
k
e
−
λ
k
!
(
1
−
(
q
/
p
)
(
z
−
k
)
)
1
−
∑
k
=
0
z
λ
k
e
−
λ
k
!
1
−
(
q
/
p
)
(
z
−
k
)
1-sum_(k=0)^(z)(lambda^(k)e^(-lambda))/(k!)(1-(q//p)^((z-k))) 1-\sum_{k=0}^{z} \frac{\lambda^{k} e^{-\lambda}}{k!}\left(1-(q / p)^{(z-k)}\right)
转换为 C 代码…
#include <math.h>
double AttackerSuccessProbability(double q, int z)
{
double p = 1.0 - q;
double lambda = z * (q / p);
double sum = 1.0;
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;
}
运行一些结果,我们可以看到概率随着 z 指数下降。
q
=
0.1
z
=
0
P
=
1.0000000
z
=
1
P
=
0.2045873
z
=
2
P
=
0.0509779
z
=
3
P
=
0.0131722
z
=
4
P
=
0.0034552
z
=
5
P
=
0.0009137
z
=
6
P
=
0.0002428
z
=
7
P
=
0.0000647
z
=
8
P
=
0.0000173
z
=
9
P
=
0.0000046
z
=
10
P
=
0.0000012
q
=
0.3
z
=
0
P
=
1.0000000
z
=
5
P
=
0.1773523
z
=
10
P
=
0.0416605
z
=
15
P
=
0.0101008
z
=
20
P
=
0.0024804
z
=
25
P
=
0.0006132
z
=
30
P
=
0.0001522
z
=
35
P
=
0.0000379
z
=
40
P
=
0.0000095
z
=
45
P
=
0.0000024
z
=
50
P
=
0.0000006
q
=
0.1
z
=
0
P
=
1.0000000
z
=
1
P
=
0.2045873
z
=
2
P
=
0.0509779
z
=
3
P
=
0.0131722
z
=
4
P
=
0.0034552
z
=
5
P
=
0.0009137
z
=
6
P
=
0.0002428
z
=
7
P
=
0.0000647
z
=
8
P
=
0.0000173
z
=
9
P
=
0.0000046
z
=
10
P
=
0.0000012
q
=
0.3
z
=
0
P
=
1.0000000
z
=
5
P
=
0.1773523
z
=
10
P
=
0.0416605
z
=
15
P
=
0.0101008
z
=
20
P
=
0.0024804
z
=
25
P
=
0.0006132
z
=
30
P
=
0.0001522
z
=
35
P
=
0.0000379
z
=
40
P
=
0.0000095
z
=
45
P
=
0.0000024
z
=
50
P
=
0.0000006
{:[q=0.1,],[z=0,P=1.0000000],[z=1,P=0.2045873],[z=2,P=0.0509779],[z=3,P=0.0131722],[z=4,P=0.0034552],[z=5,P=0.0009137],[z=6,P=0.0002428],[z=7,P=0.0000647],[z=8,P=0.0000173],[z=9,P=0.0000046],[z=10,P=0.0000012],[,],[q=0.3,],[z=0,P=1.0000000],[z=5,P=0.1773523],[z=10,P=0.0416605],[z=15,P=0.0101008],[z=20,P=0.0024804],[z=25,P=0.0006132],[z=30,P=0.0001522],[z=35,P=0.0000379],[z=40,P=0.0000095],[z=45,P=0.0000024],[z=50,P=0.0000006]:} \begin{array}{ll}
\mathrm{q}=0.1 & \\
\mathrm{z}=0 & \mathrm{P}=1.0000000 \\
\mathrm{z}=1 & \mathrm{P}=0.2045873 \\
\mathrm{z}=2 & \mathrm{P}=0.0509779 \\
\mathrm{z}=3 & \mathrm{P}=0.0131722 \\
\mathrm{z}=4 & \mathrm{P}=0.0034552 \\
\mathrm{z}=5 & \mathrm{P}=0.0009137 \\
\mathrm{z}=6 & \mathrm{P}=0.0002428 \\
\mathrm{z}=7 & \mathrm{P}=0.0000647 \\
\mathrm{z}=8 & \mathrm{P}=0.0000173 \\
\mathrm{z}=9 & \mathrm{P}=0.0000046 \\
\mathrm{z}=10 & \mathrm{P}=0.0000012 \\
& \\
\mathrm{q}=0.3 & \\
z=0 & \mathrm{P}=1.0000000 \\
z=5 & P=0.1773523 \\
z=10 & \mathrm{P}=0.0416605 \\
\mathrm{z}=15 & \mathrm{P}=0.0101008 \\
\mathrm{z}=20 & \mathrm{P}=0.0024804 \\
z=25 & P=0.0006132 \\
z=30 & P=0.0001522 \\
z=35 & P=0.0000379 \\
z=40 & P=0.0000095 \\
z=45 & P=0.0000024 \\
z=50 & P=0.0000006
\end{array}
解 P 小于
0.1
%
…
0.1
%
…
0.1%dots 0.1 \% \ldots
P
<
0.001
q
=
0.10
z
=
5
q
=
0.15
z
=
8
q
=
0.20
z
=
11
q
=
0.25
z
=
15
q
=
0.30
z
=
24
q
=
0.35
z
=
41
q
=
0.40
z
=
89
q
=
0.45
z
=
340
P
<
0.001
q
=
0.10
z
=
5
q
=
0.15
z
=
8
q
=
0.20
z
=
11
q
=
0.25
z
=
15
q
=
0.30
z
=
24
q
=
0.35
z
=
41
q
=
0.40
z
=
89
q
=
0.45
z
=
340
{:[P < 0.001],[q=0.10,z=5],[q=0.15,z=8],[q=0.20,z=11],[q=0.25,z=15],[q=0.30,z=24],[q=0.35,z=41],[q=0.40,z=89],[q=0.45,z=340]:} \begin{array}{ll}
P<0.001 \\
q=0.10 & z=5 \\
q=0.15 & z=8 \\
q=0.20 & z=11 \\
q=0.25 & z=15 \\
q=0.30 & z=24 \\
q=0.35 & z=41 \\
q=0.40 & z=89 \\
q=0.45 & z=340
\end{array}
12. 结论
我们提出了一种无需依赖信任的电子交易系统。我们从基于数字签名的硬币的常规框架开始,这提供了强大的所有权控制,但没有防止双重支付的方法是不完整的。为了解决这个问题,我们提出了一个点对点网络,使用工作量证明来记录交易的公共历史,如果诚实节点控制了大多数 CPU 算力,攻击者就很快会发现改变这一历史在计算上是不切实际的。这个网络在其无结构的简单性中是强大的。节点几乎没有协调地同时工作。它们不需要被识别,因为消息并不是路由到任何特定地点,只需尽力传递。节点可以随意离开和重新加入网络,接受工作量证明链作为它们离开期间发生的事情的证明。它们用 CPU 算力投票,通过扩展有效区块来表达对有效区块的接受,通过拒绝工作于无效区块来拒绝无效区块。任何需要的规则和激励都可以通过这种共识机制来执行。
参考文献
W. Dai, “b-money,” http://www.weidai.com/bmoney.txt, 1998. [2] H. Massias, X.S. Avila, 和 J.-J. Quisquater,“设计一个具有最小信任要求的安全时间戳服务,”在 1999 年 5 月的贝内卢克斯信息理论第 20 届研讨会上。 [3] S. Haber, W.S. Stornetta,“如何给数字文档加时间戳,”发表于《密码学杂志》,第 3 卷,第 2 期,99-111 页,1991 年。 [4] D. Bayer, S. Haber, W.S. Stornetta,“提高数字时间戳的效率和可靠性,”收录于《序列 II:通信、安全和计算机科学中的方法》,第 329-334 页,1993 年。 [5] S. Haber, W.S. Stornetta,“位串的安全名称,” 载于第 4 届 ACM 计算机与通信安全会议论文集,页码 28-35,1997 年 4 月。 [6] A. Back, “Hashcash - 一种拒绝服务的对策,”http://www.hashcash.org/papers/hashcash.pdf,2002 年。 R.C. Merkle,“公钥密码系统的协议,”发表于 1980 年安全与隐私研讨会论文集,IEEE 计算机学会,122-133 页,1980 年 4 月。 W. Feller,《概率论及其应用导论》,1957 年。