协议演进 / BIP/比特币改进提案 / BIP-118

BIP-118 Taproot 脚本的 SIGHASH_ANYPREVOUT

为 Taproot 脚本定义一种新公钥类型,使签名可以不承诺被花费的具体 UTXO,从而能动态重绑定到兼容的其他输出。本 BIP 目前处于草案状态。

一、档案卡

档案卡
编号BIP-118
标题SIGHASH_ANYPREVOUT for Taproot Scripts
作者Christian Decker <[email protected]>, Anthony Towns <[email protected]>
指定日期2017-02-28
层级Consensus (soft fork)(共识(软分叉))
类型Specification(规范类)
状态Draft(草案)
前置依赖BIP-340, BIP-341, BIP-342
阅读版https://bips.dev/118
官方原文https://github.com/bitcoin/bips/blob/master/bip-0118.mediawiki

二、放在哪一族

签名哈希(sighash)与链下协议族。它源于闪电网络论文中提出的 SIGHASH_NOINPUT 想法(由 Joseph Poon 于 2016 年 2 月正式提出),后改名为 ANYPREVOUT,以表明“任意前一输出可用、但输入的其他方面仍有承诺”。

它建立在 Taproot 三件套之上:BIP-340(Schnorr 签名)、BIP-341(Taproot 输出规则)、BIP-342(Tapscript 验证)。原文明确它只支持脚本路径花费,不支持密钥路径花费。

与同族提案的关系:BIP-119(OP_CHECKTEMPLATEVERIFY)能用模板哈希达到部分相似效果,原文专门比较过——ANYPREVOUTANYSCRIPT 可与 SIGHASH_SINGLE、SIGHASH_ANYONECANPAY 组合、允许动态找零输出,但需要签名运算;CTV 只需哈希运算、脚本更短,且能承诺输入个数与序号。两者常被放在同一张“契约工具”清单里对照,但机制互不依赖。

三、它要解决什么

链下协议靠一批尚未广播的交易互相博弈:先约定好“链上出现某笔交易时,就用另一笔预定交易回应”。问题是,回应交易里的签名默认承诺了被花费的确切 UTXO(outpoint)。同一回应要能应对多种可能的链上交易,就得为每一种可能各签一份——组合一多,签名与存储负担爆炸。

原文的解法:让签名不承诺具体的前一输出。同一份签名可以动态重绑定到另一个由同一密钥授权、条件兼容的 UTXO 上,一份签名覆盖一族情形。典型应用是 eltoo 式的链下状态更新:后签的状态要能压过先签的状态,而结算交易又要精确对应某一份更新——原文脚注用这一例说明了“为何有时要承诺脚本、有时不要”。

这种重绑定是选择性加入的:只有使用专门的 BIP 118 公钥类型的脚本才有此能力;还可以用不同密钥、让签名承诺所花脚本、使用不同金额、不同 nSequence 或 OP_CODESEPARATOR 等手段,进一步收窄一份签名可被重绑定的范围。

四、规则本身

4.1 BIP 118 公钥

通过 BIP-342 为“未知公钥类型”预留的软分叉口子引入新公钥类型,无需新操作码:

这类公钥称为 BIP 118 公钥。对它使用 CHECKSIG、CHECKSIGVERIFY、CHECKSIGADD 时,不再按未知类型(非空签名即算通过)处理,而是按下列修改后的摘要规则验证。

4.2 新的 hash_type 取值

在 BIP-341 已有取值之外,新增合法值 0x41、0x42、0x43、0xc1、0xc2、0xc3。按位定义:

使用未定义的 hash_type,或用 SIGHASH_SINGLE 却没有同序号的对应输出,验证失败。

4.3 摘要的改法

签名消息 Msg118 与扩展 Ext118 的关键差异(相对 BIP-342):

签名长度规则不变:64 字节表示 hash_type 为 0x00,65 字节时最后一字节为 hash_type;验证走 BIP-340 的 Verify。

4.4 安全代价(原文专列一节)

五、谁必须动

普通持币人:无直接动作。普通 Taproot 地址不含 BIP 118 公钥,就不具备可重绑定签名的能力。

钱包与链下协议开发者:这是主要使用者。需按 4.4 的约束设计密钥复用策略:默认让签名承诺金额与脚本,只在协议确实需要时才放宽到 ANYSCRIPT。

全节点与矿工:共识层软分叉,需升级才能真正校验 BIP 118 公钥的签名。未升级到本提案的 Taproot 节点会把这类非空签名一律当作有效,原文因此强烈建议升级。

共识层:只动 Tapscript 的签名验证一处:把 0x01 前缀的公钥从“未知类型”名单中移出,改走修改后的摘要。部署在原文中写作 TODO,仅说明可与 BIP-340、BIP-341、BIP-342 同时或在其之后以软分叉部署。

六、现在算不算数,以及一个常见误读

状态为 Draft(草案),仍是草案、未激活。Taproot 本身已经激活,但 ANYPREVOUT 没有随之生效;今天主网上的 Taproot 脚本签名仍然承诺被花费的确切 UTXO。

常见误读:“ANYPREVOUT 签名什么都不承诺,签一次就能随便花。”不对。默认的 SIGHASH_ANYPREVOUT 仍承诺金额、scriptPubKey、tapleaf 与 nSequence,只是去掉 outpoint;只有更宽的 ANYPREVOUTANYSCRIPT 才再放开金额与脚本。且能力来自专门的公钥类型,普通公钥的签名不受影响、也不能事后改成这种模式。

七、延伸

本页内容整理自 bitcoin/bips 仓库与 bips.dev,事实已与仓库核对;解读仅供学习参考。