主页 > 怎么下载imtoken钱包 > 2020-09-17 比特币私钥
2020-09-17 比特币私钥
私钥
比特币的私钥(k)是一个随机数,可以是$1$到$(n - 1)$之间的任意数,其中$n$是常数$1.158 \times 10^{77}$比特币私钥格式转换器,略小于$2^ {256}$。
生成私钥本质上就是选择一个数字。 只要所选择的方法不可预测或不可重复,它就是密码安全的。
我们可以用不同的表示法来表示同一个私钥。
格式值
十六进制原始数据 (Raw) f97c89aaacf0cd2e47ddbacc97dae1f88bec49106ac37716c451dcdd008a4b62
WIF未压缩格式(WIF未压缩)5KiANv9EHEU4o9oLzZ6A7z4xJJ3uvfK2RLEubBtTz1fSwAbpJ2U
WIF压缩格式(WIF compressed) L5agPjZKceSTkhqZF2dmFptT5LFrbr6ZGPvP7u4A6dvhTrr71WZ9
WIF 是 Wallet Import Format 的缩写。 有两种格式:压缩和未压缩。 都是对Raw格式的私钥进行Base58Check编码后的结果。
在比特币系统中,大部分需要展示给用户的数据都是使用Base58Check编码的。 它可以压缩数据,提高可读性,避免歧义,并包含错误检查,可以有效防止转录过程中的数据错误。
Base58Check编码
Base64 编码使用 26 个小写字母、26 个大写字母、10 个数字和 2 个符号(+ 和 /)在基于文本的媒体(如电子邮件)中传输二进制数据。
Base58是Base64编码格式的一个子集,舍弃了特定字体中一些容易误读和混淆的字符,不使用0(数字0)、O(大写字母o)、l(小写字母L)、I (大写 i)与 + 和 / 一起,是比特币系统中使用的唯一编码。
Base58Check在编码过程中加入校验和,最后使用Base58,是一种可逆编码。 对于要编码的数据负载:
在payload前加上版本前缀Version得到S1
对S1做两次SHA256哈希运算得到S2,取S2的前4个字节作为校验和 Checksum
在 S1 后附加 Checksum 得到 S3
在S3上做Base58编码,得到结果
对于不同类型的数据比特币私钥格式转换器,在做Base58Check编码时会加上不同的版本前缀,从而产生不同的结果,便于识别。
Base58Check 后类型版本前缀的值(十六进制)前缀
P2PKH地址001
P2SH地址053
测试网(testnet)地址6Fm或n
WIF格式的私钥805,K或L
根据BIP-38标准加密的私钥01426P
根据BIP-32标准定义的扩展公钥0488B21Expub
世界互联网论坛
为了方便用户导入私钥,定义了WIF,分为未压缩和压缩两种。
WIF是Base58Check编码的结果。 根据上表,编码时使用的WIF版本前缀为0x80。
对于Raw格式的私钥f97c89aaacf0cd2e47ddbacc97dae1f88bec49106ac37716c451dcdd008a4b62,计算其WIF解压格式:
// 私钥本身就是payloadf97c89aaacf0cd2e47ddbacc97dae1f88bec49106ac37716c451dcdd008a4b62// 下面是Base58Check 定义的过程// 给payload 添加版本前缀0x80,得到S180 f97c89aaacf0cd2e47ddbacc97dae1f88bec49106ac37716c451dcdd008a4b62// 对S1 做两次SHA256,得到S2701ccdd192515bf36a241b9fca879d7915a458cfb36ebcf2c8db1d796dc63b4a// 取S2 的前4 字节,得到Checksum701ccdd1 // S3 = S1 + Checksum80 f97c89aaacf0cd2e47ddbacc97dae1f88bec49106ac37716c451dcdd008a4b62 701ccdd1 // WIF_uncompressed = Base58 (S3),结果以5开头
稍作改动,在私钥后加一个压缩标志,计算结果为WIF压缩格式。
// 在私钥后添加压缩标志后缀0x01,得到payloadf97c89aaacf0cd2e47ddbacc97dae1f88bec49106ac37716c451dcdd008a4b62 01// 下面是Base58Check 定义的过程// 给payload 添加版本前缀0x80,得到S180 f97c89aaacf0cd2e47ddbacc97dae1f88bec49106ac37716c451dcdd008a4b62 01// 对S1 做两次SHA256,得到S214372b9cd0d344b679ac30ab70000c245c3c7888907449bccd0caf830a84c2ed// 取S2 的前4 字节,得到Checksum14372b9c// S3 = S1 + Checksum80 f97c89aaacf0cd2e47ddbacc97dae1f88bec49106ac37716c451dcdd008a4b62 01 14372b9c// WIF_uncompressed = Base58 (S3),结果以K 或L 开头L5agPjZKceSTkhqZF2dmFptT5LFrbr6ZGPvP7u4A6dvhTrr71WZ9
WIF 压缩格式和未压缩格式都使用相同的版本前缀,唯一的区别是是否在私钥后添加压缩标志后缀。
您可以使用以下工具来体验转换过程。
未压缩WIF和Raw格式私钥的转换工具
十六进制哈希工具
十六进制Base58编码工具
椭圆曲线密码学(ECC,Elliptic Curve Cryptography)
要了解比特币公钥的计算细节,需要了解ECC的一些背景知识。
ECC是一种基于椭圆曲线上离散对数数学问题的非对称加密算法。
$y^2 = x^3 - x + 1$定义了一条椭圆曲线,函数图像如下。
比特币使用的椭圆曲线是
$$y^2 = x^3 + 7 \pmod p$$
该椭圆曲线由 Secp256k1 标准定义,其中
mod 是模运算(取余),$1 = 5 \pmod 2$
p 是固定值 $2^{256} - 2^{32} - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1$,这是一个非常大的素数
由于方程两端的取模运算,这条曲线的函数图像不是连续的,而是二维空间中的一系列散点。
若$p = 17$,其函数图如下。
你可以将 Secp256k1 的函数图像想象成一个非常大的网格上的一系列更复杂的散点。
对于椭圆曲线上的两个点p1和p2,定义$p = p1 + p2$为椭圆曲线上的点的加法运算。
过点p1、p2作直线与椭圆曲线交点q
将点q绕X轴对称翻转得到点p
如果 p1 和 p2 是同一点,则通过 p1 和 p2 的直线成为通过该点的椭圆曲线的切线。 使用此工具,您可以获得更加直观和直观的体验。
乘法的定义可以从加法扩展而来,其中 k 是一个整数。
$$k \times p = \underbrace{p + p + ... + p}_{k}$$
下图是从椭圆曲线上的一点G计算2G、4G、8G的操作。
注意,为了直观理解,图中的椭圆曲线都是连续的。 比特币使用的Secp256k1曲线图不是连续的,但是它们的数学原理是一样的。 *
公钥
比特币的公钥(K)是Secp256k1定义的椭圆曲线上的一个点。
$$K = k \times G$$
其中,k为私钥(整数),G为椭圆曲线上的不动点,该点由Secp256k1标准定义,其坐标(十六进制)为
Gx = 79BE667E F9DCBBAC 55A06295 CE870B07 029BFCDB 2DCE28D9 59F2815B 16F81798G.y = 483ADA77 26A3C465 5DA4FBFC 0E1108A8 FD17B448 A685B F419 4F81B0D
比特币的私钥(k)和公钥(K)的关系是固定的,数学原理保证计算过程是单向不可逆的,可以很容易的从私钥计算出对应的公钥,反之亦然。 .
在刚才的例子中,私钥是f97c89aaacf0cd2e47ddbacc97dae1f88bec49106ac37716c451dcdd008a4b62,它对应的公钥是
x = e46dcd7991e5a4bd642739249b0158312e1aee56a60fd1bf622172ffe65bd789y = 97693d32c540ac253de7a3dc73f7e4ba7b38d2dc1ecc8e07920b496fb107d6b2
公钥也有两种表示形式,压缩的和未压缩的。
在公钥坐标前加上前缀0x04,可以直接得到解压后的公钥。
04 e46dcd7991e5a4bd642739249b0158312e1aee56a60fd1bf622172ffe65bd789 97693d32c540ac253de7a3dc73f7e4ba7b38d2dc1ecc8e07920b496fb107d6b2
为了以未压缩格式表示公钥,需要 65 个字节,1 个字节前缀,32 个字节 X 坐标,32 个字节 Y 坐标。
根据Secp256k1曲线的特点,如果知道公钥的X坐标值和Y坐标值的奇偶性,就可以直接计算出Y坐标值。 以压缩格式定义公钥:
如果Y坐标的值为偶数,则在X坐标前加上前缀0x02
如果Y坐标的值为奇数,则在X坐标前加前缀0x03
![]()
得到压缩格式的公钥为
02 e46dcd7991e5a4bd642739249b0158312e1aee56a60fd1bf622172ffe65bd789
为了以压缩格式表示公钥,需要 33 个字节,1 个字节用于前缀,32 个字节用于 X 坐标。
大家可以参考下面的代码自己试试。
package mainimport("encoding/hex" "fmt" "github.com/decred/dcrd/dcrec/secp256k1") func main() { privateKeyBytes, _ := hex. DecodeString("f97c89aaacf0cd2e47ddbacc97dae1f88bec49106ac37716c451dcdd008a4b62") _, publicKey := secp256k1. PrivKeyFromBytes(privateKeyBytes) fmt。 Println("pk.x = " + hex.EncodeToString(publicKey.X.Bytes())) fmt. Println("pk.y = " + hex.EncodeToString(publicKey.Y.Bytes())) fmt. Println("未压缩公钥 = " + hex.EncodeToString(publicKey.SerializeUncompressed())) fmt.
Println("compressed public key = " + hex.EncodeToString(publicKey.SerializeCompressed()))} // 输出 // pk。 x = e46dcd7991e5a4bd642739249b0158312e1aee56a60fd1bf622172ffe65bd789//pk。 y = 97693d32c540ac253de7a3dc73f7e4ba7b38d2dc1ecc8e07920b496fb107d6b2// uncompressed public key = 04e46dcd7991e5a4bd642739249b0158312e1aee56a60fd1bf622172ffe65bd78997693d32c540ac253de7a3dc73f7e4ba7b38d2dc1ecc8e07920b496fb107d6b2// compressed public key = 02e46dcd7991e5a4bd642739249b0158312e1aee56a60fd1bf622172ffe65bd789
总结
比特币的私钥本质上是一个数字
如果选择私钥的过程不可预测或不可重复(随机),则私钥在密码学上是安全的
私钥可以用WIF压缩格式或WIF未压缩格式表示,WIF压缩格式的私钥前缀为K或L,WIF未压缩格式的私钥前缀为5
WIF格式使用Base58Check编码,是一种可逆编码,包括版本前缀、数据块和校验和三部分,便于识别和转录
ECC是一种基于椭圆曲线数学问题的非对称加密算法。 比特币使用由 Secp256k1 标准定义的特殊椭圆曲线。 它的函数图像是一堆复杂的散点
比特币的公钥本质上是Secp256k1曲线上的一个点,由其对应的私钥计算得出
椭圆曲线的数学特性保证了从比特币私钥计算出对应的公钥是一种单向运算,不能从公钥计算出对应的私钥
公钥可以用压缩和未压缩的格式表示。 压缩格式的公钥前缀为0x02或0x03,未压缩格式的公钥前缀为0x04。
没有“压缩私钥”和“压缩公钥”之分,“压缩”只是为了表示,而不是私钥和公钥本身
您可能已经注意到,当公钥以压缩格式表示时,存储空间有效减少,但WIF压缩格式和未压缩格式在长度上没有明显差异。
你为什么要这样做? 在下一篇文章中说。