mirror of https://github.com/status-im/bip39.git
switch to tape for testing
This commit is contained in:
parent
5897d39771
commit
60dd3ee035
1
index.js
1
index.js
|
@ -28,7 +28,6 @@ function mnemonicToEntropy (mnemonic, wordlist) {
|
||||||
|
|
||||||
var words = unorm.nfkd(mnemonic).split(' ')
|
var words = unorm.nfkd(mnemonic).split(' ')
|
||||||
if (words.length % 3 !== 0) throw new Error('Invalid mnemonic')
|
if (words.length % 3 !== 0) throw new Error('Invalid mnemonic')
|
||||||
|
|
||||||
if (words.some(function (word) {
|
if (words.some(function (word) {
|
||||||
return wordlist.indexOf(word) === -1
|
return wordlist.indexOf(word) === -1
|
||||||
})) throw new Error('Invalid mnemonic')
|
})) throw new Error('Invalid mnemonic')
|
||||||
|
|
10
package.json
10
package.json
|
@ -4,9 +4,10 @@
|
||||||
"description": "Bitcoin BIP39: Mnemonic code for generating deterministic keys",
|
"description": "Bitcoin BIP39: Mnemonic code for generating deterministic keys",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"coverage": "nyc --branches 100 --functions 100 --check-coverage npm run unit",
|
||||||
|
"standard": "standard",
|
||||||
"test": "npm run standard && npm run unit",
|
"test": "npm run standard && npm run unit",
|
||||||
"unit": "mocha --reporter list test/*.js",
|
"unit": "tape test/*.js"
|
||||||
"standard": "standard"
|
|
||||||
},
|
},
|
||||||
"author": "Wei Lu",
|
"author": "Wei Lu",
|
||||||
"contributors": [
|
"contributors": [
|
||||||
|
@ -28,8 +29,9 @@
|
||||||
"unorm": "^1.3.3"
|
"unorm": "^1.3.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"mocha": "^2.2.0",
|
"nyc": "^8.3.0",
|
||||||
"proxyquire": "^1.7.10",
|
"proxyquire": "^1.7.10",
|
||||||
"standard": "*"
|
"standard": "*",
|
||||||
|
"tape": "^4.6.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
283
test/index.js
283
test/index.js
|
@ -1,199 +1,118 @@
|
||||||
/* global describe it */
|
var bip39 = require('../')
|
||||||
|
|
||||||
var assert = require('assert')
|
|
||||||
var proxyquire = require('proxyquire')
|
var proxyquire = require('proxyquire')
|
||||||
|
var WORDLISTS = {
|
||||||
var BIP39 = require('../index.js')
|
|
||||||
|
|
||||||
var wordlists = {
|
|
||||||
english: require('../wordlists/en.json'),
|
english: require('../wordlists/en.json'),
|
||||||
japanese: require('../wordlists/ja.json'),
|
japanese: require('../wordlists/ja.json'),
|
||||||
custom: require('./wordlist.json')
|
custom: require('./wordlist.json')
|
||||||
}
|
}
|
||||||
|
|
||||||
var vectors = require('./vectors.json')
|
var vectors = require('./vectors.json')
|
||||||
|
var test = require('tape')
|
||||||
|
|
||||||
describe('BIP39', function () {
|
function testVector (description, wordlist, password, v, i) {
|
||||||
describe('mnemonicToSeedHex', function () {
|
var ventropy = v[0]
|
||||||
this.timeout(20000)
|
var vmnemonic = v[1]
|
||||||
|
var vseedHex = v[2]
|
||||||
|
|
||||||
vectors.english.forEach(function (v, i) {
|
test('for ' + description + ' test vector ' + i, function (t) {
|
||||||
it('works for tests vector ' + i, function () {
|
t.plan(5)
|
||||||
assert.equal(BIP39.mnemonicToSeedHex(v[1], 'TREZOR'), v[2])
|
|
||||||
})
|
t.equal(bip39.mnemonicToEntropy(vmnemonic, wordlist), ventropy, 'mnemonicToEntropy returns ' + ventropy.slice(0, 40) + '...')
|
||||||
})
|
t.equal(bip39.mnemonicToSeedHex(vmnemonic, password), vseedHex, 'mnemonicToSeedHex returns ' + vseedHex.slice(0, 40) + '...')
|
||||||
|
|
||||||
|
t.equal(bip39.entropyToMnemonic(ventropy, wordlist), vmnemonic, 'entropyToMnemonic returns ' + vmnemonic.slice(0, 40) + '...')
|
||||||
|
|
||||||
|
function rng () { return new Buffer(ventropy, 'hex') }
|
||||||
|
t.equal(bip39.generateMnemonic(undefined, rng, wordlist), vmnemonic, 'generateMnemonic returns RNG entropy unmodified')
|
||||||
|
t.equal(bip39.validateMnemonic(vmnemonic, wordlist), true, 'validateMnemonic returns true')
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
describe('mnemonicToEntropy', function () {
|
vectors.english.forEach(function (v, i) { testVector('English', undefined, 'TREZOR', v, i) })
|
||||||
vectors.english.forEach(function (v, i) {
|
vectors.japanese.forEach(function (v, i) { testVector('Japanese', WORDLISTS.japanese, '㍍ガバヴァぱばぐゞちぢ十人十色', v, i) })
|
||||||
it('works for tests vector ' + i, function () {
|
vectors.custom.forEach(function (v, i) { testVector('Custom', WORDLISTS.custom, undefined, v, i) })
|
||||||
assert.equal(BIP39.mnemonicToEntropy(v[1]), v[0])
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
vectors.japanese.forEach(function (v, i) {
|
test('UTF8 passwords', function (t) {
|
||||||
it('works for japanese tests vector ' + i, function () {
|
t.plan(vectors.japanese.length * 2)
|
||||||
assert.equal(BIP39.mnemonicToEntropy(v[1], wordlists.japanese), v[0])
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
vectors.custom.forEach(function (v, i) {
|
vectors.japanese.forEach(function (v) {
|
||||||
it('works for custom test vector ' + i, function () {
|
var vmnemonic = v[1]
|
||||||
assert.equal(BIP39.mnemonicToEntropy(v[1], wordlists.custom), v[0])
|
var vseedHex = v[2]
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('entropyToMnemonic', function () {
|
var password = '㍍ガバヴァぱばぐゞちぢ十人十色'
|
||||||
vectors.english.forEach(function (v, i) {
|
var normalizedPassword = 'メートルガバヴァぱばぐゞちぢ十人十色'
|
||||||
it('works for tests vector ' + i, function () {
|
|
||||||
assert.equal(BIP39.entropyToMnemonic(v[0]), v[1])
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
vectors.japanese.forEach(function (v, i) {
|
t.equal(bip39.mnemonicToSeedHex(vmnemonic, password), vseedHex, 'mnemonicToSeedHex normalizes passwords')
|
||||||
it('works for japanese test vector ' + i, function () {
|
t.equal(bip39.mnemonicToSeedHex(vmnemonic, normalizedPassword), vseedHex, 'mnemonicToSeedHex leaves normalizes passwords as-is')
|
||||||
assert.equal(BIP39.entropyToMnemonic(v[0], wordlists.japanese), v[1])
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
vectors.custom.forEach(function (v, i) {
|
|
||||||
it('works for custom test vector ' + i, function () {
|
|
||||||
assert.equal(BIP39.entropyToMnemonic(v[0], wordlists.custom), v[1])
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('generateMnemonic', function () {
|
|
||||||
vectors.english.forEach(function (v, i) {
|
|
||||||
it('works for tests vector ' + i, function () {
|
|
||||||
function rng () { return new Buffer(v[0], 'hex') }
|
|
||||||
|
|
||||||
assert.equal(BIP39.generateMnemonic(undefined, rng), v[1])
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('can vary generated entropy bit length', function () {
|
|
||||||
var mnemonic = BIP39.generateMnemonic(96)
|
|
||||||
var words = mnemonic.split(' ')
|
|
||||||
|
|
||||||
assert.equal(words.length, 9)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('defaults to randombytes for the RNG', function () {
|
|
||||||
assert.equal(BIP39.generateMnemonic(32), 'imitate robot frequent')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('allows a custom RNG to be used', function () {
|
|
||||||
var rng = function (size) {
|
|
||||||
var buffer = new Buffer(size)
|
|
||||||
buffer.fill(4) // guaranteed random
|
|
||||||
return buffer
|
|
||||||
}
|
|
||||||
|
|
||||||
var mnemonic = BIP39.generateMnemonic(64, rng)
|
|
||||||
assert.equal(mnemonic, 'advice cage absurd amount doctor act')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('adheres to a custom wordlist', function () {
|
|
||||||
var rng = function (size) {
|
|
||||||
var buffer = new Buffer(size)
|
|
||||||
buffer.fill(4) // guaranteed random
|
|
||||||
return buffer
|
|
||||||
}
|
|
||||||
|
|
||||||
var mnemonic = BIP39.generateMnemonic(64, rng, wordlists.custom)
|
|
||||||
assert.equal(mnemonic, 'adv1c3 cag3 ab5urd am0unt d0ct0r act')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('validateMnemonic', function () {
|
|
||||||
vectors.english.forEach(function (v, i) {
|
|
||||||
it('passes check ' + i, function () {
|
|
||||||
assert(BIP39.validateMnemonic(v[1]))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('with a custom wordlist', function () {
|
|
||||||
vectors.custom.forEach(function (v, i) {
|
|
||||||
it('passes custom check ' + i, function () {
|
|
||||||
assert(BIP39.validateMnemonic(v[1], wordlists.custom))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('fails for mnemonics of wrong length', function () {
|
|
||||||
assert(!BIP39.validateMnemonic('sleep kitten'))
|
|
||||||
assert(!BIP39.validateMnemonic('sleep kitten sleep kitten sleep kitten'))
|
|
||||||
})
|
|
||||||
|
|
||||||
it('fails for mnemonics that contains words not from the word list', function () {
|
|
||||||
assert(!BIP39.validateMnemonic('turtle front uncle idea crush write shrug there lottery flower risky shell'))
|
|
||||||
})
|
|
||||||
|
|
||||||
it('fails for mnemonics of invalid checksum', function () {
|
|
||||||
assert(!BIP39.validateMnemonic('sleep kitten sleep kitten sleep kitten sleep kitten sleep kitten sleep kitten'))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('utf8 passwords', function () {
|
|
||||||
vectors.japanese.forEach(function (v) {
|
|
||||||
it('creates the correct seed', function () {
|
|
||||||
var utf8Password = '㍍ガバヴァぱばぐゞちぢ十人十色'
|
|
||||||
assert.equal(BIP39.mnemonicToSeedHex(v[1], utf8Password), v[2])
|
|
||||||
})
|
|
||||||
|
|
||||||
it('works with already normalized password', function () {
|
|
||||||
var normalizedPassword = 'メートルガバヴァぱばぐゞちぢ十人十色'
|
|
||||||
assert.equal(BIP39.mnemonicToSeedHex(v[1], normalizedPassword), v[2])
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('Examples in readme', function () {
|
|
||||||
var bip39 = BIP39
|
|
||||||
|
|
||||||
var mnemonic = bip39.entropyToMnemonic('133755ff') // hex input, defaults to BIP39 English word list
|
|
||||||
// 'basket rival lemon'
|
|
||||||
assert.ok((/^\w+ \w+ \w+$/).test(mnemonic))
|
|
||||||
|
|
||||||
var temp = bip39.mnemonicToEntropy(mnemonic) // hex input, defaults to BIP39 English word list
|
|
||||||
// '133755ff'
|
|
||||||
assert.equal(temp, '133755ff')
|
|
||||||
|
|
||||||
var stub = {
|
|
||||||
randombytes: function (size) {
|
|
||||||
return new Buffer('qwertyuiopasdfghjklzxcvbnm[];,./'.slice(0, size))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var proxiedBIP39 = proxyquire('../', stub)
|
|
||||||
|
|
||||||
// Generate a random mnemonic using crypto.randomBytes
|
|
||||||
mnemonic = proxiedBIP39.generateMnemonic() // strength defaults to 128 bits
|
|
||||||
// 'bench maximum balance appear cousin negative muscle inform enjoy chief vocal hello'
|
|
||||||
assert.ok(/^(\w+ ){11}\w+$/.test(mnemonic))
|
|
||||||
|
|
||||||
var str = bip39.mnemonicToSeedHex('basket actual')
|
|
||||||
// '5cf2d4a8b0355e90295bdfc565a022a409af063d5365bb57bf74d9528f494bfa4400f53d8349b80fdae44082d7f9541e1dba2b003bcfec9d0d53781ca676651f'
|
|
||||||
assert.equal(str, '5cf2d4a8b0355e90295bdfc565a022a409af063d5365bb57bf74d9528f494bfa4400f53d8349b80fdae44082d7f9541e1dba2b003bcfec9d0d53781ca676651f')
|
|
||||||
|
|
||||||
var buff = bip39.mnemonicToSeed('basket actual')
|
|
||||||
var fiveC = 5 * 16 + 12
|
|
||||||
assert.equal(buff[0], fiveC)
|
|
||||||
// <Buffer 5c f2 d4 a8 b0 35 5e 90 29 5b df c5 65 a0 22 a4 09 af 06 3d 53 65 bb 57 bf 74 d9 52 8f 49 4b fa 44 00 f5 3d 83 49 b8 0f da e4 40 82 d7 f9 54 1e 1d ba 2b ...>
|
|
||||||
|
|
||||||
var bool = bip39.validateMnemonic(mnemonic)
|
|
||||||
// true
|
|
||||||
assert.ok(bool)
|
|
||||||
|
|
||||||
bool = bip39.validateMnemonic('basket actual')
|
|
||||||
|
|
||||||
// false
|
|
||||||
assert.ok(!bool)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('exposes standard wordlists', function () {
|
|
||||||
assert(BIP39.wordlists.EN)
|
|
||||||
assert.equal(BIP39.wordlists.EN.length, 2048)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('README example 1', function (t) {
|
||||||
|
// defaults to BIP39 English word list
|
||||||
|
var entropy = '133755ff'
|
||||||
|
var mnemonic = bip39.entropyToMnemonic(entropy)
|
||||||
|
|
||||||
|
t.plan(2)
|
||||||
|
t.equal(mnemonic, 'basket rival lemon')
|
||||||
|
|
||||||
|
// reversible
|
||||||
|
t.equal(bip39.mnemonicToEntropy(mnemonic), entropy)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('README example 2', function (t) {
|
||||||
|
var stub = {
|
||||||
|
randombytes: function (size) {
|
||||||
|
return new Buffer('qwertyuiopasdfghjklzxcvbnm[];,./'.slice(0, size))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var proxiedbip39 = proxyquire('../', stub)
|
||||||
|
|
||||||
|
// mnemonic strength defaults to 128 bits
|
||||||
|
var mnemonic = proxiedbip39.generateMnemonic()
|
||||||
|
|
||||||
|
t.plan(2)
|
||||||
|
t.equal(mnemonic, 'bench maximum balance appear cousin negative muscle inform enjoy chief vocal hello')
|
||||||
|
t.equal(bip39.validateMnemonic(mnemonic), true)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('README example 3', function (t) {
|
||||||
|
var mnemonic = 'basket actual'
|
||||||
|
var seed = bip39.mnemonicToSeed(mnemonic)
|
||||||
|
var seedHex = bip39.mnemonicToSeedHex(mnemonic)
|
||||||
|
|
||||||
|
t.plan(2)
|
||||||
|
t.equal(seed.toString('hex'), seedHex)
|
||||||
|
t.equal(seedHex, '5cf2d4a8b0355e90295bdfc565a022a409af063d5365bb57bf74d9528f494bfa4400f53d8349b80fdae44082d7f9541e1dba2b003bcfec9d0d53781ca676651f')
|
||||||
|
t.equal(bip39.validateMnemonic(mnemonic), false)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('generateMnemonic can vary entropy length', function (t) {
|
||||||
|
var words = bip39.generateMnemonic(96).split(' ')
|
||||||
|
|
||||||
|
t.plan(1)
|
||||||
|
t.equal(words.length, 9, 'can vary generated entropy bit length')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('generateMnemonic only requests the exact amount of data from an RNG', function (t) {
|
||||||
|
t.plan(1)
|
||||||
|
|
||||||
|
bip39.generateMnemonic(96, function (size) {
|
||||||
|
t.equal(size, 96 / 8)
|
||||||
|
return new Buffer(size)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('validateMnemonic', function (t) {
|
||||||
|
t.plan(4)
|
||||||
|
|
||||||
|
t.equal(bip39.validateMnemonic('sleep kitten'), false, 'fails for a mnemonic that is too short')
|
||||||
|
t.equal(bip39.validateMnemonic('sleep kitten sleep kitten sleep kitten'), false, 'fails for a mnemonic that is too short')
|
||||||
|
t.equal(bip39.validateMnemonic('turtle front uncle idea crush write shrug there lottery flower risky shell'), false, 'fails if mnemonic words are not in the word list')
|
||||||
|
t.equal(bip39.validateMnemonic('sleep kitten sleep kitten sleep kitten sleep kitten sleep kitten sleep kitten'), false, 'fails for invalid checksum')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('exposes standard wordlists', function (t) {
|
||||||
|
t.plan(2)
|
||||||
|
t.same(bip39.wordlists.EN, WORDLISTS.english)
|
||||||
|
t.equal(bip39.wordlists.EN.length, 2048)
|
||||||
|
})
|
||||||
|
|
|
@ -130,12 +130,12 @@
|
||||||
[
|
[
|
||||||
"00000000000000000000000000000000",
|
"00000000000000000000000000000000",
|
||||||
"aband0n aband0n aband0n aband0n aband0n aband0n aband0n aband0n aband0n aband0n aband0n ab0ut",
|
"aband0n aband0n aband0n aband0n aband0n aband0n aband0n aband0n aband0n aband0n aband0n ab0ut",
|
||||||
"c55257c360c07c72029aebc1b53c05ed0362ada38ead3e3e9efa3708e53495531f09a6987599d18264c1e1c92f2cf141630c7a3c4ab7c81b2f001698e7463b04"
|
"a3f1b782bc3315cea2f93e8a6db3190a18b4870afe6fb40f6e3ac2fdc2216dfe33b7ef97e31845f710231d8a7a30a49fe82df5707f4a35917a92337a4da8184d"
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"15da872c95a13dd738fbf50e427583ad61f18fd99f628c417a61cf8343c90419",
|
"15da872c95a13dd738fbf50e427583ad61f18fd99f628c417a61cf8343c90419",
|
||||||
"b3y0nd 5tag3 5l33p cl1p b3cau53 tw15t t0k3n l3af at0m b3auty g3n1u5 f00d bu51n355 51d3 gr1d unabl3 m1ddl3 arm3d 0b53rv3 pa1r cr0uch t0n1ght away c0c0nut",
|
"b3y0nd 5tag3 5l33p cl1p b3cau53 tw15t t0k3n l3af at0m b3auty g3n1u5 f00d bu51n355 51d3 gr1d unabl3 m1ddl3 arm3d 0b53rv3 pa1r cr0uch t0n1ght away c0c0nut",
|
||||||
"b15509eaa2d09d3efd3e006ef42151b30367dc6e3aa5e44caba3fe4d3e352e65101fbdb86a96776b91946ff06f8eac594dc6ee1d3e82a42dfe1b40fef6bcc3fd"
|
"2e9a0929ca67cd8c1a11cf71abee2c8b51c2555758f37a133ea9f491f55c352a4a831b2bf8dda61e9a4ed0ffeeae7324704f26d1304ab35ffebf8c997f73badd"
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"japanese": [
|
"japanese": [
|
||||||
|
|
Loading…
Reference in New Issue