Skip to content

Commit 210a598

Browse files
authored
docs: add bech32 (#1121)
* docs: bech32 intro * docs: bech32 encode & decode * docs: add polyMod and code example
1 parent 9b57706 commit 210a598

File tree

1 file changed

+184
-0
lines changed

1 file changed

+184
-0
lines changed

BTC/tools/bech32.md

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
Bech32是一种编码格式,最初由Pieter Wuille等人在比特币改进提案[BIP 173](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki)中提出,主要用于比特币SegWit地址的编码方式。Bech32编码的目的是提供一种更友好的用户界面,并减少在抄写和输入时出现错误的风险。
2+
3+
### 核心特性
4+
5+
**1. 错误检测能力:**
6+
Bech32地址包含一种错误检测代码,称为多项式校验码(PolyMod),可以检测并保护地址中最多4个错误的出现。
7+
8+
**2. 字符集:**
9+
Bech32只使用小写字母和数字(除了1、b、i、o之外的小写字母和所有数字),从而避免了字母大小写的混淆和某些字母和数字之间的视觉相似性。
10+
11+
**3. 限制长度:**
12+
一个Bech32编码的地址总是有一定的长度限制,比特币的SegWit地址最长为90个字符。
13+
14+
**4. 分隔符:**
15+
Bech32地址中使用"1"作为分隔符来分开人类可读的部分(HRP,Human-readable part)和数据部分。
16+
17+
### 编码格式
18+
19+
Bech32地址的结构如下:
20+
21+
\[ \text{HRP} + "1" + \text{数据编码} + \text{校验码} \]
22+
23+
- **HRP(Human-readable part):** 这部分是地址的前缀,用来指示地址所用的网络,例如比特币主网的`bc`和测试网的`tb`
24+
- **数据编码:** 使用的是一种叫做Base32的变种编码,将数据转换成32个字符集中的字符。
25+
- **校验码:** 是一组校验码字符,用于保护整个地址不受随机错误的影响。
26+
27+
Bech32是一种用于编码和解码比特币SegWit地址的格式,具体方法由[BIP 173](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki)定义。编码和解码过程涉及多个步骤,包括数据的处理、转换以及校验。
28+
29+
在实际项目中可以使用JavaScript的常用库bech32实现的Bech32编码和解码。
30+
**Bech32编码示例**
31+
```js
32+
const bech32 = require('bech32');
33+
34+
function encodeBech32(hrp, data) {
35+
const words = bech32.toWords(Buffer.from(data));
36+
return bech32.encode(hrp, words);
37+
}
38+
39+
// 示例使用
40+
let hrp = "bc";
41+
let data = "00112233445566778899aabbccddeeff"; // 假设这是要编码的数据
42+
let encoded = encodeBech32(hrp, data);
43+
console.log("Encoded Bech32:", encoded);
44+
```
45+
46+
**Bech32解码示例**
47+
```js
48+
function decodeBech32(address) {
49+
let decoded = bech32.decode(address);
50+
decoded.data = Buffer.from(bech32.fromWords(decoded.words)).toString('hex');
51+
return decoded;
52+
}
53+
54+
// 使用之前编码的地址进行解码
55+
let decoded = decodeBech32(encoded);
56+
console.log("Decoded Bech32:", decoded);
57+
```
58+
59+
### Bech32编码过程
60+
61+
编码过程涉及以下步骤:
62+
63+
1. **确定人类可读部分(HRP)和数据部分:**
64+
- HRP表示网络,比如比特币主网的`bc`,测试网的`tb`
65+
- 数据部分包含经过编码的公钥或脚本哈希。
66+
67+
2. **将数据部分从8位字节转换为5位数组:**
68+
- Bech32使用Base32编码,这不同于传统的Base32。数据需要从其原始的8位字节形式(如在二进制文件中)转换为5位字节的数组。这种转换减少了数据的比特长度,并允许整个地址适应QR码等格式。
69+
70+
3. **计算校验码:**
71+
- 使用`PolyMod`算法计算出一个校验码,该算法可以提供错误检测功能。校验码计算依赖于HRP和转换后的数据。
72+
- 校验码有助于保护整个地址不受随机错误的影响。
73+
74+
4. **组合最终的Bech32地址:**
75+
- 最终的Bech32地址由三部分组成:HRP、分隔符(`1`)、编码后的数据和校验码。
76+
- 示例:`bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4`
77+
78+
79+
### Bech32解码过程
80+
81+
解码过程涉及以下步骤:
82+
83+
1. **验证地址的校验码:**
84+
- 使用相同的`PolyMod`算法验证地址中的校验码是否正确。如果校验失败,则地址有错误。
85+
86+
2. **分离HRP和编码数据:**
87+
- 从地址中分离出HRP和编码后的数据部分。这两部分由分隔符`1`分开。
88+
89+
3. **从5位数组转换回8位字节:**
90+
- 将从Bech32地址中提取的5位数组数据转换回原始的8位字节形式。这通常涉及二进制数据的重新分组。
91+
92+
4. **解析数据部分以获取原始的哈希或密钥信息:**
93+
- 解码后的数据通常是某种形式的哈希值或公钥信息,这取决于具体的应用场景(如P2WPKH或P2WSH)。
94+
95+
96+
`PolyMod`是一种特别设计用于Bech32编码系统中的多项式模运算算法。在Bech32地址格式中,`PolyMod`算法用于生成一个校验码,该校验码具有高错误检测能力,能够帮助确认地址在传输或书写过程中是否被错误修改。此算法是Bech32提案(BIP 173)的核心部分,对于保证地址的完整性和准确性至关重要。
97+
98+
### PolyMod算法的作用
99+
100+
在Bech32中,`PolyMod`算法的主要作用是计算一个校验码,这个校验码能够:
101+
- 检测到任何单一的错误。
102+
- 检测到任何相邻字符的交换。
103+
- 检测到最多四个错误的错误组合。
104+
105+
### PolyMod算法的实现步骤
106+
107+
`PolyMod`算法的计算可以分为以下几个步骤:
108+
109+
1. **初始化**:设置一个初始变量`c`为1。
110+
111+
2. **处理HRP**:对于HRP(人类可读部分)中的每个字符,进行以下操作:
112+
-`c`向右移动5位。
113+
- 将字符的值与`c`进行异或(XOR)运算。
114+
-`c`进行一系列的模2多项式运算,通常这涉及到与几个固定的常数进行XOR运算,这些常数由Bech32规范定义。
115+
116+
3. **处理数据部分**:类似地处理数据部分中的每个5位值,包括:
117+
-`c`向右移动5位。
118+
- 将数据值与`c`进行异或运算。
119+
-`c`进行类似上述的模2多项式运算。
120+
121+
4. **生成校验码**:完成所有字符的处理后,将`c`与一个常数进行XOR运算,得到最终的校验码。这一步确保了校验码能够有效地反映整个地址的完整性。
122+
123+
** 示例代码 **
124+
```js
125+
function polymod(values) {
126+
let generator = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3];
127+
let chk = 1;
128+
for (let value of values) {
129+
let top = chk >> 25;
130+
chk = (chk & 0x1ffffff) << 5 ^ value;
131+
for (let i = 0; i < 5; i++) {
132+
if ((top >> i) & 1) {
133+
chk ^= generator[i];
134+
}
135+
}
136+
}
137+
return chk;
138+
}
139+
140+
function hrpExpand(hrp) {
141+
let ret = [];
142+
for (let p = 0; p < hrp.length; p++) {
143+
ret.push(hrp.charCodeAt(p) >> 5);
144+
}
145+
ret.push(0);
146+
for (let p = 0; p < hrp.length; p++) {
147+
ret.push(hrp.charCodeAt(p) & 31);
148+
}
149+
return ret;
150+
}
151+
152+
function createChecksum(hrp, data) {
153+
const values = hrpExpand(hrp).concat(data).concat([0, 0, 0, 0, 0, 0]);
154+
const polymodValue = polymod(values) ^ 1;
155+
let checksum = [];
156+
for (let i = 0; i < 6; i++) {
157+
checksum.push((polymodValue >> 5 * (5 - i)) & 31);
158+
}
159+
return checksum;
160+
}
161+
162+
// Example usage
163+
let hrp = "bc";
164+
let data = [2, 3, 4, 5, 6]; // Example data part (this should be your actual converted data)
165+
let checksum = createChecksum(hrp, data);
166+
console.log("Checksum:", checksum);
167+
```
168+
169+
### 数学原理
170+
171+
`PolyMod`算法本质上是一个使用特定生成多项式的循环冗余校验(CRC)算法。这个生成多项式是经过选择的,能够最大化常见错误模式的检测能力,例如拼写错误、字符遗漏、错误插入等。
172+
173+
174+
### 使用场景
175+
176+
Bech32地址主要用于比特币的SegWit交易,其中包括了P2WPKH(Pay to Witness Public Key Hash)和P2WSH(Pay to Witness Script Hash)类型的地址。这些地址类型通过减少交易大小来降低交易费用,同时提高交易的隐私性和效率。
177+
178+
### 优点
179+
180+
- **更高的错误检测能力:** Bech32的设计提供了强大的错误检测和纠正能力。
181+
- **用户友好:** 地址全小写,易于阅读和抄写。
182+
- **效率与兼容性:** 地址长度更短,适用于QR码等多种场景。
183+
184+
Bech32编码为比特币地址提供了一个更加安全和用户友好的格式,是比特币网络中SegWit技术的一个重要组成部分。

0 commit comments

Comments
 (0)