协议演进 / BIP/比特币改进提案 / BIP-442
BIP-442
为 Tapscript 新增 OP_PAIRCOMMIT:用带标签哈希一次性承诺栈顶的两个元素,提供有限的向量承诺能力,支撑 Merkle 化的合约与数据可用性安排。本 BIP 目前处于草案状态。
一、档案卡
| 编号 | BIP-442 |
|---|---|
| 标题 | OP_PAIRCOMMIT |
| 作者 | moonsettler <[email protected]>, Brandon Black <[email protected]> |
| 指定日期 | 2024-12-09 |
| 层级 | Consensus (soft fork)(共识(软分叉)) |
| 类型 | Specification(规范类) |
| 状态 | Draft(草案) |
| 阅读版 | https://bips.dev/442 |
| 官方原文 | https://github.com/bitcoin/bips/blob/master/bip-0442.md |
二、放在哪一族
Tapscript 扩展与契约(covenant)/向量承诺一族。它是一个小而专一的新操作码:只做“把两个栈元素绑成一个哈希承诺”这一件事,复杂结构靠反复使用它搭出来。
相关提案:
BIP-342:Tapscript;本 BIP 在叶子版本 0xc0 的 Taproot 脚本花费中,用 OP_SUCCESS205(0xcd)的位置部署
BIP-340:Schnorr 签名;本 BIP 沿用其带标签哈希(tagged hash)记法与构造
BIP-443:OP_CHECKCONTRACTVERIFY;原文把“向量承诺类操作码”列为与它配合、共同搭出状态机的部件,本 BIP 正提供这类能力的一种实现
BIP-119:OP_CHECKTEMPLATEVERIFY;原文的 Lightning Symmetry 示例中与它及 OP_CHECKSIGFROMSTACK、OP_INTERNALKEY 组合使用
它也常与 LNhance 一组提案放在一起讨论,但档案上它是一份独立编号、独立规范的 BIP。
三、它要解决什么
比特币脚本经常对单个数据项做承诺,例如哈希锁、时间锁、按公钥哈希付款;但缺少原生手段把多个数据项一起承诺。
没有这种手段时,想把一组元素绑成一棵 Merkle 树、只留一个根哈希,合约要么做不了,要么绕远路。原文举了两类受影响的场景:
- 哈希锁合约的推广:承诺一棵 Merkle 树,树中任一原像都能解锁花费;
- 复杂委托:配合 OP_CHECKSIGFROMSTACK,对多个项的承诺签名,实现“时刻 t1 之后委托给 key1、时刻 t2 之后委托给 key2”之类的安排。此前这类委托要用 key laddering(一串密钥逐级签元组),验证成本更高、字节更费。
在 MATT(Merklize All The Things)框架里,这类工作原先靠 OP_CAT 拼接再哈希;原文指出朴素地用 OP_CAT 有字节移位(byte shifting)攻击的风险,拼接结果的边界不唯一。
BIP-442 的主张是:直接给一个专为“成对承诺”设计的操作码,高效、安全,不必先拼接。
四、规则本身
4.1 栈语义
在叶子版本 0xc0 的 Taproot 脚本花费中,OP_PAIRCOMMIT 重新定义 OP_SUCCESS205(0xcd)。执行时:
- 栈上少于 2 个元素,脚本执行失败;
- 设栈为 […, x1, x2](最右为栈顶),计算 pc = 带标签哈希 PairCommit(compact_size(len(x1)) ‖ x1 ‖ compact_size(len(x2)) ‖ x2),即两个元素各自先写紧凑尺寸长度、再写数据,一起送入标签为 PairCommit 的 tagged SHA256;
- 弹出 x2 与 x1,把 32 字节的 pc 压回栈。
因为每个元素都带长度前缀,(a, b) 的划分是唯一的,不会出现拼接式的边界歧义。原文还指出,标签可预计算为 SHA256 中间状态,典型情形(两个 32 字节元素)只需很少的哈希轮次。
4.2 两个以上元素:逐层成对
操作码本身只处理一对。要承诺三个元素 a、b、c,就先算 PC(b, c),再算 PC(a, PC(b, c)),得到一个总承诺;验证时把见证中的 a、b、c 依次压栈、两次执行 OP_PAIRCOMMIT,再与脚本里写死的承诺值 OP_EQUALVERIFY 即可。如此逐层成对,即可构成 Merkle 化的向量承诺:一个短哈希绑住整组元素,日后可逐个揭示。
4.3 示例:Lightning Symmetry 中的用法
原文用 Lightning Symmetry(基于 eltoo 思路的通道构造)示范数据可用性问题:争议关闭时需要拿到结算数据。做法是强迫各方把结算交易哈希放进见证:脚本先对状态哈希做模板校验,再用 OP_PAIRCOMMIT 把“状态恢复数据”与“状态哈希”绑成一对哈希,配合 OP_INTERNALKEY 取内部密钥、用 OP_CHECKSIGFROMSTACK 验签——双方必须对同一个成对哈希签名,更新数据与结算数据就被迫同时出现在见证里,后来的更新能据此重建中间状态的脚本,而各方只需保存最新状态。
4.4 被否决的替代方案
原文列出考虑过并放弃的路线,包括:OP_CAT(及其限长版本)、SHA256 流式操作码、专门的 Merkle 操作码、在 OP_CHECKTEMPLATEVERIFY 中承诺 Taproot annex、用 OP_CHECKSIGFROMSTACK 直接签 n 个元素、推广到 n 个元素的 OP_VECTORCOMMIT、ReKey/Laddering、以及 OP_RETURN。结论是 OP_PAIRCOMMIT 能在不引入 OP_CAT 风险的前提下支撑有用的脚本。
五、谁必须动
普通持币人:现在不必做任何事。本 BIP 仍是草案,未激活,部署方式在原文中写为 TBD(待定)。
钱包开发者:现在不必动。它是脚本层操作码,普通收付款钱包不直接构造这类脚本。
脚本与二层协议开发者:这是主要受众。若将来激活,设计 Merkle 化承诺、Lightning Symmetry、MATT 类合约时可直接使用;同时要注意,它依赖 OP_SUCCESS 的软分叉升级位,与 OP_CHECKSIGFROMSTACK、OP_INTERNALKEY 等提案组合时要以各自最终文本为准。
全节点与矿工:若将来激活,需按新语义验证 0xcd 在 Tapscript 中的执行。原文指出:约束 OP_SUCCESS 操作码属于向后兼容的软分叉,但原先依赖 OP_SUCCESS205 “无条件成功”行为的脚本将不再有效。
共识层:只在 Tapscript 内新增一个操作码,不动其他脚本环境。
六、现在算不算数,以及一个常见误读
状态为 Draft(草案),原文的 Deployment 一节写为 TBD。今天的主网 Tapscript 中没有 OP_PAIRCOMMIT:0xcd 仍是 OP_SUCCESS,执行到即成功,而不是算成对哈希。原文给出的成本对比(如 Lightning Symmetry 各种构造的权重比较)是提案层面的论证,不是已上线协议的实测数据。
常见误读:
“OP_PAIRCOMMIT 就是把两个元素拼起来的 OP_CAT。”
不对。OP_CAT 产出的是拼接后的原始字节,边界靠使用方自己守,朴素用法有字节移位攻击;OP_PAIRCOMMIT 不产出拼接结果,而是对“长度前缀 + 数据”做带 PairCommit 标签的哈希,压回一个 32 字节承诺值。它承诺的是这对元素,而不是把这对元素递给你。
七、延伸
- 阅读版:https://bips.dev/442
- 官方原文:https://github.com/bitcoin/bips/blob/master/bip-0442.md
- 相关:BIP-340 带标签哈希、BIP-342 Tapscript、BIP-443 OP_CHECKCONTRACTVERIFY、BIP-446 OP_TEMPLATEHASH
- 仓库总目录:https://github.com/bitcoin/bips
