跳转到正文
buybitcoinsmart

术语表 /协议与升级

OP_CHECKSIGADD

OP_CHECKSIGADD 是什么?
OP_CHECKSIGADD 在 tapscript 中逐个密钥统计签名,取代了旧的多重签名操作码,其检查方式既支持批量验证,也能适配未来的密钥类型。

规定于 BIP-342。

该操作码从堆栈中取出三个元素,即签名、累计计数和公钥,然后把计数原样或加1后压回堆栈。BIP-342为其分配了操作码186,同时禁用了 OP_CHECKMULTISIG,因此 Taproot 脚本中的所有多重签名都以这种方式编写。实际好处是,阈值策略不再止步于20个密钥。

运作方式

tapscript 阈值是一连串签名检查,检查之间传递一个累计值,最后再做一次比较。

写出来,2-of-3是这样的:压入第一个公钥,OP_CHECKSIG,压入第二个公钥,OP_CHECKSIGADD,压入第三个公钥,OP_CHECKSIGADD,压入2,OP_NUMEQUAL。执行时从左向右依次进行。OP_CHECKSIG 在堆栈上留下1或0,每个 OP_CHECKSIGADD 依次弹出一个公钥、弹出该累计总数、弹出为该密钥提供的签名,若签名验证通过,则把总数加1后压回。最后的比较决定验证通过的签名是否足够。

未参与签名的签名方以空字节串代替签名。操作码识别后,将该位置视为未签名,并原样返回累计值,这在见证数据中只占1个字节。整个机制就是这样,并且省去了 OP_CHECKMULTISIG 因原始实现中的差一错误而必须使用的那个占位堆栈元素。

每个密钥只对照一个签名检查,由此带来两个结果。验证变得可以批量进行:节点可以把区块中所有 Schnorr 签名放进一次聚合检查,而不必按顺序逐个测试候选密钥,这是 Taproot 验证提速的重要原因。另外,密钥数量受 tapscript 验证预算的限制,该预算对每个被检查的签名消耗50个权重单位,而不是受写入操作码的硬性上限限制。

在哪里会遇到它

任何需要多个签名方的 Taproot 脚本都会用到 OP_CHECKSIGADD,在钱包软件中,这通常表现为描述符,而不是原始脚本。

Bitcoin Core 在 tr() 描述符中以 multi_a 和 sortedmulti_a 片段的形式提供该功能,因此三密钥的签名阈值写作 tr(internalkey,multi_a(2,KEY1,KEY2,KEY3)),软件会为您生成操作码序列。Miniscript 的处理方式相同,支持 Taproot 策略的硬件设备也能对这些脚本签名,无需事先知道其具体结构。

这种设计还改变了签名阈值的构建方式。taptree 可以不用一个包含全部三个密钥的叶子,而是放置三个各含两个密钥的独立叶子,每个叶子对应一种可能的组合,花费时只会披露实际签名的那一对密钥。这在脚本叶子上花费更多,却在见证数据中少用一个公钥,而且相比每次花费都公布完整密钥集,这是真正的隐私改进。

OP_CHECKSIGADD vs OP_CHECKMULTISIG

OP_CHECKSIGADD 和 OP_CHECKMULTISIG 都是针对一组密钥统计签名,但只有前者能在 Taproot 叶子中使用。OP_CHECKMULTISIG 在传统脚本和 SegWit 版本0脚本中仍然完全有效,因此人们多年来使用的 bc1q 多重签名不受影响,无需迁移。

在 tapscript 内,OP_CHECKMULTISIG 和 OP_CHECKMULTISIGVERIFY 被彻底禁用。除了适用范围之外,还有三点差异:旧操作码把脚本限制在20个公钥以内,新操作码没有这个数字;旧操作码要求堆栈上有一个额外的占位元素,BIP-147后来将其强制规定为必须为空,作为一项共识规则;旧操作码无法批量验证,因为验证方事先不知道每个签名对应哪个密钥。

请勿混淆

常见问题

我现有的多重签名钱包需要迁移到 OP_CHECKSIGADD 吗?

不需要。OP_CHECKMULTISIG 在传统脚本和 SegWit 版本0脚本中仍然有效,因此 bc1q 签名阈值照常运作。新操作码仅在您创建 Taproot 多重签名地址时适用。

tapscript 阈值最多可以包含多少个密钥?

没有固定上限。限制来自 tapscript 验证预算,每检查一个签名消耗50个权重单位,因此密钥越多,只是占用的见证数据字节越多。

相关术语

协议与升级中的更多术语

阅读本页英文版