协议演进 / BIP/比特币改进提案 / BIP-347
BIP-347
提出在 Tapscript 中重新启用 OP_CAT,把栈顶两个值拼接成一个,以补上 Tapscript 缺少的一种通用拼接能力。本 BIP 目前处于已完成状态。
一、档案卡
| 编号 | BIP-347 |
|---|---|
| 标题 | OP_CAT in Tapscript |
| 作者 | Ethan Heilman <[email protected]> Armin Sabouri <[email protected]> |
| 指定日期 | 2023-12-11 |
| 讨论日期 | 2023-10-21 |
| 层级 | Consensus (soft fork)(共识(软分叉)) |
| 类型 | Specification(规范类) |
| 状态 | Complete(已完成) |
| 依赖 | BIP-340、BIP-341、BIP-342 |
| 阅读版 | https://bips.dev/347 |
| 官方原文 | https://github.com/bitcoin/bips/blob/master/bip-0347.mediawiki |
二、放在哪一族
Tapscript 能力扩展族,也是“恢复早期被禁用操作码”这一脉。本 BIP 只做一件事:把拼接操作带回 Tapscript,因此它依赖 Taproot 的整套基础:
BIP-340:Schnorr 签名
BIP-341:Taproot 输出结构
BIP-342:Tapscript 验证规则;本 BIP 正是走它留下的 OP_SUCCESSx 软分叉升级路径
它常与同批的小原语一起被讨论,如 BIP-348(OP_CHECKSIGFROMSTACK):原文列举的若干用法——比如在脚本内拼出待验签的数据再验签、构造默克尔树——靠的是 CAT 的拼接加上哈希与验签类操作码配合。原文还专门比较了它与金库的关系:按 Andrew Poelstra 的构造,OP_CAT 本身即足以在比特币上搭出金库(vault),与 BIP-345 的专用金库操作码是两种不同路线。
三、它要解决什么
Tapscript 没有一种通用的办法把栈上的两个值拼起来。这看似小事,却卡住了整整一类构造:脚本无法自己拼装并计算默克尔树及其他哈希数据结构,表达能力因此受限。
原文列举了 OP_CAT 能解锁或大幅简化的用途(非穷尽):
- Bitstream:用比特币原子交换文件解密密钥的协议;没有 CAT 时要靠复杂昂贵的可验证计算,有了 CAT 可去掉这一要求;
- 树签名(tree signatures):脚本体积只随公钥数量对数增长的多签,还能表达 n-of-m 之外的逻辑条件;原文举例,不到 1KB 的交易可支持多达 4,294,967,296 个公钥的树签名;
- Lamport 后量子签名:这类签名只要求能对栈上值做哈希与拼接;原文同时提醒,Taproot 输出还有密钥路径,量子攻击者可能绕过脚本路径,这一条并非现成的抗量子方案;
- 非否认合约(non-equivocation contracts):对支付通道中的双花/说谎行为施加罚没;
- 金库:借助 CAT 与 Schnorr 的技巧构造契约与金库,无需预签名交易;
- 复刻 CHECKSIGFROMSTACK 类构造:进而做简单的契约;
- BitVM2 的改进:原文称 OP_CAT 可让 BitVM2 去掉其证明系统中的可信设置、并减小所用交易体积。
历史背景:OP_CAT 在早期比特币里本来就有,2010 年被一个提交连同另外 15 个操作码一并禁用。流传的说法是它可被用来构造求值时内存占用随脚本长度指数膨胀的脚本——例如把 1 字节值反复 OP_DUP、OP_CAT 四十次。本 BIP 的回应是:Tapscript 已强制栈元素最大 520 字节,这个口子在今天的规则下不存在了。
四、规则本身
4.1 语义
OP_CAT 执行时:
- 从栈上弹出最顶部的两个值;
- 按栈中顺序把它们拼接起来(栈为 [x1, x2]、x2 在顶时,结果为 x1 || x2);
- 把拼接结果压回栈顶。
失败条件只有两个:栈上不足两个值;或拼接结果超过脚本元素最大尺寸 520 字节。
4.2 激活方式
以软分叉方式重定义 Tapscript 操作码 OP_SUCCESS126(十进制 126、十六进制 0x7e)为 OP_CAT。特意选 126,是因为这正是 OP_CAT 当年被禁用前使用的操作码值,沿用旧值避免多一层混淆。升级机制走 BIP-342 预留的 OP_SUCCESSx 路径。
原文还说明了一个取舍:本 BIP 不借机改动 520 字节的栈元素上限——是否放大这个上限,应当与是否重新启用 CAT 分开决策,本 BIP 对此不持立场。
4.3 适用范围
只改 Tapscript。在非 Tapscript 脚本里使用 OP_CAT,仍然触发 SCRIPT_ERR_DISABLED_OPCODE(禁用操作码错误),与今天完全一样。
参考实现只有十来行,与 2010 年被禁用前的原实现基本相同,差别只在上限:原文实现把结果大小上限从当年的 5000 字节收紧为今天的 520 字节(MAX_SCRIPT_ELEMENT_SIZE)。
五、谁必须动
普通持币人:无直接动作。地址、钱包格式都不因此改变。
钱包与脚本开发者:是直接使用者。用 CAT 拼装数据时要守住 520 字节上限,脚本设计要按拼接后尺寸核算;在它真正激活之前,任何含 OP_CAT 的 Tapscript 都不能按新语义在主网花费。
全节点与矿工:若将来部署,这是一次共识软分叉:节点把 OP_SUCCESS126 按 CAT 语义验证,并执行 520 字节上限。不升级的旧节点按 OP_SUCCESS 旧语义直接放行——这是软分叉的兼容方式。
共识层:改动严格限于 Tapscript 语境;传统脚本与 SegWit v0 脚本中的 OP_CAT 仍是禁用操作码。
六、现在算不算数,以及一个常见误读
状态为 Complete(已完成):按现行 BIP 流程,这表示规范本身已写完、定稿——原文变更日志记有 1.0.0 版于 2026-03-01 标记为 complete。但 Complete 不是 Deployed:原文通篇以“将通过软分叉激活”的口吻写 OP_SUCCESS126 的重定义,是否、何时在主网激活,不由这份文档决定,要另行走部署流程并得到节点与经济多数的采用。在激活之前,主网上的 OP_SUCCESS126 仍只是“见之即通过”的占位操作码。
常见误读:
“OP_CAT 状态已完成,就是已经在比特币主网上线了。”
不对。Complete 只说明文档定稿。它与 BIP-11 那样的 Deployed(已部署、网络在实际执行)是两个状态。把“规范完成”读成“功能上线”,会误判今天能写什么样的 Tapscript——今天在主网认真用 OP_CAT 构造的脚本,并不会按 CAT 语义被验证。
七、延伸
- 阅读版:https://bips.dev/347
- 官方原文:https://github.com/bitcoin/bips/blob/master/bip-0347.mediawiki
- 相关:BIP-340 Schnorr、BIP-341 Taproot、BIP-342 Tapscript、BIP-348 CHECKSIGFROMSTACK
- 仓库总目录:https://github.com/bitcoin/bips
