Tapscript的验证规则:成功操作码、被禁用指令与CHECKSIGADD 图 1
Tapscript的验证规则:成功操作码、被禁用指令与CHECKSIGADD · 图 1

比特币的脚本升级历来卡在两个矛盾上:想引入新操作码,就得留下将来才生效的占位指令;想让多签便宜,旧的多签校验指令又阻碍批量验签。BIP342 给 Tapscript 定的验证规则,正是围绕这两处动刀。这份规范与 BIP340(Schnorr 签名)和 BIP341(Taproot 承诺结构)配套,随 Taproot 于 2021 年 11 月在主网 709632 区块高度一起激活,当前状态为已部署。

叶子版本与入口判定

花费一个 Taproot 输出走脚本路径时,见证栈最后两个元素分别是脚本本体与 annex(可选)。去掉 annex 后,脚本前面那个字节叫叶子版本,取 0xc0 或带奇偶位的 0xc1 表示这是一次 tapscript 花费,验证规则全部换成 BIP342 这套。先按 BIP141 与 BIP341 的基础校验过关,才轮到这份规范登场。

Tapscript的验证规则:成功操作码、被禁用指令与CHECKSIGADD 图 2
Tapscript的验证规则:成功操作码、被禁用指令与CHECKSIGADD · 图 2

OP_SUCCESSx:升级系统的地基

规范把一批编号的操作码(80、98、126 至 129、131 至 134、137 至 138、141 至 142、149 至 153、187 至 254 等)改名为 OP_SUCCESS 系列:执行到就无条件通过,甚至脚本里只要存在这样的字节、哪怕位于未执行分支或后续字节无法解码,验证也直接成功。这个看似激进的设计有其道理:脚本内容已经被 Taproot 输出承诺锁定,第三方无法注入这类字节,所以脚本里出现它就等于所有者知情同意。与旧的 OP_NOP 家族只能读栈不同,OP_SUCCESSx 未来经软分叉升级后还能写栈,规则变化只会把有效脚本变成无效脚本,恰好符合软分叉的安全方向。规范同时警告:在自己的脚本里放进尚未定义含义的 OP_SUCCESSx 是不安全、可能导致资金损失的行为——今天的无条件通过,可能被明天的升级重新解释。

多签的替换方案

OP_CHECKMULTISIGOP_CHECKMULTISIGVERIFY 在 tapscript 里被彻底禁用,行为等同于 OP_RETURN 立即失败——规范解释这是为了让误用者立刻发现问题,而不是留成升级空间。接替者是编号 186(0xba)的 OP_CHECKSIGADD:它等价于先轮转、再交换、验一个签、最后把结果加到累加器上,一个字节完成三步,配合比较器就能写出 k 之 n 的门限逻辑。换掉旧多签的根本动机是批量验签:旧指令把整笔交易上下文和一组公钥签名捆在一起,Schnorr 的批量验证却无法这样打包;CHECKSIGADD 让每个公钥签名对独立成一次累加,为节点层的批量验签管线让路。签名操作里还引入未知公钥类型概念——公钥不是零长度也不是 32 字节时,验签环节视为成功但保留其他规则,为将来新增签名算法留出软分叉入口。

签名操作码预算

旧体系里签名操作数计入全区块 80000(按权重)的限额,给打包策略添乱。BIP342 改为逐输入记账:预算等于 50 加上该输入见证(含长度前缀)的序列化字节数,每执行一个带非空签名的验签类操作码就扣 50,扣穿即失败。通俗地讲,一个签名对大约占用 98 至 99 权重,刚好落在 50 权重一次的免费额度节奏里,正常多签几乎无感;想塞重复签名堆验算量的把戏则会被见证体积反噬,必须实打实付空间费。

使用与安全提示

编写 tapscript 脚本时,唯一正确的姿势是使用钱包或框架对已定义操作码的实现,不要手动拼装含 OP_SUCCESSx 的脚本。恢复或导入旧资金时要知道,709632 之前的脚本策略与之后互不通用,误用旧格式地址模板收款只会资金滞留。本文为协议规则说明,不构成投资建议;相关细节以 BIP 仓库文本为准。

资源限制的重排

除签名预算外,tapscript 还给脚本执行划了几条硬线:脚本大小含叶子版本字节最多 3600 字节;初始栈加执行期栈合计不超过 1000 个元素;单个栈元素不超过 520 字节;累计数据push不超过 10000 字节。数字看起来琐碎,实际是验证节点可预测性的来源:脚本路径被允许做更多计算,就必须把所有可能拖慢验证的维度折算成显式上限。与旧的脚本系统另一处不同是,tapscript 里若干历史遗留操作码被直接移除或改名,遇到不认识的字节不再宽容跳过,而是失败终止——规则收紧换来的,是脚本解析器可以用线性单遍扫描完成验证。