这篇文章一起学习下比特币密钥和地址的由来。
本人知识有限,如有错误和疏漏,请务必指正,多谢。
比特币秘钥
比特币的签名算法是 ECDSA (Elliptic Curve Digital Signature Algorithm), 即椭圆曲线签名算法,是数字签名算法一种,基于椭圆曲线离散对数问题的难解性。
大家平时经常接触到的可能是 RSA 算法,是基于极大整数因数分解的难解性。
这两种算法的秘钥生成、签名流程、签名的形式都是不同的。
1. 私钥如何产生
在 HD 钱包里,私钥分两种,一种是主私钥,其他的姑且都叫做其他私钥。主私钥和其他私钥的产生方式不同,具体的在 比特币-分层确定性钱包 里已经介绍,这里不再多说。
私钥的 HEX 格式是 32 个字节,这是私钥的其中一种格式,还有一些其他的格式,比如: Hex-compressed、WIF、WIF-compressed,这个在后面会说。
2. 公钥如何产生
公钥的产生,要用到特定的椭圆曲线。比特币和以太坊使用的都是 secp256k1 (每种椭圆曲线的特定参数是不一样的),曲线是这个样子:
曲线的参数 G 是固定的,是曲线上的一个点,公钥(K)是将私钥(k)与 G 点相乘得到的曲线上的另一点。\(K = k * G\), 公钥 K,被定义为一个点,\(K = (x, y)\)
生成点 G 的倍数 kG,也就是将 G 相加 k 次,在椭圆曲线中,点的相加等同于从该点画切线找到与曲线相交的另一点,然后映射到 x 轴。
从私钥得到公钥很容易,但是从公钥反推到私钥,就非常得难。
3. 公私钥的格式
公私钥都有很多格式,最主要的是他们分为压缩和非压缩格式。
先说公钥:
公钥是在椭圆曲线上的一个点,由一对坐标(x,y)组成。公钥通常表示为前缀04紧接着两个256比特的数字。其中一个256比特数字是公钥的x坐标,另一个256比特数字是y坐标。前缀04是用来区分非压缩格式公钥,压缩格式公钥是以02或者03开头。
比如这个公钥:
1
2
x = F028892BAD7ED57D2FB57BF33081D5CFCF6F9ED3D3D7F159C2E2FFF579DC341A
y = 07CF33DA18BD734C600B96A72BBC4749D5141C90EC8AC328AE52DDFE2E505BDB
非压缩格式,就是 04 + x + y:
1
04F028892BAD7ED57D2FB57BF33081D5CFCF6F9ED3D3D7F159C2E2FFF579DC341A07CF33DA18BD734C600B96A72BBC4749D5141C90EC8AC328AE52DDFE2E505BDB
因为我们知道,一个公钥是一个椭圆曲线上的点(x, y),而椭圆曲线实际是一个数学方程,曲线上的点实际是该方程的一个解。因此,如果我们知道了公钥的 x 坐标,就可以通过解方程 y2 mod p = (x3 + 7) mod p 得到 y 坐标。这种方案可以让我们只存储公钥的 x 坐标,略去 y 坐标。而因为同一个 x 可能对应与两个 y,直观来看,就是 y 可能位于 x 轴的上面或者下面,y 就是有正负的。在素数p阶的有限域上使用二进制算术计算椭圆曲线的时候,y 坐标可能是奇数或者偶数,分别对应前面所讲的 y 值的正负符号。为了区分 y 坐标的两种可能值,我们在生成压缩格式公钥时,如果 y 是偶数,则使用 02 作为前缀;如果 y 是奇数,则使用 03 作为前缀。
所以上面的例子中,因为 y 为奇数,压缩公钥就是 03 + x:
1
03F028892BAD7ED57D2FB57BF33081D5CFCF6F9ED3D3D7F159C2E2FFF579DC341A
为什么需要压缩格式的公钥?
因为当交易的发生的时候,比特币所有者必须提供签名和公钥信息,这些信息会记录到区块的每笔交易内,因此使用压缩的公钥可以减少比特币交易的字节数,从而可以节省那些运行区块链数据库的节点磁盘空间。
再说下私钥:
压缩格式私钥,指的不是私钥本身压缩,而是说,这把私钥只能用来导出压缩格式的公钥。因为如前面所说,压缩格式的公钥和非压缩格式的公钥,长度是不同的,这会导致比特币地址不同,所以当使用压缩格式的公钥的时候,导出的私钥,就一定要标明是压缩格式的。
其实压缩格式的私钥,比非压缩的私钥,还要在结尾多出一个字节(01),用来表示这个私钥是压缩格式,所以压缩格式的私钥,其实有点误导的意思。
Base58Check 编码的 WIF 格式(后面会讲)的私钥,非压缩以5开头,压缩以K/L开头。
同样的私钥,不同的格式:
4. 比特币地址
从公钥到比特币地址的生成过程,看下面这个图就很清晰了:
在比特币中,大多数需要向用户展示的数据都使用 Base58Check 编码(这种编码后的格式就是 WIF,Wallet Import Format),可以实现数据压缩,易读而且有错误检验。Base58Check 编码中的版本前缀是数据的格式易于辨别,编码之后的数据头包含了明确的属性。这些属性使用户可以轻松明确被编码的数据的类型以及如何使用它们。
上图中的 Base58check 的编码的详细流程,可以看下面这个图:
Base58Check 版本前缀和编码后的结果,可以看下面这张表:
如表,比特币地址是 1 开头,私钥是 5/K/L 开头。
就这样了,有什么问题,欢迎留言。
参考链接: