比特币协议 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) ...