From 3bd361e27aada965908e989dc370700c90038473 Mon Sep 17 00:00:00 2001 From: Yemel Jardi Date: Wed, 28 Jan 2015 18:13:38 -0300 Subject: [PATCH 1/3] Fix hd string path parsing. --- lib/hdprivatekey.js | 9 +++++++-- test/hdprivatekey.js | 12 ++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/lib/hdprivatekey.js b/lib/hdprivatekey.js index 8e40411..a5db864 100644 --- a/lib/hdprivatekey.js +++ b/lib/hdprivatekey.js @@ -106,8 +106,13 @@ HDPrivateKey._getDerivationIndexes = function(path) { } var indexes = steps.slice(1).map(function(step) { - var index = parseInt(step); - index += step != index.toString() ? HDPrivateKey.Hardened : 0; + var index = step ? +step : NaN; + + var isHardened = isNaN(index) && step[step.length-1] == "'"; + if (isHardened) { + index = (+(step.slice(0, -1))) + HDPrivateKey.Hardened; + } + return index; }); diff --git a/test/hdprivatekey.js b/test/hdprivatekey.js index e6c57e8..0888007 100644 --- a/test/hdprivatekey.js +++ b/test/hdprivatekey.js @@ -234,6 +234,9 @@ describe('HDPrivate key interface', function() { valid = HDPrivateKey.isValidPath('m/'); valid.should.equal(false); + valid = HDPrivateKey.isValidPath('m/12asd'); + valid.should.equal(false); + valid = HDPrivateKey.isValidPath(HDPrivateKey.MaxHardened); valid.should.equal(false); }); @@ -259,6 +262,15 @@ describe('HDPrivate key interface', function() { indexes = HDPrivateKey._getDerivationIndexes("bad path"); expect(indexes).to.be.null; + + indexes = HDPrivateKey._getDerivationIndexes("K"); + expect(indexes).to.be.null; + + indexes = HDPrivateKey._getDerivationIndexes("m/"); + expect(indexes).to.be.null; + + indexes = HDPrivateKey._getDerivationIndexes("m/123asd"); + expect(indexes).to.be.null; }); }); From 85e938ba724a9b2f9ee5bec1029d64bba7dd4ff7 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Mon, 9 Feb 2015 15:40:06 -0300 Subject: [PATCH 2/3] improve code style --- lib/hdprivatekey.js | 55 +++++++++++++++----------- test/hdprivatekey.js | 94 ++++++++++++++++---------------------------- 2 files changed, 67 insertions(+), 82 deletions(-) diff --git a/lib/hdprivatekey.js b/lib/hdprivatekey.js index a5db864..0b58ec5 100644 --- a/lib/hdprivatekey.js +++ b/lib/hdprivatekey.js @@ -21,7 +21,7 @@ var BufferUtil = require('./util/buffer'); var JSUtil = require('./util/js'); var MINIMUM_ENTROPY_BITS = 128; -var BITS_TO_BYTES = 1/8; +var BITS_TO_BYTES = 1 / 8; var MAXIMUM_ENTROPY_BITS = 512; @@ -106,18 +106,25 @@ HDPrivateKey._getDerivationIndexes = function(path) { } var indexes = steps.slice(1).map(function(step) { - var index = step ? +step : NaN; - - var isHardened = isNaN(index) && step[step.length-1] == "'"; + console.log(step); + var isHardened = step.slice(-1) === '\''; + if (isHardened) { + step = step.slice(0, -1); + } + if (!step || step[0] === '-') { + return NaN; + } + var index = +step; // cast to number if (isHardened) { - index = (+(step.slice(0, -1))) + HDPrivateKey.Hardened; + index += HDPrivateKey.Hardened; } return index; }); + console.log(indexes); return _.any(indexes, isNaN) ? null : indexes; -} +}; /** * Get a derivated child based on a string or number. @@ -177,10 +184,14 @@ HDPrivateKey.prototype._deriveWithNumber = function(index, hardened) { data = BufferUtil.concat([this.publicKey.toBuffer(), indexBuffer]); } var hash = Hash.sha512hmac(data, this._buffers.chainCode); - var leftPart = BN.fromBuffer(hash.slice(0, 32), {size: 32}); + var leftPart = BN.fromBuffer(hash.slice(0, 32), { + size: 32 + }); var chainCode = hash.slice(32, 64); - var privateKey = leftPart.add(this.privateKey.toBigNumber()).mod(Point.getN()).toBuffer({size: 32}); + var privateKey = leftPart.add(this.privateKey.toBigNumber()).mod(Point.getN()).toBuffer({ + size: 32 + }); var derived = new HDPrivateKey({ network: this.network, @@ -295,7 +306,7 @@ HDPrivateKey.prototype._buildFromSerialized = function(arg) { version: decoded.slice(HDPrivateKey.VersionStart, HDPrivateKey.VersionEnd), depth: decoded.slice(HDPrivateKey.DepthStart, HDPrivateKey.DepthEnd), parentFingerPrint: decoded.slice(HDPrivateKey.ParentFingerPrintStart, - HDPrivateKey.ParentFingerPrintEnd), + HDPrivateKey.ParentFingerPrintEnd), childIndex: decoded.slice(HDPrivateKey.ChildIndexStart, HDPrivateKey.ChildIndexEnd), chainCode: decoded.slice(HDPrivateKey.ChainCodeStart, HDPrivateKey.ChainCodeEnd), privateKey: decoded.slice(HDPrivateKey.PrivateKeyStart, HDPrivateKey.PrivateKeyEnd), @@ -508,20 +519,20 @@ HDPrivateKey.CheckSumSize = 4; HDPrivateKey.DataLength = 78; HDPrivateKey.SerializedByteSize = 82; -HDPrivateKey.VersionStart = 0; -HDPrivateKey.VersionEnd = HDPrivateKey.VersionStart + HDPrivateKey.VersionSize; -HDPrivateKey.DepthStart = HDPrivateKey.VersionEnd; -HDPrivateKey.DepthEnd = HDPrivateKey.DepthStart + HDPrivateKey.DepthSize; +HDPrivateKey.VersionStart = 0; +HDPrivateKey.VersionEnd = HDPrivateKey.VersionStart + HDPrivateKey.VersionSize; +HDPrivateKey.DepthStart = HDPrivateKey.VersionEnd; +HDPrivateKey.DepthEnd = HDPrivateKey.DepthStart + HDPrivateKey.DepthSize; HDPrivateKey.ParentFingerPrintStart = HDPrivateKey.DepthEnd; -HDPrivateKey.ParentFingerPrintEnd = HDPrivateKey.ParentFingerPrintStart + HDPrivateKey.ParentFingerPrintSize; -HDPrivateKey.ChildIndexStart = HDPrivateKey.ParentFingerPrintEnd; -HDPrivateKey.ChildIndexEnd = HDPrivateKey.ChildIndexStart + HDPrivateKey.ChildIndexSize; -HDPrivateKey.ChainCodeStart = HDPrivateKey.ChildIndexEnd; -HDPrivateKey.ChainCodeEnd = HDPrivateKey.ChainCodeStart + HDPrivateKey.ChainCodeSize; -HDPrivateKey.PrivateKeyStart = HDPrivateKey.ChainCodeEnd + 1; -HDPrivateKey.PrivateKeyEnd = HDPrivateKey.PrivateKeyStart + HDPrivateKey.PrivateKeySize; -HDPrivateKey.ChecksumStart = HDPrivateKey.PrivateKeyEnd; -HDPrivateKey.ChecksumEnd = HDPrivateKey.ChecksumStart + HDPrivateKey.CheckSumSize; +HDPrivateKey.ParentFingerPrintEnd = HDPrivateKey.ParentFingerPrintStart + HDPrivateKey.ParentFingerPrintSize; +HDPrivateKey.ChildIndexStart = HDPrivateKey.ParentFingerPrintEnd; +HDPrivateKey.ChildIndexEnd = HDPrivateKey.ChildIndexStart + HDPrivateKey.ChildIndexSize; +HDPrivateKey.ChainCodeStart = HDPrivateKey.ChildIndexEnd; +HDPrivateKey.ChainCodeEnd = HDPrivateKey.ChainCodeStart + HDPrivateKey.ChainCodeSize; +HDPrivateKey.PrivateKeyStart = HDPrivateKey.ChainCodeEnd + 1; +HDPrivateKey.PrivateKeyEnd = HDPrivateKey.PrivateKeyStart + HDPrivateKey.PrivateKeySize; +HDPrivateKey.ChecksumStart = HDPrivateKey.PrivateKeyEnd; +HDPrivateKey.ChecksumEnd = HDPrivateKey.ChecksumStart + HDPrivateKey.CheckSumSize; assert(HDPrivateKey.ChecksumEnd === HDPrivateKey.SerializedByteSize); diff --git a/test/hdprivatekey.js b/test/hdprivatekey.js index 0888007..1e50316 100644 --- a/test/hdprivatekey.js +++ b/test/hdprivatekey.js @@ -14,7 +14,6 @@ var Base58Check = bitcore.encoding.Base58Check; var xprivkey = 'xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi'; var json = '{"network":"livenet","depth":0,"fingerPrint":876747070,"parentFingerPrint":0,"childIndex":0,"chainCode":"873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508","privateKey":"e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35","checksum":-411132559,"xprivkey":"xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"}'; - describe('HDPrivate key interface', function() { /* jshint maxstatements: 50 */ var expectFail = function(func, error) { @@ -113,36 +112,33 @@ describe('HDPrivate key interface', function() { derivedByNumber.xprivkey.should.equal(derivedByArgument.xprivkey); }); - it('returns itself with "m" parameter', function() { + it('returns itself with \'m\' parameter', function() { var privateKey = new HDPrivateKey(xprivkey); privateKey.should.equal(privateKey.derive('m')); }); it('returns InvalidArgument if invalid data is given to getSerializedError', function() { expect( - HDPrivateKey.getSerializedError(1) instanceof - hdErrors.UnrecognizedArgument + HDPrivateKey.getSerializedError(1) instanceof hdErrors.UnrecognizedArgument ).to.equal(true); }); it('returns InvalidLength if data of invalid length is given to getSerializedError', function() { + var b58s = Base58Check.encode(new buffer.Buffer('onestring')); expect( - HDPrivateKey.getSerializedError(Base58Check.encode(new buffer.Buffer('onestring'))) instanceof - hdErrors.InvalidLength + HDPrivateKey.getSerializedError(b58s) instanceof hdErrors.InvalidLength ).to.equal(true); }); it('returns InvalidNetworkArgument if an invalid network is provided', function() { expect( - HDPrivateKey.getSerializedError(xprivkey, 'invalidNetwork') instanceof - errors.InvalidNetworkArgument + HDPrivateKey.getSerializedError(xprivkey, 'invalidNetwork') instanceof errors.InvalidNetworkArgument ).to.equal(true); }); it('recognizes that the wrong network was asked for', function() { expect( - HDPrivateKey.getSerializedError(xprivkey, 'testnet') instanceof - errors.InvalidNetwork + HDPrivateKey.getSerializedError(xprivkey, 'testnet') instanceof errors.InvalidNetwork ).to.equal(true); }); @@ -200,7 +196,7 @@ describe('HDPrivate key interface', function() { it('validates correct paths', function() { var valid; - valid = HDPrivateKey.isValidPath("m/0'/1/2'"); + valid = HDPrivateKey.isValidPath('m/0\'/1/2\''); valid.should.equal(true); valid = HDPrivateKey.isValidPath('m'); @@ -219,26 +215,22 @@ describe('HDPrivate key interface', function() { valid.should.equal(true); }); - it('rejects illegal paths', function() { - var valid; - - valid = HDPrivateKey.isValidPath('m/-1/12'); - valid.should.equal(false); - - valid = HDPrivateKey.isValidPath('bad path'); - valid.should.equal(false); - valid = HDPrivateKey.isValidPath('K'); - valid.should.equal(false); - - valid = HDPrivateKey.isValidPath('m/'); - valid.should.equal(false); - - valid = HDPrivateKey.isValidPath('m/12asd'); - valid.should.equal(false); - - valid = HDPrivateKey.isValidPath(HDPrivateKey.MaxHardened); - valid.should.equal(false); + var invalid = [ + 'm/-1/12', + 'bad path', + 'K', + 'm/', + 'm/12asd', + HDPrivateKey.MaxHardened, + 'm/1/2//3' + ]; + + invalid.forEach(function(datum) { + it('rejects illegal path ' + datum, function() { + HDPrivateKey.isValidPath(datum).should.equal(false); + expect(HDPrivateKey._getDerivationIndexes(datum)).to.equal(null); + }); }); it('generates deriving indexes correctly', function() { @@ -247,44 +239,27 @@ describe('HDPrivate key interface', function() { indexes = HDPrivateKey._getDerivationIndexes('m/-1/12'); indexes.should.eql([-1, 12]); - indexes = HDPrivateKey._getDerivationIndexes("m/0/12/12'"); + indexes = HDPrivateKey._getDerivationIndexes('m/0/12/12\''); indexes.should.eql([0, 12, HDPrivateKey.Hardened + 12]); - indexes = HDPrivateKey._getDerivationIndexes("m/0/12/12'"); + indexes = HDPrivateKey._getDerivationIndexes('m/0/12/12\''); indexes.should.eql([0, 12, HDPrivateKey.Hardened + 12]); }); - it('rejects invalid derivation path', function() { - var indexes; - - indexes = HDPrivateKey._getDerivationIndexes("m/"); - expect(indexes).to.be.null; - - indexes = HDPrivateKey._getDerivationIndexes("bad path"); - expect(indexes).to.be.null; - - indexes = HDPrivateKey._getDerivationIndexes("K"); - expect(indexes).to.be.null; - - indexes = HDPrivateKey._getDerivationIndexes("m/"); - expect(indexes).to.be.null; - - indexes = HDPrivateKey._getDerivationIndexes("m/123asd"); - expect(indexes).to.be.null; - }); }); describe('conversion to plain object/json', function() { var plainObject = { - 'network':'livenet', - 'depth':0, - 'fingerPrint':876747070, - 'parentFingerPrint':0, - 'childIndex':0, - 'chainCode':'873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508', - 'privateKey':'e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35', - 'checksum':-411132559, - 'xprivkey':'xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi' + 'network': 'livenet', + 'depth': 0, + 'fingerPrint': 876747070, + 'parentFingerPrint': 0, + 'childIndex': 0, + 'chainCode': '873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508', + 'privateKey': 'e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35', + 'checksum': -411132559, + 'xprivkey': 'xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvN' + + 'KmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi' }; it('toObject leaves no Buffer instances', function() { var privKey = new HDPrivateKey(xprivkey); @@ -308,4 +283,3 @@ describe('HDPrivate key interface', function() { }); }); }); - From edda8ea7236fb2c0225144702c18e217c0ece3ae Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Mon, 9 Feb 2015 16:06:18 -0300 Subject: [PATCH 3/3] fix broken tests --- lib/hdprivatekey.js | 2 -- test/hdprivatekey.js | 3 +-- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/hdprivatekey.js b/lib/hdprivatekey.js index 0b58ec5..7cc7e3f 100644 --- a/lib/hdprivatekey.js +++ b/lib/hdprivatekey.js @@ -106,7 +106,6 @@ HDPrivateKey._getDerivationIndexes = function(path) { } var indexes = steps.slice(1).map(function(step) { - console.log(step); var isHardened = step.slice(-1) === '\''; if (isHardened) { step = step.slice(0, -1); @@ -122,7 +121,6 @@ HDPrivateKey._getDerivationIndexes = function(path) { return index; }); - console.log(indexes); return _.any(indexes, isNaN) ? null : indexes; }; diff --git a/test/hdprivatekey.js b/test/hdprivatekey.js index 1e50316..4a0d20b 100644 --- a/test/hdprivatekey.js +++ b/test/hdprivatekey.js @@ -222,7 +222,6 @@ describe('HDPrivate key interface', function() { 'K', 'm/', 'm/12asd', - HDPrivateKey.MaxHardened, 'm/1/2//3' ]; @@ -237,7 +236,7 @@ describe('HDPrivate key interface', function() { var indexes; indexes = HDPrivateKey._getDerivationIndexes('m/-1/12'); - indexes.should.eql([-1, 12]); + expect(indexes).to.equal(null); indexes = HDPrivateKey._getDerivationIndexes('m/0/12/12\''); indexes.should.eql([0, 12, HDPrivateKey.Hardened + 12]);