北京大学肖臻老师《区块链技术与应用》公开课 笔记
比特币中的密码学原理
哈希函数性质
- Collision Resistance:
- 碰撞:x≠y,但H(x) = H(y)
- 含义:对于输入x,没有特定的方法(除了遍历x)能找到y(≠x),使得H(x) = H(y).
- 输入空间应足够大且分布均匀
- Hiding:
- 无法由哈希函数输出H(y), 反推输入x(除非遍历x)
- 输入空间应足够大,且分布均匀
- Puzzle friendly:
- 无法找到特定方法x,可以构造特定的输出H(y)。→ 这也是为什么nonce可以作为工作量证明PoW
目前区块链采用的哈希函数SHA-256 (Secure Hash Algorithm),256位
非对称加密
- 私钥对交易(tx)签名,公钥用于验证
- 具备好的随机元的情况下,生成相同公私钥对的概率几乎为0
数据结构
- 哈希指针(Hash Pointer):包含所指向的结构体的哈希值(指针只是形象的说法,其实只有哈希,没有指针)
- 区块链:使用哈希指针构成的链表,每个哈希指针保存的哈希值为前一个区块(包含哈希指针)的哈希值。只要保存根哈希指针,即可判断整条链的block是否被篡改
- 区块:Block Header(包含Block Data的Merkel Tree的根哈希值) + Block Body
- Block Header包含:
- Version -- 区块链版本
- 前一个区块block header的哈希指针
- Merkel tree的根哈希
- nBits -- 挖矿目标阈值(r字节,target简略版)
- nonce(4bytes) -- 挖矿所求随机数
- Block Header包含:
- Merkel Tree: 叶节点为所有交易,父节点包含两个指向子节点的哈希指针。 Block Body中的交易由Merkel Tree组成,用于验证某项交易存在。任意交易被篡改,则根哈希值改变
- 全节点和轻节点:
- 全节点(full node):保存区块链所有信息,验证每个交易
- 轻节点(light node):只包含block header,无法独立验证交易,只是利用区块链的信息
- Merkel proof:轻节点验证与自己相关的某个交易合法性时,只需向临近的全节点请求该交易Merkel Tree路径上相对的哈希值即可验证
- 交易: 输入为比特币来源,输出为接收者的公钥,交易通过发送者的私钥签名。发送者需提供自身公钥做验证
共识协议
- 联盟链中多数节点是诚实的,可以采用投票。公链中账户可以随意创建,如果仍采用投票,则会出现女巫攻击(即一个节点创建多于半数的公私钥对,赢取投票)
- 求解computational puzzle,获得nonce(工作量证明PoW)的节点获得记账权
- 其他节点接收到新的区块后,先验证nonce合法性,再验证每条交易的合法性
- 即使nonce和每条交易合法,如果哈希指针指向的不是最长合法链,则区块不会被节点接受
- 若两个节点几乎同时获得记账权,区块均合法,则其他节点接受先收到的区块。进行算力竞赛,直达一条链胜出,成为最长合法链。而另一区块作废
- 矿工的区块被接受,则获得出块奖励block reward(称为铸币交易coinbase transaction),该交易位于block body中,称作coinbase transaction 。每21万个区块(约4年),奖励减半。50→25→12.5,现在为12.5BTC
- 这种情况下女巫攻击无效,因为创建多个账户并不会增加算力(记账权)
比特币具体实现
UTXO
- transaction-based ledger 基于交易的账本,没有记录每个账户中有多少余额。所以交易的输入中需要包含交易的来源。比特币系统中每个全节点内存中需要维护一个UTXO,记录为被花掉的交易(没有写入区块链里)。(更安全,但需要查询以往的交易。而以太坊是基于账户的账本account-based ledger)
- Unspent Transaction Output
- total input = total output,但有的时候output略小(包含traction fee给矿工,否则矿工没有动力将别人的交易打包成区块)
- Bitcoin is secured by mining.
出块概率
- 多次伯努利实验,近似于泊松分布
- Memoryless -- 过去的工作量不会影响后续出块的概率
- 当区块链节点中,诚实的节点占大多数(指算力,不是账户数)时,恶意节点篡改数据的概率是很小的(恶意节点算力必须占大多数)
- 挖矿时除了修改nonce外,由于难度加大,可能穷尽所有取值也得不到合法值。还可以尝试修改merkel tree的根hash(通过修改coinbase域 -- extra nonce)
比特币网络
- 应用层:区块链协议
- 网络层:P2P overlay 网络
- overflooding,对带宽消耗很大,带宽是瓶颈。默认每个区块1M字节(每个区块包含大概4k个交易)
- best effort
- 比特币设计原则:简单、鲁棒而不是高效
挖矿
-
difficult to solve, but easy to verify
-
挖矿难度difficulty x target = difficulty_1_target(难度为1时的target,为常数),即成反比
-
默认每2016个block调整一次出块难度,即14天。new target = current target x (actual time / expected time),调整倍数限制在(4分之1到4倍)
-
之所以要控制出块时间,是为了避免分叉攻击。如果target固定,难度越来越小,出块时间越来越短。同一时间出现的分叉数可能会很大,导致诚实节点的算力被分散。恶意节点只需用较小的算力就能把自己的链挖成最长合法链。出块时间没有最优值,但需要稳定在某个范围。
-
全节点&轻节点:
全节点 轻节点 一直在线 不是一直在线 在本地硬盘上维护完整区块链信息 不用保存整个区块链,只要保存每个区块块头 在内存里维护UTXO集合,以便快速检验交易正确性 不用保存全部交易,只保存与自己相关的交易 监听比特币网络上的交易信息,验证每个交易合法性 无法检验大多数交易合法性,只能检验于自己相关交易的合法性 决定哪些交易会被打包到区块里 无法检测网上发布的区块正确性 挖矿:
决定沿哪条链挖下去
当出现等长分叉时,选择哪一个分叉可以验证挖矿难度
只能检测哪个是最长链,不知道哪个是最长合法链 -
比特币安全性保证:
- 密码学上公私钥签名
- 共识机制
-
挖矿历史演进:CPU→GPU→ASIC芯片(Application Specific Integrated Circuit)→ 矿池
- 由通用到专业化
- 矿池的出现:
- 由一个矿主pool manager管理多个矿工miner,miner只计算哈希值,由矿主负责全节点事务
- 通过工作量证明进行收益分配。矿主通过降低挖矿难度,让每个miner提交almost valid block,以此作为PoW
- 优点:相比miner单干,收益更稳定(miner单干要么挖到中大奖,要么打水漂)
- 缺点:单个矿池算力达到50%更为可能。矿主不需要实际拥有那么多miner,只要发动攻击时号召就够了
-
算力大于51%时的攻击形式
- 分叉攻击(Forking Attack):某笔待回滚交易后面连接6个区块确认后,矿池开始从该交易的分叉开始挖,追赶最长合法链。因为算力足够大,总能追上的
- 抵制攻击(Boycott Attack):只要链上出现包含某笔A交易的区块,就从另一分叉开始挖,直到挖成最长合法链,使A交易作废
- 盗币❌: 因为没有对方私钥,所以无法盗币。即使强行加到链上,诚实的节点也只会从另一条合法链去延伸
比特币脚本
验证形式
- Input Script 接上输入来源交易的Output Script
- 一开始是拼接后验证,现在input和output一般分开验证
- 只利用堆栈stack
脚本形式
- P2PK(Pay to Public Key)
- input: PUSHDATA(Sig)
- output:PUSHDATA(PubKey) + CHECKSIG
- P2PKH(Pay to Public Key Hash)
- input: PUSHDATA(Sig) + PUSHDATA(PubKey)
- output:DUP + Hash160 + PUSHDATA(PubKeyHash) + EqualVerify + CHECKSIG
- P2SH(Pay to Script Hash)
- input: PUSHDATA(Sig) + PUSHDATA(SeriRS)
- output: PUSHDATA(RSH) + Equal
- 第二阶段:执行反序列化的赎回脚本,验证签名
- 用处:主要用于多重签名,将签名的复杂性转移到输入端
- Proof of Burn
- output:RETURN + ...
- 销毁比特币证明。由于比特币不可篡改性质,可在输出脚本RETURN后加任意内容,如专利hash作为证明。也用于作为PoW,换取某些小币种
分叉形式
- State Fork:因出块时间接近而导致的分叉。恶意节点故意延伸的分叉也算state fork(又叫delibrate fork)
- Protocol Fork:因协议更新导致
- Hard Fork: 只要部分节点不更新协议,分叉会一直存在。e.g. 大部分算力修改出块大小上限1M → 4M,新旧节点将沿各自认可的合法链延伸(新节点认旧节点,但新节点链更长,将沿新链延伸)
- Soft Fork:分叉是临时性的,不会一直存在。e.g. 大部分算力出块大小上限1M → 4M,将主要沿新节点链延伸(因为旧节点也认新节点,且新节点链更长)
比特币的匿名性
- 由于比特币的公开性,匿名性是比较差的(或者说,pseudonomity较好,但无法防范linkability)
- 获取BTC用户信息方式
- 关联账户:一个交易中的多个input关联。输出中若存在一个output小于所有input(input个数 ≥ 2,商家只有一个),则该output为零钱账户
- 交易:买入卖出BTC、用BTC进行现实世界的交易
- 比特币保护匿名性措施:
- Mixing服务
- 某些比特币钱包也能实现mixing服务
- 比特币交易所其实也实现了mixing的功能
- 零知识证明
- 含义:证明者A向验证者B证明一个陈述是正确的,过程中不需要透露出除该陈述是正确的之外的任何信息
- 同态隐藏
- 若x ≠ y,则其加密函数值E(x) ≠ E(y) → 逆否命题:若E(x) = E(y),则x = y
- 隐匿性:很难由E(x)反推出x
- 同态运算:
- 同态加法:E(x) + E(y) = E(x + y)
- 同态乘法:E(x) * E(y) = E(x * y)
- 多项式运算类推
- 例子
- Alice向Bob证明自己知道一组x、y满足x + y = 7,但不想向Bob透露x和y值。→通过E(x)和E(y)
- 盲签方法:用户A自己生成serialNum,银行在不知道serialNum的情况下为序列号签名生成Token。交易后用户B向银行提交SerialNum和Token验证货币真实性
- 零币(zerocoin)和零钞(zerocash):相比BTC实现更好的匿名性,但用户较少。原因是性能损耗、用户需求不大、未解决与现实世界交易时的匿名性
比特币思考
- 哈希指针:只包含哈希,不包含指针。区块是存储在key-value数据库中的,key为hash,value为区块(比特币和以太坊为levelDB)
- 私钥截断分开保存的做法存在安全风险(且死账残留在UTXO中,对矿工不友好),更好的做法是采用多重签名
- 分布式共识理论上是不可能的,但实践上区块链将其变成可能
- 不要被学术界的思维限制了头脑,不要被程序员的思维限制了想象力
- 量子计算:离真正可用还很遥远,而且最先受到冲击的会是传统金融业;比特币中output中的公钥哈希本身丢失了部分数据,是不可逆的(所以公钥也不要随意泄露,每次交易后就应更换账号)