From 3cea8323b00952b6831ff5fe2e069c82a881ab21 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Sat, 14 May 2016 10:54:00 -0700 Subject: [PATCH] hd and ec refactor. --- lib/bcoin/ec.js | 18 +++++----- lib/bcoin/hd.js | 61 ++++++++++++++++----------------- lib/bcoin/protocol/constants.js | 3 +- 3 files changed, 38 insertions(+), 44 deletions(-) diff --git a/lib/bcoin/ec.js b/lib/bcoin/ec.js index 6fd3e7ef..7665410a 100644 --- a/lib/bcoin/ec.js +++ b/lib/bcoin/ec.js @@ -119,15 +119,16 @@ ec.rand = function rand(min, max) { */ ec.verify = function verify(msg, sig, key, historical, high) { - if (!Buffer.isBuffer(sig)) - return false; + if (key.getPublicKey) + key = key.getPublicKey(); + + assert(Buffer.isBuffer(msg)); + assert(Buffer.isBuffer(sig)); + assert(Buffer.isBuffer(key)); if (sig.length === 0) return false; - if (key.getPublicKey) - key = key.getPublicKey(); - if (key.length === 0) return false; @@ -150,14 +151,14 @@ ec.verify = function verify(msg, sig, key, historical, high) { return secp256k1.verify(msg, sig, key); } + // Make elliptic mimic secp256k1's // failure with high S values. if (!high && !ec.isLowS(sig)) return false; + return ec.elliptic.verify(msg, sig, key); } catch (e) { - // if (!ec.publicKeyVerify(key)) - // bcoin.debug('Public key is invalid.'); return false; } }; @@ -294,9 +295,6 @@ ec.isLowS = function isLowS(sig) { } } - // Technically a negative S value is low, - // but we don't want to ever use negative - // S values in bitcoin. if (sig.s.cmpn(0) <= 0) return false; diff --git a/lib/bcoin/hd.js b/lib/bcoin/hd.js index be15ca69..bad0237d 100644 --- a/lib/bcoin/hd.js +++ b/lib/bcoin/hd.js @@ -359,14 +359,14 @@ HD.isExtended = function isExtended(data) { HD.parsePath = function parsePath(path, max) { var parts = path.split('/'); var root = parts.shift(); - var indexes = []; + var result = []; var i, hardened, index; if (max == null) max = constants.hd.MAX_INDEX; if (constants.hd.PATH_ROOTS.indexOf(path) !== -1) - return indexes; + return result; if (constants.hd.PATH_ROOTS.indexOf(root) === -1) throw new Error('Bad path root.'); @@ -378,21 +378,21 @@ HD.parsePath = function parsePath(path, max) { if (hardened) index = index.slice(0, -1); - index = +index; - - if (!(index >= 0)) + if (!/^\d+$/.test(index)) throw new Error('Non-number path index.'); + index = +index; + if (hardened) index += constants.hd.HARDENED; if (!(index >= 0 && index < max)) throw new Error('Index out of range.'); - indexes.push(index); + result.push(index); } - return indexes; + return result; }; /** @@ -496,15 +496,16 @@ HDPrivateKey.prototype.__defineGetter__('xpubkey', function() { */ HDPrivateKey.prototype.derive = function derive(index, hardened) { - var cached, p, data, hash, leftPart, chainCode, privateKey, child; + var p, id, data, hash, left, chainCode, privateKey, child; if (typeof index === 'string') return this.derivePath(index); - cached = HD.cache.get(this.xprivkey + '/' + index); + id = this.xprivkey + '/' + index; + child = HD.cache.get(id); - if (cached) - return cached; + if (child) + return child; hardened = index >= constants.hd.HARDENED ? true : hardened; if (index < constants.hd.HARDENED && hardened) @@ -527,18 +528,16 @@ HDPrivateKey.prototype.derive = function derive(index, hardened) { data = p.render(); hash = utils.hmac('sha512', data, this.chainCode); - leftPart = new bn(hash.slice(0, 32)); + left = new bn(hash.slice(0, 32)); chainCode = hash.slice(32, 64); - privateKey = leftPart + privateKey = left .add(new bn(this.privateKey)) .mod(ec.elliptic.curve.n) .toBuffer('be', 32); - if (!this.fingerPrint) { - this.fingerPrint = utils.ripesha(this.publicKey) - .slice(0, constants.hd.PARENT_FINGERPRINT_SIZE); - } + if (!this.fingerPrint) + this.fingerPrint = utils.ripesha(this.publicKey).slice(0, 4); child = new HDPrivateKey({ network: this.network, @@ -549,7 +548,7 @@ HDPrivateKey.prototype.derive = function derive(index, hardened) { privateKey: privateKey }); - HD.cache.set(this.xprivkey + '/' + index, child); + HD.cache.set(id, child); return child; }; @@ -702,9 +701,6 @@ HDPrivateKey.prototype.derivePath = function derivePath(path) { HDPrivateKey.parseSeed = function parseSeed(seed, network) { var hash, chainCode, privateKey; - if (!seed) - seed = {}; - assert(Buffer.isBuffer(seed)); if (seed.length < constants.hd.MIN_ENTROPY @@ -759,6 +755,8 @@ HDPrivateKey.fromMnemonic = function fromMnemonic(mnemonic, network) { if (mnemonic.seed || mnemonic.phrase || mnemonic.entropy) return HDPrivateKey.fromSeed(mnemonic.toSeed(), network); + // Very unlikely, but not impossible + // to get an invalid private key. for (;;) { try { key = HDPrivateKey.fromSeed(mnemonic.toSeed(), network); @@ -1083,16 +1081,17 @@ HDPublicKey.prototype.__defineGetter__('xpubkey', function() { */ HDPublicKey.prototype.derive = function derive(index, hardened) { - var cached, p, data, hash, leftPart, chainCode; + var p, id, data, hash, left, chainCode; var publicPoint, point, publicKey, child; if (typeof index === 'string') return this.derivePath(index); - cached = HD.cache.get(this.xpubkey + '/' + index); + id = this.xpubkey + '/' + index; + child = HD.cache.get(id); - if (cached) - return cached; + if (child) + return child; if (index >= constants.hd.HARDENED || hardened) throw new Error('Index out of range.'); @@ -1106,18 +1105,16 @@ HDPublicKey.prototype.derive = function derive(index, hardened) { data = p.render(); hash = utils.hmac('sha512', data, this.chainCode); - leftPart = new bn(hash.slice(0, 32)); + left = new bn(hash.slice(0, 32)); chainCode = hash.slice(32, 64); publicPoint = ec.elliptic.curve.decodePoint(this.publicKey); - point = ec.elliptic.curve.g.mul(leftPart).add(publicPoint); + point = ec.elliptic.curve.g.mul(left).add(publicPoint); publicKey = new Buffer(point.encode('array', true)); assert(publicKey.length === 33); - if (!this.fingerPrint) { - this.fingerPrint = utils.ripesha(this.publicKey) - .slice(0, constants.hd.PARENT_FINGERPRINT_SIZE); - } + if (!this.fingerPrint) + this.fingerPrint = utils.ripesha(this.publicKey).slice(0, 4); child = new HDPublicKey({ network: this.network, @@ -1128,7 +1125,7 @@ HDPublicKey.prototype.derive = function derive(index, hardened) { publicKey: publicKey }); - HD.cache.set(this.xpubkey + '/' + index, child); + HD.cache.set(id, child); return child; }; diff --git a/lib/bcoin/protocol/constants.js b/lib/bcoin/protocol/constants.js index cc0029f9..b2f88bf5 100644 --- a/lib/bcoin/protocol/constants.js +++ b/lib/bcoin/protocol/constants.js @@ -515,10 +515,9 @@ exports.rejectByVal = utils.revMap(exports.reject); exports.hd = { HARDENED: 0x80000000, - MAX_INDEX: 2 * 0x80000000, + MAX_INDEX: 0x100000000, MIN_ENTROPY: 128 / 8, MAX_ENTROPY: 512 / 8, - PARENT_FINGERPRINT_SIZE: 4, PATH_ROOTS: ['m', 'M', 'm\'', 'M\''] };