在聊区块链记账原理之前我们先来了解几个知识点,随后再慢慢说明:
- 区块链就是一个不断增长的全网总账本
- 每个完全节点都拥有完整的区块链
- 节点总是信任最长的区块链
- 伪造区块链需要拥有超过51%的全网算力
哈希算法
区块链是由一个个区块构成的有序列表,每一个区块都记录了一系列交易,并且每一个区块都指向了前一个区块从而形成一个链条。如果我们观察一个区块,我们可以看到以下信息:
- 每一个区块都有一个唯一的哈希标识,称为区块哈希;
- 区块通过上一个区块的哈希来指向上一个区块;
- Merkle Hash用来确保所有交易记录无法被篡改;
- 区块的主要数据就是一些列交易;
- 第一条交易通常是Coinbase交易,也就是旷工的挖矿奖励;
- 后续交易都是用户的交易。
区块链的不可篡改特性是由哈希算法保证的。什么是哈希算法?
哈希算法又称散列算法,它是一个单向函数:
h = H(x)
,它把任意长度的输入数据转化为固定长度的输出。
例如,将"morning"和"bitcoin"进行哈希运算,他们得出的输出长度都是固定的:
H("morning") = c7c3169c21f1d92e9577871831d067c8
H("bitcoin") = cd5b1e4947e304476c788cd474fb579a
因为哈希算法是一个单向函数,因此通过输入可以很容易地计算输出,但是通过输出无法反推输入,只能暴力穷举!
还是上面的例子,你只有输出,几乎是无法计算出输入的:
H("???????") = c7c3169c21f1d92e9577871831d067c8
H("???????") = cd5b1e4947e304476c788cd474fb579a
安全的哈希算法需要具备几个特点。第一个是碰撞率低,什么是碰撞呢?
如果两个输入数据不同却恰好计算出了相同的哈希值我们说发生了碰撞。因为输入数据的长度是不固定的,因此输入数据是一个无限大的集合。而输出数据的长度是有限的,所以是一个有限的集合。把一个无限集合的数据映射到有限集合中就必然存在某些不同的输入而有相同的输出。这就是碰撞。
例如,将"data-123456"和"data-ABCDEF"进行哈希运算恰好计算出了相同的结果:
H("data-123456") = a76b1fb579a02a476c789d9115d4b201
H("data-ABCEDF") = a76b1fb579a02a476c789d9115d4b201
我们假设某个哈希函数,它的输出是固定的长度3bit,那么输出的范围就是二进制的000 ~ 111
,也就是10进制的数组0 ~ 7
。当我们计算8种水果的哈希时,假定没有碰撞,那么第九种水果的哈希必然会与其中一种发生碰撞:
哈希碰撞的本质是把无限的集合映射到有限的集合时必然产生的碰撞,我们需要计算的是碰撞的概率。很显然,碰撞的概率和输出的集合大小有关,输出的哈希位数越多输出集合越大,碰撞率就越低。
安全的哈希算法需要具备的第二个特点是输出无规律,什么是输出无规律呢?
输入数据任意一个bit的改动,会导致输出完全不同。从而让攻击者无法通过输出猜测输入,只能依靠暴力穷举来破解。
例如,将"hello-1"改为"hello-2"得到的哈希值完全不同:
H("hello-1") = 970db54ab8a93b7173cb48f55e67fd2c
H("hello-2") = 8284353b768977f05ac600baad8d3d17
哈希算法的作用
假设我们相信一个安全的哈希算法,如果两个哈希值完全相同,那么对应的输入就是完全相同的。比如两个文件的hash相同,说明文件没有被修改过。很多官方网站就是让用户通过这种方法确认hash值是不是一致的去确认文件是否被修改过。和文件类似,如果两份数据的哈希值是完全相同的说明数据没有被篡改。
比特币就是通过哈希算法来保证所有的交易不可修改,就是计算和记录交易的哈希。如果交易被篡改,那么哈希验证将无法通过,说明这个区块是无效的。
常用的哈希算法有:
- MD5
- RipeMD160
- SHA-1
- SHA-256
- SHA-512
比特币使用的哈希算法有两种:
- SHA-256
- RipeMD160
SHA-256的理论碰撞概率:
尝试2的130次方次随机输入,有99.8%的概率碰撞,差不多是1361万亿亿亿亿次。以现有计算机的计算能力是不可能在短期内破解的。
比特币中的哈希算法
比特币使用了两种哈希算法:
- 两次SHA-256。对数据进行两次SHA-256的计算,这种算法在比特币协议中通常称为
hash256
:
hash256 = sha256(sha256(data))
- 先计算SHA-256,再计算RipeMD160。这种算法在比特币协议中通常称为
hash160
:
hash160 = ripemd160(sha256(data))
前面我们知道在区块的头部有一个Merkle Hash,记录了本区块的所有交易的Merkle Hash。那Merkle Hash是如何计算出来的呢?
假设这个区块有5笔交易,首先,对每一笔交易进行第一hash,也就是2次SHA-256的运算,得到5个哈希值,也就是a1、a2、a3、a4、a5,这五个哈希值也可以看做是数据,将a1和a2拼起来、a3和a4拼起来,再计算出2个哈希值b1和b2。那a5怎么办呢?答案是将a5复制一份在与a5拼起来进行哈希计算得到b3;继续将b1和b2拼起来进行哈希运算得到c1,同样的b3会被复制一份再与b3拼起来进行哈希运算得到c2;最后将c1和c2拼起来进行哈希运算得到最终的哈希值,这个哈希值就是Merckle Hash。
从Merkle Hash的计算方法可以得出结论:修改任意一笔交易,哪怕是一个字节,或者交换两个交易的顺序,都会导致Merkle Hash验证失败,也就会导致这个区块本身是无效的。所以Merkle Hash记录在头部,它的作用就是保证交易记录永远不能够被修改。
区块本身用Block Hash来标识。一个区块自己的区块哈希并没有记录在区块头部,而是通过计算区块头部的哈希得到的。
区块头部的Prev Hash记录了上一个区块的哈希。这样可以通过Prev Hash追踪到上一个区块。由于下一个区块的Prev Hash又会指向当前区块,这样每一个区块的Prev Hash都指向了上一个区块。这些区块串起来就形成了区块链。
如果一个恶意攻击者修改了其中的某个交易,那么这个区块的Merkle Hash就不会验证通过,所以攻击者只能重新计算Merkle Hash,然后把区块头的Merkle Hash也修改了。这时我们就会发现,这个区块本身的哈希又变了,所以下一个区块的指向它的链接就断掉了。由于比特币的哈希值必须满足一个难度值,因此攻击者必须重新计算这个区块的哈希,然后把后续所有区块全部重新计算并且伪造出来才能够修改整个区块链。
我们看到修改一个区块的成本就已经非常非常高了,要修改后续所有区块,这个攻击者必须掌握全网51%以上的算力才行。所以修改区块链的难度是非常非常大的。并且由于正常的区块链在不断的增长,同样一个区块,修改它的难度会随着时间的推移而不断的增加。所以我们得出结论:
- 区块链依靠安全的哈希算法保证所有区块数据不可更改
- 工作量证明机制保证修改区块链的难度非常巨大从而无法实现
下次我们继续探讨去中心化交易原理。敬请期待!