1 package hd
2 3 import (
4 "bytes"
5 "encoding/hex"
6 "testing"
7 )
8 9 // seed is the BIP32 test vector 1 seed.
10 var seed = mustHex("000102030405060708090a0b0c0d0e0f")
11 12 // mustHex decodes a hex string or fails the test.
13 func mustHex(text string) []byte {
14 out, err := hex.DecodeString(text)
15 16 if err != nil {
17 panic(err)
18 }
19 20 return out
21 }
22 23 // TestMasterIsDeterministic: the same seed is the same tree, which is the whole promise of
24 // a backup.
25 func TestMasterIsDeterministic(t *testing.T) {
26 first, err := NewMaster(seed)
27 28 if err != nil {
29 t.Fatal(err)
30 }
31 32 second, err := NewMaster(seed)
33 34 if err != nil {
35 t.Fatal(err)
36 }
37 38 if !bytes.Equal(first.Private[:], second.Private[:]) ||
39 !bytes.Equal(first.ChainCode[:], second.ChainCode[:]) {
40 t.Fatal("the same seed gave two master keys")
41 }
42 43 if first.Depth != 0 || len(first.Path) != 0 {
44 t.Fatalf("the master key is at depth %d, path %v", first.Depth, first.Path)
45 }
46 47 // A different seed is a different tree.
48 other, err := NewMaster(mustHex("0f0e0d0c0b0a09080706050403020100"))
49 50 if err != nil {
51 t.Fatal(err)
52 }
53 54 if bytes.Equal(first.Private[:], other.Private[:]) {
55 t.Fatal("two different seeds gave the same master key")
56 }
57 }
58 59 // TestHardenedAndNormalDiffer: the same index on the two branches is two keys, which is
60 // what a hardened level buys.
61 func TestHardenedAndNormalDiffer(t *testing.T) {
62 master, err := NewMaster(seed)
63 64 if err != nil {
65 t.Fatal(err)
66 }
67 68 normal, err := master.ChildKey(0)
69 70 if err != nil {
71 t.Fatal(err)
72 }
73 74 hardened, err := master.ChildKey(Hardened)
75 76 if err != nil {
77 t.Fatal(err)
78 }
79 80 if bytes.Equal(normal.Private[:], hardened.Private[:]) {
81 t.Fatal("the normal and hardened children of one index are the same key")
82 }
83 84 if normal.Depth != 1 || hardened.Depth != 1 {
85 t.Fatalf("depths are %d and %d", normal.Depth, hardened.Depth)
86 }
87 }
88 89 // TestPathIsCarried: a key says where it came from, because a wallet's address is recorded
90 // as a path.
91 func TestPathIsCarried(t *testing.T) {
92 master, err := NewMaster(seed)
93 94 if err != nil {
95 t.Fatal(err)
96 }
97 98 path, err := ParsePath("m/84'/0'/0'/1/7")
99 100 if err != nil {
101 t.Fatal(err)
102 }
103 104 key, err := master.Derive(path)
105 106 if err != nil {
107 t.Fatal(err)
108 }
109 110 if got := key.ChildPath(); got != "m/84'/0'/0'/1/7" {
111 t.Fatalf("the key's path is %q", got)
112 }
113 114 if key.Depth != 5 {
115 t.Fatalf("the depth is %d", key.Depth)
116 }
117 118 // The same path twice is the same key: derivation is a function, not a walk.
119 again, err := master.Derive(path)
120 121 if err != nil {
122 t.Fatal(err)
123 }
124 125 if !bytes.Equal(key.Private[:], again.Private[:]) {
126 t.Fatal("the same path gave two keys")
127 }
128 }
129 130 // TestParsePath: the notation a person copies, and what it refuses.
131 func TestParsePath(t *testing.T) {
132 good := map[string]string{
133 "m/84'/0'/0'/0/0": "m/84'/0'/0'/0/0",
134 "m/84h/0h/0h/0/0": "m/84'/0'/0'/0/0",
135 "m": "m",
136 " m/0 ": "m/0",
137 }
138 139 for input, want := range good {
140 path, err := ParsePath(input)
141 142 if err != nil {
143 t.Fatalf("%q: %v", input, err)
144 }
145 146 if got := path.String(); got != want {
147 t.Fatalf("%q parsed to %q, want %q", input, got, want)
148 }
149 }
150 151 for _, bad := range []string{
152 "", "84'/0'", "m//0", "m/x", "m/84''", "m/2147483648", "/0", "m/-1",
153 } {
154 if _, err := ParsePath(bad); err == nil {
155 t.Errorf("%q was accepted as a path", bad)
156 }
157 }
158 }
159 160 // TestPublicIsStable: the same private key is the same public key, and a child's is not
161 // its parent's.
162 func TestPublicIsStable(t *testing.T) {
163 master, err := NewMaster(seed)
164 165 if err != nil {
166 t.Fatal(err)
167 }
168 169 first := master.Public()
170 second := master.Public()
171 172 if !bytes.Equal(first, second) || len(first) != 33 {
173 t.Fatalf("the public key is %d bytes and %v", len(first),
174 bytes.Equal(first, second))
175 }
176 177 child, err := master.ChildKey(Hardened)
178 179 if err != nil {
180 t.Fatal(err)
181 }
182 183 if bytes.Equal(child.Public(), first) {
184 t.Fatal("a child has its parent's public key")
185 }
186 187 // A public key is a compressed point, so its first byte is a parity marker.
188 if first[0] != 0x02 && first[0] != 0x03 {
189 t.Fatalf("the public key starts with %#x", first[0])
190 }
191 }
192 193 // TestSeedLength: BIP32 defines 16 to 64 bytes.
194 func TestSeedLength(t *testing.T) {
195 for _, size := range []int{16, 32, 64} {
196 if _, err := NewMaster(make([]byte, size)); err != nil {
197 t.Errorf("%d bytes: %v", size, err)
198 }
199 }
200 201 for _, size := range []int{0, 15, 65} {
202 if _, err := NewMaster(make([]byte, size)); err == nil {
203 t.Errorf("%d bytes was accepted", size)
204 }
205 }
206 207 // An all-zero seed is still a seed: it is a bad one for a person to pick, but it is
208 // representable, and refusing it would refuse a valid derivation.
209 if _, err := NewMaster(make([]byte, 32)); err != nil {
210 t.Fatalf("the zero seed was refused: %v", err)
211 }
212 }
213