协议演进 / BIP/比特币改进提案 / BIP-371
BIP-371
为 PSBT 新增一组 Taproot 字段,让未签名交易能携带密钥路径与脚本路径花费所需的签名、叶子脚本、内部密钥与派生路径。本 BIP 目前处于已部署状态。
一、档案卡
| 编号 | BIP-371 |
|---|---|
| 标题 | Taproot Fields for PSBT |
| 作者 | Ava Chow <[email protected]> |
| 指定日期 | 2021-06-21 |
| 层级 | Applications(应用) |
| 类型 | Specification(规范类) |
| 状态 | Deployed(已部署) |
| 阅读版 | https://bips.dev/371 |
| 官方原文 | https://github.com/bitcoin/bips/blob/master/bip-0371.mediawiki |
二、放在哪一族
PSBT(Partially Signed Bitcoin Transaction,未完全签名交易)扩展族,专为 Taproot 服务。
PSBT 本体由 BIP-174(PSBTv0)与 BIP-370(PSBTv2)定义:把一笔未签完的交易连同签名所需信息装进一个标准容器,在构造者、更新者、签名者、合并者、终结者之间传递,硬件钱包与多方协作签名都靠它。
Taproot 由 BIP-340(Schnorr 签名)、BIP-341(Taproot 输出结构)与 BIP-342(Tapscript)定义。BIP-371 是两者之间的接口层:Taproot 改变了签名算法与脚本嵌入方式之后,PSBT 该多带哪些字段。
它也是后续多篇 PSBT 扩展的前置:BIP-373(MuSig2 字段)与 BIP-376(花费静默支付输出)都建立在它定义的 Taproot 签名字段之上。
三、它要解决什么
Taproot 给比特币带来了一套全新的创建与花费输出的方式:Schnorr 签名、密钥路径与脚本路径两种花费方式、脚本藏在默克尔树里只在花费时揭示用到的那一片叶子。
原有 PSBT 字段撑不住这种结构:
- 旧签名相关字段是按 ECDSA 时代设计的,放不下 64 或 65 字节的 Schnorr 签名及其归属信息;
- 脚本路径花费需要知道叶子脚本本身、控制块(control block)与默克尔路径,旧字段没有位置装这些;
- 签名者需要知道内部密钥(internal key)与各公钥的 BIP32 派生路径,才能判断某个输入是不是自己能签、该用哪把私钥签,旧的派生字段不带叶子哈希信息,无法区分同一公钥出现在哪几片叶子里。
没有这组字段,PSBT 就无法携带签一个 Taproot 输入所需的全部信息,硬件钱包与离线签名流程也就用不上 Taproot。BIP-371 要补的正是这一块。
四、规则本身
4.1 每输入字段(六个)
PSBT_IN_TAP_KEY_SIG(0x13):密钥路径花费的 Schnorr 签名,64 或 65 字节。无键数据——密钥路径签名直接对应输出脚本里的公钥,不需要再标归属。PSBT_IN_TAP_SCRIPT_SIG(0x14):脚本路径花费的签名。键数据是 32 字节 x-only 公钥拼接其所在叶子的 32 字节叶子哈希,指明这份签名是为哪把公钥、哪片叶子作的。PSBT_IN_TAP_LEAF_SCRIPT(0x15):键数据是该叶子的控制块(内含到该叶子的默克尔路径,见 BIP-341);值是脚本本身加 1 字节叶子版本。只应包含签名者预期能签的那些叶子。PSBT_IN_TAP_BIP32_DERIVATION(0x16):以 32 字节 x-only 公钥为键;值先列该公钥涉及的叶子哈希(内部密钥不涉及叶子,数量记 0),再接 4 字节主密钥指纹与派生路径。该公钥可以是输出密钥、内部密钥,或某片叶子脚本里的密钥。PSBT_IN_TAP_INTERNAL_KEY(0x17):32 字节 x-only 内部密钥。它不一定等于输出脚本里的密钥——BIP-341 建议对密钥作微调,签名者需要知道真正的内部密钥才能判断自己能否签。PSBT_IN_TAP_MERKLE_ROOT(0x18):32 字节默克尔根哈希。
上述输入字段在终结者构造出 PSBT_IN_FINAL_SCRIPTWITNESS 后都应被移除。
4.2 每输出字段(三个)
构造新 Taproot 输出时使用:
PSBT_OUT_TAP_INTERNAL_KEY(0x05):该输出的内部密钥;PSBT_OUT_TAP_TREE(0x06):Taproot 树的全部叶子,每片叶子记深度、叶子版本、脚本长度与脚本,必须按深度优先顺序排列,以便完整重建整棵树;PSBT_OUT_TAP_BIP32_DERIVATION(0x07):与输入侧同构,记录输出密钥、内部密钥或叶子中公钥的叶子哈希、指纹与派生路径。
4.3 适用版本与 UTXO 类型
这组字段同时适用于 PSBTv0 与 PSBTv2(允许纳入的版本为 0 与 2),不改 PSBT 的基本结构,只是新增字段;PSBT 本就可扩展,旧软件会忽略不认识的字段。
原文还指出一个细节:BIP-174 出于防欺诈考虑建议所有输入都带 PSBT_IN_NON_WITNESS_UTXO,但 Taproot 签名会承诺全部输入的金额与输出脚本,更新者若谎报金额只会得到无效签名,因此 Taproot 输入只用 PSBT_IN_WITNESS_UTXO 即可。
五、谁必须动
普通持币人:无直接动作。是否受益取决于所用钱包是否支持 Taproot 与 PSBT 协作签名。
钱包开发者:构造或解析 Taproot 交易的 PSBT 时,要能读写上述九个字段,尤其是叶子脚本、控制块与带叶子哈希的派生路径;终结时按规定清掉已用完的输入字段。
硬件钱包与离线签名者:签名设备靠内部密钥、叶子脚本与派生路径判断“这个输入我能不能签、该走密钥路径还是脚本路径”,实现 BIP-371 才能参与 Taproot 的 PSBT 流程。
全节点与矿工:无需动作。本 BIP 不改共识规则,只改链下传递的未签名交易格式。
六、现在算不算数,以及一个常见误读
状态为 Deployed(已部署)。它定义的字段是 PSBT 处理 Taproot 输入输出的标准做法,后续的 MuSig2、静默支付 PSBT 扩展都以它为地基。原文给出的参考实现指向 Bitcoin Core 的相关合并请求。
常见误读:“ BIP-371 是 Taproot 升级本身。”不对。Taproot 的共识规则在 BIP-340、BIP-341、BIP-342 里;BIP-371 只规定链下协作签名时,PSBT 容器里该怎么装 Taproot 的签名与脚本数据。节点不实现它,照样能验证 Taproot 交易;钱包不实现它,只是没法用 PSBT 流程签 Taproot 输入。
七、延伸
- 阅读版:https://bips.dev/371
- 官方原文:https://github.com/bitcoin/bips/blob/master/bip-0371.mediawiki
- 相关:BIP-174 PSBTv0、BIP-370 PSBTv2、BIP-340 Schnorr 签名、BIP-341 Taproot、BIP-342 Tapscript、BIP-373 MuSig2 PSBT 字段
- 仓库总目录:https://github.com/bitcoin/bips
