Comparing version 1.1.0 to 1.2.0
92
index.js
var CryptoJS = require('crypto-js') | ||
var path = require('path') | ||
var includeFolder = require('include-folder') | ||
var Wordlists = includeFolder(path.join(__dirname, 'wordlists')) | ||
var crypto = require('crypto') | ||
var secureRandom = require('secure-random') | ||
module.exports = BIP39 | ||
var includeFolder = require('include-folder') | ||
var path = require('path') | ||
var wordlists = includeFolder(path.join(__dirname, 'wordlists')) | ||
function BIP39(language){ | ||
function BIP39(language) { | ||
language = language || 'en' | ||
this.wordlist = JSON.parse(Wordlists[language]) | ||
this.wordlist = JSON.parse(wordlists[language]) | ||
} | ||
BIP39.prototype.mnemonicToSeed = function(mnemonic, password){ | ||
BIP39.prototype.mnemonicToSeed = function(mnemonic, password) { | ||
var options = {iterations: 2048, hasher: CryptoJS.algo.SHA512, keySize: 512/32} | ||
@@ -19,55 +19,70 @@ return CryptoJS.PBKDF2(mnemonic, salt(password), options).toString(CryptoJS.enc.Hex) | ||
BIP39.prototype.entropyToMnemonic = function(entropy){ | ||
BIP39.prototype.entropyToMnemonic = function(entropy) { | ||
var entropyBuffer = new Buffer(entropy, 'hex') | ||
var hash = crypto.createHash('sha256').update(entropyBuffer).digest() | ||
var entropyBits = bytesToBinary([].slice.call(entropyBuffer)) | ||
var checksum = checksumBits(entropyBuffer) | ||
var combined = Buffer.concat([entropyBuffer, hash]) | ||
var bitLength = entropyBuffer.length * 8 + entropyBuffer.length / 4 | ||
var bits = bytesToBinary([].slice.call(combined)).substr(0, bitLength) | ||
var bits = entropyBits + checksum | ||
var chunks = bits.match(/(.{1,11})/g) | ||
var chunks = (bits).match(/(.{1,11})/g) | ||
return chunks.map(function(binary){ | ||
var words = chunks.map(function(binary) { | ||
var index = parseInt(binary, 2) | ||
return this.wordlist[index] | ||
}, this).join(' ') | ||
}, this) | ||
return words.join(' ') | ||
} | ||
BIP39.prototype.generateMnemonic = function(strength){ | ||
BIP39.prototype.generateMnemonic = function(strength, rng) { | ||
strength = strength || 128 | ||
var entropy = crypto.randomBytes(strength/8).toString('hex') | ||
return this.entropyToMnemonic(entropy) | ||
rng = rng || secureRandom.randomBuffer | ||
var hex = rng(strength / 8).toString('hex') | ||
return this.entropyToMnemonic(hex) | ||
} | ||
BIP39.prototype.validate = function(mnemonic){ | ||
mnemonic = mnemonic.split(' ') | ||
BIP39.prototype.validate = function(mnemonic) { | ||
var words = mnemonic.split(' ') | ||
if(mnemonic.length % 3 !== 0) return false | ||
if (words.length % 3 !== 0) return false | ||
var wordlist = this.wordlist | ||
var belongToList = mnemonic.reduce(function(memo, m){ | ||
return memo && (wordlist.indexOf(m) > -1) | ||
}, true) | ||
var belongToList = words.every(function(word) { | ||
return wordlist.indexOf(word) > -1 | ||
}) | ||
if(!belongToList) return false | ||
if (!belongToList) return false | ||
var bits = mnemonic.map(function(m){ | ||
var id = wordlist.indexOf(m) | ||
return lpad(id.toString(2), '0', 11) | ||
// 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('') | ||
var length = bits.length | ||
var dividerIndex = Math.floor(length / 33) * 32 | ||
var checksum = bits.substring(dividerIndex) | ||
// 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) | ||
var data = bits.substring(0, dividerIndex) | ||
var bytes = data.match(/(.{1,8})/g).map(function(bin){ | ||
// calculate the checksum and compare | ||
var entropyBytes = entropy.match(/(.{1,8})/g).map(function(bin) { | ||
return parseInt(bin, 2) | ||
}) | ||
var hash = crypto.createHash('sha256').update(new Buffer(bytes)).digest() | ||
var checksumBits = bytesToBinary([].slice.call(hash)) | ||
var checksum2 = checksumBits.substr(0, length - dividerIndex) | ||
var entropyBuffer = new Buffer(entropyBytes) | ||
var newChecksum = checksumBits(entropyBuffer) | ||
return checksum === checksum2 | ||
return newChecksum === checksum | ||
} | ||
function checksumBits(entropyBuffer) { | ||
var hash = crypto.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) | ||
} | ||
function salt(password) { | ||
@@ -77,3 +92,3 @@ return encode_utf8('mnemonic' + (password || '')) | ||
function encode_utf8(s){ | ||
function encode_utf8(s) { | ||
return unescape(encodeURIComponent(s)) | ||
@@ -95,1 +110,2 @@ } | ||
module.exports = BIP39 |
{ | ||
"name": "bip39", | ||
"version": "1.1.0", | ||
"version": "1.2.0", | ||
"description": "Bitcoin BIP39: Mnemonic code for generating deterministic keys", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "mocha --reporter list test/*.js" | ||
"test": "mocha --reporter list test/*.js", | ||
"compile": "browserify index.js -s BIP39 > bip39.js" | ||
}, | ||
@@ -18,3 +19,4 @@ "author": "Wei Lu", | ||
"require-json-tree": "~1.1.0", | ||
"include-folder": "~0.7.0" | ||
"include-folder": "~0.7.0", | ||
"secure-random": "1.0.0" | ||
}, | ||
@@ -21,0 +23,0 @@ "devDependencies": { |
@@ -24,1 +24,9 @@ bip39 | ||
``` | ||
### Browser | ||
Compile `bip39.js` with the following command: | ||
$ npm run compile | ||
After loading this file in your browser, you will be able to use the global `BIP39` object. | ||
@@ -0,10 +1,10 @@ | ||
var assert = require('assert') | ||
var wordlist = require('../wordlists/en.json') | ||
var vectors = require('./vectors.json').english | ||
var BIP39 = require('../index.js') | ||
var wordlist = require('../Wordlists/en.json') | ||
var assert = require('assert') | ||
var bip39 = new BIP39() | ||
describe('constructor', function(){ | ||
it('defaults language to english', function(){ | ||
describe('constructor', function() { | ||
it('defaults language to english', function() { | ||
assert.deepEqual(bip39.wordlist, wordlist) | ||
@@ -14,5 +14,5 @@ }) | ||
describe('mnemonicToSeed', function(){ | ||
vectors.forEach(function(v, i){ | ||
it('works for tests vector ' + i, function(){ | ||
describe('mnemonicToSeed', function() { | ||
vectors.forEach(function(v, i) { | ||
it('works for tests vector ' + i, function() { | ||
assert.equal(bip39.mnemonicToSeed(v[1], 'TREZOR'), v[2]) | ||
@@ -23,5 +23,5 @@ }) | ||
describe('entropyToMnemonic', function(){ | ||
vectors.forEach(function(v, i){ | ||
it('works for tests vector ' + i, function(){ | ||
describe('entropyToMnemonic', function() { | ||
vectors.forEach(function(v, i) { | ||
it('works for tests vector ' + i, function() { | ||
assert.equal(bip39.entropyToMnemonic(v[0]), v[1]) | ||
@@ -32,5 +32,25 @@ }) | ||
describe('validate', function(){ | ||
vectors.forEach(function(v, i){ | ||
it('passes check ' + i, function(){ | ||
describe('generateMnemonic', function() { | ||
it('generates a mnemonic', function() { | ||
var mnemonic = bip39.generateMnemonic(96) | ||
var words = mnemonic.split(' ') | ||
assert.equal(words.length, 9) | ||
}) | ||
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') | ||
}) | ||
}) | ||
describe('validate', function() { | ||
vectors.forEach(function(v, i) { | ||
it('passes check ' + i, function() { | ||
assert(bip39.validate(v[1])) | ||
@@ -40,3 +60,3 @@ }) | ||
it('fails for mnemonics of wrong length', function(){ | ||
it('fails for mnemonics of wrong length', function() { | ||
assert(!bip39.validate('sleep kitten')) | ||
@@ -46,9 +66,9 @@ assert(!bip39.validate('sleep kitten sleep kitten sleep kitten')) | ||
it('fails for mnemonics that contains words not from the word list', function(){ | ||
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")) | ||
}) | ||
it('fails for mnemonics of invalid checksum', function(){ | ||
it('fails for mnemonics of invalid checksum', function() { | ||
assert(!bip39.validate('sleep kitten sleep kitten sleep kitten sleep kitten sleep kitten sleep kitten')) | ||
}) | ||
}) |
Sorry, the diff of this file is not supported yet
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
37822
8
2312
32
4
+ Addedsecure-random@1.0.0
+ Addedsecure-random@1.0.0(transitive)