-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsecp256k1.go
167 lines (147 loc) · 5.33 KB
/
secp256k1.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/*
*/
package hdwallet
import (
"crypto/hmac"
"crypto/sha512"
"encoding/binary"
"math/big"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcutil"
)
type Secp256K1 struct{}
var _ ChildKey = &Secp256K1{}
func (s *Secp256K1) Child(k ExtendedKey, i uint32) (*ExtendedKey, error) {
// Prevent derivation of children beyond the max allowed depth.
if k.depth == maxUint8 {
return nil, ErrDeriveBeyondMaxDepth
}
// There are four scenarios that could happen here:
// 1) Private extended key -> Hardened child private extended key
// 2) Private extended key -> Non-hardened child private extended key
// 3) Public extended key -> Non-hardened child public extended key
// 4) Public extended key -> Hardened child public extended key (INVALID!)
// Case #4 is invalid, so error out early.
// A hardened child extended key may not be created from a public
// extended key.
isChildHardened := i >= HardenedKeyStart
if !k.isPrivate && isChildHardened {
return nil, ErrDeriveHardFromPublic
}
// The data used to derive the child key depends on whether or not the
// child is hardened per [BIP32].
//
// For hardened children:
// 0x00 || ser256(parentKey) || ser32(i)
//
// For normal children:
// serP(parentPubKey) || ser32(i)
keyLen := 33
data := make([]byte, keyLen+4)
if isChildHardened {
// Case #1.
// When the child is a hardened child, the key is known to be a
// private key due to the above early return. Pad it with a
// leading zero as required by [BIP32] for deriving the child.
copy(data[1:], k.key)
} else {
// Case #2 or #3.
// This is either a public or private extended key, but in
// either case, the data which is used to derive the child key
// starts with the secp256k1 compressed public key bytes.
copy(data, pubKeyBytes(&k))
}
binary.BigEndian.PutUint32(data[keyLen:], i)
// Take the HMAC-SHA512 of the current key's chain code and the derived
// data:
// I = HMAC-SHA512(Key = chainCode, Data = data)
hmac512 := hmac.New(sha512.New, k.chainCode)
hmac512.Write(data)
ilr := hmac512.Sum(nil)
// Split "I" into two 32-byte sequences Il and Ir where:
// Il = intermediate key used to derive the child
// Ir = child chain code
il := ilr[:len(ilr)/2]
childChainCode := ilr[len(ilr)/2:]
// Both derived public or private keys rely on treating the left 32-byte
// sequence calculated above (Il) as a 256-bit integer that must be
// within the valid range for a secp256k1 private key. There is a small
// chance (< 1 in 2^127) this condition will not hold, and in that case,
// a child extended key can't be created for this index and the caller
// should simply increment to the next index.
ilNum := new(big.Int).SetBytes(il)
if ilNum.Cmp(btcec.S256().N) >= 0 || ilNum.Sign() == 0 {
return nil, ErrInvalidChild
}
// The algorithm used to derive the child key depends on whether or not
// a private or public child is being derived.
//
// For private children:
// childKey = parse256(Il) + parentKey
//
// For public children:
// childKey = serP(point(parse256(Il)) + parentKey)
var isPrivate bool
var childKey []byte
if k.isPrivate {
// Case #1 or #2.
// Add the parent private key to the intermediate private key to
// derive the final child key.
//
// childKey = parse256(Il) + parenKey
keyNum := new(big.Int).SetBytes(k.key)
ilNum.Add(ilNum, keyNum)
ilNum.Mod(ilNum, btcec.S256().N)
childKey = ilNum.Bytes()
isPrivate = true
} else {
// Case #3.
// Calculate the corresponding intermediate public key for
// intermediate private key.
ilx, ily := btcec.S256().ScalarBaseMult(il)
if ilx.Sign() == 0 || ily.Sign() == 0 {
return nil, ErrInvalidChild
}
// Convert the serialized compressed parent public key into X
// and Y coordinates so it can be added to the intermediate
// public key.
pubKey, err := btcec.ParsePubKey(k.key, btcec.S256())
if err != nil {
return nil, err
}
// Add the intermediate public key to the parent public key to
// derive the final child key.
//
// childKey = serP(point(parse256(Il)) + parentKey)
childX, childY := btcec.S256().Add(ilx, ily, pubKey.X, pubKey.Y)
pk := btcec.PublicKey{Curve: btcec.S256(), X: childX, Y: childY}
childKey = pk.SerializeCompressed()
}
// The fingerprint of the parent for the derived child is the first 4
// bytes of the RIPEMD160(SHA256(parentPubKey)).
parentFP := btcutil.Hash160(pubKeyBytes(&k))[:4]
return NewExtendedKey(childKey, childChainCode, parentFP,
k.depth+1, i, isPrivate), nil
}
// pubKeyBytes returns bytes for the serialized compressed public key associated
// with this extended key in an efficient manner including memoization as
// necessary.
//
// When the extended key is already a public key, the key is simply returned as
// is since it's already in the correct form. However, when the extended key is
// a private key, the public key will be calculated and memoized so future
// accesses can simply return the cached result.
func pubKeyBytes(k *ExtendedKey) []byte {
// Just return the key if it's already an extended public key.
if !k.isPrivate {
return k.key
}
// This is a private extended key, so calculate and memoize the public
// key if needed.
if len(k.pubKey) == 0 {
pkx, pky := btcec.S256().ScalarBaseMult(k.key)
pubKey := btcec.PublicKey{Curve: btcec.S256(), X: pkx, Y: pky}
k.pubKey = pubKey.SerializeCompressed()
}
return k.pubKey
}