From b8f57df90cfcb8ad26b8a5ea43d242049c584f66 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Fri, 11 Aug 2017 05:19:46 -0700 Subject: [PATCH] hd: use a u32 for fingerprints. --- lib/hd/common.js | 5 +++-- lib/hd/private.js | 35 +++++++++++++++++------------------ lib/hd/public.js | 31 +++++++++++++++---------------- 3 files changed, 35 insertions(+), 36 deletions(-) diff --git a/lib/hd/common.js b/lib/hd/common.js index e39f77f3..0f1cee3d 100644 --- a/lib/hd/common.js +++ b/lib/hd/common.js @@ -109,7 +109,7 @@ common.parsePath = function parsePath(path, hard) { common.isMaster = function isMaster(key) { return key.depth === 0 && key.childIndex === 0 - && key.parentFingerPrint.readUInt32LE(0, true) === 0; + && key.parentFingerPrint === 0; }; /** @@ -135,5 +135,6 @@ common.isBIP44 = function isBIP44(key, account) { */ common.isBIP45 = function isBIP45(key) { - return key.depth === 1 && (key.childIndex & ~common.HARDENED) === 45; + const index = (common.HARDENED | 45) >>> 0; + return key.depth === 1 && key.childIndex === index; }; diff --git a/lib/hd/private.js b/lib/hd/private.js index 25e4f4ac..0867e56d 100644 --- a/lib/hd/private.js +++ b/lib/hd/private.js @@ -34,13 +34,13 @@ const SEED_SALT = Buffer.from('Bitcoin seed', 'ascii'); * @param {Object|Base58String} options * @param {Base58String?} options.xkey - Serialized base58 key. * @param {Number?} options.depth - * @param {Buffer?} options.parentFingerPrint + * @param {Number?} options.parentFingerPrint * @param {Number?} options.childIndex * @param {Buffer?} options.chainCode * @param {Buffer?} options.privateKey * @property {Network} network * @property {Number} depth - * @property {Buffer} parentFingerPrint + * @property {Number} parentFingerPrint * @property {Number} childIndex * @property {Buffer} chainCode * @property {Buffer} privateKey @@ -52,13 +52,13 @@ function HDPrivateKey(options) { this.network = Network.primary; this.depth = 0; - this.parentFingerPrint = encoding.ZERO_U32; + this.parentFingerPrint = 0; this.childIndex = 0; this.chainCode = encoding.ZERO_HASH; this.privateKey = encoding.ZERO_HASH; this.publicKey = encoding.ZERO_KEY; - this.fingerPrint = null; + this.fingerPrint = -1; this._xprivkey = null; @@ -77,7 +77,7 @@ function HDPrivateKey(options) { HDPrivateKey.prototype.fromOptions = function fromOptions(options) { assert(options, 'No options for HD private key.'); assert(util.isU8(options.depth)); - assert(Buffer.isBuffer(options.parentFingerPrint)); + assert(util.isU32(options.parentFingerPrint)); assert(util.isU32(options.childIndex)); assert(Buffer.isBuffer(options.chainCode)); assert(Buffer.isBuffer(options.privateKey)); @@ -155,16 +155,13 @@ HDPrivateKey.prototype.xpubkey = function xpubkey() { HDPrivateKey.prototype.destroy = function destroy(pub) { this.depth = 0; this.childIndex = 0; + this.parentFingerPrint = 0; - cleanse(this.parentFingerPrint); cleanse(this.chainCode); cleanse(this.privateKey); cleanse(this.publicKey); - if (this.fingerPrint) { - cleanse(this.fingerPrint); - this.fingerPrint = null; - } + this.fingerPrint = -1; if (this._hdPublicKey) { if (pub) @@ -226,8 +223,10 @@ HDPrivateKey.prototype.derive = function derive(index, hardened) { return this.derive(index + 1); } - if (!this.fingerPrint) - this.fingerPrint = digest.hash160(this.publicKey).slice(0, 4); + if (this.fingerPrint === -1) { + const fp = digest.hash160(this.publicKey); + this.fingerPrint = fp.readUInt32BE(0, true); + } const child = new HDPrivateKey(); child.network = this.network; @@ -403,7 +402,7 @@ HDPrivateKey.prototype.equals = function equals(obj) { return this.network === obj.network && this.depth === obj.depth - && this.parentFingerPrint.equals(obj.parentFingerPrint) + && this.parentFingerPrint === obj.parentFingerPrint && this.childIndex === obj.childIndex && this.chainCode.equals(obj.chainCode) && this.privateKey.equals(obj.privateKey); @@ -423,7 +422,7 @@ HDPrivateKey.prototype.compare = function compare(key) { if (cmp !== 0) return cmp; - cmp = this.parentFingerPrint.compare(key.parentFingerPrint); + cmp = this.parentFingerPrint - key.parentFingerPrint; if (cmp !== 0) return cmp; @@ -471,7 +470,7 @@ HDPrivateKey.prototype.fromSeed = function fromSeed(seed, network) { this.network = Network.get(network); this.depth = 0; - this.parentFingerPrint = Buffer.from([0, 0, 0, 0]); + this.parentFingerPrint = 0; this.childIndex = 0; this.chainCode = right; this.privateKey = left; @@ -551,7 +550,7 @@ HDPrivateKey.prototype.fromKey = function fromKey(key, entropy, network) { assert(Buffer.isBuffer(entropy) && entropy.length === 32); this.network = Network.get(network); this.depth = 0; - this.parentFingerPrint = Buffer.from([0, 0, 0, 0]); + this.parentFingerPrint = 0; this.childIndex = 0; this.chainCode = entropy; this.privateKey = key; @@ -608,7 +607,7 @@ HDPrivateKey.prototype.fromReader = function fromReader(br, network) { this.network = Network.fromPrivate(version, network); this.depth = br.readU8(); - this.parentFingerPrint = br.readBytes(4); + this.parentFingerPrint = br.readU32BE(); this.childIndex = br.readU32BE(); this.chainCode = br.readBytes(32); assert(br.readU8() === 0); @@ -664,7 +663,7 @@ HDPrivateKey.prototype.toWriter = function toWriter(bw, network) { bw.writeU32BE(network.keyPrefix.xprivkey); bw.writeU8(this.depth); - bw.writeBytes(this.parentFingerPrint); + bw.writeU32BE(this.parentFingerPrint); bw.writeU32BE(this.childIndex); bw.writeBytes(this.chainCode); bw.writeU8(0); diff --git a/lib/hd/public.js b/lib/hd/public.js index 6ff97a97..0cc59c2a 100644 --- a/lib/hd/public.js +++ b/lib/hd/public.js @@ -25,13 +25,13 @@ const common = require('./common'); * @param {Object|Base58String} options * @param {Base58String?} options.xkey - Serialized base58 key. * @param {Number?} options.depth - * @param {Buffer?} options.parentFingerPrint + * @param {Number?} options.parentFingerPrint * @param {Number?} options.childIndex * @param {Buffer?} options.chainCode * @param {Buffer?} options.publicKey * @property {Network} network * @property {Number} depth - * @property {Buffer} parentFingerPrint + * @property {Number} parentFingerPrint * @property {Number} childIndex * @property {Buffer} chainCode * @property {Buffer} publicKey @@ -43,12 +43,12 @@ function HDPublicKey(options) { this.network = Network.primary; this.depth = 0; - this.parentFingerPrint = encoding.ZERO_U32; + this.parentFingerPrint = 0; this.childIndex = 0; this.chainCode = encoding.ZERO_HASH; this.publicKey = encoding.ZERO_KEY; - this.fingerPrint = null; + this.fingerPrint = -1; this._xpubkey = null; @@ -65,7 +65,7 @@ function HDPublicKey(options) { HDPublicKey.prototype.fromOptions = function fromOptions(options) { assert(options, 'No options for HDPublicKey'); assert(util.isU8(options.depth)); - assert(Buffer.isBuffer(options.parentFingerPrint)); + assert(util.isU32(options.parentFingerPrint)); assert(util.isU32(options.childIndex)); assert(Buffer.isBuffer(options.chainCode)); assert(Buffer.isBuffer(options.publicKey)); @@ -128,15 +128,12 @@ HDPublicKey.prototype.xpubkey = function xpubkey() { HDPublicKey.prototype.destroy = function destroy() { this.depth = 0; this.childIndex = 0; + this.parentFingerPrint = 0; - cleanse(this.parentFingerPrint); cleanse(this.chainCode); cleanse(this.publicKey); - if (this.fingerPrint) { - cleanse(this.fingerPrint); - this.fingerPrint = null; - } + this.fingerPrint = -1; this._xpubkey = null; }; @@ -186,8 +183,10 @@ HDPublicKey.prototype.derive = function derive(index, hardened) { return this.derive(index + 1); } - if (!this.fingerPrint) - this.fingerPrint = digest.hash160(this.publicKey).slice(0, 4); + if (this.fingerPrint === -1) { + const fp = digest.hash160(this.publicKey); + this.fingerPrint = fp.readUInt32BE(0, true); + } const child = new HDPublicKey(); child.network = this.network; @@ -318,7 +317,7 @@ HDPublicKey.prototype.equals = function equals(obj) { return this.network === obj.network && this.depth === obj.depth - && this.parentFingerPrint.equals(obj.parentFingerPrint) + && this.parentFingerPrint === obj.parentFingerPrint && this.childIndex === obj.childIndex && this.chainCode.equals(obj.chainCode) && this.publicKey.equals(obj.publicKey); @@ -338,7 +337,7 @@ HDPublicKey.prototype.compare = function compare(key) { if (cmp !== 0) return cmp; - cmp = this.parentFingerPrint.compare(key.parentFingerPrint); + cmp = this.parentFingerPrint - key.parentFingerPrint; if (cmp !== 0) return cmp; @@ -469,7 +468,7 @@ HDPublicKey.prototype.fromReader = function fromReader(br, network) { this.network = Network.fromPublic(version, network); this.depth = br.readU8(); - this.parentFingerPrint = br.readBytes(4); + this.parentFingerPrint = br.readU32BE(); this.childIndex = br.readU32BE(); this.chainCode = br.readBytes(32); this.publicKey = br.readBytes(33); @@ -514,7 +513,7 @@ HDPublicKey.prototype.toWriter = function toWriter(bw, network) { bw.writeU32BE(network.keyPrefix.xpubkey); bw.writeU8(this.depth); - bw.writeBytes(this.parentFingerPrint); + bw.writeU32BE(this.parentFingerPrint); bw.writeU32BE(this.childIndex); bw.writeBytes(this.chainCode); bw.writeBytes(this.publicKey);