-
Notifications
You must be signed in to change notification settings - Fork 8
/
xpub.go
83 lines (67 loc) · 1.88 KB
/
xpub.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
package bip32
import (
"crypto/ed25519"
"crypto/hmac"
"crypto/sha512"
"encoding/binary"
"encoding/hex"
)
// XPub is exntend public key for ed25519
type XPub struct {
xpub []byte
}
// NewXPub create XPub by plain xpub bytes
func NewXPub(raw []byte) XPub {
if len(raw) != XPubSize {
panic("bip32-ed25519: NewXPub: size should be 64 bytes")
}
return XPub{xpub: append([]byte(nil), raw...)}
}
// String implements Stringer interface and returns plain hex string
func (x XPub) String() string {
return hex.EncodeToString(x.xpub)
}
// Bytes returns intenal bytes
func (x XPub) Bytes() []byte {
return append([]byte(nil), x.xpub...)
}
// PublicKey returns the current public key
func (x XPub) PublicKey() []byte {
return append([]byte(nil), x.xpub[:32]...)
}
// ChainCode returns chain code bytes
func (x XPub) ChainCode() []byte {
return append([]byte(nil), x.xpub[32:]...)
}
// Derive derives new XPub by a soft index
func (x XPub) Derive(index uint32) XPub {
if index > HardIndex {
panic("bip32-ed25519: xpub.Derive: expected a soft derivation")
}
var pubkey [32]byte
copy(pubkey[:], x.xpub[:32])
chaincode := append([]byte(nil), x.xpub[32:]...)
zmac := hmac.New(sha512.New, chaincode)
imac := hmac.New(sha512.New, chaincode)
seri := make([]byte, 4)
binary.LittleEndian.PutUint32(seri, index)
_, _ = zmac.Write([]byte{2})
_, _ = zmac.Write(pubkey[:])
_, _ = zmac.Write(seri)
_, _ = imac.Write([]byte{3})
_, _ = imac.Write(pubkey[:])
_, _ = imac.Write(seri)
left, ok := pointPlus(&pubkey, pointOfTrunc28Mul8(zmac.Sum(nil)[:32]))
if !ok {
panic("bip32-ed25519: can't convert bytes to edwards25519.ExtendedGroupElement")
}
var out [64]byte
copy(out[:32], left[:32])
copy(out[32:], imac.Sum(nil)[32:])
return XPub{xpub: out[:]}
}
// Verify verifies signature by message
func (x XPub) Verify(msg, sig []byte) bool {
pk := x.xpub[:32]
return ed25519.Verify(pk, msg, sig)
}