《精通比特币》解读 第四章 - 密钥,地址

这一章主要讲了私钥,公钥,以及比特币地址

私钥、公钥和比特币地址之间的关系如下图所:
这里写图片描述

私钥
私钥是什么:私钥是一个随机产生的256位bit的数字
私钥如何产生:生成一个比特币私钥在本质上与“在1 到2^256之间选一个数字”无异。只要选取的结果是不可预测或不可重复的,那么选取数字的具体方法并不重要。你可以用硬币、铅笔和纸来随机生成你的私钥:掷硬币256次,用纸和笔记录正反面并转换为0和1,随机得到的256位二进制数字可作为比特币钱包的私钥。比特币软件使用操作系统底层的随机数生成器来产生256位的熵。
私钥的的作用:私钥可进一步生成公钥。私钥控制着一个对应比特币地址的所有资金。
私钥空间大小:2^256,约为1.158 * 10^77
使用比特币核心客户端生成一个新的密钥:
可使用 getnewaddress 命令。出于安全考虑,命令运行后只 显示生成的公钥,而不显示私钥。如果要bitcoind显示私钥,可以使用 dumpprivkey 命令。

$ bitcoin-cli getnewaddress
1J7mdg5rbQyUHENYdx39WVWK7fsLpEoXZy
$ bitcoin-cli dumpprivkey 1J7mdg5rbQyUHENYdx39WVWK7fsL
KxFC1jmwwCoACiCAWZ3eXa96mBM6tb3TYzGmf6YwgdGWZgawvrtJ

公钥

公钥是什么:公钥是通过私钥生成的一个由数字和字母组成的字符串。
通过椭圆曲线乘法可以从私钥计算得到公钥,这是不可逆转的过程:K = k * G 。其中k是私钥,G是一个常数点,称为生成点,而K是所得公钥。其反向运算,被称为“寻找离散对数”——已知公钥K来求出私钥k——是非常困难的,就像去试验所有可能的k值,即暴力搜索。

比特币使用了secp256k1标准所定义的一种特殊的椭圆曲线和一系列数学常数。

生成公钥:
以一个随机生成的私钥k为起点,我们将其与曲线上预定的生成点G相乘以获得曲线上的另一点,也就是相应的公钥 K。生成点是secp256k1标准的一部分,比特币密钥的生成点都是相同的。
{K = k * G}
其中k是私钥,G是生成点,在该曲线上所得的点K是公钥。因为所有比特币用户的生成点是相同的,一个私钥k乘以G将得到相同的公钥K。
因为其中的数学运算是单向的,所以私钥可以转换为公钥,但公钥不能转换回私钥。

比特币地址

比特币地址是什么:比特币地址是通过公钥生成的一个由数字和字母组成的字符串,以数字“1”开头。
如:1J7mdg5rbQyUHENYdx39WVWK7fsLpEoXZy
比特币地址可以代表一对公钥/私钥对的所有者
如何生成比特币地址:比特币地址可由公钥经过单向的加密哈希算法得到。算法是Secure Hash Algorithm (SHA)和the RACE Integ rity Primitives Evaluation Message Digest (RIPEMD),具体地说是SHA256和RIPEMD160。
以公钥 K 为输入,计算其SHA256哈希值,并以此结果计算RIPEMD160 哈希值,得到一个长度为160位(20字节)的数字:
A = RIPEMD160(SHA256(K))
公式中,K是公钥,A是生成的比特币地址。
通常用户见到的比特币地址是经过“Base58Check”编码的,这种编码使用了58个字符(一种Base58数字系统)和校验码,提高了可读性、避免歧义并有效防止了在地址转录和输入中产生 的错误。
下图描述了如何从公钥生成比特币地址:
这里写图片描述

Base58和Base58Check编码

Base58: Base58不含Base64中的0(数字0)、O(大写字母o)、l(小写字母 L)、I(大写字母i),以及“+”和“/”两个字符
Base58Check: 是一种常用在比特币中的Base58编码格式,带有内置的检查错误的编码(校验和),以防止书写错误和转录错误。
作用:使用Base58check编码时,解码软件会计算数据的校验和并和编码中自带的校验和进行对比。二者不匹配则表明有错误产生,那么这个Base58Check的数据就是无效的。一个错误比特币地址就不会被钱包软件认为是有效的地址,否则这种错误会造成资金的丢失。

