中本聪比特币原始论文笔记
总结
- 本文提出了一个去中心的分布式交易系统
- 首先通过私钥公钥的验证方式来确保发出货币者的货币所有权
- 通过网络广播的方式来解决双重支付问题
- 然后我们通过工作证明(挖矿)加链式结构的方式使得作弊的成本大大增加
- 网络整体去中心,全体匿名
- 所有节点都可以自由离开并加入,在加入时只要同步最长区块链就可以了解整个交易历史
- 记录交易的权利按照算力随机
- 对挖矿奖励,以激励节点记录交易
- 网络用符合各方利益的机制,在去中心的情况下保证可以正常运行
综述
目前的网上交易大多数是通过权威的第三方担保达成,但是由于要保证交易不被篡改、欺诈等问题,第三方机构需要花费额外的成本去维护整个系统
事实上这些成本可以在双方使用传统货币进行交易的情况下得以避免,但是目前没有任何一个商人会放心地在一个去中心的网络里进行交易
所以我们需要一个系统:
- 用密码学来实现信任
- 让双方可以在没有权威中心的担保下直接交易
由于计算量非常大,篡改交易是不可行的,以此保护卖家利益;用第三方托管凭据机制来保护买方利益
我们接下来会提出一个满足上述要求的端对端的分布式系统
系统的安全性由“诚实节点数目多余恶意节点数目”来保证
交易
我们定义电子硬币为一堆数字签名所链接成的串
交易流程是这样的:
- 用收款人的公钥+上一笔交易用特定hash算法生成发款人的签名
- 发款人用自己的私钥在生成的签名上签字(加密)
- 收款人可以用发款人的公钥验证(解密)
- 关于加密和解密的操作详见这里
但是这里有个问题——收款人并不能防止发款人把同样的钱花两遍
传统方式是用一个权威中心通过“造币厂”方法对每笔交易做验证:
- 每次交易后硬币被造币厂回收
- 同时发放新的硬币给收款人
- 只有造币厂生产的硬币可以直接用于流通
问题得以解决,不过需要一个中心——整个货币系统的命运都掌握在造币厂手里
如果要验证一笔钱是否之前用过,那把之前的所有交易都过过一遍是必须的
在造币厂模型里,造币厂就把这个事情办了
但是在去中心的设定下,必须要对每笔交易进行广播才能达到这个要求1
同时需要一个系统,让所有节点对每笔交易按序进行确认
收款人需要在交易时确认,这笔钱被大多数节点承认是第一次花
时间戳服务
要实现上述解决方案,我们首先需要一个时间戳服务
时间戳服务的工作流程:
- 首先我们有定义区块:由多个Item打包而成
- 把区块信息做hash
- 将hash结果连同上一个时间戳一起打包成新的结果
- 把这个结果广播出去
工作证明
为了在一个端到端的基础上实现一个分布式时间戳服务,我们采用了和Adam Back’s Hashcash6一样的工作证明机制——要求用特定hash算法运算出的结果前面N位必须是0
这个工作证明的生成时间随着N的增长呈指数级增长并且易于验证是否合法
具体的做法是在区块中额外增加一个随机数,让这个随机数和整个区块的hash结果符合工作证明
这样一来,如果要篡改区块里面的数据,就要重做工作证明
更要命的是由于后面的块包含前一块的hash结果,所以要把需要篡改的块及以后区块的工作证明一起重做了,计算量简直爆炸
图中的Nonce既是我们额外增加的随机数
工作证明还解决了在意见表决时选出大多数的问题:
- 把选择主流意见抽象为一个投票过程
- 如果按照每个IP投一票的规则,那么这个系统会被那些可以申请大量IP的人所攻击(攻击成本低)
- 那么换成工作证明这种方式的话实际上是按照每个CPU一票(或者按照算力分配票数,攻击成本高)
- 假设多数的算力掌握在诚实的用户手里,那么最长链一定是真实的,整个系统是稳定的
- 此外,工作证明可以调节难度——根据每个小时生成区块的数量采用滑动平均的方式调节N
PS: 这个寻找工作证明的过程就是我们所说的挖矿
网络
整个网络的运转流程如下:
- 有一些新的交易要发起了了!广播至全网络!
- 每个节点将新的交易收集到同一个区块中
- 每个节点都针对这个新生成的区块做工作证明(hash运算),通常这是个艰难的过程
- 如果一个节点做出了合法的工作证明,广播至全网络:“我找到了!”
- 其余的节点对这个节点找到工作证明一事以及这个区块里面所有的交易都是合法的一事(没有双重支付)进行验证——两者都为真,验证通过
- 节点表达验证通过的方式比较有意思,这里单独说一下——是通过把当前区块的hash值当做下一个区块的hash生成材料之一表达对这个区块的认可
- 细想一下这个设计确实巧妙,因为如果接受了一个错误的区块,那么下一个生成的区块也必将不合法,相当于被踢出主链——让每个节点都对自己的验证操作负责
- 多数节点表示通过则这个区块被接受,接到区块链的尾巴上
所有节点都具有最长链共识
——只认可最长的链,并在这个链上挖矿
如果有两个工作证明同时被发现,那么有的节点会接受一个,有些节点会接收另外一个
这时,节点会承认第一个接收到并且会记录另外一个,以防另外的链变的更长(这实际上是分叉了),直到下一个工作证明被挖出来,大家都转到较长的那个链上去了(合并分叉)
新交易的广播不一定要广播至所有节点,只要传播的足够广这个交易就会被加入到下一个区块中
区块广播对于信息丢失也有一定容忍,当下一个区块到来时,那些没有接到上一个区块信息的节点会知道自己丢了信息并和整个网络同步
奖励
做工作证明这么费劲,没有奖励谁会挖?所以奖励机制是整个系统所不可或缺的
挖矿奖励
我们规定,一个区块中的第一笔交易是给这个区块的生成者(即工作证明的生成者)一个新的交易货币,作为奖励
同时,由于没有中心,也就没有初始的货币发行机构,所以我们也通过这种方式将初始货币投入系统流通
这种投入新币的方式和金矿工挖新的金子投入市场的速度差不多
在我们的场景中是对CPU时间和电力的投入
交易费奖励
对于区块中的任意一笔交易:如果收款人接到的钱小于发款人转出的钱,其中的差值就是交易费,一起加入到区块的建立者的奖励中
因为整个货币系统的挖矿奖励总额是固定的,后期的奖励主要来自于交易费奖励——整个比特币系统是永远不会通货膨胀的
保持诚实
这种奖励制度也可以促使节点保持诚实
否则如果出现了拥有了超过50%算力的攻击者,他的算力可以保证用挖矿的方式不断得到奖励,造成对于其他财富的掠夺,进而导致整个系统崩塌,货币失去价值
所以每个节点保持验证的客观性也是保护节点自身的利益
空间优化
当一笔钱的最新一次交易后面已经接了很多区块后(保证篡改数据的计算量非常恐怖),这笔交易之前关于这笔钱的交易数据就不需要存储了,以释放磁盘空间
为了在释放空间的前提下保证hash链的完整性,我们使用Merkle Tree来存储区块链
一旦一个区块的hash值加入新的区块,之前的交易的hash值就没必要存储了
应用这样的技术后,对于大部分历史交易我们可以只存储区块头(80B),按照比特币10分钟新出一个区块的速度来看,每年存储空间的增长应该是4.2MB每年,远比不上摩尔定律下内存空间的增长速度(至少1.2GB每年)
简化交易验证
如果一个用户想要验证一笔交易的合法性:
- 用户只需复制一份最长区块链的区块头部分
- 通过询问网络中的其他节点的方式来保证手头的链最长
- 将对应交易的Merkle分支连接到对应的区块中
- 看看网络中的节点是否接受这笔交易
事实上,验证一笔交易的合法性并不需要全网络的节点都参与,用户可以自行验证,但是这加大了被恶意节点攻击的危险
不过这种风险可以通过接受网络中关于不一致的警告来缓解
合并交易
对于发钱放的多个输入会合并为两个输出:
- 一个是总共花了多少钱
- 一个是花的钱和收入的差值,如果不为0那么返回给发钱方
私密性
传统银行保持私密性的方式是限制其余人对于交易的知情权
对于比特币而言,因为我们要进行广播,所以这招就不能用了
但是我们可以通过保证公钥的匿名性来保护交易双方的隐私
换句话说,新的匿名方式是在所有者与公钥之间建立信息障碍
通过公钥,我们所能知道的只是某些交易是由同一个用户参与
关于安全性的数学验证
即使攻击者伪造了一条比真实区块链更长的链让大家去接受,攻击者也不能任意的修改数据:
- 不能无中生有的变出钱来
- 不能持有曾经不属于自己的钱
所能做的只是撤销自己的支出交易让自己的钱回来
我们把攻击节点与诚实节点之前的竞赛抽象为一个二项随机游走问题:
- 成功事件是诚实节点挖出一个区块,分数+1
- 失败事件是攻击节点挖出一个区块,分数-1
我们定义:
- p为成功事件发生概率
- q为失败事件发生概率
- $q_z$为攻击链在落后z个区块的时候能够追上真实链的概率
则:
假设一个攻击者要在一笔交易之后要伪造交易数据,私自造一条攻击链,这条链的长度可以超过真实链的概率服从一个参数为$\lambda = z \frac {q} {p}$的泊松分布,其概率非常之小
引用
1. https://en.bitcoin.it/wiki/B-money ↩
6. http://www.hashcash.org/papers/hashcash.pdf ↩