区块链核心技术:哈希与加密算法
imToken 是一款全球领先的区块链数字资产管理工具[ZB],帮助你安全管理BTC, ETH, ATOM, EOS, TRX, CKB, BCH, LTC, DOT, KSM, FIL, XTZ 资产,同时支持去中心化币币兑换功能 ...
区块链的两大核心技术就是共识机制和密码学,由于共识机制是公链的基础,所以在之前的内容中我已经优先讲解了这部分,接下来我会讲解区块链的密码学基础,大家只要了解它的基本原理和区块链密码学的优缺点就可以了。
区块链中采用的密码算法主要有两类,第一类是哈希算法,第二类是非对称加密算法。
我们首先来看一下哈希算法。
1.哈希算法
哈希算法是一种数学函数算法,又称散列算法,是一种数据映射关系。为了便于举例,我们假设h = HASH(X | z),你输入一个任意长度的数据z,经过哈希运算后,返回一个固定长度的数据h。z称为原图,h为哈希结果,又称“数据指纹”,z是构成X的可选数据集。
哈希算法具有以下四个特点。
原像不可逆。原像不可逆意味着对于任意给定的h,无法根据h本身的信息推导出z。 谜题友好性。谜题友好性可以简单理解为,想要得到一道谜题的答案,只能强行枚举,没有比这更好的办法了。在h = HASH(X | z)中,无法从h推导出z,只能不停地计算、尝试。那么z所在的值集合就构成了X,而X的大小是哈希算法的安全因素之一。 发散性。发散性意味着对于任意的z,哪怕我们只改变非常小的信息,比如改变1bit生成z',那么HASH(z)和HASH(z')就是两个完全不同的结果,完全不一样。 防碰撞。防碰撞意味着对于任意两个不同的z,它们对应的h值也是不一样的。 如果对于任何 y 不等于 z,则 HASH(y) 不等于 HASH(z);满足上述定义的哈希特性的算法也称为严格防碰撞的算法。
目前流行的哈希算法有MD5、SHA-1和SHA-2,其中MD5已被证明不具备“强防碰撞”性。SHA(Hash)是一个哈希函数家族,分为SHA-1、SHA-2、SHA-3,代表三代哈希标准。目前比较常用的是SHA-2系列。第一代SHA-1是基于MD4的设计,并模仿了该算法。SHA-1已被证明不具备“强防碰撞”性,因此安全性不够高。为了提高安全性,第二代SHA-2共包括SHA-224、SHA-256、SHA-384、SHA-512等算法(统称为SHA-2),与SHA-1算法类似。SHA-3相关算法也已被提出,它的出现并不是为了取代SHA-2,因为SHA-2目前还没有明显的弱点。 由于MD5和SHA-1被成功破解,我们需要一个与以前的算法不同且可替代的加密哈希算法,现在的算法是SHA-3。
1.1 区块链上的哈希算法
哈希算法被广泛用于区块和交易的构造和完整性验证。由于哈希算法的四个特性,我们可以将任意交易数据做成数据摘要,然后逐一链接起来,形成数据区块的链式结构。这样,我们可以通过验证每一个区块来间接验证交易,进而每笔交易原始数据也可以做成哈希数据摘要,以验证交易数据的完整性。我们借用比特币开发者文档中的图表,它表达了区块链的基本数据结构。
图中可以看到,当前区块包含了前一个区块的hash,形成了一个hash指针链表。由于hash的发散性,这个链表也具有很大的发散性。我们可以用代码来模拟,我们先构造5个简化的区块,呈一个列表的形式,第一个区块为创世区块,我们规定它指向的前向区块的hash全为零;第二、第三个区块分别记录两笔交易。这里为了方便理解,我用文字来表达交易的内容,其实区块链上的交易都是二进制格式的数据,并不是文本数据。hash不是在代码中填写的,而是在运行时填写的。
#!/usr/bin/env python
import hashlib
def main():
# example:
block_headers = [
{"prev_block_hash":"0000000000000000000000000000000000000000000000000000000000000000", "content":"genesis block:A pay C 12.3 BTC"},
{"prev_block_hash":"to_be_hashed", "content":"2nd block:C pay B 2.0 BTC"},
{"prev_block_hash":"to_be_hashed", "content":"3th block:transactions..."},
{"prev_block_hash":"to_be_hashed", "content":"4th block:transactions...j"},
{"prev_block_hash":"to_be_hashed", "content":"5th block:transactions..."}
]
# hash prev block header
index = 0
for header in block_headers:
# genesis block, ignore
if index == 0:
print header
index = index + 1
continue
# generate hash chain
prev_block_header = block_headers[index - 1]
target_buffer = prev_block_header["content"] + prev_block_header["prev_block_hash"]
header["prev_block_hash"] = hashlib.sha256(target_buffer).hexdigest()
print header
index = index + 1
if __name__ == '__main__':
main()
我们可以直接得到结果,这是一个典型的hash指针链表,每个block的指向前一个block的hash。
{'content': 'genesis block:A pay C 12.3 BTC', 'prev_block_hash': '0000000000000000000000000000000000000000000000000000000000000000'}
{'content': '2nd block:C pay B 2.1 BTC', 'prev_block_hash': '01279c1208a8eca3d4a47a123119b04f1dcc592c818aace2715b2c418b38822a'}
{'content': '3th block:transactions...', 'prev_block_hash': '6d96c220b22371dc1d2b3549da42bd3ea2191f07f18112bf195bc6675bbc6b97'}
{'content': '4th block:transactions...j', 'prev_block_hash': '9e41c61fa151320145a56a38e85c01b8c025729614f4c10596d99068ea0b3395'}
{'content': '5th block:transactions...', 'prev_block_hash': '34f002b445a38fa7402e590629e76943060ffc4de96b1b9bc6b0f564e5a7bc72'}
如果我们将第二个区块从“C 支付 B 2.1 BTC”修改为“C 支付 B 2.0 BTC”,会得到如下结果,我们可以发现从第三个区块开始所有区块指向的前一个区块的哈希都不再与上面的一致。
{'content': 'genesis block:A pay C 12.3 BTC', 'prev_block_hash': '0000000000000000000000000000000000000000000000000000000000000000'}
{'content': '2nd block:C pay B 2.0 BTC', 'prev_block_hash': '01279c1208a8eca3d4a47a123119b04f1dcc592c818aace2715b2c418b38822a'}
{'content': '3th block:transactions...', 'prev_block_hash': 'f91faad6b874fb97a20ad9cbc57ef1302a431a2cce4ac5efe28a64b353526849'}
{'content': '4th block:transactions...j', 'prev_block_hash': '99d17dfe9a9fab68cffd6a82bc3786fe3c2d3165f1fba30b3f2ffc418c97fc8b'}
{'content': '5th block:transactions...', 'prev_block_hash': 'd2f42291ef0811e5babc1d38ca8019ee457f84b323a3d549a04b6a4535357d7f'}
以上我们构建了一个非常简单的区块链基本结构,区块头描述了一个区块的基本信息,在实际应用中,通常包含以下内容。
图中显示了当前区块高度、本区块哈希、前一个区块哈希、nonce值等以太坊和比特币区块链钱包,因此前一个区块哈希是区块头中必不可少的数据字段。这种链式结构具有发散性,篡改历史越久远,越容易造成大规模影响,这也叫历史逆向修改的难度。
在PoW共识机制下,这种反向修改的难度会随着当前网络算力的增加而线性增加。
1.2 树
哈希算法的一个重要应用就是树。树是一种数据结构,通常是二叉树,但也可以是多分支树,按照特定的方式一层层计算,直到最顶层,最顶层称为根。最常见、最简单的树是二叉树。树的基本结构如下图所示。
比特币和以太坊都采用了树的数据结构,但是其中存储的数据是经过哈希处理的。我们可以在比特币核心版源代码中的注释中找到介绍。
以太坊对比特币的设计做了改进,称为 树。与比特币在区块头中只有一棵树相比,以太坊有三棵树。
区块链的挖矿算法也是采用哈希算法,挖矿算法利用了其难度友好性,我们在PoW共识机制中已经讲解过,这里就不再赘述了。
2.非对称加密算法
非对称加密算法是相对于对称算法而言的,二者共同构成了密码学的核心内容。二者在使用上的不同体现在密钥是否可以公开。对称密钥要求在加密和解密过程中使用同一个密钥,而非对称加密则可以提供一对密钥imToken,私钥由用户保管,公钥可以公开。常见的对称加密算法有DES、3DES、AES、IDEA等,常见的非对称加密算法有RSA、ECC等。
在比特币等很多数字货币项目中,主要在账户层面采用非对称加密算法。在对称加密算法中,由于双方需要提前共享密钥,因此在使用过程中存在很多不便。非对称算法的出现解决了这个问题。
在非对称算法中,私钥一般由一个随机数生成,我们也称这个随机数为种子。从这个角度来说,知道这个随机数就相当于知道了私钥。但是私钥生成的范围非常大,在比特币中是2的256次方,也就是大概是10的70次方的数量级。
如果你用来生成随机数的算法足够均匀分布,那么私钥碰撞的概率比中一亿彩票和被雷击中的概率还要小几亿倍。所以区块链对生成随机数的算法要求比较高,要求是真正的均匀随机分布,而不是计算机伪随机数。如果我们有私钥,那么就会如图所示:
从私钥到公钥的转移由非对称加密算法保证,比特币使用的算法是ECDSA算法,ECDSA算法中选取的椭圆曲线就是这个名字,从公钥到地址的转移由哈希算法保证,在这个步骤中,用到了sum。
椭圆曲线加密算法ECC利用“寻找离散对数”的难度来提供单向不可逆性,具体原理大家可以去查资料了解。在区块链上,一笔比特币交易的生成由两部分组成,第一部分是签名锁,对应交易的输出,第二部分是解锁成本,对应交易的输入。我们在构造交易的时候,必须使用私钥,这也是所有数字货币资产的控制权都由私钥保证的根本原因。具体的逻辑,下篇文章讲解UTXO的时候会讲到。
最后说一下量子威胁,我在讨论比特币等很多数字货币项目的时候,很多人问我怎么看待量子计算的威胁,大家都认为量子计算强大的算力威胁到了哈希的防碰撞性。
其实这不是设计缺陷,而是区块链发展过程中可以解决的开发问题。对于量子计算威胁论,我有以下几点看法。即使存在量子计算破解非对称加密算法的问题,首先要看是什么算法,比如RSA还是ECC。
其次,要看攻击成本是否足够低,因为理论上可行不代表工程上可行,这是两码事。比如持续攻击比特币需要花费 1 亿美元,攻击需要 20 多年才能见效,所以这笔交易显然不划算。量子计算威胁的不只是加密货币,而是整个密码学体系,如果发生破解事件,很有可能是银行或者互联网后端系统。目前整个互联网应用都是基于 HTTPS,如果 HTTPS 被破解,传统的账号和密码在量子计算面前几乎无法使用。
虽然目前量子计算的发展看起来很有前景,但距离实际应用还很远。许多计算不是通用的,而是专用的。也就是说,量子计算机中编写的算法只能解决特定问题,而且是概率解决方案。其可用性和易用性还需要很长时间才能实现。