Base58check编码过程:
1. 首先我们要对数据添加一个称作“版本字节”的前缀,这个前缀用来识别编码的数据的类型。
2. 接下来,计算“双哈希”校验和,即对之前的结果(前缀和数据)运行两次SHA256哈希算法:
checksum = SHA256(SHA256(prefix+data))
在产生的长32个字节的哈希值(两次哈希运算)中,我们只取前4个字节。这4个字节就作为检验错误的代码或者校验和。校验码会添加到数据之后。
3. 结果由三部分组成:前缀、数据和校验和。然后将这个结果采用之前描述的Base58进行编码。

下图描述了Base58Check编码的过程:
这里写图片描述

在比特币中,大多数需要向用户展示的数据都使用Base58Check编码,可以实现数据压缩,易读而且有错误检验。
Base58Check编码中的版本前缀是用来创造易于辨别的格式,版本前缀编码后是一些特殊的字符,这些字符使用户可以轻松识别被编码的数据的类型以及如何使用它们。展示了一些版本前缀和他们对应的Base58编码后的字符:
这里写图片描述

回顾比特币地址产生的完整过程,从私钥、到公钥(椭圆曲线上某个点)、再到两次哈希的地址,到最终的Base58Check编码。下面的C++代码完整详细的展示了从私钥到Base58Check编码的比特币地址的步骤。代码中使用“3.3 其他客户端、资料库、工具包 ”一节中介绍的libbitcoin library来实现某些辅助功能:

#include <bitcoin/bitcoin.hpp>
int main()
{
// Private secret key.
bc::ec_secret secret;
bool success = bc::decode_base16(secret,
"038109007313a5807b2eccc082c8c3fbb988a973cacf1a7df9ce725c31b14776");
assert(success);
// Get public key.
bc::ec_point public_key = bc::secret_to_public_key(secret);
std::cout << "Public key: " << bc::encode_hex(public_key) << std::endl;
// Create Bitcoin address.
// Normally you can use:
// bc::payment_address payaddr;
// bc::set_public_key(payaddr, public_key);
// const std::string address = payaddr.encoded();
// Compute hash of public key for P2PKH address.
const bc::short_hash hash = bc::bitcoin_short_hash(public_key);
bc::data_chunk unencoded_address;
// Reserve 25 bytes
// [ version:1 ]
// [ hash:20 ]
// [ checksum:4 ]
unencoded_address.reserve(25);
// Version byte, 0 is normal BTC address (P2PKH).
unencoded_address.push_back(0);
// Hash data
bc::extend_data(unencoded_address, hash);
// Checksum is computed by hashing data, and adding 4 bytes from hash.
bc::append_checksum(unencoded_address);
// Finally we must encode the result in Bitcoin's base58 encoding.
assert(unencoded_address.size() == 25);
const std::string address = bc::encode_base58(unencoded_address);
std::cout << "Address: " << address << std::endl;
return 0;
}

编译并运行addr代码:

# Compile the addr.cpp code
$ g++ -o addr addr.cpp $(pkg-config --cflags --libs libbitcoin)
# Run the addr executable
$ ./addr
Public key: 0202a406624211f2abbdc68da3df929f938c3399dd79fac1b51b0e4ad1d26a47aa
Address: 1PRTTaJesdNovgne6Ehcdu1fpEdX7913CK

密钥的格式
公钥和私钥的都可以有多种格式。一个密钥被不同的格式编码后,虽然结果看起来可能不同,但都是由同一个数字编码而来。这些不同的编码格式主要是用来方便人们无误地使用和识别密钥。

私钥的格式:
私钥可以以许多不同的格式表示,所有这些都对应于相同的256位的数字。
下表展示了私钥的三种常见格式:
这里写图片描述
不同的格式用在不同的场景下。十六进制和原始的二进制格式用在软件的内部,很少展示给用户看。WIF格式用在钱包之间密钥的输入和输出,也用于代表私钥的二维码(条形码)。
下表展示了三种格式生成的私钥:
这里写图片描述

从Base58Check解码
使用Bitcoin Explorer命令解码Base58Check格式
1.使用base58check-decode命令解码未压缩的密钥:

$ bx base58check-decode 5J3mBbAH58CpQ3Y5RNJpUKPE62SQ5tfcvU2JpbnkeyhfsYB1Jcn
wrapper
{
checksum 4286807748
payload 1e99423a4ed27608a15a2616a2b0e9e52ced330ac530edcc32c8ffc6a526aedd
version 128
}

结果包含密钥作为有效载荷,WIF版本前缀128和校验和。

2.使用base58check-decode命令解码压缩的密钥:

