加密货币其实是不加密的。区块链上所有的信息都是公开的,包括交易的地址交易的金额。比特币中主要用到了密码学中的两个功能,一个是哈希,一个是签名。
密码学中用的哈希函数被称为 crypotographic hash function
crypotographic hash function有两个重要的性质:
这就叫哈希碰撞。两个不同的输入,算出来的哈希值是相等的。哈希碰撞是很常见的,像我们使用哈希表的过程中就会用到哈希碰撞,不同的输入可能会被映射到哈希表中的同一个位置。
一般来说哈希碰撞是不可避免的。因为输入空间是远远大于输出空间的。
比如说我们有一个256位的哈希值,输出空间就是 2 256 2^{256} 2256。但是输入空间是无限大的,所以有任意多种输入的可能性,所以必然会出现两个输入被映射到同一个结果的可能性。
有的书上管这个叫collision free 。这个说法容易给人造成误解。实际上碰撞在理论上是存在的。
比如说我们有一个 message 叫 m,对 m 取哈希值 H(m),这个哈希值可以认为是它的digest,用来检测对这个message的篡改。比如说如果有人改这个message的内容,它的哈希值就会发生变化。这个collision resistance性质就是说你找不到另外一个 m’ ,使得 m’ 取哈希值后的 H(m‘) 与原来的哈希值 H(m) 恰好相等。 所以没有办法篡改内容而又不被检测出来的。
比如说你有一个很大的文件,你想把它存放到某个云服务器,用的时候再下载回来。那么你怎么知道你下载的版本和你上传的版本是一样的?这时候就可以用到collision resistance 性质,在你上传的时候先算一个哈希值出来,将这个哈希值存在本地,将来你下载下来以后再算一个哈希值,跟原来存的哈希值比较一下,如果是一样的话,说明上传的这个文件没有被篡改,下载的还是当初的版本。这就是collision resistance 的用法。
有一点需要注意:
也就是说这个重要的性质从理论上是证明不出来的,只能靠实践中的经验。有些哈希函数,经过长期的实践检验,世界上有那么多密码学专家,谁也没有能找到能够人为制造哈希碰撞的方法,所以我们认为这些哈希函数是collision resistance的。这是实践经验。
也有一些哈希函数,以前我们认为它是collision resistance的,但是后来大家找到了人为制造哈希碰撞的方法。例如MD5,MD5曾经是一个很流行的哈希函数,大家原来认为它很安全,但是现在已经知道如何人为的去制造哈希碰撞了。
哈希函数的制造过程是单向的,不可逆的。
x ----> H(x)
x取哈希值H(x),但是从 H(x) 是没有办法反推出原来的输入x的。换句话说这个哈希值没有泄露输入的任何信息。这就叫hiding。
但是如果想知道这个输入依然是有办法的,蛮力求解是一种反推的办法,我把输入所有可能的取值遍历一遍,看哪个结果与 H(x) 这个哈希值相等。
digital commitment 有时候也叫做 digital equivalent of a sealed envelope
现实生活中 sealed envelope 能做什么呢?
比如说有人预测明天某股票能够涨停,明天看一下新闻看看是否涨停。怎么证明呢?先公布后检测这个行为有什么问题?
预测可能影响结果。如果他是个股神,本来这个股票不涨停的,他一预测这个股票涨停大家都去买。这说明预测结果不能提前公开。但是如果预测结果不提前公开,怎么知道公布的结果是否是原来提前预测的结果?
这个时候就要用到sealed envelope,把预测写好交给第三方公正机构保管,等第二天收盘以后再公布验证。
把预测结果作为x,算出一个哈希值H(x),因为我们有hiding这个性质,所以我们不知道输入值是什么;因为我们有collision resistance这个性质,所以哈希值是不可篡改的,这样就确定了输入值不会被篡改。
H(x || nonce)输入值 x 后面拼接一个随机数 nonce,保证输入是足够随机的,分布是的足够均匀的。
除了密码学中的这两个性质,比特币还要求第三个性质:
哈希值的计算事先是不可预知的,光是看输入很难才出来后面的输出是什么,所以如果想要输出落在某一个范围之内,是没有什么好办法的,只能一个个去算看哪些是落在指定范围内的。
例如:
0000 ⋯ 0000 ⎵ k times x x x x . . . . . . x x x x \underbrace{0000⋯0000}_{k\text{ times}}xxxx......xxxx k times 0000⋯0000xxxx......xxxx
一个256位的哈希值,k个0,要想前面k位都是0,没有什么好的办法,只能一个个去试,看结果有哪些前k位是0。
比特币挖矿的过程也是一样,实际上就是找一个随机数 nonce,这个 nonce 跟区块块头里的其他信息作为输入,取出一个哈希来,这个哈希值要小于等于某一个目标域值。
H ( b l o c k h e a d e r ) ≤ t a r g e t H(block header) \le target H(blockheader)≤target
比特币是区块链,区块链就是一个一个区块组成的链表,每一个区块有一个块头block header,block header 里面有很多的域,其中有一个域是我们可以设置的随机数 nonce 。那么挖矿的过程就是不断地去试随机数 nonce 使得整个block header 取哈希之后的 H(block header) 落在指定的范围之内,小于等于指定的target。
puzzle friendly 是说挖矿的过程没有捷径,只能通过不断的工作才能找到符合的nonce,这就是工作证明proof of work。你挖到矿了,一定是因为你做了大量的工作,因为没有其他捷径。
但是一旦你找到了矿,你发布出去,别人来验证只需要做一次哈希计算,把这个nonce放到header里面去看这个哈希值是否在指定范围内。
这就是 difficult to solve, but easy to verify
比特币中用的哈希函数叫做SHA-256,这里面SHA的意思是Secure Hash Algorithm。我们说的collision resistance, hiding, puzzle friendly这三个性质SHA-256都是满足的。
很简单,就是创立公私钥对。
public key, porivate key
在本地创建公私钥对。
公私钥这个概念来源于非对称加密体系 asymmetric encryption algorithm
非对称加密体系来源于对称加密体系 symmetric encryption algorithm
密钥 encyption key
我把这个信息加密发给你,你收到信息后再用密钥解密。前提是我们假设有一种安全方式把密钥安全发送给交易双方。这就是对称加密体系的弱点,密钥的分发不是很方便。因为你显然不能以明文方式发送密钥,我们假设网络本身是不安全的有可能被窃听的。
为了解决这个问题,就提出了非对称加密体系。
非对称加密体系中,我们不是用一个密钥,而是用一对密钥,加密用的是公钥,解密用的是私钥。我用你的公钥给数据加密,你收到后,再用你的私钥进行解密得到原来的信息。大家注意,我们用的是同一个人的公私钥对,都是接收方的公钥和私钥。这有什么好处呢?
公钥是不用保密的,私钥是要保密的,但是私钥只需要保存在本地就行了,私钥不需要传给对方。你要回复他的话,你再用他的公钥加密就行,都不需要知道对方的私钥。
比特币系统中你要创建一个账户,你就在本地创建一对公钥和私钥,公钥就相当于银行的账户,私钥就相当于银行密码。比特币我们说是不加密的,信息都是公开的,那么这些公私钥是用来做什么的呢?是用来签名的。
我在发布这个交易的时候,我用自己的私钥在这个上面签名,验证签名别人用我的公钥就能验证。
这也是一种比特币攻击方式,只要碰出私钥就能把对方的钱转走。
但是256位的哈希值,出现两个人的公私钥相同的概率目前技术来看是可以忽略不计的,概率过小。
我们这里假设产生公私钥的时候,有一个好的随机源 a good source of randomness。
如果你选取的公私钥随机源不好的话,前面的所有的分析都不成立了。
比特币中用的签名算法,不光是生成公私钥的时候要有好的随机源,后面每一次交易都要有好的随机源,只要有一次用的随机源不好,就全完了。
比特币中一般是对一个随机值取一个哈希,再用公私钥进行签名。