Private Key Tools

Bech32 / Bech32m 解码与校验

把 bc1q… 或 bc1p… 地址拆成可读部分、witness 版本与 witness 程序,查看构成它的 5 位字,确认匹配的是哪个校验和常量 —— 字符串非法时给出一句人话说明原因。

以下都可以:bc1qy86hkm0telzmvuvzm76279jp7z5p3yqjnaerk6(P2WPKH,witness v0)、bc1pmsrhxnvmj8tjxxu9wj69ntvwvhvr28qufyc26tshz3rjj777tx3sh54u63(P2TR,witness v1),以及它们的 tb1… 测试网形式。允许全大写,不允许大小写混用。
还没有输入

请在上方输入内容后点击「转换」。不知道填什么?点「填入示例」即可载入占位符里的演示数据。

技术原理详解

本页做什么

bech32 地址就是一串带 BCH 校验和的 base32 字符串,解码后只得到两个事实:witness 版本与 witness 程序。这两个事实就是地址的全部 —— scriptPubKey 字面上就是 OP_n 加上那个程序:

scriptPubKey = OP_witness版本 ‖ <推送长度> ‖ witness 程序
bc1qy86hkm0…→ hrp "bc"→ 分隔符 1→ 5 位数据字→ 校验和常量→ witness v0 + 20 字节程序→ 0014…

把任意 bc1…、tb1…、v0 或 v1 地址粘进来即可。本页会展示解码的每一个阶段,告诉你 匹配的是哪个校验和常量(因此适用于 BIP173 还是 BIP350),遇到非法输入则原样打印解码器给出的原因,而不是 自己猜。

1. bech32 字符串的构成

部分规则在 bc1qy86hkm0telzmvuvzm76279jp7z5p3yqjnaerk6 中
可读部分(hrp)1–83 个 US-ASCII 字符,取值 33–126bc(主网)/ tb(测试网)
分隔符恒为字符 1;若 hrp 里本来就有 1,则以最后一个为界下标 2,一个字符
数据部分至少 6 个字符,取自 32 字符集;最后 6 个是校验和qy86hkm0telzmvuvzm76279jp7z5p3yqjnaerk6(39 个字符)
校验和数据部分最后 6 个字符 —— 30 位,不承载任何载荷信息naerk6
总长度最多 90 个字符42 个字符

分隔符的作用是让 hrp 不必转义就能写出,而它选数字 1 而不是某个符号,是因为符号在复制粘贴时 很容易出问题。用 1 是安全的,因为它被刻意排除在数据字符集之外,hrp 到哪里结束永远没有歧义。

2. 5 位字符集,以及为什么是 5 位

数据部分是以这个字母表、这个顺序构成的 base32 字符串:

取值01234567
+0qpzry9x8
+8gf2tvdw0
+16s3jn54kh
+24ce6mua7l

恰好 32 个字符,所以每个字符恰好 5 位 —— 「5 位」这个数字就是这么来的。注意少了哪些字符: 1(它是分隔符)、b、i、o(视觉歧义),这也意味着不会 有两个形近字形同时参与编码。该字母表还经过挑选,使「看起来相似却相差不止 1 个比特」的字符对尽可能少, 因为校验和的优化目标正是检测少量的比特错误。

代价是长度 —— base32 比 base256 大约多出 15% 的字符;收益是没有大小写可弄错、可以毫无歧义地念出来, 并且能使用二维码的字母数字模式(比字节模式紧凑 45%)。

3. 8 位到 5 位的转换与补零规则

witness 程序是字节串,数据部分是 5 位值的串。转换按最高位在前进行:取出程序的比特,每 5 位切一组, 最后一组不足时用 0 补齐。

程序长度比特5 位字补零比特
2 字节(最小)164(20 位)4
20 字节(P2WPKH)16032(160 位)0
32 字节(P2WSH / P2TR)25652(260 位)4
40 字节(最大)32064(320 位)0

因为补零最多只有 4 位,多一个或少一个 base32 字符都会明显不对。所以这条规则很严格,也是解码器必须 强制执行的规则:

末尾不完整的一组 MUST 不超过 4 位、MUST 全为零,并被丢弃

