-
Notifications
You must be signed in to change notification settings - Fork 0
/
ed25519.go
87 lines (73 loc) · 2.49 KB
/
ed25519.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
/*
*/
package hdwallet
import (
"crypto/hmac"
"crypto/sha512"
"encoding/binary"
"errors"
"github.com/btcsuite/btcutil"
)
type Ed25519 struct{}
var _ ChildKey = &Ed25519{}
var (
ErrNonHardenedChild = errors.New("ed25519 does not support non hardened children")
ErrPublicParentDerivation = errors.New("derivation from public parent not supported")
)
func (e *Ed25519) 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.
return nil, ErrNonHardenedChild
}
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:]
childKey := il
isPrivate := true
// 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
}