
比特币地址使用Base58Check编码方式,它是在Base58 binary-to-text编码的基础上修改而成的。
简单地说说,Base58Check编码的作用是将比特币中的字节数组编码转化为人类可键入的字符串。
背景
在最初版本的比特币客户端源代码里,解释了比特币使用base58编码的原因,源代码如下:
base58.h:
// Why base-58 instead of standard base-64 encoding? // - Don't want 0OIl characters that look the same in some fonts and // could be used to create visually identical looking account numbers. // - A string with non-alphanumeric characters is not as easily accepted as an account number. // - E-mail usually won't line-break if there's no punctuation to break at. // - Double clicking selects the whole number as one word if it's all alphanumeric.
对应的中文翻译供参考:
// 为什么使用base-58编码而不是标准的base-64编码?
// – 因为不希望在某些字体的情况下,0OIl字符看起来一样,以及不希望产生看起来相同的帐号。
// – 包含非字母数字字符的字符串不像帐号数字那样容易被接受。
// – 如果没有标点符号,那么在电子邮件中通常就不会自动换行。
// – 如果全部是字母数字,则双击会将整个数字选为一个单词。
Base58Check的特点
Base58Check具有以下特点:
- 可以负载任意大小的数据;
- 它由58种字母和数字符号组成,字母区分大小写,不使用数字0、大写字母O和I 以及小写字母l;
- 有1字节数据代表当前版本号/应用程序信息。目前此字段为 0x00(未来可能使用 0x05);
- 有4字节(32 位)的数据是基于SHA256的错误检查代码;此代码可用于自动检测并可能更正拼写错误;
- 有一个额外的步骤,保留数据中前导零。
创建Base58Check字符串
Base58Check字符串是基于版本/应用程序字段和有效负载信息之上创建的,如下所示。
- 取版本字段和有效负载信息,并将它们连接在一起(以字节为单位);
- 步骤1的结果进行两次SHA256变换,取结果的前4个字节;
- 将步骤1的结果和步骤2的结果连接在一起(以字节为单位);
- 将第3步的结果作为单个大端大数,使用正常的数学步骤(大数除法)并对应下文的base-58字母表,将其转换为base-58。结果应该进行标准化,使其没有任何base-58前导零(字符“1”);
- 前导字符“1”在base58中代表的值为0,当它在处于base-58的前导位置时,尽管值为0,但是它会被保留下来用于表示字符串的前导零字节。必要时可以有一个或多个前导“1”来表示一个或多个前导零字节。统计第3步骤结果中的前导零字节的数量(对于旧比特币地址,由于版本/应用程序字段的存在,总是至少存在一个前导零字节),然后在最终结果中,每个前导零字节应由字符“1”表示;
- 将步骤5中的“1”与步骤4的结果连接起来。就得到了Base58Check的结果。
对一个比特币地址进行编码
比特币地址是由ECDSA公钥哈希的Base58Check编码实现的:
- Pay-to-pubkey-hash (p2pkh):负载为RIPEMD160(SHA256(ECDSA_publicKey)),其中ECDSA_publicKey是钱包知道的与私钥对应的公钥;版本号0x00(这些地址以数字“1”开头)
生成的哈希值始终是20个字节,使用大端字节排序规则。请注意生成地址时,你的代码必须正确处理要裁剪的前导零,以及恰当地在最前面添加额外的“1”(参考上文的Base58Check规则),否则你可能会生成看起来有效但实际上无效的地址,这种地址可以接受比特币,收到的比特币之后不能被花费掉,这将导致你永远的丢失这些资金。
对私钥进行编码
Base58Check编码也可用于对钱包导入格式的ECDSA私钥进行编码。该私钥除了版本/应用程序字段为0x80,以及有效载荷是32字节而不是20字节(比特币的私钥是单个32字节的无符号大端整数)之外,它与比特币地址的形式完全相同。对于与未压缩公钥关联的私钥,Base58Check编码将始终生成长度为 51 个字符的字符串,这些字符串以“5”开头,或者更具体地说,以“5H”、“5J”或“5K”开头。
Base58符号图表
比特币中使用的Base58符号图表是专门比特币项目制定的,与比特币系统以外的Base58实现不同(比特币Base58删除的字符是:数字0、大写字母O和I 、小写字母l)。
编码address_byte_string的算法是:
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();
版本字段
以下是一些常见的版本字段:

其它参考资料
- 在线 Base58 解码器、编码器和验证器:http://lenschulwitz.com/base58
源代码
- BitcoinSV节点客户端C++代码库(解码和编码,不需要外部库):https://github.com/bitcoin-sv/bitcoin-sv/blob/master/src/base58.cpp