比特币地址是一串数字和字母,可以分享给任何想给你比特币的人。公钥(也是由数字和字母组成的字符串)生成的比特币地址以数字“1”开头。
在交易中,比特币地址通常作为收款方出现。如果把一笔比特币交易比作一张支票,比特币地址就是收款方,这也是我们要写在收款方一栏的内容。支票的收款人可以是银行账户、公司、机构,甚至是现金支票。支票不需要指定具体的账户,而是使用一个通用名称作为收款人,这使其成为一种相当灵活的支付工具。同样,比特币地址的使用使得比特币交易变得灵活。比特币地址可以代表一对公钥和私钥的所有者,或者其他东西,比如支付脚本。现在,让我们看一个从公钥生成比特币地址的简单例子。
比特币地址可以通过单向加密哈希算法从公钥中获得。哈希算法是一个单向函数,它接收任意长度的输入来生成指纹摘要。加密函数在比特币中应用广泛:比特币地址、脚本地址、挖掘中的工作量证明算法。安全哈希算法(SHA)和竞争完整性原语评估消息摘要(ripemd)用于根据公钥(尤其是SHA256和RIPEMD160)生成比特币地址。
以公钥K为输入,计算其SHA256哈希值,并基于此结果计算RIPEMD160哈希值,得到一个长度为160位(20字节)的数:
A=RIPEMD160(SHA256(K))
公式中,K是公钥,A是生成的比特币地址。
比特币地址不同于公钥。比特币地址是由公钥的单向哈希函数生成的。
用户通常看到的比特币地址是用‘base 58 check’编码的。这种编码使用58个字符(Base58数字系统)和校验码,提高了可读性,避免了歧义,并有效地防止了地址转录和输入中的错误。base 58校验码还用于比特币的其他地方,如比特币地址、私钥、加密密钥、脚本哈希等,提高输入的可读性和准确性。在下一节中,我们将详细解释Base58Check的编码机制,以及它产生的结果。下图描述了如何从公钥生成比特币地址。
4.2.1Base58和Base58校验码
为了更简洁、更方便地表达一长串数字,许多计算机系统会使用由数字和字母组成的比十进制大的记数法。例如,传统的十进制计数系统使用从0到9的十个数字,而十六进制系统使用六个额外的字母A-F,同样一个数,它的十六进制表示会比十进制表示短。此外,Base64使用26个小写字母,
26个大写字母、10个数字和两个符号(如“”和“/”)用于在基于文本的介质(如电子邮件)中传输二进制数据。Base64通常用于对邮件中的附件进行编码。Base58是一种基于文本的二进制编码格式,用于比特币和其他加密货币。这种编码格式不仅实现了数据压缩,保持了易读性,还具有错误诊断的功能。Base58是Base64编码模式的子集。它还使用了大小写字母和10个数字,但丢弃了一些在某些字体中容易发音错误和混淆的字符。具体来说,Base58不包含
0(数字0)、O(大写字母O)、L(小写字母L)、I(大写字母I)以及Base64中的“”和“/”字符。简而言之,Base58由大小写字母和数字组成,不包括(0,o,l,I)。例4-1比特币的Base58字母表123456789 abcdefghjklmnpqrstuvwxyzabcdefghijkmnopqrsttuwxyz
Base58Check是比特币常用的Base58编码格式,增加了一个错误校验码,用于检查数据转录中的错误。校验码为4字节长,添加到要编码的数据中。校验码是从要编码的数据的哈希值中获得的,因此可以用来检测和避免转录和输入中的错误。使用Base58check编码格式时,编码软件会计算原始数据的校验码,并与结果数据中的校验码进行比较。两者不匹配说明有错误,所以Base58Check格式的数据无效。比如一个错误的比特币地址不会被钱包认为是有效地址,否则这个错误会造成资金损失。为了使用Base58Check编码格式对数据(数字)进行编码,我们首先为数据添加一个名为“版本字节”的前缀,用于指定要编码的数据类型。比如比特币地址的前缀是0(十六进制0x00),而私钥的前缀是128(十六进制0x80)。下表列出了前缀的一些常见版本。
接下来,我们计算“双重哈希”校验码,这意味着我们必须对之前的结果(前缀和数据)运行两次SHA256哈希算法:
校验和=sha256 (sha256(前缀数据))在生成的32个字节的哈希值中(两次哈希运算),我们只取前4个字节。这4个字节用作校验码。将校验码添加到数据中。
结果由三部分组成:前缀、数据和校验码。这个结果由前面描述的Base58字母表编码。下图描述了Base58Check的编码过程。
Base58Check编码:一个版本,用Base58格式验证过的格式,可以清晰的对比特币数据进行编码。在比特币中,大部分需要显示给用户的数据都是用Base58Check编码的,可以实现数据压缩,方便读取和错误检查。Base58Check编码中的版本前缀是数据的格式容易区分,编码后的数据头包含确定的属性。这些属性使用户很容易知道编码数据的类型以及如何使用它们。例如,我们可以看到它们之间的区别。Base58Check编码的比特币地址以1开头,Base58Check编码的私钥WIF以5开头。表4-1显示了一些版本前缀及其对应的Base58格式。
表4-1 Base58校验版本前缀和编码结果类型版本前缀(十六进制)Base58格式比特币地址0x001
付费脚本哈希地址0x053
比特币Testnet地址0x6Fm或n私钥WIF0x805,K或L BIP38加密私钥0x01426P BIP32扩展公钥0x0488B21Expub
我们回顾一下比特币地址生成的全过程,从私钥,到公钥(椭圆曲线上的一点),再到经过两次哈希的地址,最后生成Base58Check格式的比特币地址。前面的C代码完整详细地展示了从私钥到Base58Check编码的比特币地址的步骤。代码使用了‘其他客户端、库、工具包’中介绍的libbitcoinlibrary来实现一些辅助功能。
从私钥生成以Base58Check格式编码的比特币地址。
#包括
int main() {
//私有密钥。
BC:EC _ secret secret=BC:decode _ hash(
038109007313 a 5807 b 2 ECC c 082 c8 c 3 fbb 988 a 973 CAC f1 a 7 df 9 ce 725 C3 1b 14776’);
//获取公钥。bc:ec_point public_key=
BC:secret _ to _ public _ key(secret);
std:cout \’公钥:\’ bc:encode_hex(public_key)
STD:endl;
//创建比特币地址。
//通常可以使用:
//BC:payment _ address payaddr;
//bc:set_public_key(payaddr,public _ key);
//const STD:string address=pay addr . encoded();
//计算P2PKH地址的公钥哈希。const bc:short_hash hash=
BC:bit coin _ short _ hash(public _ key);
BC:data _ chunk uncoded _ address;//保留25个字节
//[版本:1 ]
//[哈希:20 ]
//[checksum:4]uncoded _ address . reserve(25);
//版本字节,0是正常的BTC地址(P2PKH)。uncoded _ address . push _ back(0);
//哈希数据bc:extend_data(未编码地址,哈希);
//校验和是通过对数据进行哈希运算,并从哈希中添加四个字节来计算的. bc:追加_校验和(未编码地址);
//最后我们必须在比特币的base58编码维护中对结果进行编码(未编码_地址。size()==25);
const STD:string address=BC:encode _ base 58(未编码_地址);
\’ STD:cout \’ Address:\’ Address STD:endl;返回0;
}
正如编译并运行地址代码中展示的,由于代码使用预定义的私钥,所以每次运行都会产生相同的比特币地址。
编译并运行地址代码
#编译addr.cpp代码
$ g-o地址地址。CPP $(pkg-config-cflags-libs库比特币)
#运行地址可执行文件
$ ./addr公钥:
0202 a 406624211 F2 abb DC 68 da 3d f 929 f 938 c 3399 DD 79 fac 1b 51 b 0 E4 ad 1d 26a 47 aa
地址:1 pttajesdnovgne 6 ehc du 1 fpedx 7913 CK