本文档定义了Bech32的改进版本Bech32m,并修改了BIP173,以便为版本1及更高版本的原生隔离见证输出使用Bech32m。Bech32仍然用于版本0的隔离见证输出。Bech32m通过修改校验和算法来解决Bech32中存在的插入漏洞问题,并提供了详细的规范、兼容性考虑和测试向量。
forked from bitcoin/bips
bip-anyprevout
搜索此仓库
/
复制路径
Blame更多文件操作
Blame更多文件操作
合并拉取请求 bitcoin#1066 from SomberNight/202002_bip350_fix_links
打开提交详情
2021年2月9日
faeb2cc · 2021年2月9日
打开提交详情
336 行 (267 loc) · 26.3 KB
/
顶部
预览
代码
Blame
336 行 (267 loc) · 26.3 KB
复制原始文件
下载原始文件
大纲
编辑和原始操作
BIP: 350
Layer: Applications
Title: Bech32m format for v1+ witness addresses
Author: Pieter Wuille <pieter@wuille.net>
Comments-Summary: No comments yet.
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0350
Status: Draft
Type: Standards Track
Created: 2020-12-16
License: BSD-2-Clause
Replaces: 173
Post-History: 2021-01-05: https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2021-January/018338.html [bitcoin-dev] Bech32m BIP: new checksum, and usage for segwit address
## 目录<br>永久链接:目录<br>- 简介 <br> - 摘要<br> - 版权<br> - 动机<br>- 规范 <br> - Bech32m<br> - 隔离见证输出的地址<br>- 兼容性<br>- 参考实现<br>- 测试向量 <br> - Bech32m 的测试向量<br> - v0-v16 原生隔离见证地址的测试向量<br>- 附录:校验和设计 & 属性 <br> - 错误模式 & 检测概率<br> - Bech32m 的检测属性<br> - 选择过程<br>- 脚注<br>- 致谢 |
本文档定义了一种改进的 Bech32 变体,称为 Bech32m,并修改 BIP173 以对版本 1 及更高版本的原生隔离见证输出使用 Bech32m。Bech32 仍用于版本 0 的隔离见证输出。
本 BIP 采用 2-clause BSD 许可。
BIP173 定义了一种通用的带校验和的 base 32 编码格式,称为 Bech32。它用于版本 0 的隔离见证输出(P2WPKH 和 P2WSH,参见 BIP141)和其他应用。
Bech32 有一个意想不到的弱点:每当最后一个字符是“p”时,在其紧前面插入或删除任意数量的“q”字符不会使校验和失效。由于版本 0 的 BIP173 地址限制为两个特定长度,因此这不会影响现有用途,但可能会影响未来使用和/或使用 Bech32 编码的其他应用。
本文档通过指定 Bech32m 来解决这个问题, Bech32m 是 Bech32 的一个变体,可缓解此插入弱点和相关问题。
我们首先指定新的校验和算法,然后记录它应该如何用于未来的比特币地址。
Bech32m 修改了 Bech32 规范的校验和,用 0x2bc830a3 替换了最后异或到校验和中的常量 1。生成的校验和验证和创建算法(在 Python 中,参见 Bech32 section 中的代码):
BECH32M_CONST = 0x2bc830a3
def bech32m_polymod(values):
GEN = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3]
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
def bech32m_hrp_expand(s):
return [ord(x) >> 5 for x in s] + [0] + [ord(x) & 31 for x in s]
def bech32m_verify_checksum(hrp, data):
return bech32m_polymod(bech32m_hrp_expand(hrp) + data) == BECH32M_CONST
def bech32m_create_checksum(hrp, data):
values = bech32m_hrp_expand(hrp) + data
polymod = bech32m_polymod(values + [0,0,0,0,0,0]) ^ BECH32M_CONST
return [(polymod >> 5 * (5 - i)) & 31 for i in range(6)]
Bech32 的所有其他方面保持不变,包括其人类可读部分 (HRP)。
可以使用以下代码编写一个组合函数来同时解码 Bech32 和 Bech32m:
class Encoding(Enum):
BECH32 = 1
BECH32M = 2
def bech32_bech32m_verify_checksum(hrp, data):
check = bech32_polymod(bech32_hrp_expand(hrp) + data)
if check == 1:
return Encoding.BECH32
elif check == BECH32M_CONST:
return Encoding.BECH32M
else:
return None
如果失败,则返回 None,或者返回 BECH32 / BECH32M 枚举值之一,以指示根据各自标准成功解码。
版本 0 输出(具体来说,P2WPKH 和 P2WSH 地址)继续使用 BIP173 中指定的 Bech32[ 1]。版本 1 到 16 的隔离见证输出地址使用 Bech32m。同样,编码的所有其他方面保持不变,包括“bc”HRP。
要生成隔离见证输出的地址:
要解码地址,客户端软件应使用 Bech32 和 Bech32m 解码器[ 2]进行解码,或使用同时支持两者的解码器。在这两种情况下,地址解码器都必须验证编码是否与解码后的见证版本(版本 0 为 Bech32,其他版本为 Bech32m)的预期相符。
以下代码演示了需要执行的检查。有关调用函数的完整详细信息,请参阅下面参考实现部分中链接的 Python 代码。
def decode(hrp, addr):
hrpgot, data, spec = bech32_decode(addr)
if hrpgot != hrp:
return (None, None)
decoded = convertbits(data[1:], 5, 8, False)
# Witness programs are between 2 and 40 bytes in length.
# 见证程序长度介于 2 到 40 字节之间。
if decoded is None or len(decoded) < 2 or len(decoded) > 40:
return (None, None)
# Witness versions are in range 0..16.
# 见证版本范围为 0..16。
if data[0] > 16:
return (None, None)
# Witness v0 programs must be exactly length 20 or 32.
# 见证 v0 程序必须正好是长度 20 或 32。
if data[0] == 0 and len(decoded) != 20 and len(decoded) != 32:
return (None, None)
# Witness v0 uses Bech32; v1 through v16 use Bech32m.
# 见证 v0 使用 Bech32;v1 到 v16 使用 Bech32m。
if data[0] == 0 and spec != Encoding.BECH32 or data[0] != 0 and spec != Encoding.BECH32M:
return (None, None)
# Success.
# 成功。
return (data[0], decoded)
错误定位
像 Bech32 一样,Bech32m 确实支持定位[ 3]一些替换错误的位置。要将此功能与本文档提出的隔离见证地址结合使用,只需尝试定位 Bech32 和 Bech32m 的错误即可。如果只有一个找到错误位置,则报告该位置。如果两者都找到了(这应该非常罕见),则有多种选择:
有关上述示例,请参见下面精美的 Javascript 解码器。
本文档为 v1 隔离见证输出和更高版本引入了一种新的编码方式。接收方不应存在任何兼容性问题;由于该输出类型在主网上不可用,因此尚无钱包创建 v1 隔离见证地址。
另一方面,Bech32m 提案打破了向前兼容性,无法发送到 v1 及更高版本的隔离见证地址。这种不兼容是有意的。已经考虑了一种替代设计,其中 Bech32 仍用于未来地址的某些子集,但最终放弃了。通过引入一个彻底的突破,我们不仅可以保护新软件,还可以保护现有发送方免受突变问题的影响,因为新地址与现有的 Bech32 地址验证不兼容。Taproot 支持者的实验表明,几乎没有钱包和服务支持发送到更高的隔离见证输出版本,因此通过打破向前兼容性损失不大。此外,这些实验确定了隔离见证实现会导致钱包在发送到版本 1 地址时烧毁资金的情况。如果仍在使用中,则选择的方法将阻止此类软件在尝试发送到 Bech32m 地址时销毁资金。
实施建议 测试 BIP173 实施的实验发现,许多钱包和服务不支持发送到更高版本的隔离见证输出。为了预见到拟议的Taproot软分叉在网络上引入 v1 隔离见证输出,我们强烈建议采用下面提供的完整测试向量集,并确保你的实施支持发送到 v1 及更高版本。所有更高版本的原生隔离见证输出都应被识别为有效的接收者。由于网络上未定义更高版本,因此任何钱包都不应创建它们,并且任何接收者都不应将它们提供给发送者。接收者也不应该错误地提供它们,因为接收者只会看到打算支付给自己的款项被烧毁。但是,通过现在将更高版本定义为有效接收者,未来引入更高版本的原生隔离见证输出的软分叉将与所有正确实施 Bech32m 规范的钱包向前兼容。
以下字符串是有效的 Bech32m:
A1LQFN3A
a1lqfn3a
an83characterlonghumanreadablepartthatcontainsthetheexcludedcharactersbioandnumber11sg7hg6
abcdef1l7aum6echk45nj3s0wdvt2fg8x9yrzpqzd3ryx
11llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllludsr8
split1checkupstagehandshakeupstreamerranterredcaperredlc445v
?1v759aa
没有字符串可以同时是有效的 Bech32 和 Bech32m,因此以上示例也可以用作 Bech32 的无效测试向量。
以下字符串不是有效的 Bech32m(无效的原因):
1xj0phk
: HRP 字符超出范围1g6xzxy
: HRP 字符超出范围1vctc34
: HRP 字符超出范围an84characterslonghumanreadablepartthatcontainsthetheexcludedcharactersbioandnumber11d6pts4
: 超过总最大长度qyrz8wqd2c9m
: 没有分隔符字符1qyrz8wqd2c9m
: 空 HRPy1b0jsk6g
: 无效的数据字符lt1igcx5c0
: 无效的数据字符in1muywd
: 校验和太短mm1crxm3i
: 校验和中的无效字符au1s5cgom
: 校验和中的无效字符M1VUXWEZ
: 使用 HRP 的大写形式计算的校验和16plkw9
: 空 HRP1p2gdwpf
: 空 HRP以下列表给出了有效的 segwit 地址以及它们转换为的 scriptPubKey (十六进制)。
BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4
: 0014751e76e8199196d454941c45d1b3a323f1433bd6
tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7
: 00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262
bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kt5nd6y
: 5128751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6
BC1SW50QGDZ25J
: 6002751e
bc1zw508d6qejxtdg4y5r3zarvaryvaxxpcs
: 5210751e76e8199196d454941c45d1b3a323
tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy
: 0020000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433
tb1pqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesf3hn0c
: 5120000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433
bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqzk5jj0
: 512079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798
以下列表给出了无效的 segwit 地址以及它们无效的原因。
tc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq5zuyut
: 无效的人类可读部分bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqh2y7hd
: 无效的校验和(Bech32 而不是 Bech32m)tb1z0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqglt7rf
: 无效的校验和(Bech32 而不是 Bech32m)BC1S0XLXVLHEMJA6C4DQV22UAPCTQUPFHLXM9H8Z3K2E72Q4K9HCZ7VQ54WELL
: 无效的校验和(Bech32 而不是 Bech32m)bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kemeawh
: 无效的校验和(Bech32m 而不是 Bech32)tb1q0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq24jc47
: 无效的校验和(Bech32m 而不是 Bech32)bc1p38j9r5y49hruaue7wxjce0updqjuyyx0kh56v8s25huc6995vvpql3jow4
: 校验和中的无效字符BC130XLXVLHEMJA6C4DQV22UAPCTQUPFHLXM9H8Z3K2E72Q4K9HCZ7VQ7ZWS8R
: 无效的见证版本bc1pw5dgrnzv
: 无效的程序长度(1 字节)bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7v8n0nx0muaewav253zgeav
: 无效的程序长度(41 字节)BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P
: 见证版本 0 的程序长度无效(根据 BIP141)tb1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq47Zagq
: 混合大小写bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7v07qwwzcrf
: 超过 4 位的零填充tb1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vpggkg4j
: 8 到 5 转换中的非零填充bc1gmk9yu
: 空数据段校验和用于检测传输过程中引入数据的错误。基于哈希函数的校验和 (如 Base58Check) 以统一的方式检测任何类型的错误,但并非所有类型的错误在实践中都同样可能发生。Bech32 优先检测替换错误,但改进一类错误的检测不可避免地会降低其他类型错误的检测。在 Bech32 的设计过程中,假设除了替换之外的其他简单错误模式的检测率与基于哈希函数的设计中的检测率相似,并且只有对于复杂且不切实际的错误,检测才会更差。发现的插入弱点表明情况并非如此。
对于 Bech32m,我们的目标是保留 Bech32 对替换错误的保证,但要确保其他常见错误不会比基于哈希函数的校验和的性能更差。为了确保新标准易于实施,我们将设计空间限制为仅修改异或的最终常量,因为观察到这足以缓解“q”插入问题,同时保留预期的替换错误检测。在下文中,我们将解释如何选择新常量 0x2bc830a3。
我们将错误模式定义为首先是一个或多个删除,然后是相邻字符的交换,然后是替换、插入和重复(按该顺序)的序列,所有这些都位于特定位置,应用于具有有效校验和的字符串(否则是随机选择的)。对于插入和替换,我们假设使用均匀随机的新字符。例如,“删除第 17 个字符,将第 11 个字符与第 12 个字符交换,并在第 24 个位置插入一个随机字符”是一种错误模式。“将第 43 到 48 个字符替换为‘aardvark’”不是有效的错误模式,因为新字符不是随机的,并且没有理由为什么此特定字符串比任何其他字符串更可能被替换。
具有 30 位哈希的基于哈希函数的校验和设计对于每个错误模式都具有等于 2-30 的错误接受概率。对于最多包含 4 个替换的错误模式,Bech32 的错误接受概率为 0 - 它们始终会被检测到。“q”-插入问题表明,对于 Bech32,存在一个概率为 2-10 的简单错误模式(“在倒数第二个位置插入一个随机字符”):它要求最后一个字符为“p”(仅留下 32 个字符串中的 1 个),并且要求插入的字符为“q”(仅允许 32 个可能的插入字符中的 1 个)。
请注意,什么 是错误模式(哪些类型的错误以及在何处)不是我们的概率的一部分:我们尝试确保_每种_模式都表现良好,而不仅仅是随机选择的模式,因为据推测,人类比其他模式更容易犯某些类型的错误,并且我们- errors 考虑的最大单个错误数
这些属性分为两类:一类是在所有可能的HRP(human readable parts,人类可读部分)上平均时,适用于所有字符串的属性;另一类是特定于“bc1”HRP的属性,具有隔离见证地址施加的长度限制[ 7]。
errors | of type | window | code/verifier | error patterns with failure probability | |||||
---|---|---|---|---|---|---|---|---|---|
0 | 2-30 | 2-25 | 2-20 | 2-15 | 2-10 | ||||
Properties averaged over all HRPs | |||||||||
≤ 4 | only subst. | any | Bech32m/Bech32m | 100.00% | none(a) | ||||
any | any | ≤ 4 | 56.16% | 43.84% | none(b) | ||||
≤ 2 | any | ≤ 68 | 7.71% | 92.28% | none(b) | ||||
≤ 2 | any | any | 7.79% | 92.20% | 0.004% | none(b) | |||
≤ 3 | any | ≤ 69 | 7.73% | 92.23% | 0.033%(d) | none(b) | |||
≤ 3 | any | any | 7.77% | 92.19% | 0.034% | 0.000065% | none(b) | ||
≤ 4 | only subst. | any | Bech32/Bech32 | 100.00% | none | ||||
any | any | ≤ 4 | 54.00% | 43.84% | 1.08% | 0.90% | 0.17% | 0.0091% | |
≤ 2 | any | ≤ 68 | 4.59% | 92.29% | 1.09% | 1.01% | 0.99% | 0.039% | |
≤ 2 | any | any | 4.58% | 92.21% | 1.11% | 1.04% | 1.02% | 0.038% | |
≤ 3 | any | ≤ 69 | 6.69% | 92.23% | 0.56% | 0.48% | 0.041% | 0.00055% | |
≤ 3 | any | any | 6.66% | 92.19% | 0.59% | 0.52% | 0.041% | 0.00053% | |
0 | - | - | Bech32m/Bech32 | 100.00% | none(a) | ||||
1 | any | - | 46.53% | 53.46% | none(b) | ||||
≤ 2 | any | any | 22.18% | 77.77% | 0.048% | none(b) | |||
Properties for segregated witness addresses with HRP "bc" | |||||||||
≤ 4 | only subst. | any | Bech32m/Bech32m | 100.00% | none(a) | ||||
1 | any | - | 24.34% | 75.66% | none(c) | ||||
≤ 2 | any | ≤ 28 | 16.85% | 83.15% | none(c) | ||||
any | any | ≤ 4 | 74.74% | 25.25% | 0.0016% | none(c) | |||
≤ 2 | any | any | 15.72% | 84.23% | 0.039% | 0.0053% | none(c) | ||
≤ 3 | any | any | 13.98% | 85.94% | 0.078% | 0.00063% | none(c) | ||
≤ 4 | only subst. | any | Bech32/Bech32 | 100.00% | none | ||||
1 | any | - | 14.63% | 75.71% | 2.43% | 2.43% | 2.43% | 2.38% | |
≤ 2 | any | ≤ 28 | 14.22% | 83.15% | 0.94% | 0.84% | 0.79% | 0.054% | |
any | any | ≤ 4 | 73.23% | 25.26% | 0.76% | 0.63% | 0.12% | 0.0064% | |
≤ 2 | any | any | 12.79% | 84.24% | 1.06% | 0.95% | 0.92% | 0.041% | |
≤ 3 | any | any | 13.00% | 85.94% | 0.57% | 0.45% | 0.044% | 0.00067% | |
≤ 3 | only subst. | any | Bech32m/Bech32 | 100.00% | none(c) | ||||
1 | any | - | 70.89% | 29.11% | none(c) | ||||
≤ 2 | any | any | 36.12% | 63.79% | 0.092% | 0.00049% | none(c) |
该表中的数字,以及与 "1" 常量和早期提出的改进常量的比较,可以在这里找到。
选择过程的详细信息可以在这里找到,但简而言之:
感谢 Greg Maxwell 完成了代码选择和分析的大部分计算和评论。 感谢 Mark Erhardt 在撰写和编辑本文档方面的帮助。 感谢 Rusty Russell 和 bitcoin-dev 列表上的其他人对有意破坏与现有发送方兼容性的讨论,该讨论已在此规范中使用。
- 原文链接: github.com/ajtowns/bips/...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!