协议演进 / BIP/比特币改进提案 / BIP-341
BIP-341
新增 SegWit v1 输出:32 字节 Taproot 输出公钥,平时用密钥路径一签花费,必要时才用脚本路径揭示默克尔树中的一条脚本。本 BIP 目前处于已激活状态。
一、档案卡
| 编号 | BIP-341 |
|---|---|
| 标题 | Taproot: SegWit version 1 spending rules |
| 作者 | Pieter Wuille <[email protected]>; Jonas Nick <[email protected]>; Anthony Towns <[email protected]> |
| 指定日期 | 2020-01-19 |
| 讨论日期 | 2019-05-06、2019-10-09 |
| 层级 | Consensus (soft fork)(共识(软分叉)) |
| 类型 | Specification(规范类) |
| 状态 | Deployed(已激活) |
| 依赖 | BIP-340 |
| 阅读版 | https://bips.dev/341 |
| 官方原文 | https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki |
二、放在哪一族
Taproot 三件套的核心一篇。BIP-340 定 Schnorr 签名,BIP-341 定输出结构与花费规则,BIP-342 定脚本路径里脚本的执行语义(Tapscript);三者同批部署,缺一不可。
往上接的是隔离见证族:Taproot 输出就是 BIP-141 框架下的 SegWit 版本 1 输出;其地址编码是 BIP-350 的 Bech32m。思想来源包括 MAST(默克尔化脚本树,前序提案 BIP-114、BIP-117)与 Greg Maxwell 最初的 Taproot 构想。原文 Design 一节特意划界:新的叹息哈希模式(如 BIP-118)、跨输入聚合等想法不在本批之列,留待独立升级。
激活方式另有专文:BIP-343 曾提出用 BIP8(LOT=true)强制激活本提案,最终未被采用(见第六节)。
三、它要解决什么
原文 Motivation 把目标定为三点,且明确不引入新的安全假设:提高比特币脚本能力的隐私、效率与灵活性。
旧格局下,付款给公钥与付款给脚本是两套互斥的构造,花费时必须把实际执行的条件、乃至脚本全文亮出来。观察者因此能知道:这笔钱原本可以怎么花、有哪些备选路径。而现实中的绝大多数应用,最终的花费往往是“所有参与方都同意”后的一次普通签名——为这一常态付出的,却是把全部条件上链公开的代价。
Taproot 的解法分两层:
- 默克尔分支:把全部备选脚本组织成一棵默克尔树,花费时只揭示真正执行的那一条,其余分支只以哈希形态出现在证明里,内容永不公开;
- Taproot 微调:在此之上,把“公钥路径”与“脚本树”合并进同一个输出。输出只是一个公钥;用密钥路径花费时,外界根本看不出它还承诺了一棵脚本树。
再加上 Schnorr 的密钥聚合:多方公钥可聚合成一个公钥、合作签出一份与单签无异的签名,使“各方同意”的常态正好走最省、最隐蔽的密钥路径。原文还顺手修了签名哈希的几个老问题(见 4.3),并为未来预留了叶子版本与 annex 等升级位。
四、规则本身
4.1 输出长什么样
Taproot 输出是原生 SegWit 输出:见证版本 1,见证程序为 32 字节。程序内容不是脚本哈希,而是一个公钥 Q(按 BIP-340 的 x-only 编码),称为 Taproot 输出公钥。构造方式:
Q = P + int(hash_TapTweak(P ‖ m))·G
其中 P 是内部公钥,m 是脚本树的默克尔根(没有脚本树时,微调只对内部公钥本身计算)。原文解释了为何把公钥直接放进输出而不放哈希:为保证批量可验证,验证者最终必须拿到公钥本身,放哈希反而要在见证里多补 32 字节;且要达到 128 位碰撞安全,哈希也需 256 位,大小并不吃亏。
以下规则只适用于花费这种输出;版本 1 而长度非 32 字节的程序、P2SH 包装的 v1 输出,都不受本 BIP 约束。
4.2 两条花费路径
先处理 annex:若见证栈至少两个元素且最后一个元素首字节为 0x50,该元素即 annex(保留的未来扩展位),从栈中移除;它始终被签名承诺并计入交易重量,但当前验证中被忽略。原文警告:在另一场软分叉给它定义含义之前,用户不应在交易中包含 annex,否则可能永久损失资金。
- 密钥路径:移除 annex 后见证栈恰剩一个元素,即针对输出公钥 Q 的 BIP-340 签名。验过即花费成功,脚本树是否存在无从知晓;
- 脚本路径:见证栈剩至少两个元素。倒数第二个是脚本 s,最后一个是控制块 c:长度须为 33 + 32·m(m 为 0 到 128 的整数),内含内部公钥 p、叶子版本 v,以及 m 个默克尔路径哈希。节点用 TapLeaf / TapBranch 标签哈希自底向上重算默克尔根,再算微调 t 与 Q′,要求 Q′ 的 x 坐标等于输出中的 q、且控制块首字节的最低位与 Q′ 的 y 坐标奇偶一致;通过后按适用脚本规则(叶子版本 0xc0 即 BIP-342)执行脚本。
默克尔路径中的子节点哈希前要先按字典序排序,故证明里不必携带左右方向信息。
4.3 签名哈希(sighash)改造
密钥路径签名是 64 字节 Schnorr 签名加可选的叹息字节:省略时为 64 字节、隐含新增的 SIGHASH_DEFAULT(0x00,语义等同 SIGHASH_ALL);带叹息字节时为 65 字节且该字节不得为 0x00,以防第三方把 64 字节签名锻成 65 字节、改变 wtxid 与费率。
共同签名消息 SigMsg 沿用旧体系的 SIGHASH_ALL / NONE / SINGLE / ANYONECANPAY 语义,但作了几项修正:
- 消息承诺被花费输出的 scriptPubKey;非 ANYONECANPAY 时,还承诺全部输入的金额与 scriptPubKey——离线签名设备由此能核对手续费、能确认被花的是哪个输出,堵住“对硬件钱包撒谎”的老问题;
- 哈希改用单次 SHA256(不再双重哈希)与标签哈希 TapSighash,并以 0x00 的“叹息纪元”字节开头,为将来大改签名哈希留接口;
- 序列化按交易级、输入级、输出级的逻辑顺序组织,子哈希可缓存,验签成本下降。
4.4 构造指引(钱包层,非共识)
原文专设一节给钱包软件(明确声明不属共识关键部分):内部公钥优先选最可能用到的单钥条件(聚合后);没有任何单钥条件时,可加一个“所有参与方聚合”的条件,或用无已知离散对数的 NUMS 点作内部公钥;聚合公钥场景下,即使不需要脚本路径,也应让输出公钥承诺一个不可花费的脚本路径,以防恶意一方偷偷塞入只利于自己的脚本分支;脚本树的组织,同概率用平衡树、已知概率用 Huffman 树。
4.5 部署参数
与 BIP-342 同时部署。主网与 testnet3 使用修改版 BIP-9 版本位部署:名称 taproot、比特位 2,另加 min_activation_height 参数。主网参数:开始时间 2021-04-24(UTC 零点)、超时 2021-08-11(UTC 零点)、锁定阈值 1815 块(90%,低于 BIP-9 惯常的 95%)、最小激活高度 709632;原文记载主网已在高度 709632 激活,testnet3 在高度 2011968 激活(阈值 75%)。Signet 上则恒为激活状态。
五、谁必须动
普通持币人:不动也能照常收付旧类型地址;想用 Taproot,需钱包支持生成与花费 P2TR 输出。向 v1 程序付款需要对方钱包支持 BIP-350 的 Bech32m 地址。
钱包开发者:实现输出构造(内部公钥、脚本树、微调计算与控制块生成)、新签名哈希与两条花费路径的签名流程;原文提供了钱包层测试向量(scriptPubKey 计算、密钥路径花费、控制块构造)。
全节点与矿工:升级才能强制执行新规则。原文向后兼容一节说得直白:未升级节点会把 SegWit v1 见证程序一律当作“任何人可花费”,强烈建议升级以便完整验证。
共识层:这是一次软分叉:旧软件无需修改即可继续运行(只是不验证新规则),新规则只收紧、不放松有效性判定。
六、现在算不算数,以及一个常见误读
状态为 Deployed,且已在主网激活:原文 Deployment 一节明确记载主网于区块高度 709632 激活。P2TR 自此是比特币的现行输出类型之一。激活走的是 Bitcoin Core 发布的“Speedy Trial”路径(修改版 BIP-9,见 4.5 的参数);同为激活方案的 BIP-343(BIP8 LOT=true)未被采用,其状态已是 Closed。
常见误读:
“Taproot 把一笔钱的全部花费条件都写在链上了,只是换了种编码。”
恰恰相反。输出里只有一个 32 字节公钥;脚本树只以默克尔根的形态被微调值承诺,任何一条备选脚本都不出现在输出里。用密钥路径花费时,连“有没有脚本树”都不会泄露;用脚本路径花费时,也只揭示被执行的那一条脚本加一条默克尔路径,未执行的分支永远保持哈希形态。这正是本提案隐私目标的落点。
七、延伸
- 阅读版:https://bips.dev/341
- 官方原文:https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki
- 相关:BIP-340 Schnorr 签名、BIP-342 Taproot 脚本验证、BIP-350 Bech32m 地址、BIP-343 强制激活方案(未采用)
- 仓库总目录:https://github.com/bitcoin/bips
