faster mnemonic creation.

This commit is contained in:
Christopher Jeffrey 2016-04-30 01:52:30 -07:00
parent 27d5f2370b
commit 96139ad31c
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
2 changed files with 38 additions and 26 deletions

View File

@ -104,7 +104,7 @@ var unorm = require('../../vendor/unorm');
* be generated if not present).
* @param {String?} options.passphrase - Optional salt for
* key stretching (empty string if not present).
* @param {String?} options.lang - Language.
* @param {String?} options.language - Language.
*/
function Mnemonic(options) {
@ -118,7 +118,7 @@ function Mnemonic(options) {
this.entropy = options.entropy;
this.phrase = options.phrase;
this.passphrase = options.passphrase || '';
this.lang = options.lang || 'english';
this.language = options.language || 'english';
this.seed = null;
assert(this.bits >= 128);
@ -154,29 +154,40 @@ Mnemonic.prototype.toSeed = function toSeed() {
*/
Mnemonic.prototype.createMnemonic = function createMnemonic() {
var bin = '';
var mnemonic = [];
var wordlist = Mnemonic.getWordlist(this.lang);
var i, wi, hash, bits;
var bits = this.entropy.length * 8;
var wordlist = Mnemonic.getWordlist(this.language);
var i, j, word, entropy, oct, bit;
for (i = 0; i < this.entropy.length; i++)
bin += ('00000000' + this.entropy[i].toString(2)).slice(-8);
// Append the hash to the entropy to
// make things easy when grabbing
// the checksum bits.
entropy = Buffer.concat([
this.entropy,
utils.sha256(this.entropy)
]);
hash = utils.sha256(this.entropy);
bits = new bn(hash).toString(2);
while (bits.length % 256 !== 0)
bits = '0' + bits;
// Include the first `ENT / 32` bits
// of the hash (the checksum).
bits += bits / 32;
bin += bits.slice(0, (this.entropy.length * 8) / 32);
assert(bin.length % 11 === 0);
for (i = 0; i < bin.length / 11; i++) {
wi = parseInt(bin.slice(i * 11, (i + 1) * 11), 2);
mnemonic.push(wordlist[wi]);
// Build the mnemonic by reading
// 11 bit indexes from the entropy.
for (i = 0; i < bits; i++) {
i--;
word = 0;
for (j = 0; j < 11; j++) {
i++;
oct = i / 8 | 0;
bit = i % 8;
word <<= 1;
word |= (entropy[oct] >>> (7 - bit)) & 1;
}
mnemonic.push(wordlist[word]);
}
if (this.lang === 'japanese')
// Japanese likes double-width spaces.
if (this.language === 'japanese')
return mnemonic.join('\u3000');
return mnemonic.join(' ');
@ -184,12 +195,12 @@ Mnemonic.prototype.createMnemonic = function createMnemonic() {
/**
* Retrieve the wordlist for a language.
* @param {String} lang
* @param {String} language
* @returns {String[]}
*/
Mnemonic.getWordlist = function getWordlist(lang) {
switch (lang) {
Mnemonic.getWordlist = function getWordlist(language) {
switch (language) {
case 'simplified chinese':
return require('../../etc/chinese-simplified.js');
case 'traditional chinese':
@ -203,7 +214,7 @@ Mnemonic.getWordlist = function getWordlist(lang) {
case 'japanese':
return require('../../etc/japanese.js');
default:
assert(false, 'Unknown language: ' + lang);
assert(false, 'Unknown language: ' + language);
}
};
@ -656,7 +667,8 @@ HDPrivateKey.prototype.derivePath = function derivePath(path) {
/**
* Create an hd private key from a seed.
* @param {Buffer|Mnemonic|Object} options - A buffer, HD seed, or HD seed options.
* @param {Buffer|Mnemonic|Object} options - A buffer,
* HD seed, or HD seed options.
* @param {String?} networkType
* @returns {Object} A "naked" key (a
* plain javascript object which is suitable

View File

@ -13,7 +13,7 @@ describe('Mnemonic', function() {
var xpriv = data[3];
it('should create an english mnemonic (' + i + ')', function() {
var mnemonic = new bcoin.hd.mnemonic({
lang: 'english',
language: 'english',
entropy: entropy,
passphrase: 'TREZOR'
});
@ -32,7 +32,7 @@ describe('Mnemonic', function() {
var xpriv = data.bip32_xprv;
it('should create a japanese mnemonic (' + i + ')', function() {
var mnemonic = new bcoin.hd.mnemonic({
lang: 'japanese',
language: 'japanese',
entropy: entropy,
passphrase: passphrase
});