0%

HD Wallet 系列:种子与公钥

参考 bip32bip44

  • 定义了种子生成树状密钥对的算法与规则
  • 定义了5层路径规则,可兼容多账号多币种

一、密钥扩展算法

1. 概念

  • private extended key :

    (k , c) k为私钥,c为chaincode

  • public extended key :

    (K , c) K为公钥,c为chaincode

  • Child key derivation functions:

    CKD(extended key , index)
    normal child keys 范围: 0-2^31-1
    hardened child keys 范围: 2^31 - 2^32-1

2. 可生成的规则:

  • Private extended key -> Hardened child private extended key
  • Private extended key -> Non-hardened child private extended key
  • Public extended key -> Non-hardened child public extended key
  • Public extended key -> Hardened child public extended key (不允许)

3. 具体过程

  1. 计算 HMAC-SHA512(“Bitcoin seed” , seed(128-512bits)) 获取512bits
  2. 将 1 的结果分为L和R,各占32字节,分别作为master extended Key 的private key和chaincode,得到master extended Key(private extended key)
  3. 通过 CKD(extended key , index) 方法派扩展密钥对

二、5层路径规则

1. 路径含义

路径:m/purpse’/coin_type’/account’/change/address_index(‘ 表示hardencode index 需要大于或等于 2^31)

m:主扩展密钥
purpose: bip44/bip45
coin_type: 币种
account: 钱包账户
change: 0 对外 / 1 找零
address_index: 地址索引

1
2
3
4
5
6
7
8
9
10
graph TD
A[masterNode] -->B(BIP44)
B -->C[coinType 0]
B -->D[coinType 10]
C --> E[account 0]
D --> F[account 0]
E --> G[change 0]
E --> H[change 1]
G --> I[address 0]
G --> J[address 1]

2. 获取公钥

通过层层扩展,拿到第五层的扩展密钥 (k,c),其中的k即为privkey,然后结合椭圆曲线的算法即可得到pubKey

三、代码实战

代码参考: https://github.com/tpkeeper/addrtool/blob/master/address_test.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
func TestSeedToPubkey(t *testing.T) {
seed := "04ef53d66b17fdfb6538c5d183f0b0569fc1c79d07f044f7670c3038aff411e5abcbe8c457b584d0c1e3504ab94fb311f9097a793c20dfc746a87087ed5dc119"
hexByte, _ := hex.DecodeString(seed)
//m
masterExtKey, _ := bip32.NewMasterKey(hexByte)
//m/purpose'
purposeExtKey,_:=masterExtKey.NewChildKey(bip32.FirstHardenedChild+44)
//m/purpose'/cointype'
coinTypeExtKey,_:=purposeExtKey.NewChildKey(bip32.FirstHardenedChild+0)
//m/purpose'/cointype'/account'
accountExtKey,_:=coinTypeExtKey.NewChildKey(bip32.FirstHardenedChild+0)
//m/purpose'/cointype'/account'/change
changeExtKey,_:=accountExtKey.NewChildKey(0)
//m/purpose'/cointype'/account'/change/addrIndex
addrIndex0ExtKey,_:=changeExtKey.NewChildKey(0)
//pubkey
t.Log(hex.EncodeToString(addrIndex0ExtKey.PublicKey().Key))
}