协议演进 / BIP/比特币改进提案 / BIP-143
BIP-143
为 0 版见证程序定义新的交易摘要算法,减少验签时的重复哈希,并让签名承诺所花输入的金额。本 BIP 目前处于已激活状态。
一、档案卡
| 编号 | BIP-143 |
|---|---|
| 标题 | Transaction Signature Verification for Version 0 Witness Program |
| 作者 | Johnson Lau <[email protected]>, Pieter Wuille <[email protected]> |
| 指定日期 | 2016-01-03 |
| 层级 | Consensus (soft fork)(共识(软分叉)) |
| 类型 | Specification(规范类) |
| 状态 | Deployed(已激活) |
| 阅读版 | https://bips.dev/143 |
| 官方原文 | https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki |
二、放在哪一族
隔离见证(SegWit)共识族的核心配套文档之一。BIP-141 定义见证的共识层结构,本篇紧随其后,专门规定 0 版见证程序里的签名到底对什么数据负责。
同族关系:
BIP-141:隔离见证(共识层),本篇随它一同部署
BIP-144:隔离见证(对等服务),管见证数据怎么在节点间传输
BIP-147:处理哑栈元素可锻性,与本篇同属 segwit 部署包
再往后,Taproot 的签名摘要另由 BIP-342 一系规定,不沿用本篇算法;本篇只管 0 版见证程序。
三、它要解决什么
原有脚本系统的签名摘要算法(SignatureHash)有两个原文明确指出的弱点。
3.1 哈希量随交易规模平方增长
每验一个签名,都要把交易的一个子集序列化后做双重 SHA256,哈希量与交易大小成正比;一笔交易里签名操作(sigops)越多,整体验签成本按 O(n²) 增长。原文举例:普通 1 MB 区块在 2015 年的一般电脑上约 2 秒可验完,而一笔含 5569 个 sigops 的 1 MB 交易可能要 25 秒。这类构造会拖慢全网验证。
3.2 签名不承诺输入金额
原算法不把“这个输入花了多少钱”算进摘要。在线节点可以自己去查被花输出的金额,但离线签名设备(冷钱包、硬件钱包)不知道金额,就算不出确切的花费与手续费;要补这个信息,又得把整笔被花交易搬进来,与轻量、气隙(air-gapped)设备的目标相冲突。
在原脚本系统里直接修这两点,要么是硬分叉,要么只能对新操作码做软分叉且限制很多。隔离见证软分叉恰好提供了一个干净的切口:可以为见证程序另定一套脚本语义,未升级节点仍把这类输出看作“任何人可花”,不破坏原系统。
四、规则本身
4.1 新摘要的十个字段
新算法只适用于 0 版见证程序中的签名操作。摘要是对下列序列化结果做双重 SHA256:
- 交易的 nVersion(4 字节小端);
- hashPrevouts(32 字节);
- hashSequence(32 字节);
- 当前输入的 outpoint(32 字节哈希 + 4 字节小端);
- 当前输入的 scriptCode;
- 本输入所花输出的金额(8 字节小端);
- 当前输入的 nSequence(4 字节小端);
- hashOutputs(32 字节);
- 交易的 nLocktime(4 字节小端);
- 签名的 sighash 类型(4 字节小端)。
其中第 6 项是关键新增:所有 sighash 类型都承诺本输入的金额。若有人给冷钱包喂了假金额,签出的签名会无效,资金不会因此丢失。
4.2 三个可复用的中间哈希
hashPrevouts、hashSequence、hashOutputs 先按 sighash 标志算好,同一交易的不同输入可以复用:
- 未设 ANYONECANPAY 时,hashPrevouts 为全部输入 outpoint 序列化的双重 SHA256;否则为全零的 uint256;
- 未设 ANYONECANPAY、SINGLE、NONE 中任一标志时,hashSequence 为全部输入 nSequence 的双重 SHA256;否则为全零;
- sighash 既非 SINGLE 也非 NONE 时,hashOutputs 为全部输出的双重 SHA256;为 SINGLE 且输入序号小于输出个数时,只承诺同序号的那一个输出;其余情形为全零。
靠这层复用,整笔交易的哈希复杂度从 O(n²) 降到 O(n)。
4.3 与原算法的语义差异
sighash 类型的语义总体不变,但原文列明几处调整:
- 序列化方式改为上述十项结构;
- 全部类型都承诺输入金额;
- 不再对 scriptCode 做 FindAndDelete(删除签名本身的操作);
- OP_CODESEPARATOR 的处理改为:只去掉最后一个已执行 OP_CODESEPARATOR 及其之前的部分,其后的不再额外删除;
- SINGLE 不再单独承诺输入序号;未设 ANYONECANPAY 时,序号已由 hashPrevouts 与 outpoint 隐含承诺;与 ANYONECANPAY 组合时,允许输入—输出配对在等价序号间调换。
scriptCode 的取法也分两种:P2WPKH 时固定为 0x1976a914{20 字节公钥哈希}88ac,即等价的传统 P2PKH 脚本;P2WSH 时为 witnessScript 本身(按 CTxOut 中的脚本格式序列化),含 OP_CODESEPARATOR 时按上条规则截取。
4.4 公钥类型限制(策略层)
作为默认策略,P2WPKH 与 P2WSH 只接受压缩公钥:传入签名操作的每个公钥首字节必须为 0x02 或 0x03、长度必须为 33 字节,不合规的交易默认不转发、不打包。原文同时警告:这是为未来软分叉做准备,用户不得在 0 版见证程序中使用未压缩公钥,以免将来资金受损。
4.5 部署方式
原文写明:本提案随隔离见证软分叉(BIP-141)一同部署。
五、谁必须动
普通持币人:不必单独做什么。使用 SegWit 钱包时,签名由钱包按新算法生成即可;注意不要在 0 版见证程序中使用未压缩公钥。
钱包开发者:花费 v0 见证输出时,必须实现本篇的十项摘要算法,正确处理三个中间哈希在不同 sighash 标志下的取值,并把输入金额纳入签名;离线签名设备尤其要按新算法核对金额与手续费。
全节点与矿工:升级后按新算法验证见证程序中的签名;未升级节点看不到、也不验证见证数据,会把见证程序一律当作任何人可花。
共识层:本篇是软分叉的一部分,只对 0 版见证程序重新定义签名验证;原脚本系统的摘要算法原样保留,不受影响。
六、现在算不算数,以及一个常见误读
状态为 Deployed,中文状态记为已激活。它是隔离见证共识规则的组成部分:今天任何一笔 P2WPKH、P2WSH 花费,节点验签时用的都是这套摘要算法。原文未逐项列出各软件的实现情况,本页不另行臆测。
常见误读:
“BIP-143 把全网的签名算法都换掉了。”
不对。它只适用于 0 版见证程序内的签名操作;传统非见证输入仍用原有 SignatureHash 算法。两套算法并存,按输入类型分别适用——这正是它能以软分叉方式落地的原因。
七、延伸
- 阅读版:https://bips.dev/143
- 官方原文:https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki
- 相关:BIP-141 隔离见证(共识层)、BIP-144 隔离见证(对等服务)、BIP-147 哑栈元素可锻性
- 仓库总目录:https://github.com/bitcoin/bips
