我们看一下比特币系统中用到的密码学原理。比特币被称为加密货币,但其实它是不加密的,区块链上所有的交易内容都是公开的,包括账户的地址、转账的金额都是公开的。
比特币中主要用到了密码学中的两个功能。一个是哈希,另外一个是签名。
密码学中用的哈希函数被称为cryptographic hash function。它有两个重要的性质,一个叫做collision resistance。这个地方的collision是指哈希碰撞,如果有两个输入x和y,x不等于y,哈希函数是H。算出来的H(x)等于H(y),那么这就叫做哈希碰撞——两个不同的输入算出来的哈希值是相等的。我们使用哈希表的过程中就会遇到哈希碰撞,不同的输入可能会被映射到哈希表中的同一个位置。
一般来说,哈希碰撞是不可避免。因为输入空间是远远大于输出空间的。比如,我们有一个256位的哈希值,那输出空间有多大呢?所有哈希值的取值可能性就是2的254方,输出空间就这么大。但是输入空间可以是无限大的,所以它是有任意多种数的可能性。按照鸽笼原理的话,必然会出现有两个输入被映射到同一个输出的情况。所以这里的collision resistance并不是说不会出现哈希碰撞。有的书上管这个性质叫做collision free,这个说法并不准确,因为这容易给人造成误解,好像碰撞不会发生。但实际上碰撞是客观存在的。他这个意思是说没有什么高效的方法人为的去制造哈希碰撞。给定一个x,没有什么高效的办法,能找到另外一个y,使得x和y的哈希值恰好相等。
collision resistance这个性质有什么用呢?它可以用来对一个message求digest,比如有一个message叫m,我们取他的哈希值H(m),这个哈希值可以认为是这个message digest用来检测对这个message的篡改,假如有人改了这个message的内容。它的哈希值就会发生变化,这个collision resistance性质。使得你找不到另外一个m一撇,使得这个m一撇,取哈希之后,和原来的哈希值相等。所以没有办法能够篡改内容,而又不被检测出来。
这就是collision resistance的一个用处。要注意,没有哪个哈希函数能够在数学上证明是collision resistance的,也就是说刚才讲这么重要的一个性质,从理论上是证不出来的,这个只能靠实践中的经验,有些哈希函数经过长期的实践检验,世界上有那么多密码学的专家。谁也没有能够找到人为制造哈希碰撞的方法,所以呢,我们就认为。这些哈希函数是collision resistance的,这就是实践经验也有一些哈希函数。以前我们认为是collision resistance,但是后来大家找到了制造哈希碰撞的方法,这里面一个很著名的例子就是md5。
md5曾经是个很流行的哈希函数。大家原来以为他很安全了,但是现在不行了,我们已经知道怎么去人为的制造哈希碰撞。
密码学用的哈希函数,还有第二个性质,叫做hiding。Hiding的意思是,哈希函数的计算过程是单向的,是不可逆的。给定一个输入x,可以算出它的哈希值H(x),但是从这个哈希值H(x)没有办法反推出原来的输入x。换句话说,这个哈希值没有泄露有关输入的任何信息,这是hiding。当然,如果想知道这个输入,也是有办法的。还是用穷举方法,把这个输入所有可能的取值遍历一遍,看看哪个哈希值跟那个输出相等,就能知道原来的输入是什么,蛮力求解。
Hiding这个性质成立的前提是输入空间要足够大,使得蛮力求解的方法是不可行的,而且输入的分布要比较均匀,各种取值的可能性都差不多。如果输入空间虽然很大,但是绝大多数情况下取值都是集中在少数几个值,那么也是比较容易被破解的。
Hiding和collision resistance性质结合在一起,可以用来实现digital commitment。Digital commitment有时候也叫做digital equivalent of a sealed envelope。
现实生活中sealed envelope是干嘛用的?比如,你把你的预测结果写在一张纸上,放到一个信封里封好了,这个信封交给第三方的公证机构保管。第二天把它打开,验证一下这个结果。在电子世界里,可以把这个预测结果作为输入x算出一个哈希值,然后把这个哈希值公布出去。因为有hiding的性质,所以从这个哈希值不知道预测结果是什么,把预测结果公布出去之后,因为有collision resistance的性质,所以这个预测结果是不可篡改的,如果改了的话,就跟当初公布的哈希值对不上了。这就是一个sealed envelope的功能。
实际操作中,有一些细节要注意,就是hiding这个性质的前提是输入空间要足够大,分布要比较均匀。如果这个输入不满足这个性质,那么常用的方法是把这个输入后面拼接一个随机数,然后再一起取哈希。这个时候,x后面拼接一个随机的叫nonce,然后整个取哈希H(x||nonce)。这个nonce是选取的一个随机数,保证拼接之后整个输入是足够随机的,然后分布也是足够均匀。这是实际操作中要注意的一些细节。
除了密码学中要求的以上两个性质之外,比特币中用到的哈希函数还要求第三个性质叫pazzle friendly。这个意思是,哈希值的计算事先是不可预测的。只看输入,是很难猜出最后的哈希值是什么的。所以,如果要想算出来的哈希值是落在某个范围之内的,那没有什么好办法,只能一个一个地输入去试,看哪个输入算出来的哈希值恰好是落在要求的范围之内。比如,想得到一个哈希值,前面k位都是0,后面可以是任意的,整个是256位的。什么样的输入会算出这样的哈希值呢?不知道。这个pazzle friendly性质表明,事先不知道哪个输入更有可能算出这个哈希值。那要得到这个哈希值,就只能一个一个去试,没有什么捷径。
这个性质为什么叫pazzle friendly。后面讲到比特币挖矿的过程,就是找一个nonce —— 找这么一个随机数,这个nonce跟区块的块头里的其他信息组合在一起作为输入,得到一个哈希值,这个哈希值要小于等于某个指定的目标域值。
比特币是区块链,区块链就是一个一个区块组成的链表。每个区块有一个块头——block header。Block header里面有很多的域,其中有一个域,是我们可以设置的随机数——nonce。挖矿的过程就是不停的去试各随机数,使得整个block header的取哈希之后落在指定的范围之内。小于等于一个target space。这个pazzle friendly性质是说,挖矿的过程没有捷径,只能靠不停地去试大量的nonce,才能找到符合要求的结果,所以这个过程才可以用来作为工作量证明,叫做proof of work。你挖到矿了,找到符合要求的nonce,一定是因为你做了大量的工作,因为没有别的捷径。这里要注意,虽然挖矿的过程需要很多的工作量,才能找到一个符合要求的nonce,但是一旦有人找到这样一个nonce,发布出去之后,其他人很容易验证这个nonce是不是符合要求。只要算一次哈希值就行了,把这个nonce作为header的一部分,算一次哈希值,看它是不是小于等于目标域值。这表明,挖矿虽然很难,但验证很容易。这个性质叫做difficult to solve; but easy to verify。
比特币中用的哈希函数叫做SHA – 256。这个SHA的意思是Securec Hash Algorithm,我们说的这三个性质(collision resistance, hiding, pazzle friendly)它都是满足的。Puzzle friendly 与collision resistance有点相似,这两个性质是有一定的联系,但不是完全一样。