区块链(一)
一、区块链
1. BTC——密码学原理
(1)Crypto-currency 加密货币
(2)比特币系统中主要用到了密码学中的两个功能:哈希和签名(先计算哈希,再对哈希值签名)
①密码学中的哈希函数:Cryptographic hash function,其有几个重要的性质:
- collision resistance(哈希碰撞)
- 两个不同的输入算出来的值是一样的(被映射到哈希表的同一个位置)。x≠y,但H(x)=H(y),一般来说,哈希碰撞是不可避免的,因为输入空间远远大于输出空间。
- 作用:用于检测对Massage是否篡改。例如,有一个Massage为m,它原本的哈希值为H(m)=digest,若进行篡改,则没有办法篡改内容而又不被检测。,即找到一个m'使得H(m')=digest。
- 比如你有一个很大的文件,你想把它存储在某个云存储服务上,将来用到时再下载,那么你怎么知道你现在下载的版本和当初上传的版本是一样的呢?这就可以用到哈希函数的Coliision resistance,在你上传文件前先计算一个哈希值,其存在本地,你下载之后再计算一个哈希值,与上传时的哈希值进行比较,如果是一样的,则上传的文件没有被篡改,反之则被篡改。
- 目前找不到认为制造人为制造哈希碰撞的方法,不能靠理论证出来,只能依靠实践经验。
- MD5:曾经是一个很流行的哈希函数,原来以为很安全,但现在已经知道如何认为制造哈希碰撞。
- hiding(单向,不可逆)
- 给定一个输入x,可以算出哈希值H(x),但是无法反推,即哈希值没有泄露有关输入x的任何信息。(蛮力也可求解)
- hiding成立的前提是:输入空间要足够的大(使得蛮力求解不可行);输入的分布比较均匀(各种取值都有)
- 作用:与collision resistance结合在一起可以实现digital commitment/digital equivalent of a sealed envelope。
- 【sealed envelope】有人可以预测第二天哪些股票会涨,怎么证明这个人的预测是否准确呢?一种方法是这个人在电视上公布他的预测,收盘之后看结果就知道预测是否准确。这样做的问题是:他的预测可能会影响股市,说明预测结果不能提前公开。你把预测结果放在一张纸存在信封里,将它交给第三方的公证机构保管,等第二天收盘之后再打开验证结果即可。
- 把预测结果作为输入x,算出哈希值,把哈希值公布出去(hiding性质,公布不影响),第二天收盘之后再把预测结果公布出去(collision resistance),预测结果不可篡改。
- ps:实际操作要注意,如果输入空间不够大,则在输入x后加入一个随机数,对其整个取哈希H(x || nonce),保证拼接后整个输入足够随机,分布也是足够均匀。
- puzzle friendly(没有捷径,只有不断地试)
- 如果你想要算出来的哈希值落在某个范围内,只能一个一个输入去试。例如,你想得到一个哈希值(前面k位都是0,后面任意,整个是256位)。
- 比特币挖矿:找一个nouce(随机数),H(bklock header)<=target,每个区块有个块头,里面有很多域,其中有一个是我们可以随机设置的域nonce。挖矿的过程就是不停地去试各种的随机数,使得整个block header取哈希之后落在指定的范围内。这可以作为一个工作量证明(proof of work),因为没有捷径可走。
- 挖矿的过程需要很多的工作量,但是一旦有人找到了nonce,发布出去后,其他人要验证这个nonce是否符合要求,就很容易,只需要计算一次哈希值。【挖矿很难,验证很容易:difficult to solve, but easy to verify.】
- 比特币中用到的哈希函数:SHA-256(Secure Hash Algorithm),满足上面三个性质。
②比特币中的签名:
- 日常生活中要开账户,带上证件去银行办理开户手续,这是中心化系统的账户管理方式。比特币是去中心化的,用户自己开户,不需要任何人批准,开户的过程只需要创一个公钥(public key)和私钥(private key)。
- 对称加密是最早的,两个人要进行通信,先商量一个encryption key,发送方把信息加密后发给接收方,接收方收到后再用密钥解密,加密和解密用的是同一个密钥。前提是:有某种安全的通道能够传输密钥,这也是对称加密的一个弱点,密钥的分发不方便。
- 公私钥概念来自非对称加密(asymmetric encryption algorithm)。通信时用一对密钥(加密和解密用的都是接收方的公钥和私钥),加密用公钥,解密用私钥。比如,A把信息传给B,A用B的公钥给信息加密,B收到后用B的私钥解密,得到原来的信息。好处:公钥不用保密,私钥要保密,私钥只要保存在本地,不要传送给对方,解决了对称加密中密钥分发不方便的问题。
- 比特币系统中开户就在本地产生一对公钥和私钥:公钥——银行账号,私钥——密码。
- 公钥和私钥的作用是签名。比如A要转10个比特币给B,把交易发布在区块链上,别人怎么知道这个交易是A本人发布的,这就需要A在发布交易时用自己的私钥给此交易签名,其他人收到交易时再用A的公钥去验证签名的正确性。
- 假设产生公私钥对时要有一个好的随机源(a good source of randomness),如若不好则有可能出现两个人的公私钥对一样。比特币中用的签名算法不光是生成公私钥对时要有好的随机源,后面每一次签名时也要有好的随机源,只要有一次不好,就有可能泄露私钥。
2. BTC——数据结构
(1)Hash pointers(哈希指针)
- 普通指针存储的是某个结构体在内存中的地址。哈希指针除了要存地址外,还要保存结构体的哈希值(不光能找到结构体的位置,还能检测出结构体的内容是否被篡改)
(2)比特币中的数据结构
① 区块链与普通的链表有什么区别?
- 用哈希指针——>普通指针
- 普通链表:对其中一个节点做改变,对其他的节点没有影响。区块链(牵一发而动全身):只用记最后存在系统中的哈希值,即可判断前面任何一个的区块是否被篡改。

