-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathMnemonic.test.ts
177 lines (154 loc) · 6.38 KB
/
Mnemonic.test.ts
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
168
169
170
171
172
173
174
175
176
177
import Mnemonic from '../../../dist/cjs/src/compat/Mnemonic'
import { wordList as enWordList } from '../../../dist/cjs/src/compat/bip-39-wordlist-en'
import Random from '../../../dist/cjs/src/primitives/Random'
import vectors from './Mnemonic.vectors'
import HD from '../../../dist/cjs/src/compat/HD'
import { toBase58Check, toHex, toArray } from '../../../dist/cjs/src/primitives/utils'
describe('Mnemonic', function () {
it('should initialize the class', () => {
expect(Mnemonic).toBeDefined()
expect(new Mnemonic()).toBeDefined()
})
it('should have a wordlist of length 2048', () => {
expect(enWordList.value.length).toEqual(2048)
})
it('should handle this community-derived test vector', () => {
// There was a bug in Copay and bip32jp about deriving addresses with Mnemonic
// and bip44. This confirms we are handling the situation correctly and
// derive the correct value.
//
// More information here:
// https://github.com/iancoleman/bip39/issues/58
const seed = Mnemonic.fromString('fruit wave dwarf banana earth journey tattoo true farm silk olive fence').toSeed(
'banana'
)
let bip32 = HD.fromSeed(seed)
bip32 = bip32.derive("m/44'/0'/0'/0/0")
const pkh = bip32.pubKey.toHash()
const addr = toBase58Check(pkh)
expect(addr).toEqual('17rxURoF96VhmkcEGCj5LNQkmN9HVhWb7F')
})
it('should generate a mnemonic phrase that passes the check', () => {
let mnemonic
// should be able to make a mnemonic with or without the default wordlist
let m = new Mnemonic().fromRandom(128)
expect(m.check()).toEqual(true)
m = new Mnemonic().fromRandom(128)
expect(m.check()).toEqual(true)
const entropy = Array(32)
entropy.fill(0)
m = new Mnemonic().fromEntropy(entropy)
expect(m.check()).toEqual(true)
mnemonic = m.mnemonic
// mnemonics with extra whitespace do not pass the check
m = new Mnemonic().fromString(mnemonic + ' ')
expect(m.check()).toEqual(false)
// mnemonics with a word replaced do not pass the check
const words = mnemonic.split(' ')
expect(words[words.length - 1]).not.toEqual('zoo')
words[words.length - 1] = 'zoo'
mnemonic = words.join(' ')
expect(new Mnemonic().fromString(mnemonic).check()).toEqual(false)
})
describe('#toBinary', () => {
it('should convert to a binary array', () => {
const m = new Mnemonic().fromRandom()
expect(m.seed).toBeDefined()
expect(m.mnemonic).toBeDefined()
const buf = m.toBinary()
expect(buf.length).toBeGreaterThan(512 / 8 + 1 + 1)
})
})
describe('#fromBinary', () => {
it('should convert from a binary array', () => {
const mA = new Mnemonic().fromRandom()
const mB = new Mnemonic().fromBinary(mA.toBinary())
expect(mA.mnemonic).toEqual(mB.mnemonic)
expect(toHex(mA.seed as number[])).toEqual(toHex(mB.seed as number[]))
})
})
describe('#fromRandom', () => {
it('should throw an error if bits is too low', () => {
expect(() => {
new Mnemonic().fromRandom(127)
}).toThrow('bits must be multiple of 32')
})
it('should throw an error if bits is not a multiple of 32', () => {
expect(() => {
new Mnemonic().fromRandom(256 - 1)
}).toThrow('bits must be multiple of 32')
})
})
describe('@fromRandom', () => {
it('should throw an error if bits is too low', () => {
expect(() => {
Mnemonic.fromRandom(127)
}).toThrow('bits must be multiple of 32')
})
it('should throw an error if bits is not a multiple of 32', () => {
expect(() => {
Mnemonic.fromRandom(256 - 1)
}).toThrow('bits must be multiple of 32')
})
})
describe('#fromEntropy', () => {
it('should build from entropy', () => {
const m = new Mnemonic().fromEntropy(Random(32))
expect(m).toBeDefined()
})
})
describe('@fromEntropy', () => {
it('should build from entropy', () => {
const m = Mnemonic.fromEntropy(Random(32))
expect(m).toBeDefined()
})
})
describe('#entropy2Mnemonic', () => {
it('should throw an error if you do not use enough entropy', () => {
const buf = Buffer.alloc(128 / 8 - 1)
buf.fill(0)
expect(() => {
new Mnemonic().entropy2Mnemonic([...buf])
}).toThrow('Entropy is less than 128 bits. It must be 128 bits or more.')
})
})
describe('#fromString', () => {
it('should throw an error in invalid mnemonic', () => {
expect(() => {
new Mnemonic().fromString('invalid mnemonic').toSeed()
}).toThrow(
'Mnemonic does not pass the check - was the mnemonic typed incorrectly? Are there extra spaces?'
)
})
})
describe('@isValid', () => {
it('should know this is valid', () => {
const isValid = Mnemonic.isValid(
'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about',
'TREZOR'
)
expect(isValid).toBe(true)
})
it('should know this is invalid', () => {
const isValid = Mnemonic.isValid(
'abandonnnnnnn abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about',
'TREZOR'
)
expect(isValid).toEqual(false)
})
})
describe('vectors', () => {
// eslint-disable-next-line ban/ban
vectors.english.forEach((vector, v) => {
it('should pass english test vector ' + v, () => {
const entropy = toArray(vector.entropy, 'hex')
const m = new Mnemonic().fromEntropy(entropy)
expect(m.toString()).toEqual(vector.mnemonic)
expect(m.check()).toEqual(true)
const seed = m.toSeed(vector.passphrase)
expect(toHex(seed)).toEqual(vector.seed)
expect(HD.fromSeed(seed).toString()).toEqual(vector.bip32_xprv)
})
})
})
})