修改后的Base58二进制到文本编码被称为Base58Check,用于编码比特币地址。
通俗来讲,Base58Check编码用于将比特币中的字节数组编码为可分类、易读的字符串。
背景
最初的比特币客户端源代码解释了base58编码背后的原因:
base58.h:
为什么是base-58而不是标准的base-64编码?
- 不希望0oIl字符在某些字体中看起来相同,可以用来创建视觉上相同的账号
- 具有非字母数字字符的字符串并不像帐号那么容易被接受。
- 如果没有标点符号,电子邮件通常不会换行。
- 如果全部是字母数字,双击就可以选择整个数字。
Base58Check的功能
Base58Check具有以下功能:
- 一个任意大小的
payload
。 - 一组58个字母数字符号,由易于区分的大小写字母组成(不使用0OIl)
- 一个字节的版本/应用程序信息。比特币地址为这个字节使用0x00(未来的可能使用0x05)。
- 四个字节(32位)基于SHA256的错误检查代码。此代码可用于自动检测并可能纠正排版错误。
- 保留数据中零开头的额外步骤。
创建一个Base58Check字符串
Base58Check字符串是从版本/应用程序字节和payload
创建的,如下所示。
- 获取版本字节和
payload
字节,并将它们连接在一起(按字节顺序)。 - 取
SHA256(SHA256(步骤1的结果))
的前四个字节 - 将步骤1的结果和步骤2的结果连在一起(按字节顺序)。
- 处理步骤3的结果 - 一系列字节 - 作为单个大端序号,使用正常的数学步骤(bignumber division)和下面描述的base-58字母表转换为base-58。结果应该被标准化为没有任何前导零(字符'1')的base-58。
- 在base58中,值为零的前导字符'1'被保留用于表示整个前导零字节,就像它处于前导位置时一样,没有值作为base-58符号。必要时可以有一个或多个前导'1'来表示一个或多个前导零字节。计算步骤3结果中的前导零字节数(对于旧的比特币地址,至少有一个用于版本/应用程序字节;对于新地址,将永远不会有)。每个前导零字节在最终结果中应由其自己的字符'1'表示。
- 将步骤5中的1与步骤4 的结果连接起来。这是Base58Check的结果。
流程图如下所示:
image编码比特币地址
比特币地址的实现使用哈希的Base58Check编码:
- Pay-to-script-hash(p2sh):
payload
是:RIPEMD160(SHA256(redeemScript))
,其中redeemScript
是钱包知道如何消费的脚本; 版本号0x05
(这些地址以数字'3'
开头) - Pay-to-pubkey-hash (p2pkh):
payload
是RIPEMD160(SHA256(ECDSA_publicKey))
,其中ECDSA_publicKey
是钱包知道的私有密钥的公共密钥; 版本号0x00
(这些地址以数字'1'
开头)
在这两种情况下得到的散列总是恰好为20个字节。这些是大端字节(最重要的字节在前)。(注意那些限制前导0x00字节的数字编码实现,或者预先增加额外的0x00字节来表示符号 - 你的代码必须妥善处理这些情况,否则你可能会生成可以发送但不能花的看起来有效的地址 -导致硬币的永久损失。)
编码一个私钥
Base58Check编码也用于编码钱包导入格式中的ECDSA私钥。除了0x80用于版本/应用程序字节,并且payload
是32字节而不是20(比特币中的私钥是单个32字节无符号的大端整数)之外,它与比特币地址完全相同。 。对于与未压缩的公钥相关联的私钥,这种编码总是会产生一个以'5'开头的51个字符的字符串,或者更具体地说'5H','5J'或'5K'开头。
Base58符号图表
比特币中使用的Base58符号图特定于比特币项目,并不打算与比特币之外使用的任何其他Base58实现(排除的字符为:0,O,I和l)相同。
Value | Character | Value | Character | Value | Character | Value | Character |
---|---|---|---|---|---|---|---|
0 | 1 | 1 | 2 | 2 | 3 | 3 | 4 |
4 | 5 | 5 | 6 | 6 | 7 | 7 | 8 |
8 | 9 | 9 | A | 10 | B | 11 | C |
12 | D | 13 | E | 14 | F | 15 | G |
16 | H | 17 | J | 18 | K | 19 | L |
20 | M | 21 | N | 22 | P | 23 | Q |
24 | R | 25 | S | 26 | T | 27 | U |
28 | V | 29 | W | 30 | X | 31 | Y |
32 | Z | 33 | a | 34 | b | 35 | c |
36 | d | 37 | e | 38 | f | 39 | g |
40 | h | 41 | i | 42 | j | 43 | k |
44 | m | 45 | n | 46 | o | 47 | p |
48 | q | 49 | r | 50 | s | 51 | t |
52 | u | 49 | v | 54 | w | 55 | x |
56 | y | 57 | z |
编码address_byte_string的算法(由1-byte_version + hash_or_other_data + 4-byte_check_code组成)是
code_string = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
x = convert_bytes_to_big_integer(hash_result)
output_string = ""
while(x > 0)
{
(x, remainder) = divide(x, 58)
output_string.append(code_string[remainder])
}
repeat(number_of_leading_zero_bytes_in_hash)
{
output_string.append(code_string[0]);
}
output_string.reverse();
版本字节
以下是一些常见的版本字节:
版本号 | 前缀 | 使用 |
---|---|---|
0 | 1 | 比特币公钥哈希 |
5 | 3 | 比特币脚本哈希 |
21 | 4 | 压缩的比特币公钥 |
52 | M or N | Namecoin 公钥哈希 |
128 | 5 | 比特币私钥 |
111 | m or n | 比特币测试网络公钥哈希 |
196 | 2 | 比特币测试网络脚本哈希 |
地址前缀列表是一个更完整的列表。
网友评论