- 有这个性质之后比特币中有些节点就不一定要保存整条区块链的内容,可以只保存最近的。如果要用到以前的区块,可以问系统中的其他节点要这个区块。有些节点可能有恶意,这是一个去中心化的系统,用到哈希指针可以判断,算前一个区块的哈希值与自己保存的哈希值进行比较,即可发现是否被篡改。
② Merkle tree

- 这个区块所包含的所有交易组成的merkle tree的根哈希值是存在这个区块的block header里,但是block header里没有交易的具体内容,block body里面有交易的列表。
- 作用:提供Merkle proof
- 比特币中的节点有两类:全节点、轻节点
- 全节点:保存整个区块的内容,有交易的具体信息,包括block header 和 block body
- 轻节点:手机上的比特币钱包应用,只保存block header

-
- 问题:如何向一个轻节点证明某个交易是写入到区块链?
- A在B这买点东西,需要转给B一些钱,A向B说:你给我转钱的交易已经写到区块链上了,支付已经完成。轻节点就不知道交易是否完成。这就要用到Merkle tree,在Merkle tree中找到交易节点,一直往上到根节点的路径就叫做Merkle proof。
- 全节点在Merkle proof提供的这几个哈希值,就是从黄色的交易所在的链节点的位置到树根的路径上用到的哈希值。
- 轻节点收到了Merkle proof后,只要从下往上验证沿途的哈希值是否正确,即可确认交易是否真的完成。(只能查一条路径的哈希值)
- proof of membership/ proof of inclusion。对于轻节点来说,你发给我一个Merkle proof的时间/空间复杂度是O(log(n))。
- 怎么证明proof of non-membership?一种方法是把整个树都传给对方,看整体的构造是否正确,说明树里只有这些叶节点,复杂度是O(n)。另一种思路是对叶节点的哈希值按从小到大的顺序排列。假设交易C处于A和B之间,验证A和B往上的路径是正确的,根节点的哈希值也正确,说明A与B确实相邻。C如果存在,应该是在A和B中间,但它没有出现,所以不存在。叫做sorted Merkle tree。
【PS:哈希指针还能用在什么地方?】只要数据结构无环,都可以用哈希指针替代普通指针,会变成循环依赖。
3. BTC——协议
(1)花两次攻击(double spending attack)
(2)一个去中心化的货币要解决两个问题:数字货币的发行、怎么验证交易的有效性
(3)coin base transaction
(4)Bitcoin Script
(5)Block header / Block body(结构)
(6)怎么写到区块链中的?按照什么顺序写进去?账本的内容要取得分布式的共识
(7)分布式哈希表
(8)比特币中的共识协议(怎么投票)
(9)sybil attack
(10)合法的区块
(11)比特币
(12)怎么防范sybil attack
(13)挖矿
4. BTC——比特币系统的实现
(1)比特币采用的是基于交易的这种账本模式(transaction-based ledger)
- 隐私保护比较好,每个区块里记录的是交易信息,有转账交易、铸币交易。但是系统中没有显示每个账户上有多少钱,需要通过交易记录推算(哪些已经被花掉了,哪些没有花掉)。
- 比特币系统的全节点要维护一个叫做utxo(Unspent Transaction Output,还没有被花掉的数据的集合)的数据结构。
【注】一个交易可能有多个输出。
- 为什么要维护utxo?防止double spending。新发布的一个交易是否合法,我们要查utxo,要花的币只有在这个集合里才是合法的,若不在,则说明此币不存在或已经花掉了。
- 随着交易的发布,每个交易要消耗一些utxo的输出,同时也会产生一些新的输出。(要永久保存在utxo中的:不想花的、密钥丢失的)
- total inputs = total outputs。输入可以有多个,而且多个输入不一定是来自于同一个地址,这也是为什么一个交易可能需要有多个签名,每个输入地址都要有对应的签名。
① 第一个交易机制:出块奖励(逐渐减小,每隔21万个区块就减半)。
有些交易可能total input略微大于total output。例如total input为1BTC,total output为0.99BTC,则把这0.01BTC作为交易费给获得记账权发布交易的那个区块,为什么节点要消耗计算资源来竞争这个记账权,为了获得出块奖励。发布一个区块可以有特殊的coin base traction,获得一定数量的比特币作为报酬。所谓的block reward。但是光有出块奖励是不够的,就可能出现这个节点不管别人的交易,只打包自己的。
② 第二个激励机制:交易费。
(2)基于账户的模式(account-based ledger)
- 以太坊用的就是这种模式。系统要显示每个账户上有多少个币。
- Block header的数据结构中有一个nounce,可以调整,它有2^32个取值。
- 还可以改根哈希值。每个发布的区块里有个特殊的铸币交易(没有输入),coin base transaction,这是比特币系统中产生新的比特币的唯一方式。它有一个coin base域,可以写入任何内容,没人检查。改变这个域的内容,这个交易的哈希值发生变化,随着merkle tree向上传递,最后导致block header的根哈希值发生变化。
- 把coin base这个域的前八个字节当作extra nounce来用,这样搜索空间一下子就增大到了2^96。所以真正的挖矿是有两层循环,外层循环调整coin base域的extra nounce,算出根哈希值后,内层循环再调整block header里的nounce。
- 将某交易里的输入脚本与前面那个提供币的来源的那个交易里的输出脚本配对,如果他们拼接在一起能顺利执行,不出现错误,则这个交易是合法的。
(3)挖矿概率分析
- 挖矿就是不断尝试各种nounce来求解puzzle。每次尝试nounce可以堪称一次Bernoulli trial a random experiment with binary outcome。如果做很多次bernoulli trial,那么就是Bernoulli process(无记忆性,跟过去的实验结果没关系): a sequence of independent Bernoulli trials。
- Poisson process,实验的次数很多,每次成功的概率很小,可以用这个。我们关心出块时间,其服从指数分布。将来要挖多长时间,和已经挖了多长时间是没有关系的(progress free),可以保证挖矿公平(不然的话算力强的矿工会有不成比例的优势)。
(4)比特币的总量
- geometric series几何序列。
- 21万x50+21万x25+21万x12.5+......=21万x50x(1+1/2+1/4+...)=21万x100=2100w
- 比特币的稀缺性是人为造成的,因为出块奖励减少了。
- Bitcoin is secured by mining. 挖矿从表面看好像没用,但这对于维护整个比特币的系统安全性很重要。虽然现在得到出块的比特币数目变少了,但是价值变多了。
(5)比特币安全性
- 假设大部分算力是掌握在诚实的矿工手里,能不能保证写入区块链的交易都是合法的?不能。
①恶意矿工能不能偷币?虽然它有记账权,但是它没有对方的签名。如果要把这个交易硬写在区块链。诚实的节点不会接受交易。
②double spending可以吗?分叉攻击。M购买商品,这个网站支持比特币支付,它发起交易,把账转给这个网站,网站监听,以为支付成功了,结果把商品给了M,M拿到商品之后,又发起一个交易,把钱转给他自己,然后把这个扩展成最长合法链,上面的区块就作废了。所以它这样攻击的目的是既得到商品,又把花出去的钱收回来了,达到了double spending attack的目的。
如何防范?若这个转账交易不是最后一个,那么这个攻击的难度就会大大增加。——多等几个确认(区块),比特币中缺省的是要等6个confirmation(大概一个小时)。这时候才会认为钱敏这个交易是不可篡改的。