忽略这条规则的解码器,会让同一个程序对应多个不同的字符串,这对地址完整性不利,而且会让补零比特成为 错字藏身之处。BIP173 与 BIP350 都为这一点准备了测试向量: bc1zw508d6qejxtdg4y5r3zarvaryvqyzf3du 属于「补零超过 4 位」, tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv 属于「非零补零」。 本页解码器用 Invalid padding: invalid padding 拒绝了这两个 —— 具体检查是:最后一个完整字节 之后剩余的比特数必须小于 5,且移位后的累加器必须为零。

4. BCH 校验和

校验和不是哈希。它是定义在 GF(32) 上的 BCH 码 —— 一种线性纠错码,其代数结构能对「哪些错误一定被 抓到」给出保证:

GEN = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3]

def polymod(values):
    chk = 1
    for v in values:
        b = chk >> 25
        chk = (chk & 0x1ffffff) << 5 ^ v
        for i in range(5):
            chk ^= GEN[i] if ((b >> i) & 1) else 0
    return chk

# hrp 以 [每个字符的高 3 位] + [0] + [每个字符的低 5 位] 的形式参与
验证:  polymod(hrp_expand(hrp) + data) == 1          # bech32
验证:  polymod(hrp_expand(hrp) + data) == 0x2bc830a3 # bech32m
属性取值
有限域GF(32) —— 那个 5 位字母表
生成常量0x3b6a57b2、0x26508e6d、0x1ea119fa、0x3d4233dd、0x2a1462b3
校验符号6 个字符 = 30 位
bech32 常量1
bech32m 常量0x2bc830a3 = 734539939
保证检测任何影响至多 4 个字符的错误
漏检更严重错误的机会低于十亿分之一(渐近值 1 / 230 = 每十亿次 0.931 次)

hrp 也参与校验和,而且按「高位在前」折叠进去:[ord(c) >> 5 for c in hrp] + [0] + [ord(c) & 31 for c in hrp]。这个顺序意味着:只在 hrp 字符低 5 位内部翻比特的错误(比如把 b 变成 c)依然落在该码设计的保护范围内。这也正是为什么 M1VUXWEZ 无效 —— 它的校验和 是按大写 hrp 算的;而 BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4(校验和按小写取值算) 是有效的。

BIP173 还测量了错误字符超过 4 个时的表现。下表单位是「每十亿次中的失败次数」,而随机的 30 位校验和 基线是每十亿次 0.931:

窗口长度说明错 5 个字符错 6 个字符错 7 个及以上
8能检测 6 个错误的最长窗口01.1270.909 – 0.931
196 个错误的最差情况窗口0.0930.9720.931
39P2WPKH 地址的长度0.7560.9350.931
59P2WSH 地址的长度0.8050.9330.931
89能检测 4 个错误的最长窗口0.8670.9330.931

BIP350 对新常量重做了这套分析,并给出了专门针对 bc1 地址形态的数字。对于用 bech32m 解码器 校验的 bech32m 字符串:24.34% 的单错误模式被确定检出,75.66% 以概率 1 − 2−30 检出;对落在 28 字符窗口内的至多两个错误是 16.85% / 83.15%;对任意位置的至多两个错误是 15.72% / 84.23%,另有 0.039% 落在 2−25。同样这些字符串若交给 bech32 解码器,表现明显更差 —— 这正是「干净 切割」的意义。

5. bech32 与 bech32m —— 逼出 BIP350 的插入弱点

这是本页最关键的部分,因为它解释了为什么同一种地址会存在两套几乎相同的编码。

2020 年人们发现 bech32 的校验和有个洞。引用 BIP350 的原话:

BIP350 自己是怎么说的

「Bech32 有一个始料未及的弱点:当最后一个字符是 'p' 时,在它前面紧邻处插入或删除任意数量的 'q' 字符 都不会使校验和失效。」插入与删除并不在 BCH 码被优化覆盖的错误类型里,而字符串又不携带长度信息,于是被改 动过的字符串可以仍然是合法字符串 —— 只是载荷不同了。

我们用本页自己的解码器复现了它。取一个合法、末字符为 p 的 bech32 v0 地址,在那个末尾 p 之前紧邻插入 q:

字符串polymod 结果校验和
bc1qk4sgyl3plhx0pmh6w80r0m2m5pmknw75uteaqp1合法 bech32
bc1qk4sgyl3plhx0pmh6w80r0m2m5pmknw75uteaqqp(插入一个 q)1仍然通过校验和
bc1qk4sgyl3plhx0pmh6w80r0m2m5pmknw75uteaqqqqp(插入三个)1仍然通过校验和
bc1qk4sgyl3plhx0pmh6w80r0m2m5pmknw75uteap(删掉原有的那个 q)1仍然通过校验和

