本文参考北京大学计算机系肖臻老师的区块链技术与应用,可以在b站搜到老师账号发布的公开课视频,老师讲的深入浅出,非常推荐!!!
2008年日本的中本聪发布了比特币的先行版本,由于其去中心化性、匿名性、不可篡改性、可追溯性等特征,BTC价值在十几年间翻了几百万倍。
密码学原理:
比特币一共用到密码学的俩个功能,一个是hash,一个是签名。
hash
hash(x)=y
x为输入,y为经过hash函数后的输出值。理想中的hash函数为,不同的x输入后,得到的是不同的输出,即每个x对应唯一的y。
相对理想状态有一个概念叫做hash碰撞,俩个不同的x1和x2,hash(x1)=y,hash(x2)=y,不同的输入得到了相同的输出。
hash的性质
collision resistance(抗碰撞性):人为不能制造出hash碰撞,此性质从数学理论上无法证明,但经验上讲,只要目前不能人为制造即具有此性质。如:MD5算法以前是collision resistance,但现在随着算力增强,可以找到不同输入对应同一输出。
hiding(隐蔽性):无法从输出值y反推出输入值x为多少,从而保护输入信息。除了暴力反推,遍历所有可能的输入。为达成hiding性质,避免暴力反推,则希望输入空间很大,同时分布均匀。但实际中,输入空间不够大时,可以在输入值后面拼接随机数nonce后再hash,以达到扩大输入空间。
除了以上俩个密码学性质外,比特币还有以下性质:
puzzle friendly:不能事先知道哪个输入x更有可能输出怎么样的y值,比如:不知道哪个输入更有可能算出前k位为0的hash值。比特币中广为人知的挖矿就是寻找一个随机数nonce,使得H(block header)≤target[目标值]。puzzle friendly性质使挖矿没有捷径,只能不断的试大量的nonce,这个工作量就叫做POW(proof of work)。POW就是区块链共识算法的其中一种,也是比特币所使用的共识算法,除此之外还有POS权益证明、PBFT拜占庭容错等共识算法。大家所熟知的以太坊2.0使用的便是POS,以太坊的原理将会在比特币板块结束后详细介绍。
比特币使用的hash算法:SHA-256(Security Hash Algorithm)

签名
比特币创建账户不要任何审批,任何一个人都能在任意设备上创建属于自己的账户,这也体现了BTC去中心化的特征,任何人都能参与到BTC中,每个创建的账户都可以看做一个节点。创建账户只需要在本地创建public key(公钥)和private key(私钥)即可,公私钥来源于非对称加密 asymmetric encryption algorithm,非对称加密广泛应用于计算机网络中,如https。公钥字面意思可以看出其他人也可以知道,别人可以根据你的公钥对你发起交易,而私钥就得自己好好保管,这相当于我们账户的密码。
如果我想交易比特币给别人,我需要用我的私钥加密我的信息对交易签名,别人用我的公钥便能验证这个交易的确是我发起的,从而防止他人冒名顶替。简单来说公钥加密,私钥解密。
这时候你可能在想,万一俩个人随机生成的公私钥一样,那岂不是俩个人公用一个账户?
当使用256位的公私钥对时,能生成相同的公私钥对概率几乎为0,当然这也需要我们有一个好的随机源,否则前面的安全理论就不复存在。
比特币使用的签名算法:椭圆曲线数字签名算法(Elliptic Curve Digital Signature Algorithm,ECDSA)
数据结构
抛开区块内部复杂的结构,我绘制了图一,简单的只包含五个区块的区块链示意图,看得出来其结构上和链表几乎是一模一样的!
图一 简单的区块结构示意图
第一个区块称为创世块(genesis block)。最后一个区块称为most recent block,hash(most recent block)的值保存在系统中,这个值可以防止区块被篡改,有助于节点识别和同步到最长链,避免因分叉导致的数据不一致。
图2 完整的区块链结构示意图
图2为完整的区块链结构示意图,block由俩部分组成:block header和block body。
普通链表可以修改链表中任意一个的内容,而区块链中的一个区块只要修改,会导致后面的所有区块的hash值发生变化。因为每个区块的全部内容经过hash得到的值,都会保存下一个区块中。这就是为什么区块链具有不可篡改性。
因为不可篡改性,每个节点可以选择保存最后多少个区块即可,无需保存全部区块链,这减轻了大部分设备的压力。当需要再之前的区块,我们可以通过其他节点获取。从其他节点获取到区块后,要怎么判断是否别人给我的是正确的区块呢?
之前我们提到每个区块保存着上一个区块的hash值,而我们的节点保存的第一个区块中保存着上一个区块hash值,只需hash(获取的最后一个区块),判断两者是否相等,相等则说明其他节点给的区块是正确的。
在具体分析结构之前,我相信你和我最开始学习时一样着急,想知道我们常听到的比特币挖矿到底是什么?
挖矿的矿工可以是任何一个具有计算能力的设备。图2中可以看出,区块头中有一个参数是随机数nonce,而挖矿就是跨工已知区块中除随机数以外的其他参数,不断尝试不同的随机数nonce,计算整个区块头的hash值,判断hash值是否小于等于目标值:
hash(block header)<=target
target的大小代表了挖矿难度,target越小,解空间越小,难度也就越大,target是图二区块头中的参数:难度。
具体这个区块怎么组装,(二)中详细介绍了。
Merkel Tree 默克尔树
Merkel Tree是二叉树结构,以图2为例,交易1的hash值为hash1,交易2的hash值为hash2,再将hash1与hash2拼接后hash,得到hash12。同理得到hash34,hash12和hash34拼接后hash,得到hash1234,区块头中只要保存hash1234,这个值就是Merkel根。
由hash的性质可知,只需要保存Merkel根,便可以知道区块内包含的任意一个交易是否被修改。只要有一个交易的信息被修改,Merkel根就会发生变化。
节点分为全节点和轻节点,全节点保存block的全部内容,轻节点如区块链在手机端,只保存block header,节省很大的空间。那么轻节点如何证明别人(全节点)对自己的某个交易tx是否真的写到了区块链中?
图3 Merkel Proof
图3为该证明的示意图,步骤如下:
step1:向对应的全节点请求红色部分的hash值
step2:从待证明交易处(黄色部分)开始,轻节点计算其hash值,即绿色的hash值
step3:以此类推,轻节点一层一层的向上计算绿色hash值,最后判断Merkel root是否相同,相同则该交易已修改的区块链中。
核心思想是只计算交易分支的hash值,红色hash是请求来的,理论上提供了篡改数据的可能性,但由于hash的collision resistance性质,实际上是不可行的。当树有n层时,证明的时间复杂度是O(log(n))
而证明该交易不是该轻节点的proof of non-membership :
暴力方法:请求整个树,自己全部验证一遍。有n层时,时间复杂度是O(n)
sorted merkle tree(排序默克尔树):将merkle tree的所有交易hash值按大小排序,通过待验证交易应该插入位置的分支hash值,有n层时,时间复杂度是O(log(n)),但是比特币不需要验证不存在性,故不需要排序。
剩下的内容过俩天整理出来,嘿嘿。在github,我创建了一个项目,是由纯go语言打造的区块链平台,使用echo作为web框架,支持接口操作区块链。使用自定义的RPC的远程调用接口,传输层使用channel和TCP分别实现。使用ecdsa算法对交易和信息传递签名,内置虚拟机以支持自定义智能合约,共识算法目前使用PBFT。在一个大佬未完成的demo上想接着做,本意是为了完成我的论文,也欢迎志同道合的朋友一起完善项目。不熟悉区块链的朋友可以将原理和代码结合,方便理解。