forked from bitcoinjs/bip39
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
139 lines (107 loc) · 3.75 KB
/
index.js
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
var createHash = require('create-hash')
var pbkdf2 = require('pbkdf2').pbkdf2Sync
var randomBytes = require('randombytes')
// use unorm until String.prototype.normalize gets better browser support
var unorm = require('unorm')
var ENGLISH_WORDLIST = require('./wordlists/english.json')
var DEFAULT_WORDLIST = ENGLISH_WORDLIST
function salt (password) {
return 'mnemonic' + (password || '')
}
function mnemonicToSeed (mnemonic, password) {
var mnemonicBuffer = new Buffer(unorm.nfkd(mnemonic), 'utf8')
var saltBuffer = new Buffer(salt(unorm.nfkd(password)), 'utf8')
return pbkdf2(mnemonicBuffer, saltBuffer, 2048, 64, 'sha512')
}
function mnemonicToSeedHex (mnemonic, password) {
return mnemonicToSeed(mnemonic, password).toString('hex')
}
function mnemonicToEntropy (mnemonic, wordlist) {
wordlist = wordlist || DEFAULT_WORDLIST
var words = unorm.nfkd(mnemonic).split(' ')
if (words.length % 3 !== 0) throw new Error('Invalid mnemonic')
if (words.some(function (word) {
return wordlist.indexOf(word) === -1
})) throw new Error('Invalid mnemonic')
// convert word indices to 11 bit binary strings
var bits = words.map(function (word) {
var index = wordlist.indexOf(word)
return lpad(index.toString(2), '0', 11)
}).join('')
// split the binary string into ENT/CS
var dividerIndex = Math.floor(bits.length / 33) * 32
var entropy = bits.slice(0, dividerIndex)
var checksum = bits.slice(dividerIndex)
// calculate the checksum and compare
var entropyBytes = entropy.match(/(.{1,8})/g).map(function (bin) {
return parseInt(bin, 2)
})
var entropyBuffer = new Buffer(entropyBytes)
var newChecksum = checksumBits(entropyBuffer)
// recreate properly chunked and padded bits to get the properly padded checksum
var bits2 = (entropy + newChecksum).match(/(.{1,11})/g).map(function (index) {
return lpad(index, '0', 11)
}).join('')
var dividerIndex2 = Math.floor(bits2.length / 33) * 32
var newChecksum2 = bits2.slice(dividerIndex2)
if (newChecksum2 !== checksum) {
throw new Error('Invalid mnemonic checksum')
}
return entropyBuffer.toString('hex')
}
function entropyToMnemonic (entropy, wordlist) {
wordlist = wordlist || DEFAULT_WORDLIST
var entropyBuffer = new Buffer(entropy, 'hex')
var entropyBits = bytesToBinary([].slice.call(entropyBuffer))
var checksum = checksumBits(entropyBuffer)
var bits = entropyBits + checksum
var chunks = bits.match(/(.{1,11})/g)
var words = chunks.map(function (binary) {
var index = parseInt(binary, 2)
return wordlist[index]
})
return words.join(' ')
}
function generateMnemonic (strength, rng, wordlist) {
strength = strength || 128
rng = rng || randomBytes
var hex = rng(strength / 8).toString('hex')
return entropyToMnemonic(hex, wordlist)
}
function validateMnemonic (mnemonic, wordlist) {
try {
mnemonicToEntropy(mnemonic, wordlist)
} catch (e) {
return false
}
return true
}
function checksumBits (entropyBuffer) {
var hash = createHash('sha256').update(entropyBuffer).digest()
// Calculated constants from BIP39
var ENT = entropyBuffer.length * 8
var CS = ENT / 32
return bytesToBinary([].slice.call(hash)).slice(0, CS)
}
// =========== helper methods from bitcoinjs-lib ========
function bytesToBinary (bytes) {
return bytes.map(function (x) {
return lpad(x.toString(2), '0', 8)
}).join('')
}
function lpad (str, padString, length) {
while (str.length < length) str = padString + str
return str
}
module.exports = {
mnemonicToSeed: mnemonicToSeed,
mnemonicToSeedHex: mnemonicToSeedHex,
mnemonicToEntropy: mnemonicToEntropy,
entropyToMnemonic: entropyToMnemonic,
generateMnemonic: generateMnemonic,
validateMnemonic: validateMnemonic,
wordlists: {
EN: ENGLISH_WORDLIST,
english: ENGLISH_WORDLIST,
}
}