hd: use a u32 for fingerprints.

This commit is contained in:
Christopher Jeffrey 2017-08-11 05:19:46 -07:00
parent aa327131e8
commit b8f57df90c
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
3 changed files with 35 additions and 36 deletions

View File

@ -109,7 +109,7 @@ common.parsePath = function parsePath(path, hard) {
common.isMaster = function isMaster(key) { common.isMaster = function isMaster(key) {
return key.depth === 0 return key.depth === 0
&& key.childIndex === 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) { 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;
}; };

View File

@ -34,13 +34,13 @@ const SEED_SALT = Buffer.from('Bitcoin seed', 'ascii');
* @param {Object|Base58String} options * @param {Object|Base58String} options
* @param {Base58String?} options.xkey - Serialized base58 key. * @param {Base58String?} options.xkey - Serialized base58 key.
* @param {Number?} options.depth * @param {Number?} options.depth
* @param {Buffer?} options.parentFingerPrint * @param {Number?} options.parentFingerPrint
* @param {Number?} options.childIndex * @param {Number?} options.childIndex
* @param {Buffer?} options.chainCode * @param {Buffer?} options.chainCode
* @param {Buffer?} options.privateKey * @param {Buffer?} options.privateKey
* @property {Network} network * @property {Network} network
* @property {Number} depth * @property {Number} depth
* @property {Buffer} parentFingerPrint * @property {Number} parentFingerPrint
* @property {Number} childIndex * @property {Number} childIndex
* @property {Buffer} chainCode * @property {Buffer} chainCode
* @property {Buffer} privateKey * @property {Buffer} privateKey
@ -52,13 +52,13 @@ function HDPrivateKey(options) {
this.network = Network.primary; this.network = Network.primary;
this.depth = 0; this.depth = 0;
this.parentFingerPrint = encoding.ZERO_U32; this.parentFingerPrint = 0;
this.childIndex = 0; this.childIndex = 0;
this.chainCode = encoding.ZERO_HASH; this.chainCode = encoding.ZERO_HASH;
this.privateKey = encoding.ZERO_HASH; this.privateKey = encoding.ZERO_HASH;
this.publicKey = encoding.ZERO_KEY; this.publicKey = encoding.ZERO_KEY;
this.fingerPrint = null; this.fingerPrint = -1;
this._xprivkey = null; this._xprivkey = null;
@ -77,7 +77,7 @@ function HDPrivateKey(options) {
HDPrivateKey.prototype.fromOptions = function fromOptions(options) { HDPrivateKey.prototype.fromOptions = function fromOptions(options) {
assert(options, 'No options for HD private key.'); assert(options, 'No options for HD private key.');
assert(util.isU8(options.depth)); assert(util.isU8(options.depth));
assert(Buffer.isBuffer(options.parentFingerPrint)); assert(util.isU32(options.parentFingerPrint));
assert(util.isU32(options.childIndex)); assert(util.isU32(options.childIndex));
assert(Buffer.isBuffer(options.chainCode)); assert(Buffer.isBuffer(options.chainCode));
assert(Buffer.isBuffer(options.privateKey)); assert(Buffer.isBuffer(options.privateKey));
@ -155,16 +155,13 @@ HDPrivateKey.prototype.xpubkey = function xpubkey() {
HDPrivateKey.prototype.destroy = function destroy(pub) { HDPrivateKey.prototype.destroy = function destroy(pub) {
this.depth = 0; this.depth = 0;
this.childIndex = 0; this.childIndex = 0;
this.parentFingerPrint = 0;
cleanse(this.parentFingerPrint);
cleanse(this.chainCode); cleanse(this.chainCode);
cleanse(this.privateKey); cleanse(this.privateKey);
cleanse(this.publicKey); cleanse(this.publicKey);
if (this.fingerPrint) { this.fingerPrint = -1;
cleanse(this.fingerPrint);
this.fingerPrint = null;
}
if (this._hdPublicKey) { if (this._hdPublicKey) {
if (pub) if (pub)
@ -226,8 +223,10 @@ HDPrivateKey.prototype.derive = function derive(index, hardened) {
return this.derive(index + 1); return this.derive(index + 1);
} }
if (!this.fingerPrint) if (this.fingerPrint === -1) {
this.fingerPrint = digest.hash160(this.publicKey).slice(0, 4); const fp = digest.hash160(this.publicKey);
this.fingerPrint = fp.readUInt32BE(0, true);
}
const child = new HDPrivateKey(); const child = new HDPrivateKey();
child.network = this.network; child.network = this.network;
@ -403,7 +402,7 @@ HDPrivateKey.prototype.equals = function equals(obj) {
return this.network === obj.network return this.network === obj.network
&& this.depth === obj.depth && this.depth === obj.depth
&& this.parentFingerPrint.equals(obj.parentFingerPrint) && this.parentFingerPrint === obj.parentFingerPrint
&& this.childIndex === obj.childIndex && this.childIndex === obj.childIndex
&& this.chainCode.equals(obj.chainCode) && this.chainCode.equals(obj.chainCode)
&& this.privateKey.equals(obj.privateKey); && this.privateKey.equals(obj.privateKey);
@ -423,7 +422,7 @@ HDPrivateKey.prototype.compare = function compare(key) {
if (cmp !== 0) if (cmp !== 0)
return cmp; return cmp;
cmp = this.parentFingerPrint.compare(key.parentFingerPrint); cmp = this.parentFingerPrint - key.parentFingerPrint;
if (cmp !== 0) if (cmp !== 0)
return cmp; return cmp;
@ -471,7 +470,7 @@ HDPrivateKey.prototype.fromSeed = function fromSeed(seed, network) {
this.network = Network.get(network); this.network = Network.get(network);
this.depth = 0; this.depth = 0;
this.parentFingerPrint = Buffer.from([0, 0, 0, 0]); this.parentFingerPrint = 0;
this.childIndex = 0; this.childIndex = 0;
this.chainCode = right; this.chainCode = right;
this.privateKey = left; this.privateKey = left;
@ -551,7 +550,7 @@ HDPrivateKey.prototype.fromKey = function fromKey(key, entropy, network) {
assert(Buffer.isBuffer(entropy) && entropy.length === 32); assert(Buffer.isBuffer(entropy) && entropy.length === 32);
this.network = Network.get(network); this.network = Network.get(network);
this.depth = 0; this.depth = 0;
this.parentFingerPrint = Buffer.from([0, 0, 0, 0]); this.parentFingerPrint = 0;
this.childIndex = 0; this.childIndex = 0;
this.chainCode = entropy; this.chainCode = entropy;
this.privateKey = key; this.privateKey = key;
@ -608,7 +607,7 @@ HDPrivateKey.prototype.fromReader = function fromReader(br, network) {
this.network = Network.fromPrivate(version, network); this.network = Network.fromPrivate(version, network);
this.depth = br.readU8(); this.depth = br.readU8();
this.parentFingerPrint = br.readBytes(4); this.parentFingerPrint = br.readU32BE();
this.childIndex = br.readU32BE(); this.childIndex = br.readU32BE();
this.chainCode = br.readBytes(32); this.chainCode = br.readBytes(32);
assert(br.readU8() === 0); assert(br.readU8() === 0);
@ -664,7 +663,7 @@ HDPrivateKey.prototype.toWriter = function toWriter(bw, network) {
bw.writeU32BE(network.keyPrefix.xprivkey); bw.writeU32BE(network.keyPrefix.xprivkey);
bw.writeU8(this.depth); bw.writeU8(this.depth);
bw.writeBytes(this.parentFingerPrint); bw.writeU32BE(this.parentFingerPrint);
bw.writeU32BE(this.childIndex); bw.writeU32BE(this.childIndex);
bw.writeBytes(this.chainCode); bw.writeBytes(this.chainCode);
bw.writeU8(0); bw.writeU8(0);

View File

@ -25,13 +25,13 @@ const common = require('./common');
* @param {Object|Base58String} options * @param {Object|Base58String} options
* @param {Base58String?} options.xkey - Serialized base58 key. * @param {Base58String?} options.xkey - Serialized base58 key.
* @param {Number?} options.depth * @param {Number?} options.depth
* @param {Buffer?} options.parentFingerPrint * @param {Number?} options.parentFingerPrint
* @param {Number?} options.childIndex * @param {Number?} options.childIndex
* @param {Buffer?} options.chainCode * @param {Buffer?} options.chainCode
* @param {Buffer?} options.publicKey * @param {Buffer?} options.publicKey
* @property {Network} network * @property {Network} network
* @property {Number} depth * @property {Number} depth
* @property {Buffer} parentFingerPrint * @property {Number} parentFingerPrint
* @property {Number} childIndex * @property {Number} childIndex
* @property {Buffer} chainCode * @property {Buffer} chainCode
* @property {Buffer} publicKey * @property {Buffer} publicKey
@ -43,12 +43,12 @@ function HDPublicKey(options) {
this.network = Network.primary; this.network = Network.primary;
this.depth = 0; this.depth = 0;
this.parentFingerPrint = encoding.ZERO_U32; this.parentFingerPrint = 0;
this.childIndex = 0; this.childIndex = 0;
this.chainCode = encoding.ZERO_HASH; this.chainCode = encoding.ZERO_HASH;
this.publicKey = encoding.ZERO_KEY; this.publicKey = encoding.ZERO_KEY;
this.fingerPrint = null; this.fingerPrint = -1;
this._xpubkey = null; this._xpubkey = null;
@ -65,7 +65,7 @@ function HDPublicKey(options) {
HDPublicKey.prototype.fromOptions = function fromOptions(options) { HDPublicKey.prototype.fromOptions = function fromOptions(options) {
assert(options, 'No options for HDPublicKey'); assert(options, 'No options for HDPublicKey');
assert(util.isU8(options.depth)); assert(util.isU8(options.depth));
assert(Buffer.isBuffer(options.parentFingerPrint)); assert(util.isU32(options.parentFingerPrint));
assert(util.isU32(options.childIndex)); assert(util.isU32(options.childIndex));
assert(Buffer.isBuffer(options.chainCode)); assert(Buffer.isBuffer(options.chainCode));
assert(Buffer.isBuffer(options.publicKey)); assert(Buffer.isBuffer(options.publicKey));
@ -128,15 +128,12 @@ HDPublicKey.prototype.xpubkey = function xpubkey() {
HDPublicKey.prototype.destroy = function destroy() { HDPublicKey.prototype.destroy = function destroy() {
this.depth = 0; this.depth = 0;
this.childIndex = 0; this.childIndex = 0;
this.parentFingerPrint = 0;
cleanse(this.parentFingerPrint);
cleanse(this.chainCode); cleanse(this.chainCode);
cleanse(this.publicKey); cleanse(this.publicKey);
if (this.fingerPrint) { this.fingerPrint = -1;
cleanse(this.fingerPrint);
this.fingerPrint = null;
}
this._xpubkey = null; this._xpubkey = null;
}; };
@ -186,8 +183,10 @@ HDPublicKey.prototype.derive = function derive(index, hardened) {
return this.derive(index + 1); return this.derive(index + 1);
} }
if (!this.fingerPrint) if (this.fingerPrint === -1) {
this.fingerPrint = digest.hash160(this.publicKey).slice(0, 4); const fp = digest.hash160(this.publicKey);
this.fingerPrint = fp.readUInt32BE(0, true);
}
const child = new HDPublicKey(); const child = new HDPublicKey();
child.network = this.network; child.network = this.network;
@ -318,7 +317,7 @@ HDPublicKey.prototype.equals = function equals(obj) {
return this.network === obj.network return this.network === obj.network
&& this.depth === obj.depth && this.depth === obj.depth
&& this.parentFingerPrint.equals(obj.parentFingerPrint) && this.parentFingerPrint === obj.parentFingerPrint
&& this.childIndex === obj.childIndex && this.childIndex === obj.childIndex
&& this.chainCode.equals(obj.chainCode) && this.chainCode.equals(obj.chainCode)
&& this.publicKey.equals(obj.publicKey); && this.publicKey.equals(obj.publicKey);
@ -338,7 +337,7 @@ HDPublicKey.prototype.compare = function compare(key) {
if (cmp !== 0) if (cmp !== 0)
return cmp; return cmp;
cmp = this.parentFingerPrint.compare(key.parentFingerPrint); cmp = this.parentFingerPrint - key.parentFingerPrint;
if (cmp !== 0) if (cmp !== 0)
return cmp; return cmp;
@ -469,7 +468,7 @@ HDPublicKey.prototype.fromReader = function fromReader(br, network) {
this.network = Network.fromPublic(version, network); this.network = Network.fromPublic(version, network);
this.depth = br.readU8(); this.depth = br.readU8();
this.parentFingerPrint = br.readBytes(4); this.parentFingerPrint = br.readU32BE();
this.childIndex = br.readU32BE(); this.childIndex = br.readU32BE();
this.chainCode = br.readBytes(32); this.chainCode = br.readBytes(32);
this.publicKey = br.readBytes(33); this.publicKey = br.readBytes(33);
@ -514,7 +513,7 @@ HDPublicKey.prototype.toWriter = function toWriter(bw, network) {
bw.writeU32BE(network.keyPrefix.xpubkey); bw.writeU32BE(network.keyPrefix.xpubkey);
bw.writeU8(this.depth); bw.writeU8(this.depth);
bw.writeBytes(this.parentFingerPrint); bw.writeU32BE(this.parentFingerPrint);
bw.writeU32BE(this.childIndex); bw.writeU32BE(this.childIndex);
bw.writeBytes(this.chainCode); bw.writeBytes(this.chainCode);
bw.writeBytes(this.publicKey); bw.writeBytes(this.publicKey);