mnemonic: optimize fromPhrase.

This commit is contained in:
Christopher Jeffrey 2017-08-09 18:17:25 -07:00
parent fbd99ea1b9
commit bff9e25796
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD

View File

@ -19,6 +19,12 @@ const wordlist = require('./wordlist');
const common = require('./common'); const common = require('./common');
const nfkd = require('../utils/nfkd'); const nfkd = require('../utils/nfkd');
/*
* Constants
*/
const wordlistCache = new Map();
/** /**
* HD Mnemonic * HD Mnemonic
* @alias module:hd.Mnemonic * @alias module:hd.Mnemonic
@ -191,7 +197,7 @@ Mnemonic.prototype.getPhrase = function getPhrase() {
// Build the mnemonic by reading // Build the mnemonic by reading
// 11 bit indexes from the entropy. // 11 bit indexes from the entropy.
const wordlist = Mnemonic.getWordlist(this.language); const list = Mnemonic.getWordlist(this.language);
let phrase = []; let phrase = [];
for (let i = 0; i < bits / 11; i++) { for (let i = 0; i < bits / 11; i++) {
@ -203,7 +209,7 @@ Mnemonic.prototype.getPhrase = function getPhrase() {
index <<= 1; index <<= 1;
index |= (entropy[oct] >>> (7 - bit)) & 1; index |= (entropy[oct] >>> (7 - bit)) & 1;
} }
phrase.push(wordlist[index]); phrase.push(list.words[index]);
} }
// Japanese likes double-width spaces. // Japanese likes double-width spaces.
@ -224,6 +230,9 @@ Mnemonic.prototype.getPhrase = function getPhrase() {
*/ */
Mnemonic.prototype.fromPhrase = function fromPhrase(phrase) { Mnemonic.prototype.fromPhrase = function fromPhrase(phrase) {
assert(typeof phrase === 'string');
assert(phrase.length <= 1000);
const words = phrase.split(/[ \u3000]+/); const words = phrase.split(/[ \u3000]+/);
let bits = words.length * 11; let bits = words.length * 11;
const cbits = bits % 32; const cbits = bits % 32;
@ -240,14 +249,14 @@ Mnemonic.prototype.fromPhrase = function fromPhrase(phrase) {
ent.fill(0); ent.fill(0);
const lang = Mnemonic.getLanguage(words[0]); const lang = Mnemonic.getLanguage(words[0]);
const wordlist = Mnemonic.getWordlist(lang); const list = Mnemonic.getWordlist(lang);
// Rebuild entropy bytes. // Rebuild entropy bytes.
for (let i = 0; i < words.length; i++) { for (let i = 0; i < words.length; i++) {
const word = words[i]; const word = words[i];
const index = wordlist.indexOf(word); const index = list.map.get(word);
if (index === -1) if (index == null)
throw new Error('Could not find word.'); throw new Error('Could not find word.');
for (let j = 0; j < 11; j++) { for (let j = 0; j < 11; j++) {
@ -267,9 +276,9 @@ Mnemonic.prototype.fromPhrase = function fromPhrase(phrase) {
for (let i = 0; i < cbits; i++) { for (let i = 0; i < cbits; i++) {
const bit = i % 8; const bit = i % 8;
const oct = (i - bit) / 8; const oct = (i - bit) / 8;
const a = (chk1[oct] >>> (7 - bit)) & 1; const b1 = (chk1[oct] >>> (7 - bit)) & 1;
const b = (chk2[oct] >>> (7 - bit)) & 1; const b2 = (chk2[oct] >>> (7 - bit)) & 1;
if (a !== b) if (b1 !== b2)
throw new Error('Invalid checksum.'); throw new Error('Invalid checksum.');
} }
@ -337,8 +346,8 @@ Mnemonic.fromEntropy = function fromEntropy(entropy, lang) {
Mnemonic.getLanguage = function getLanguage(word) { Mnemonic.getLanguage = function getLanguage(word) {
for (const lang of Mnemonic.languages) { for (const lang of Mnemonic.languages) {
const wordlist = Mnemonic.getWordlist(lang); const list = Mnemonic.getWordlist(lang);
if (wordlist.indexOf(word) !== -1) if (list.map.has(word))
return lang; return lang;
} }
@ -347,12 +356,22 @@ Mnemonic.getLanguage = function getLanguage(word) {
/** /**
* Retrieve the wordlist for a language. * Retrieve the wordlist for a language.
* @param {String} language * @param {String} lang
* @returns {String[]} * @returns {Object}
*/ */
Mnemonic.getWordlist = function getWordlist(language) { Mnemonic.getWordlist = function getWordlist(lang) {
return wordlist.get(language); const cache = wordlistCache.get(lang);
if (cache)
return cache;
const words = wordlist.get(lang);
const list = new WordList(words);
wordlistCache.set(lang, list);
return list;
}; };
/** /**
@ -530,6 +549,23 @@ Mnemonic.isMnemonic = function isMnemonic(obj) {
&& typeof obj.toSeed === 'function'; && typeof obj.toSeed === 'function';
}; };
/**
* Word List
* @constructor
* @ignore
* @param {Array} words
*/
function WordList(words) {
this.words = words;
this.map = new Map();
for (let i = 0; i < words.length; i++) {
const word = words[i];
this.map.set(word, i);
}
}
/* /*
* Expose * Expose
*/ */