$ bx base58check-decode KxFC1jmwwCoACiCAWZ3eXa96mBM6tb3TYzGmf6YwgdGWZgawvrtJ
wrapper
{
checksum 2339607926
payload 1e99423a4ed27608a15a2616a2b0e9e52ced330ac530edcc32c8ffc6a526aedd01
version 128
}

请注意,压缩密钥的“有效负载”附加了后缀01,表示导出的公钥要压缩。

将十六进制密钥转换为Base58Check编码
使用Bitcoin Explorer的base58check-encode命令

bx base58check-encode 1e99423a4ed27608a15a2616a2b0e9e52ced330ac530edcc32c8ffc6a526aedd --version 128
5J3mBbAH58CpQ3Y5RNJpUKPE62SQ5tfcvU2JpbnkeyhfsYB1Jcn

将十六进制密钥(压缩格式密钥)转换为Base58Check编码
需在十六进制私钥的后面添加后缀01,然后使用跟上面一样的方法:

$ bx base58check-encode 1e99423a4ed27608a15a2616a2b0e9e52ced330ac530edcc32c8ffc6a526aedd01 --version 128
KxFC1jmwwCoACiCAWZ3eXa96mBM6tb3TYzGmf6YwgdGWZgawvrtJ

生成的WIF压缩格式的私钥以字母“K”开头,用以表明被编码的私钥有一个后缀“01”,且该私钥只能被用于生成压缩格式 的公钥(参见“压缩格式公钥”一节)。

公钥的格式
公钥也可以用多种不同格式来表示,通常分为非压缩格式或压缩格式公钥这两种形式。
我们从前文可知,公钥是在椭圆曲线上的一个点,由一对坐标(x,y)组成。公钥通常表示为前缀04紧接着两个256比特的数字。其中一个256比特数字是公钥的x坐标,另一个256比特数字是y坐标。前缀04是用来区分非压缩格式公钥, 压缩格式公钥是以02或者03开头。
非压缩格式公钥:
下面是由前文中的私钥所生成的公钥,其坐标x和y如下:
x = F028892BAD7ED57D2FB57BF33081D5CFCF6F9ED3D3D7F159C2E2FFF579DC341A
y = 07CF33DA18BD734C600B96A72BBC4749D5141C90EC8AC328AE52DDFE2E505BDB

下面是同样的公钥以520比特的数字(130个十六进制数字)来表达。这个520比特的数字以前缀04开头,紧接着是x及y 坐标,组成格式为04 x y:
K = 04F028892BAD7ED57D2FB57BF33081D5CFCF6F9ED3D3D7F159C2E2FFF579DC341A07CF33DA18BD734C600B96A72BBC4749D5141C90EC8AC328AE 52DDFE2E505BDB

压缩格式公钥:
未压缩格式公钥使用04作为前缀,而压缩格式公钥是以02或03作为前缀。需要这两种不同前缀的原因是:
因为椭圆曲线加密的公式的左边是y2 ,也就是说y的解是来自于一个平方根,可能是正值也可能是负值。更形象地说,y坐标可能在x坐标轴的上面或者下面。 当我们在素数p阶的有限域上使用二进制算术计算椭圆曲线的时候,y坐标可能是奇数或者偶数,分别对应前面所讲的y值的正负符号。因此,为了区分y坐标的两种可能值,我们在生成压缩格式公钥时,如果y是偶数,则使用02作为前缀;如果y是奇数,则使用03作为前缀。这样就可以根据公钥中给定的x值,正确推导出对应的y坐标,从而将公钥解压缩为在椭圆曲线上的完整的点坐标。
下图阐释了公钥压缩:
这里写图片描述

下面是前述章节所生成的公钥,使用了264比特(66个十六进制数字)的压缩格式公钥格式,其中前缀03表示y坐标是一个奇数:
K = 03F028892BAD7ED57D2FB57BF33081D5CFCF6F9ED3D3D7F159C2E2FFF579DC341A

压缩格式私钥:
实际上“压缩格式私钥”是一种名称上的误导,私钥是非压缩的,也不能被压缩。“压缩的私钥”实际上只是表示“用于生成压缩格式公钥的私钥”,而“非压缩格式私钥”用来表明“用于生成非压缩格式公钥的私钥”。
下图展示相同的私钥,不同的格式:
这里写图片描述

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yzpbright/article/details/80342918
想对作者说点什么? 我来说一句

精通比特币

2018年02月23日 32.08MB 下载

精通比特币中文版

2016年04月05日 5.24MB 下载

没有更多推荐了,返回首页

不良信息举报

《精通比特币》解读 第四章 - 密钥,地址

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