diff --git a/lib/hdprivatekey.js b/lib/hdprivatekey.js index 8d5ed1b..33ec363 100644 --- a/lib/hdprivatekey.js +++ b/lib/hdprivatekey.js @@ -225,6 +225,11 @@ HDPrivateKey.prototype._deriveWithNumber = function(index, hardened, nonComplian size: 32 }); + if (!PrivateKey.isValid(privateKey)) { + // Index at this point is already hardened, we can pass null as the hardened arg + return this._deriveWithNumber(index + 1, null, nonCompliant); + } + var derived = new HDPrivateKey({ network: this.network, depth: this.depth + 1, diff --git a/test/hdkeys.js b/test/hdkeys.js index 377e18b..d57a54b 100644 --- a/test/hdkeys.js +++ b/test/hdkeys.js @@ -13,6 +13,7 @@ var _ = require('lodash'); var should = require('chai').should(); var expect = require('chai').expect; +var sinon = require('sinon'); var bitcore = require('..'); var Networks = bitcore.Networks; var HDPrivateKey = bitcore.HDPrivateKey; @@ -253,6 +254,42 @@ describe('BIP32 compliance', function() { derived.privateKey.toString().should.equal('4811a079bab267bfdca855b3bddff20231ff7044e648514fa099158472df2836'); }); + describe('edge cases', function() { + var sandbox = sinon.sandbox.create(); + afterEach(function() { + sandbox.restore(); + }); + it('will handle edge case that derived private key is invalid', function() { + var invalid = new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex'); + var privateKeyBuffer = new Buffer('5f72914c48581fc7ddeb944a9616389200a9560177d24f458258e5b04527bcd1', 'hex'); + var chainCodeBuffer = new Buffer('39816057bba9d952fe87fe998b7fd4d690a1bb58c2ff69141469e4d1dffb4b91', 'hex'); + var unstubbed = bitcore.crypto.BN.prototype.toBuffer; + var count = 0; + var stub = sandbox.stub(bitcore.crypto.BN.prototype, 'toBuffer', function(args) { + // On the fourth call to the function give back an invalid private key + // otherwise use the normal behavior. + count++; + if (count === 4) { + return invalid; + } + var ret = unstubbed.apply(this, arguments); + return ret; + }); + sandbox.spy(bitcore.PrivateKey, 'isValid'); + var key = HDPrivateKey.fromObject({ + network: 'testnet', + depth: 0, + parentFingerPrint: 0, + childIndex: 0, + privateKey: privateKeyBuffer, + chainCode: chainCodeBuffer + }); + var derived = key.derive("m/44'"); + derived.privateKey.toString().should.equal('b15bce3608d607ee3a49069197732c656bca942ee59f3e29b4d56914c1de6825'); + bitcore.PrivateKey.isValid.callCount.should.equal(2); + }); + }); + describe('seed', function() { it('should initialize a new BIP32 correctly from test vector 1 seed', function() {