1.简介
从区块链的整体发展来看,现在还处于非常早期的阶段。
区块链不等于比特币。比特币只不过是基于区块链技术的一种加密货币而已,不要被比特币限制了想象力。
以太坊方面主要是要看一些他的白皮书和黄皮书,涉及到智能合约编程的,要看solidity文档,另外就是看原代码。由于以太坊的技术发展比较快,并且中间经过了多次的修改,所以文档都不是很完美,甚至以太访黄皮书上的一些内容跟他真正的代码实现也有一些差别。应该遵循以代码为准的原则,所以有遇到搞不清楚的地方,还是要看原代码。
这些文章里用的所有的加密货币的例子,都是出于技术研究的目的,不构成任何投资建议,炒币有风险,投资需谨慎。
2.比特币系统的密码学原理
首先,我们看一下比特币系统中用到的密码学原理。比特币被称为加密货币,但其实它是不加密的,区块链上所有的交易内容都是公开的,包括账户的地址、转账的金额都是公开的。
比特币中主要用到了密码学中的两个功能。一个是哈希,另外一个是签名。
密码学中用的哈希函数被称为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有点相似,这两个性质是有一定的联系,但不是完全一样。
前面提到比特币中用到了密码学的两个功能,一个是哈希,另一个是签名。哈希讲完了,下面讲签名。
要讲签名,得先讲一下比特币系统中的账户管理。日常生活中,如果你想开一个账户的话,你得带上证件去银行办理开户手续。这是中心化系统的账户管理方式。,比特币是去中心化的,它没有像银行这样的执业机构,那怎么开账户呢?每个用户自己完成开户,不需要任何人批准。开户的过程很简单,就是创立一个公钥和私钥的对。
在本地创立一个公私钥对就是一个账户,这个在比特币中就代表了一个账户。
公私钥这个概念来源于非对称加密体系,叫做asymmetric encryption algorithm。最早的加密体系是对称的,就是没有这个a,叫做symmetric encryption algorithm。比如,两个人之间要进行通讯,我要把某个信息发给你,但是这个通讯的网络是有可能被窃听的。那怎么办呢?咱们俩事先商量好一个秘钥,一个叫encryption key。我把这个信息加密之后发给你,你收到之后再用这个秘钥解密。因为这个加密和解密用的是同一个秘钥,所以这种叫做对称的加密体系。这个前提是,假设有某种安全的渠道能够把这个秘钥分发给通讯双方。你显然不能够说把这个秘钥以明文的形式在网络上传输。我们假设网络本身就是不安全的,有可能被窃听。这是对称加密体系的一个弱点,就是秘钥的分发不方便。为了解决这个问题,就提出了非对称加密体系。即不是用一个秘钥,而是用一对秘钥。有一个公钥和一个私钥。加密用的是公钥,解密用的是私钥。比如,我要把一个信息发给你,我用你的公钥给这个信息加密;你收到之后,再用你的私钥解密,得到原来的信息。要注意,这个加密和解密用的是同一个人的公钥和私钥,即都是这个接收方的公钥和私钥。
这有什么好处呢?这个公钥是不用保密的,你可以告诉所有人,有的人他的homepage上就列出他的public key。私钥是要保密的,因为解密是使用私钥解密的。但是,私钥只要保存在本地就行,不用传给对方,就是说和你通讯的那个人不需要知道你的私钥。他是用你的公钥加密。你如果要回复他,你就用他的公钥加密。双方都不需要知道对方的私钥。这就解决了对称加密当中秘钥分发不方便的问题。
比特币系统中,要创建一个账户,就在本地产生一对公钥和私钥。这个公钥就相当于你的银行账号,别人要给你转账,只要知道你的公钥就行,这个私钥相当于你的账户密码。知道这个私钥就可以把这个账户上的钱转走。那么有一个问题,前面说比特币系统是不加密的,它虽然叫加密货币,但他其实是不加密的,信息都是公开的。那要这个公钥和私钥干嘛呢?实际上是用来做签名。
现在讲第二个功能签名。假如我要转十个比特币给你,我把这个交易发布到区块链上。别人怎么知道这个交易确实是我发起的呢?会不会是有人冒名顶替,想偷偷地把我的账上的钱转走?这就需要我在发布这个交易的时候,用我自己的私钥对这个交易做签名,那其他人收到这个交易的信息之后,再用我的公钥去验证这个签名的正确性。也就是说,签名用的是私钥,验证签名用的是这个人的公钥,仍然是同一个人的公私钥对。
这里你可能有一个疑问。既然每个人是独立的产生账户,在本地独立的生成公私钥对,不需要任何人批准,那么如果两个人生成的公钥恰好相同怎么办?比如有人想偷取比特币,一种方法是就不停的产生大量的公私钥,然后对比一下我产生的这个公钥跟区块链上某个已有的公钥是不是相同。如果相同,就可以用对应的私钥把这个账上的钱给偷走。这种攻击方法从理论上似乎可行,但实际中是不可行的。因为如果是256位的哈希值,产生相同的公私钥的可能性是微乎其微的。
要强调一点,就是我们是假设产生公私钥的时候是有一个好的随机源,叫做a good source of randomness。生成公私钥的过程显然是随机的,如果不是随机的,那等于大家都生成同样的公私钥。如果选取的这个随机源不好,那么前面的分析就不成立了。比如,就有可能出现两个人生成的公私钥对是一样的情况。比特币中用的签名算法只是生成公私钥的时候要有好的随机源,之后每次签名的时候也要有好的随机源。只要有一次签名的时候用的随机源不好,就有可能泄露私钥,然后整个比特币系统就全完了。这一点一定要特别注意。
这一章讲了两个功能,一个是哈希,一个是签名。这两个功能是可以结合起来用的。比特币系统中,一般是先对一个message取一个哈希,然后再对这个哈希值签名。关于密码学的部分就到这里了。