比特币协议 Secp256k1
Secp256k1 即 Standards for Efficient Cryptography Parameters,是指比特币中使用的ECDSA(椭圆曲线数字签名算法)曲线的参数,并且在高效密码学标准中进行了定义。可参照 http://www.secg.org/sec2-v2.pdf。
Secp256k1 基于Fp有限域上的椭圆曲线,由于其特殊构造的特殊性,其优化后的实现比其他曲线性能上可以特高30%。
比特币系统选用的 secp256k1 ,椭圆曲线方程:
y2 = x3+7。
椭圆曲线方程参数:
- p = 0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F = 2256 − 232− 29 − 28− 27 − 26 − 24− 1
- a = 0, b = 7
- G=(0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798,0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8)
- n = 0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141
- h = 01
其中,p 和 n 均是 256bit 的大数,其值接近 2256,有效地保证了密码破解的难度。
1. 私钥
私钥是一个 256 位的随机数,有效私钥的范围由 secp256k1 和 ECDSA算法决定。私钥的取值范围 1 到 n,即 0x1 到 0xFFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFE BAAE DCE6 AF48 A03B BFD2 5E8C D036 4141。
例如,用 16 进制显示:0xbef05ca99c4bb9d17f9f164a5bffd48ee2f99f866a3621dd9a4be62412c28148
私钥通常使用 16 进制表示,长度为 64 个字符:
bef05ca99c4bb9d17f9f164a5bffd48ee2f99f866a3621dd9a4be62412c28148
2. 公钥
公钥其实是 secp256k1 椭圆曲线的一个坐标点,即 (x,y) 形式。
例如,用 16 进制显示:(0xd061e9c5891f579fd548cfd22ff29f5c642714cc7e7a9215f0071ef5a5723f69,0x1757b28e31be71f09f24673eed52348e58d53bcfd26f4d96ec6bf1489eab429d)
比特币中可以使用两种格式表示公钥:未压缩公钥 和 压缩公钥。
1) 未压缩公钥
未压缩公钥通常将 x 和 y 的 16 进制表示拼接起来,并在首部添加前缀标识 04 来表示,长度为 130 个字符。
例如:04d061e9c5891f579fd548cfd22ff29f5c642714cc7e7a9215f0071ef5a5723f691757b28e31be71f09f24673eed52348e58d53bcfd26f4d96ec6bf1489eab429d
2) 压缩公钥
由于从公钥的 x 可以推导出 y,所以公钥中的 y 可以省略。省略 y 的公钥称为压缩公钥。
从 x 可以推导出 y 有两个,一个是奇数,一个是偶数,需要通过标识加以确定。
如果压缩形式以 02 开头,则选择最低有效位为偶数的根。如果压缩形式从03开始,则选择其最低有效位为奇数的根。
例如:0x1757......429d 从最后一位 0xd 来看,这个数是奇数,所以压缩公钥是 03d061e9c5891f579fd548cfd22ff29f5c642714cc7e7a9215f0071ef5a5723f69。
压缩公钥通常将前缀标识 和 x 的 16 进制表示拼接起来表示,长度为 66 个字符。
现在一般都使用压缩公钥,压缩和未压缩公钥生成的地址确实会不一样,压缩公钥已成了主流。
3. go 生成私钥、公钥
Golang ecdsa package 公钥、私钥的结构体:
公钥、私钥的结构体:
// PublicKey represents an ECDSA public key. type PublicKey struct { elliptic.Curve X, Y *big.Int } // PrivateKey represents a ECDSA private key. type PrivateKey struct { PublicKey D *big.Int }
生成密钥对的函数:
// GenerateKey generates a public and private key pair. func GenerateKey(c elliptic.Curve, rand io.Reader) (*PrivateKey, error) { k, err := randFieldElement(c, rand) if err != nil { return nil, err } priv := new(PrivateKey) priv.PublicKey.Curve = c priv.D = k priv.PublicKey.X, priv.PublicKey.Y = c.ScalarBaseMult(k.Bytes()) return priv, nil }
我们使用 crypto/ecdsa 包生成的密钥:
package main import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "encoding/hex" "fmt" ) func main() { key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { return } privateKey := key.D.Bytes() fmt.Println("privateKey:",privateKey) fmt.Println("PrivateKey Hex:",hex.EncodeToString(privateKey)) publicKey := key.PublicKey fmt.Println("publicKey X:",publicKey.X.Bytes()) fmt.Println("publicKey Y:",publicKey.Y.Bytes()) publicKeyHex := hex.EncodeToString(append(publicKey.X.Bytes(),publicKey.Y.Bytes()...)) fmt.Println("PublicKey Hex:",publicKeyHex) }
输出结果:
privateKey: [214 85 137 40 136 173 9 60 19 144 188 234 89 1 216 157 96 206 16 158 130 115 214 31 130 253 155 45 151 183 175 18] PrivateKey Hex: d655892888ad093c1390bcea5901d89d60ce109e8273d61f82fd9b2d97b7af12 publicKey X: [75 131 72 241 8 224 193 64 66 100 74 226 157 169 150 194 71 86 68 115 93 228 136 188 11 14 238 75 235 105 41 110] publicKey Y: [136 68 216 215 202 178 61 41 38 1 112 116 16 149 19 228 65 79 222 37 18 123 151 12 237 36 121 155 128 134 174 191] PublicKey Hex: 4b8348f108e0c14042644ae29da996c2475644735de488bc0b0eee4beb69296e8844d8d7cab23d2926017074109513e4414fde25127b970ced24799b8086aebf
下一章:数字证书获取流程
网络安全中最知名的人物大概就是 Bob 和 Alice 了,因为很多安全原理阐述中都用这两个虚拟人物来进行实例说明。我们来看看Bob是怎么从CA中心获得一个数字证书的:1、 Bob首先创建他自己的密钥对(key pair) ...