Comparing version 1.2.0 to 2.0.0
97
index.js
@@ -0,50 +1,18 @@ | ||
var assert = require('assert') | ||
var CryptoJS = require('crypto-js') | ||
var crypto = require('crypto') | ||
var secureRandom = require('secure-random') | ||
var includeFolder = require('include-folder') | ||
var path = require('path') | ||
var wordlists = includeFolder(path.join(__dirname, 'wordlists')) | ||
var DEFAULT_WORDLIST = require('./wordlists/en.json') | ||
function BIP39(language) { | ||
language = language || 'en' | ||
this.wordlist = JSON.parse(wordlists[language]) | ||
} | ||
BIP39.prototype.mnemonicToSeed = function(mnemonic, password) { | ||
var options = {iterations: 2048, hasher: CryptoJS.algo.SHA512, keySize: 512/32} | ||
function mnemonicToSeedHex(mnemonic, password) { | ||
var options = { iterations: 2048, hasher: CryptoJS.algo.SHA512, keySize: 512/32 } | ||
return CryptoJS.PBKDF2(mnemonic, salt(password), options).toString(CryptoJS.enc.Hex) | ||
} | ||
BIP39.prototype.entropyToMnemonic = function(entropy) { | ||
var entropyBuffer = new Buffer(entropy, 'hex') | ||
var entropyBits = bytesToBinary([].slice.call(entropyBuffer)) | ||
var checksum = checksumBits(entropyBuffer) | ||
function mnemonicToEntropy(mnemonic, wordlist) { | ||
wordlist = wordlist || DEFAULT_WORDLIST | ||
var bits = entropyBits + checksum | ||
var chunks = bits.match(/(.{1,11})/g) | ||
var words = chunks.map(function(binary) { | ||
var index = parseInt(binary, 2) | ||
return this.wordlist[index] | ||
}, this) | ||
return words.join(' ') | ||
} | ||
BIP39.prototype.generateMnemonic = function(strength, rng) { | ||
strength = strength || 128 | ||
rng = rng || secureRandom.randomBuffer | ||
var hex = rng(strength / 8).toString('hex') | ||
return this.entropyToMnemonic(hex) | ||
} | ||
BIP39.prototype.validate = function(mnemonic) { | ||
var words = mnemonic.split(' ') | ||
assert(words.length % 3 === 0, 'Invalid mnemonic') | ||
if (words.length % 3 !== 0) return false | ||
var wordlist = this.wordlist | ||
var belongToList = words.every(function(word) { | ||
@@ -54,3 +22,3 @@ return wordlist.indexOf(word) > -1 | ||
if (!belongToList) return false | ||
assert(belongToList, 'Invalid mnemonic') | ||
@@ -75,5 +43,44 @@ // convert word indices to 11 bit binary strings | ||
return newChecksum === checksum | ||
assert(newChecksum === checksum, '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 || crypto.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) { | ||
@@ -110,2 +117,8 @@ var hash = crypto.createHash('sha256').update(entropyBuffer).digest() | ||
module.exports = BIP39 | ||
module.exports = { | ||
mnemonicToSeedHex: mnemonicToSeedHex, | ||
mnemonicToEntropy: mnemonicToEntropy, | ||
entropyToMnemonic: entropyToMnemonic, | ||
generateMnemonic: generateMnemonic, | ||
validateMnemonic: validateMnemonic | ||
} |
{ | ||
"name": "bip39", | ||
"version": "1.2.0", | ||
"version": "2.0.0", | ||
"description": "Bitcoin BIP39: Mnemonic code for generating deterministic keys", | ||
@@ -11,2 +11,9 @@ "main": "index.js", | ||
"author": "Wei Lu", | ||
"contributors": [ | ||
{ | ||
"name": "Daniel Cousens", | ||
"email": "email@dcousens.com", | ||
"url": "http://dcousens.com" | ||
} | ||
], | ||
"repository": { | ||
@@ -18,14 +25,8 @@ "type": "git", | ||
"dependencies": { | ||
"crypto-js": "^3.1.2-2", | ||
"require-json-tree": "~1.1.0", | ||
"include-folder": "~0.7.0", | ||
"secure-random": "1.0.0" | ||
"crypto-js": "^3.1.2-2" | ||
}, | ||
"devDependencies": { | ||
"mocha": "^1.17.1", | ||
"folderify": "~0.6.0" | ||
}, | ||
"browserify": { | ||
"transform": [ "folderify" ] | ||
"browserify": "^5.9.1", | ||
"mocha": "^1.17.1" | ||
} | ||
} |
@@ -1,2 +0,2 @@ | ||
bip39 | ||
BIP39 | ||
===== | ||
@@ -11,15 +11,15 @@ | ||
```javascript | ||
var BIP39 = require('bip39') | ||
var BIP39 = require('BIP39') | ||
bip39 = new BIP39() // 'en' is the default language | ||
bip39.entropyToMnemonic('1337') // hex input | ||
var mnemonic = BIP39.entropyToMnemonic('1337') // hex input, defaults to BIP39 English word list | ||
// 'basket actual' | ||
bip39.mnemonicToSeed('basket actual') // wait for it... | ||
// or | ||
mnemonic = BIP39.generateMnemonic() // strength defaults to 128 bits | ||
// 'seed sock milk update focus rotate barely fade car face mechanic mercy' | ||
BIP39.mnemonicToSeedHex('basket actual') // wait for it... | ||
// '5cf2d4a8b0355e90295bdfc565a022a409af063d5365bb57bf74d9528f494bfa4400f53d8349b80fdae44082d7f9541e1dba2b003bcfec9d0d53781ca676651f' | ||
``` | ||
bip39.generateMnemonic() // strength defaults to 128 bits | ||
// 'seed sock milk update focus rotate barely fade car face mechanic mercy' | ||
``` | ||
### Browser | ||
@@ -32,2 +32,1 @@ | ||
After loading this file in your browser, you will be able to use the global `BIP39` object. | ||
var assert = require('assert') | ||
var wordlist = require('../wordlists/en.json') | ||
var vectors = require('./vectors.json').english | ||
var BIP39 = require('../index.js') | ||
var bip39 = new BIP39() | ||
describe('constructor', function() { | ||
it('defaults language to english', function() { | ||
assert.deepEqual(bip39.wordlist, wordlist) | ||
}) | ||
}) | ||
var wordlists = { | ||
english: require('../wordlists/en.json'), | ||
custom: require('./wordlist.json') | ||
} | ||
describe('mnemonicToSeed', function() { | ||
vectors.forEach(function(v, i) { | ||
it('works for tests vector ' + i, function() { | ||
assert.equal(bip39.mnemonicToSeed(v[1], 'TREZOR'), v[2]) | ||
var vectors = require('./vectors.json') | ||
describe('BIP39', function() { | ||
describe('mnemonicToSeedHex', function() { | ||
this.timeout(20000) | ||
vectors.english.forEach(function(v, i) { | ||
it('works for tests vector ' + i, function() { | ||
assert.equal(BIP39.mnemonicToSeedHex(v[1], 'TREZOR'), v[2]) | ||
}) | ||
}) | ||
}) | ||
}) | ||
describe('entropyToMnemonic', function() { | ||
vectors.forEach(function(v, i) { | ||
it('works for tests vector ' + i, function() { | ||
assert.equal(bip39.entropyToMnemonic(v[0]), v[1]) | ||
describe('mnemonicToEntropy', function() { | ||
vectors.english.forEach(function(v, i) { | ||
it('works for tests vector ' + i, function() { | ||
assert.equal(BIP39.mnemonicToEntropy(v[1]), v[0]) | ||
}) | ||
}) | ||
vectors.custom.forEach(function(v, i) { | ||
it('works for custom test vector ' + i, function() { | ||
assert.equal(BIP39.mnemonicToEntropy(v[1], wordlists.custom), v[0]) | ||
}) | ||
}) | ||
}) | ||
}) | ||
describe('generateMnemonic', function() { | ||
it('generates a mnemonic', function() { | ||
var mnemonic = bip39.generateMnemonic(96) | ||
var words = mnemonic.split(' ') | ||
describe('entropyToMnemonic', function() { | ||
vectors.english.forEach(function(v, i) { | ||
it('works for tests vector ' + i, function() { | ||
assert.equal(BIP39.entropyToMnemonic(v[0]), v[1]) | ||
}) | ||
}) | ||
assert.equal(words.length, 9) | ||
vectors.custom.forEach(function(v, i) { | ||
it('works for custom test vector ' + i, function() { | ||
assert.equal(BIP39.entropyToMnemonic(v[0], wordlists.custom), v[1]) | ||
}) | ||
}) | ||
}) | ||
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 | ||
} | ||
describe('generateMnemonic', function() { | ||
it('generates a mnemonic', function() { | ||
var mnemonic = BIP39.generateMnemonic(96) | ||
var words = mnemonic.split(' ') | ||
var mnemonic = bip39.generateMnemonic(64, rng) | ||
assert.equal(mnemonic, 'advice cage absurd amount doctor act') | ||
}) | ||
}) | ||
assert.equal(words.length, 9) | ||
}) | ||
describe('validate', function() { | ||
vectors.forEach(function(v, i) { | ||
it('passes check ' + i, function() { | ||
assert(bip39.validate(v[1])) | ||
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('fails for mnemonics of wrong length', function() { | ||
assert(!bip39.validate('sleep kitten')) | ||
assert(!bip39.validate('sleep kitten sleep kitten sleep kitten')) | ||
}) | ||
it('adheres to a custom wordlist', function() { | ||
var rng = function(size) { | ||
var buffer = new Buffer(size) | ||
buffer.fill(4) // guaranteed random | ||
return buffer | ||
} | ||
it('fails for mnemonics that contains words not from the word list', function() { | ||
assert(!bip39.validate("turtle front uncle idea crush write shrug there lottery flower risky shell")) | ||
var mnemonic = BIP39.generateMnemonic(64, rng, wordlists.custom) | ||
assert.equal(mnemonic, 'adv1c3 cag3 ab5urd am0unt d0ct0r act') | ||
}) | ||
}) | ||
it('fails for mnemonics of invalid checksum', function() { | ||
assert(!bip39.validate('sleep kitten sleep kitten sleep kitten sleep kitten sleep kitten sleep kitten')) | ||
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')) | ||
}) | ||
}) | ||
}) |
@@ -123,3 +123,15 @@ { | ||
] | ||
], | ||
"custom": [ | ||
[ | ||
"00000000000000000000000000000000", | ||
"aband0n aband0n aband0n aband0n aband0n aband0n aband0n aband0n aband0n aband0n aband0n ab0ut", | ||
"c55257c360c07c72029aebc1b53c05ed0362ada38ead3e3e9efa3708e53495531f09a6987599d18264c1e1c92f2cf141630c7a3c4ab7c81b2f001698e7463b04" | ||
], | ||
[ | ||
"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", | ||
"b15509eaa2d09d3efd3e006ef42151b30367dc6e3aa5e44caba3fe4d3e352e65101fbdb86a96776b91946ff06f8eac594dc6ee1d3e82a42dfe1b40fef6bcc3fd" | ||
] | ||
] | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
64200
1
9
4417
31
- Removedinclude-folder@~0.7.0
- Removedrequire-json-tree@~1.1.0
- Removedsecure-random@1.0.0
- Removedinclude-folder@0.7.0(transitive)
- Removedlodash@2.4.2(transitive)
- Removedrequire-json-tree@1.1.0(transitive)
- Removedsecure-random@1.0.0(transitive)