协议演进 / BIP/比特币改进提案 / BIP-350
BIP-350
定义 Bech32 的改进版 Bech32m(只改校验和常量),并规定见证版本 1 及以后的地址改用 Bech32m,版本 0 仍用 Bech32。本 BIP 目前处于已部署状态。
一、档案卡
| 编号 | BIP-350 |
|---|---|
| 标题 | Bech32m format for v1+ witness addresses |
| 作者 | Pieter Wuille <[email protected]> |
| 指定日期 | 2020-12-16 |
| 讨论日期 | 2021-01-05 |
| 层级 | Applications(应用) |
| 类型 | Specification(规范类) |
| 状态 | Deployed(已部署) |
| 取代 | BIP-173 |
| 阅读版 | https://bips.dev/350 |
| 官方原文 | https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki |
二、放在哪一族
地址编码族。它是 BIP-173 的修订版:档案关系上标为 Replaces BIP-173,但内容上是“修订”而非推翻——Bech32 本身不废弃,v0 地址继续用它。
上下游关系:
BIP-173:Bech32 编码与 v0 见证地址(bc1q…)的定义,本 BIP 修它的一个校验和弱点
BIP-141:隔离见证,定义了见证版本与见证程序;v0 的 P2WPKH、P2WSH 仍走 Bech32
BIP-341:Taproot,即见证版本 1 的输出。原文正是在 Taproot 上线之前赶着把 v1 地址的编码定下来,因此你今天见到的 bc1p… 开头的 Taproot 地址,用的就是 Bech32m
它和共识无关:改的是“地址长什么样、钱包怎么编解码”,链上 scriptPubKey 一个字节都没变。
三、它要解决什么
Bech32 有一个当初没料到的弱点:当地址最后一个字符是 ‘p’ 时,在它前面插入或删去任意多个 ‘q’,校验和居然仍然成立——这类手误骗得过校验。
这个弱点没有伤到既有的 v0 地址,因为 v0 地址只允许两种固定长度(见证程序 20 或 32 字节),插删字符会改变长度、当场露馅。但它可能影响 Bech32 的未来用途与其他应用。原文的处理办法干脆利落:趁 v1 地址还没有任何钱包在生成、主网还不能用,先把编码修好再让 v1 上路。
修法也刻意做得最小:不动字符集、不动人类可读部分(HRP)、不动编码流程,只换校验和最后异或的那个常量。这就是 Bech32m 与 Bech32 的全部差别。
原文还交代了一个刻意的决定:让新编码与旧钱包不向前兼容。曾有方案想让部分未来的地址继续用 Bech32,最终被放弃。干净地切开有双重好处:老软件遇到 v1+ 地址会直接报错拒绝,而不是用有弱点的校验放行;原文还引述实验称,当时已有个别见证实现向 v1 地址付款会把币烧掉,新编码正好让这类软件在付款前被挡住。
四、规则本身
4.1 Bech32m:只改一个常量
Bech32 校验和在最后一步异或的常量是 1;Bech32m 把它换成 0x2bc830a3。其余一切——生成多项式、HRP 展开、6 个校验字符的产生与验证方式——与 BIP-173 完全相同。
这个常量不是随手挑的。原文附录记了筛选过程:从全部 2^30−1 个候选常量出发,按“替换错误必然检出、其他常见错误模式的漏检概率不差于哈希型校验”等一整套标准逐层淘汰,先筛到 12054 个,再按专门针对 bc 见证地址的标准筛到 79 个,最后选漏检错误类最少的那一个,得出 0x2bc830a3。两个有用的性质随之成立:
- 没有任何字符串能同时是合法的 Bech32 又是合法的 Bech32m;
- Bech32m 与 Bech32 一样,仍能定位少数字符替换错误的位置(原文给了组合两种解码做错误定位的办法)。
4.2 哪种版本用哪种编码
生成地址时:
- 见证版本 0:用 Bech32;
- 见证版本 1 至 16:用 Bech32m。
其余编码细节不变,包括主网 HRP 仍是 ‘bc’。
4.3 解码时必须交叉核对
解码软件要么同时备好 Bech32 与 Bech32m 两个解码器,要么用一个能同时识别两者的解码器;解码之后必须核对:编码与解出的见证版本要对得上——v0 而解码结果是 Bech32m、或 v1+ 而是 Bech32,一律拒绝。
原文还顺带规定了其他有效性条件:见证版本须在 0..16 之间;见证程序长度须在 2 至 40 字节之间;v0 程序长度必须恰好是 20 或 32 字节。
4.4 给实现者的测试向量与建议
原文附了三组测试向量:合法与非法的 Bech32m 字符串、v0–v16 原生见证地址与对应 scriptPubKey 的对照、以及注明非法原因的地址清单——其中多条非法原因正是“v1 用了 Bech32 校验和”或“v0 用了 Bech32m 校验和”。
原文特别强调:钱包必须支持向 v1 及更高版本的地址付款,并把所有更高版本都认作合法收款方——这样将来引入更高见证版本的软分叉能与今天正确实现 Bech32m 的钱包向前兼容;但任何钱包都不应生成未定义版本的地址,收款方也不应把未定义版本的地址给付款方。
五、谁必须动
普通持币人:不必做任何事。你手里的 bc1q…(v0)地址不变、照样收付;收到 bc1p…(v1,Taproot)地址时,背后用的就是 Bech32m,只是你不需要知道这件事。唯一要留神的是抄写时别改字符——两种编码都靠校验和兜底检错。
钱包开发者:必须动。要点有三:生成地址时按见证版本选编码;解码时两种编码都要支持并与版本交叉核对;用原文给的全套测试向量验收。原文点名批评过一个常见毛病:许多钱包与服务当初不支持向更高版本见证输出付款,这是实现 Bech32m 时必须补上的。
交易所与支付服务:同钱包开发者,尤其是“能否向 bc1p… 付款”这一项,要在上线前用测试向量核实,而不是等用户投诉。
全节点与矿工:无事可做。本 BIP 不改共识:地址只是 scriptPubKey 的一种显示与传输格式,节点验证的是 scriptPubKey 本身。
六、现在算不算数,以及一个常见误读
状态为 Deployed(已部署):这就是现行规则。今天主网上 v0 见证地址(bc1q…)用 Bech32、v1 见证地址(bc1p…,Taproot)用 Bech32m,正是本 BIP 的分工,后续更高见证版本若出现也照此办理。
常见误读:
“Bech32m 取代了 Bech32,以后所有 bc1 地址都改用 Bech32m。”
不对。档案上的 Replaces 说的是文档关系——本 BIP 修订了 BIP-173 中关于见证地址的规则——不是编码上的一刀切替换。v0 地址永远使用 Bech32:原文专门解释,不允许 v0 同时接受两种编码,因为那会把校验和的有效检错能力砍掉一截(等效于只剩 29 位校验)。把 bc1q 地址按 Bech32m 重新编码,得到的是一个无效地址,而不是“新版地址”。
七、延伸
- 阅读版:https://bips.dev/350
- 官方原文:https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki
- 相关:BIP-173 Bech32、BIP-141 隔离见证、BIP-341 Taproot
- 仓库总目录:https://github.com/bitcoin/bips
