-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmaster_key.go
67 lines (57 loc) · 2.19 KB
/
master_key.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
package bip32
import (
"crypto/hmac"
"crypto/sha512"
"io"
)
// GenerateMasterKey is a more convinient implemenation w.r.t to
// NewMasterKey. The seed needed is read from the given entropy source
// rand, and the seed length is optional which would be RecommendedSeedLen
// if omitted.
func GenerateMasterKey(rand io.Reader, keyID Magic,
strength ...int) (*PrivateKey, error) {
seedLen := RecommendedSeedLen
if len(strength) > 0 && strength[0] >= MinSeedBytes &&
strength[0] <= MaxSeedBytes {
seedLen = strength[0]
}
seed := make([]byte, seedLen)
if _, err := io.ReadFull(rand, seed); nil != err {
return nil, ErrNoEnoughEntropy
}
// delegate the common derivation routine
return newMaster(seed, keyID)
}
// NewMasterKey creates a new master node for use in creating a hierarchical
// deterministic key chain. The seed must be between 128 and 512 bits and
// should be generated by a cryptographically secure random source.
//
// NOTE: There is an extremely small chance (< 1 in 2^127) the provided seed
// will derive to an unusable secret key. The ErrUnusable error will be
// returned if this should occur, so the caller must check for it and generate a
// new seed accordingly.
func NewMasterKey(seed []byte, keyID Magic) (*PrivateKey, error) {
// Per [BIP32], the seed must be in range [MinSeedBytes, MaxSeedBytes].
if len(seed) < MinSeedBytes || len(seed) > MaxSeedBytes {
return nil, ErrInvalidSeedLen
}
return newMaster(seed, keyID)
}
// newMaster is helper function to derives a extended private key based on the
// given valid seed and the provided keyID.
//
// Official specification goes as https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#master-key-generation
func newMaster(seed []byte, keyID Magic) (*PrivateKey, error) {
// I = HMAC-SHA512(Key = "Bitcoin seed", Data = S)
hmac512 := hmac.New(sha512.New, masterHMACKey)
hmac512.Write(seed)
I := hmac512.Sum(nil)
secretKey, chainCode := I[:len(I)/2], I[len(I)/2:]
// Ensure the key in usable.
if _, ok := ToUsableScalar(secretKey); !ok {
return nil, ErrUnusableSeed
}
// fingerprint of parent
parentFP := []byte{0x00, 0x00, 0x00, 0x00}
return NewPrivateKey(keyID[:], 0, parentFP, 0, chainCode, secretKey), nil
}