BIP350 的修法刻意做到最小:其他一切不变,只把异或进校验和的那个常量从 1 改成 0x2bc830a3。对 bech32m 字符串做同样的插入,校验和就不再能通过(polymod 返回 920205498 而不是 734539939),于是这次改动是被校验和自己抓到的,而不是靠运气。

bech32bech32m
校验和常量10x2bc830a3
规范文件BIP173BIP350(修订 BIP173)
用于witness v0:P2WPKH、P2WSHwitness v1–v16:P2TR 及未来类型
末尾 p 前插入 q校验和检测不到校验和能检测到
冲突规则没有任何字符串能同时合法:等长的合法 bech32 与 bech32m 字符串至少相差 3 个字符
为什么不给 v0 同时允许两种?BIP350:那会令错误检测能力退化到相当于只有 29 位校验和

还有两点补全整个图景。第一,已有的 v0 地址从未处于危险之中:BIP350 指出该弱点「由于限制在两种特定长度, 不影响 witness v0 的 BIP173 地址现有用法」。插入字符会改变字数,于是程序要么长度变了、要么破坏了补零规则 —— 在我们上面的复现里,被改动的字符串其实是被本页的 Invalid padding 检查拒绝的;而 v1+ 的插入 则由 bech32m 常量拦下。第二,BIP173 自己在 2024 年补充了一条披露:该方案「对少于 5 个连续字符的插入与删除 并不总是稳健」,这也是 BIP173 现在只适用于 v0 输出的原因。

6. 本页执行的合法性规则

规则要求出处
长度整体最多 90 个字符BIP173
大小写全小写或全大写;混用即非法BIP173
hrp非空;比特币地址为 bc(主网)或 tb(测试网)BIP173
分隔符必须存在 1,以最后一个为界BIP173
数据部分至少 6 个字符,且全部在字符集内BIP173
校验和v0 用 1,v1+ 用 0x2bc830a3BIP173 / BIP350
witness 版本0 – 16(含)BIP173
witness 程序2 – 40 字节BIP141 / BIP173
v0 程序长度必须恰好 20 字节(P2WPKH)或 32 字节(P2WSH)BIP141
补零剩余比特不超过 4 位且全为零BIP173

由此地址长度被严格约束:14 到 74 个字符,且长度对 8 取余不可能是 0、3、5;v0 地址永远是 42 或 62 个 字符。

witness 版本范围,以及为什么这条很容易漏掉

witness 版本必须落在 0–16 之间,因为 OP_n 只对 n ≤ 16 存在;版本字为 17–31 的字符串 不是合法的 segwit 地址,哪怕它的校验和、补零与程序长度全部通过检查。BIP350 就列出了 这样一个非法向量:全大写字符串 BC130XLXVLHEMJA6C4DQV22UAPCTQUPFHLXM9H8Z3K2E72Q4K9HCZ7VQ7ZWS8R(版本 17)通过了其余 所有规则。本解码器会以 Witness version 17 is invalid: only versions 0-16 are defined 拒绝它 —— 你可以把它粘到上面的 输入框里,亲眼看到这条拒绝结果,再与版本字为 1 的 bc1p… 对照。

7. 实例演算:示例 P2WPKH 地址

步骤值
地址bc1qy86hkm0telzmvuvzm76279jp7z5p3yqjnaerk6(42 个字符)
hrpbc
分隔符下标2
数据部分qy86hkm0telzmvuvzm76279jp7z5p3yqjnaerk6(39 个字符)
第一个数据值q = 0 → witness 版本 0
程序字(去掉校验和)y86hkm0telzmvuvzm76279jp7z5p3yqj(32 个字)
这些字的 5 位取值4,7,26,23,22,27,15,11,25,31,2,27,12,28,12,2,27,30,26,10,30,5,18,1,30,2,20,1,17,4,0,18
校验和字符naerk6
匹配的校验和常量1 → bech32,BIP173
witness 程序21f57b6debcfc5b67182dfb4af1641f0a8189012(20 字节)
scriptPubKey001421f57b6debcfc5b67182dfb4af1641f0a8189012
可读脚本OP_0 <20 字节推送> —— 最经典的 P2WPKH 输出
同一程序的测试网形式tb1qy86hkm0telzmvuvzm76279jp7z5p3yqjemzsdf —— 20 字节完全相同,hrp 不同,因此校验和也不同

