From 667fa4b7968aec86d7a6adf1ed65f9ed81fdd9df Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Thu, 30 Jun 2016 06:50:29 -0700 Subject: [PATCH] bip39 again. --- lib/bcoin/hd.js | 231 ++++++++++++++++++++++++------------------------ 1 file changed, 117 insertions(+), 114 deletions(-) diff --git a/lib/bcoin/hd.js b/lib/bcoin/hd.js index de01b05a..a3964dad 100644 --- a/lib/bcoin/hd.js +++ b/lib/bcoin/hd.js @@ -198,118 +198,6 @@ Mnemonic.fromOptions = function fromOptions(options) { return new Mnemonic().fromOptions(options); }; -/** - * Inject properties from entropy. - * @private - * @param {Buffer} entropy - * @param {String?} lang - */ - -Mnemonic.prototype.fromEntropy = function fromEntropy(entropy, lang) { - assert(Buffer.isBuffer(entropy)); - assert(entropy.length * 8 >= 128); - assert((entropy.length * 8) % 32 === 0); - assert(!lang || Mnemonic.languages.indexOf(lang) !== -1); - - this.entropy = entropy; - this.bits = entropy.length * 8; - - if (lang) - this.language = lang; - - return this; -}; - -/** - * Instantiate mnemonic from entropy. - * @param {Buffer} entropy - * @param {String?} lang - * @returns {Mnemonic} - */ - -Mnemonic.fromEntropy = function fromEntropy(entropy, lang) { - return new Mnemonic().fromEntropy(entropy, lang); -}; - -/** - * Inject properties from phrase. - * @private - * @param {String} phrase - */ - -Mnemonic.prototype.fromPhrase = function fromPhrase(phrase) { - var i, j, bits, pos, oct, bit, b, ent, entropy, lang; - var chk, word, wordlist, index, cbits, cbytes, words; - - assert(typeof phrase === 'string'); - - words = phrase.split(/[ \u3000]+/); - bits = words.length * 11; - lang = Mnemonic.getLanguage(words[0]); - ent = new Buffer(Math.ceil(bits / 8)); - wordlist = Mnemonic.getWordlist(lang); - - ent.fill(0); - - for (i = 0; i < words.length; i++) { - word = words[i]; - index = wordlist.indexOf(word); - - if (index === -1) - throw new Error('Could not find word.'); - - for (j = 0; j < 11; j++) { - pos = i * 11 + j; - bit = pos % 8; - oct = (pos - bit) / 8; - b = (index >>> (10 - j)) & 1; - ent[oct] |= b << (7 - bit); - } - } - - // Checksum bits: - cbits = bits % 32; - cbytes = Math.ceil(cbits / 8); - - entropy = ent.slice(0, ent.length - cbytes); - - ent = ent.slice(ent.length - cbytes); - chk = utils.sha256(entropy); - - for (i = 0; i < cbits; i++) { - bit = i % 8; - oct = (i - bit) / 8; - b = (ent[oct] >>> (7 - bit)) & 1; - j = (chk[oct] >>> (7 - bit)) & 1; - if (b !== j) - throw new Error('Invalid checksum.'); - } - - bits -= cbits; - - assert(bits / 8 === entropy.length); - assert(bits >= 128); - assert(bits % 32 === 0); - - this.bits = bits; - this.language = lang; - this.entropy = entropy; - this.phrase = phrase; - - return this; -}; - -/** - * Instantiate mnemonic from a phrase (validates checksum). - * @param {String} phrase - * @returns {Mnemonic} - * @throws on bad checksum - */ - -Mnemonic.fromPhrase = function fromPhrase(phrase) { - return new Mnemonic().fromPhrase(phrase); -}; - /** * Generate the seed. * @param {String?} passphrase @@ -407,6 +295,117 @@ Mnemonic.prototype.getPhrase = function getPhrase() { return phrase; }; +/** + * Inject properties from phrase. + * @private + * @param {String} phrase + */ + +Mnemonic.prototype.fromPhrase = function fromPhrase(phrase) { + var i, j, bits, pos, oct, bit, b, ent, entropy, lang; + var chk, word, wordlist, index, cbits, cbytes, words; + + assert(typeof phrase === 'string'); + + words = phrase.split(/[ \u3000]+/); + bits = words.length * 11; + lang = Mnemonic.getLanguage(words[0]); + ent = new Buffer(Math.ceil(bits / 8)); + wordlist = Mnemonic.getWordlist(lang); + + ent.fill(0); + + for (i = 0; i < words.length; i++) { + word = words[i]; + index = wordlist.indexOf(word); + + if (index === -1) + throw new Error('Could not find word.'); + + for (j = 0; j < 11; j++) { + pos = i * 11 + j; + bit = pos % 8; + oct = (pos - bit) / 8; + b = (index >>> (10 - j)) & 1; + ent[oct] |= b << (7 - bit); + } + } + + // Checksum bits: + cbits = bits % 32; + cbytes = Math.ceil(cbits / 8); + + entropy = ent.slice(0, ent.length - cbytes); + ent = ent.slice(ent.length - cbytes); + chk = utils.sha256(entropy); + + for (i = 0; i < cbits; i++) { + bit = i % 8; + oct = (i - bit) / 8; + b = (ent[oct] >>> (7 - bit)) & 1; + j = (chk[oct] >>> (7 - bit)) & 1; + if (b !== j) + throw new Error('Invalid checksum.'); + } + + bits -= cbits; + + assert(bits / 8 === entropy.length); + assert(bits >= 128); + assert(bits % 32 === 0); + + this.bits = bits; + this.language = lang; + this.entropy = entropy; + this.phrase = phrase; + + return this; +}; + +/** + * Instantiate mnemonic from a phrase (validates checksum). + * @param {String} phrase + * @returns {Mnemonic} + * @throws on bad checksum + */ + +Mnemonic.fromPhrase = function fromPhrase(phrase) { + return new Mnemonic().fromPhrase(phrase); +}; + +/** + * Inject properties from entropy. + * @private + * @param {Buffer} entropy + * @param {String?} lang + */ + +Mnemonic.prototype.fromEntropy = function fromEntropy(entropy, lang) { + assert(Buffer.isBuffer(entropy)); + assert(entropy.length * 8 >= 128); + assert((entropy.length * 8) % 32 === 0); + assert(!lang || Mnemonic.languages.indexOf(lang) !== -1); + + this.entropy = entropy; + this.bits = entropy.length * 8; + + if (lang) + this.language = lang; + + return this; +}; + +/** + * Instantiate mnemonic from entropy. + * @param {Buffer} entropy + * @param {String?} lang + * @returns {Mnemonic} + */ + +Mnemonic.fromEntropy = function fromEntropy(entropy, lang) { + return new Mnemonic().fromEntropy(entropy, lang); +}; + /** * Determine a single word's language. * @param {String} word @@ -510,9 +509,12 @@ Mnemonic.fromJSON = function fromJSON(json) { Mnemonic.prototype.toRaw = function toRaw(writer) { var p = new BufferWriter(writer); + var lang = Mnemonic.languages.indexOf(this.language); + + assert(lang !== -1); p.writeU16(this.bits); - p.writeVarString(this.language, 'utf8'); + p.writeU8(lang); p.writeBytes(this.getEntropy()); p.writeVarString(this.getPhrase(), 'utf8'); p.writeVarString(this.passphrase, 'utf8'); @@ -533,11 +535,12 @@ Mnemonic.prototype.fromRaw = function fromRaw(data) { var p = new BufferReader(data); this.bits = p.readU16(); - this.language = p.readVarString('utf8'); + this.language = Mnemonic.languages[p.readU8()]; this.entropy = p.readBytes(this.bits / 8); this.phrase = p.readVarString('utf8'); this.passphrase = p.readVarString('utf8'); + assert(this.language); assert(this.bits >= 128); assert(this.bits % 32 === 0);