|
|
@ -69,15 +69,51 @@ function HDPrivateKey(arg) { |
|
|
|
* @param {boolean?} hardened |
|
|
|
* @return {boolean} |
|
|
|
*/ |
|
|
|
HDPrivateKey.prototype.isValidPath = function(arg, hardened) { |
|
|
|
try { |
|
|
|
this.derive(arg, hardened); |
|
|
|
return true; |
|
|
|
} catch (err) { |
|
|
|
return false; |
|
|
|
HDPrivateKey.isValidPath = function(arg, hardened) { |
|
|
|
if (_.isString(arg)) { |
|
|
|
var indexes = HDPrivateKey._getDerivationIndexes(arg); |
|
|
|
return indexes !== null && _.all(indexes, HDPrivateKey.isValidPath); |
|
|
|
} |
|
|
|
|
|
|
|
if (_.isNumber(arg)) { |
|
|
|
if (arg < HDPrivateKey.Hardened && hardened === true) { |
|
|
|
arg += HDPrivateKey.Hardened; |
|
|
|
} |
|
|
|
return arg >= 0 && arg < HDPrivateKey.MaxIndex; |
|
|
|
} |
|
|
|
|
|
|
|
return false; |
|
|
|
}; |
|
|
|
|
|
|
|
/** |
|
|
|
* Internal function that splits a string path into a derivation index array. |
|
|
|
* It will return null if the string path is malformed. |
|
|
|
* It does not validates if a indexes are in bounds. |
|
|
|
* |
|
|
|
* @param {string} path |
|
|
|
* @return {Array} |
|
|
|
*/ |
|
|
|
HDPrivateKey._getDerivationIndexes = function(path) { |
|
|
|
var steps = path.split('/'); |
|
|
|
|
|
|
|
// Special cases:
|
|
|
|
if (_.contains(HDPrivateKey.RootElementAlias, path)) { |
|
|
|
return []; |
|
|
|
} |
|
|
|
|
|
|
|
if (!_.contains(HDPrivateKey.RootElementAlias, steps[0])) { |
|
|
|
return null; |
|
|
|
} |
|
|
|
|
|
|
|
var indexes = steps.slice(1).map(function(step) { |
|
|
|
var index = parseInt(step); |
|
|
|
index += step != index.toString() ? HDPrivateKey.Hardened : 0; |
|
|
|
return index; |
|
|
|
}); |
|
|
|
|
|
|
|
return _.any(indexes, isNaN) ? null : indexes; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Get a derivated child based on a string or number. |
|
|
|
* |
|
|
@ -114,18 +150,15 @@ HDPrivateKey.prototype.derive = function(arg, hardened) { |
|
|
|
HDPrivateKey.prototype._deriveWithNumber = function(index, hardened) { |
|
|
|
/* jshint maxstatements: 20 */ |
|
|
|
/* jshint maxcomplexity: 10 */ |
|
|
|
if (index >= HDPrivateKey.Hardened) { |
|
|
|
hardened = true; |
|
|
|
if (!HDPrivateKey.isValidPath(index, hardened)) { |
|
|
|
throw new hdErrors.InvalidPath(index); |
|
|
|
} |
|
|
|
|
|
|
|
if (index < HDPrivateKey.Hardened && hardened) { |
|
|
|
hardened = index >= HDPrivateKey.Hardened ? true : hardened; |
|
|
|
if (index < HDPrivateKey.Hardened && hardened === true) { |
|
|
|
index += HDPrivateKey.Hardened; |
|
|
|
} |
|
|
|
|
|
|
|
if (index < 0 || index >= HDPrivateKey.MaxIndex) { |
|
|
|
throw new hdErrors.InvalidPath(index); |
|
|
|
} |
|
|
|
|
|
|
|
var cached = HDKeyCache.get(this.xprivkey, index, hardened); |
|
|
|
if (cached) { |
|
|
|
return cached; |
|
|
@ -157,24 +190,16 @@ HDPrivateKey.prototype._deriveWithNumber = function(index, hardened) { |
|
|
|
}; |
|
|
|
|
|
|
|
HDPrivateKey.prototype._deriveFromString = function(path) { |
|
|
|
var steps = path.split('/'); |
|
|
|
|
|
|
|
// Special cases:
|
|
|
|
if (_.contains(HDPrivateKey.RootElementAlias, path)) { |
|
|
|
return this; |
|
|
|
} |
|
|
|
if (!_.contains(HDPrivateKey.RootElementAlias, steps[0])) { |
|
|
|
if (!HDPrivateKey.isValidPath(path)) { |
|
|
|
throw new hdErrors.InvalidPath(path); |
|
|
|
} |
|
|
|
steps = steps.slice(1); |
|
|
|
|
|
|
|
var result = this; |
|
|
|
for (var step in steps) { |
|
|
|
var index = parseInt(steps[step]); |
|
|
|
var hardened = steps[step] !== index.toString(); |
|
|
|
result = result._deriveWithNumber(index, hardened); |
|
|
|
} |
|
|
|
return result; |
|
|
|
var indexes = HDPrivateKey._getDerivationIndexes(path); |
|
|
|
var derived = indexes.reduce(function(prev, index) { |
|
|
|
return prev._deriveWithNumber(index); |
|
|
|
}, this); |
|
|
|
|
|
|
|
return derived; |
|
|
|
}; |
|
|
|
|
|
|
|
/** |
|
|
|