注意这个 witness 程序就等于同一把密钥在 hash160 → 地址 里打印的那个 hash160; 而测试网地址携带同样的程序、却是另外 6 个校验和字符:hrp 参与校验和计算,所以「主网/测试网搞混」这种情况 不可能蒙混过关。

8. 实例演算:示例 P2TR 地址

步骤值
地址bc1pmsrhxnvmj8tjxxu9wj69ntvwvhvr28qufyc26tshz3rjj777tx3sh54u63(62 个字符)
hrp / 分隔符下标bc / 2
数据部分pmsrhxnvmj8tjxxu9wj69ntvwvhvr28qufyc26tshz3rjj777tx3sh54u63(59 个字符)
第一个数据值p = 1 → witness 版本 1
程序字msrhxnvmj8tjxxu9wj69ntvwvhvr28qufyc26tshz3rjj777tx3s(52 个字)
校验和字符h54u63
匹配的校验和常量0x2bc830a3(734539939)→ bech32m,BIP350
witness 程序dc07734d9b91d7231b8574b459ad8e65d8351c1c4930ad2e171447297bde59a3(32 字节)
scriptPubKey5120dc07734d9b91d7231b8574b459ad8e65d8351c1c4930ad2e171447297bde59a3
可读脚本OP_1 <32 字节推送> —— 注意 OP_1 的操作码是 0x51,不是 0x01
程序从哪来它是调整后输出公钥的 x 坐标:内部公钥 ff812e26…ee80、TapTweak bae91685…fa4d、输出公钥 dc07734d…59a3

最后一行就是两个示例地址在一句话里的区别:P2WPKH 的程序是公钥的哈希,而 P2TR 的程序本身 就是一把公钥(调整后的那把)。其余一切 —— 编码、分隔符、5 位字、6 字符校验和 —— 完全相同;不同的 只有版本字与校验和常量。

9. 本页展示的失败路径

下面的非法字符串在每一次运行中都会被现场测试,和你粘贴的内容一起:

测试结果
把末字符换成字符集里的下一个字符Checksum verification failed (the address contains a typo or is truncated)
把地址的一部分改成大写Mixed case is not allowed in bech32 strings
把 v0 程序用 bech32m 常量重新编码(BIP350 向量 bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kemeawh)Witness v0 must use bech32, not bech32m
把 v1 程序用 bech32 常量重新编码(BIP350 向量 bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqh2y7hd)Witness v1+ must use bech32m, not bech32
完全没有分隔符No separator "1" found
数据部分出现字符集之外的字符,例如 bCharacter "b" is not in the bech32 charset
超过 90 个字符Length 93 exceeds the BIP173 limit of 90 characters
v0 程序长 25 字节Witness v0 program must be 20 bytes (P2WPKH) or 32 bytes (P2WSH)

还有一条会让人意外的边界说明:BIP350 自己的测试向量里包含一些合法的 bech32m 字符串(例如 A1LQFN3A),它们根本不是 segwit 地址(数据部分只有校验和)。segwit 地址解码器会在其上再套一层 地址规则,因此会拒绝它们 —— 这是正确的,会给出理由,也不会崩。

10. 安全须知与常见错误

它在链条中的位置

上游:私钥 → P2WPKH 地址 与 私钥 → P2TR 地址 负责构造这些字符串;hash160 → 地址 产出 v0 所需的 20 字节程序。下游另一种地址 编码见 Base58Check 编码 / 解码 —— 版本字节、WIF 与校验和失败都在那里。

11. 速查表

项目值
字符集qpzry9x8gf2tvdw0s3jn54khce6mua7l(32 个字符,每个 5 位)
分隔符1,取最后一次出现
校验和长度6 个字符(30 位)
bech32 常量 / 规范1 / BIP173 —— witness v0
bech32m 常量 / 规范0x2bc830a3 / BIP350 —— witness v1+
总长度上限90 个字符
v0 地址长度42 个字符(P2WPKH)或 62 个(P2WSH)
程序长度2 – 40 字节;v0 必须恰好 20 或 32
保证的错误检测任何影响至多 4 个字符的错误
已知弱点仅 bech32:末尾 p 之前的 q 插入 / 删除