Add validations to derivation path
This commit is contained in:
parent
754add30df
commit
2aa5c65945
|
@ -62,6 +62,22 @@ function HDPrivateKey(arg) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies that a given path is valid.
|
||||||
|
*
|
||||||
|
* @param {string|number} arg
|
||||||
|
* @param {boolean?} hardened
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
HDPrivateKey.prototype.isValidPath = function(arg, hardened) {
|
||||||
|
try {
|
||||||
|
this.derive(arg, hardened);
|
||||||
|
return true;
|
||||||
|
} catch (err) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a derivated child based on a string or number.
|
* Get a derivated child based on a string or number.
|
||||||
*
|
*
|
||||||
|
@ -101,9 +117,15 @@ HDPrivateKey.prototype._deriveWithNumber = function(index, hardened) {
|
||||||
if (index >= HDPrivateKey.Hardened) {
|
if (index >= HDPrivateKey.Hardened) {
|
||||||
hardened = true;
|
hardened = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index < HDPrivateKey.Hardened && hardened) {
|
if (index < HDPrivateKey.Hardened && hardened) {
|
||||||
index += HDPrivateKey.Hardened;
|
index += HDPrivateKey.Hardened;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (index < 0 || index >= HDPrivateKey.MaxIndex) {
|
||||||
|
throw new hdErrors.InvalidPath(index);
|
||||||
|
}
|
||||||
|
|
||||||
var cached = HDKeyCache.get(this.xprivkey, index, hardened);
|
var cached = HDKeyCache.get(this.xprivkey, index, hardened);
|
||||||
if (cached) {
|
if (cached) {
|
||||||
return cached;
|
return cached;
|
||||||
|
@ -443,6 +465,8 @@ HDPrivateKey.DefaultFingerprint = 0;
|
||||||
HDPrivateKey.DefaultChildIndex = 0;
|
HDPrivateKey.DefaultChildIndex = 0;
|
||||||
HDPrivateKey.DefaultNetwork = Network.livenet;
|
HDPrivateKey.DefaultNetwork = Network.livenet;
|
||||||
HDPrivateKey.Hardened = 0x80000000;
|
HDPrivateKey.Hardened = 0x80000000;
|
||||||
|
HDPrivateKey.MaxIndex = 2 * HDPrivateKey.Hardened;
|
||||||
|
|
||||||
HDPrivateKey.RootElementAlias = ['m', 'M', 'm\'', 'M\''];
|
HDPrivateKey.RootElementAlias = ['m', 'M', 'm\'', 'M\''];
|
||||||
|
|
||||||
HDPrivateKey.VersionSize = 4;
|
HDPrivateKey.VersionSize = 4;
|
||||||
|
|
|
@ -65,6 +65,22 @@ function HDPublicKey(arg) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies that a given path is valid.
|
||||||
|
*
|
||||||
|
* @param {string|number} arg
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
HDPublicKey.prototype.isValidPath = function(arg) {
|
||||||
|
try {
|
||||||
|
this.derive(arg);
|
||||||
|
return true;
|
||||||
|
} catch (err) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a derivated child based on a string or number.
|
* Get a derivated child based on a string or number.
|
||||||
*
|
*
|
||||||
|
@ -86,11 +102,10 @@ function HDPublicKey(arg) {
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* @param {string|number} arg
|
* @param {string|number} arg
|
||||||
* @param {boolean?} hardened
|
|
||||||
*/
|
*/
|
||||||
HDPublicKey.prototype.derive = function (arg, hardened) {
|
HDPublicKey.prototype.derive = function (arg) {
|
||||||
if (_.isNumber(arg)) {
|
if (_.isNumber(arg)) {
|
||||||
return this._deriveWithNumber(arg, hardened);
|
return this._deriveWithNumber(arg);
|
||||||
} else if (_.isString(arg)) {
|
} else if (_.isString(arg)) {
|
||||||
return this._deriveFromString(arg);
|
return this._deriveFromString(arg);
|
||||||
} else {
|
} else {
|
||||||
|
@ -98,11 +113,14 @@ HDPublicKey.prototype.derive = function (arg, hardened) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
HDPublicKey.prototype._deriveWithNumber = function (index, hardened) {
|
HDPublicKey.prototype._deriveWithNumber = function (index) {
|
||||||
if (hardened || index >= HDPublicKey.Hardened) {
|
if (index >= HDPublicKey.Hardened) {
|
||||||
throw new hdErrors.InvalidIndexCantDeriveHardened();
|
throw new hdErrors.InvalidIndexCantDeriveHardened();
|
||||||
}
|
}
|
||||||
var cached = HDKeyCache.get(this.xpubkey, index, hardened);
|
if (index < 0) {
|
||||||
|
throw new hdErrors.InvalidPath(index);
|
||||||
|
}
|
||||||
|
var cached = HDKeyCache.get(this.xpubkey, index, false);
|
||||||
if (cached) {
|
if (cached) {
|
||||||
return cached;
|
return cached;
|
||||||
}
|
}
|
||||||
|
@ -123,12 +141,16 @@ HDPublicKey.prototype._deriveWithNumber = function (index, hardened) {
|
||||||
chainCode: chainCode,
|
chainCode: chainCode,
|
||||||
publicKey: publicKey
|
publicKey: publicKey
|
||||||
});
|
});
|
||||||
HDKeyCache.set(this.xpubkey, index, hardened, derived);
|
HDKeyCache.set(this.xpubkey, index, false, derived);
|
||||||
return derived;
|
return derived;
|
||||||
};
|
};
|
||||||
|
|
||||||
HDPublicKey.prototype._deriveFromString = function (path) {
|
HDPublicKey.prototype._deriveFromString = function (path) {
|
||||||
/* jshint maxcomplexity: 8 */
|
/* jshint maxcomplexity: 8 */
|
||||||
|
if (_.contains(path, "'")) {
|
||||||
|
throw new hdErrors.InvalidIndexCantDeriveHardened();
|
||||||
|
}
|
||||||
|
|
||||||
var steps = path.split('/');
|
var steps = path.split('/');
|
||||||
|
|
||||||
// Special cases:
|
// Special cases:
|
||||||
|
@ -143,8 +165,7 @@ HDPublicKey.prototype._deriveFromString = function (path) {
|
||||||
var result = this;
|
var result = this;
|
||||||
for (var step in steps) {
|
for (var step in steps) {
|
||||||
var index = parseInt(steps[step]);
|
var index = parseInt(steps[step]);
|
||||||
var hardened = steps[step] !== index.toString();
|
result = result._deriveWithNumber(index);
|
||||||
result = result._deriveWithNumber(index, hardened);
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
|
@ -190,6 +190,24 @@ describe('HDPrivate key interface', function() {
|
||||||
derivedByNumber.xprivkey.should.equal(derivedByString.xprivkey);
|
derivedByNumber.xprivkey.should.equal(derivedByString.xprivkey);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('validates correct paths', function() {
|
||||||
|
var privateKey = new HDPrivateKey(xprivkey);
|
||||||
|
var valid = privateKey.isValidPath('m/0\'/1/2\'');
|
||||||
|
valid.should.equal(true);
|
||||||
|
|
||||||
|
var valid = privateKey.isValidPath(123, true);
|
||||||
|
valid.should.equal(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('validates illigal paths', function() {
|
||||||
|
var privateKey = new HDPrivateKey(xprivkey);
|
||||||
|
var valid = privateKey.isValidPath('m/-1/12');
|
||||||
|
valid.should.equal(false);
|
||||||
|
|
||||||
|
var valid = privateKey.isValidPath(HDPrivateKey.MaxHardened);
|
||||||
|
valid.should.equal(false);
|
||||||
|
});
|
||||||
|
|
||||||
describe('conversion to plain object/json', function() {
|
describe('conversion to plain object/json', function() {
|
||||||
var plainObject = {
|
var plainObject = {
|
||||||
'network':'livenet',
|
'network':'livenet',
|
||||||
|
|
|
@ -216,10 +216,28 @@ describe('HDPublicKey interface', function() {
|
||||||
|
|
||||||
it('can\'t derive hardened keys', function() {
|
it('can\'t derive hardened keys', function() {
|
||||||
expectFail(function() {
|
expectFail(function() {
|
||||||
return new HDPublicKey(xpubkey).derive(HDPublicKey.Hardened + 1);
|
return new HDPublicKey(xpubkey).derive(HDPublicKey.Hardened);
|
||||||
}, hdErrors.InvalidDerivationArgument);
|
}, hdErrors.InvalidDerivationArgument);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('validates correct paths', function() {
|
||||||
|
var publicKey = new HDPublicKey(xpubkey);
|
||||||
|
var valid = publicKey.isValidPath('m/123/12');
|
||||||
|
valid.should.equal(true);
|
||||||
|
|
||||||
|
var valid = publicKey.isValidPath(123, true);
|
||||||
|
valid.should.equal(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('validates illigal paths', function() {
|
||||||
|
var publicKey = new HDPublicKey(xpubkey);
|
||||||
|
var valid = publicKey.isValidPath('m/-1/12');
|
||||||
|
valid.should.equal(false);
|
||||||
|
|
||||||
|
var valid = publicKey.isValidPath(HDPublicKey.Hardened);
|
||||||
|
valid.should.equal(false);
|
||||||
|
});
|
||||||
|
|
||||||
it('should use the cache', function() {
|
it('should use the cache', function() {
|
||||||
var pubkey = new HDPublicKey(xpubkey);
|
var pubkey = new HDPublicKey(xpubkey);
|
||||||
var derived1 = pubkey.derive(0);
|
var derived1 = pubkey.derive(0);
|
||||||
|
|
Loading…
Reference in New Issue