- irrevocable ledger。是不是凡是写入区块链中的内容都不能篡改呢?只是概率上的保证,刚刚写入区块链的内容,相对来说是比较容易被修改的。等待一段时间后或是跟着好几个确认后,被篡改的概率就大幅度下降。
- zero confirmation:这个转账交易发布出去了,但是没有被写在区块链中。这在现实中用的比较普遍,因为1)比特币协议缺省的设置是节点接受最先听到的那个交易,后面再发布的(M->M')。很多购物网站从你支付成功到它把货品发给你,是有时间间隔的。
③故意不把某些合法的交易写在区块链上。后面总有诚实的节点会接受。平常情况下也有可能出现这种情况,交易数目太多的情况会出现。
④selfish mining,挖到区块之后先藏起来,等上面的M->A出来后,再一次性放出来。
5. BTC——比特币网络
(1)比特币工作在应用层:Bitcon Block chain
网络层:P2P Overlay Network
(2)比特币网络中所有的节点都是平等的,没有Super node或master node。要进入比特币网络就要先和种子节点(seed node)联系,它会把它知道的节点告诉你,通过P2P的方式通信。
- 退出比特币网络时,就只要退出应用程序即可。
(3)比特币网络的设计原则是:简单simple、鲁棒robust,而不是高效。
- 消息传播在网络上采取的是flooding的方式,把它传播给其他的邻居节点,同时记录下这个消息已经收到了,如若下一次再收到,就不用再转发给邻居节点了。邻居节点的选取是随机的,没有考虑底层的结构。
(4)比特币系统中要维护一个等待要写入区块链的集合。第一次听到交易时把这个交易写入到集合,并且转发这个交易给邻居节点,后续就不用再转发了,以防陷入循环。现有一个A-->B的交易,如果这个交易完成了,则可以从集合中删除。
(5)比特币系统对区块的大小有限制:1M,比特币网络采用的传播方式特别耗带宽,一个新发布的节点可能需要几十秒才能传递给所有节点。
(6)比特币网络中的传播属于best effort。一个交易发布到比特币网络上,不一定所有节点都会收到。网络传播存在延迟,双方接收到的时间也不一定一样。而且有的节点不一定按照比特币系统的要求进行转发。
(7)如果商家收到付款,但是不发货,这个问题不能通过交易系统内部解决,而是要靠其他的手段辅助解决,比如投诉等。
6. BTC——挖矿难度
(1)挖矿就是不断地尝试block header里的nounce值,使block header的哈希值小于等于目标域值。H(block header)<=target。
(2)比特币用的哈希算法是SHA-256,整个输出空间是2^256。
(3)挖矿难度和目标域值成反比。
- target越小,挖矿难度越大。
- 挖矿难度最小就是1,这时对应的目标域值是个非常大的数。
- difficulty = (difficulty_1_target) / target。
- 为什么要调整挖矿难度?系统总算力越来越强,出块时间越来越短,参与的人更多。
- 出块时间太短会有什么问题?分叉会成为常态,算力被分散了,让恶意节点快速扩展链。
(4)比特币系统默认的出块时间是10分钟,但不一定是最优。不论设计成多长,都需要保持稳定,不能无限地减少下去。
(5)怎么调整挖矿难度?
- 比特币系统规定,每隔2016个区块,要重新调整目标域值(大致是两个星期)
- 公式:target = target x (actual time) / (expected time)。看实际时间的大小,如果大于两个星期,说明出块时间太慢了,需要降低挖矿难度。最多减小/增大四倍。
- 如果遇到有恶意的矿工,该调的时候就是不调,那么这个时候检查的这个区块合法性就通不过。每个节点要独立验证发布的区块的合法性,检查的内容就包括nBits与目标域设置的对不对。如果设置一个过大的target,这个区块则不会被接受。
(6)比特币系统中的实际情况
- 在比特币没有流行起来之前,算力增长得不快。后面加密货币增长很猛,算力呈指数型得增长。
浙公网安备 33010602011771号