|
@ -12,6 +12,7 @@ var Point = require('./crypto/point'); |
|
|
var PublicKey = require('./publickey'); |
|
|
var PublicKey = require('./publickey'); |
|
|
|
|
|
|
|
|
var assert = require('assert'); |
|
|
var assert = require('assert'); |
|
|
|
|
|
var inherits = require('inherits'); |
|
|
|
|
|
|
|
|
var jsUtil = require('./util/js'); |
|
|
var jsUtil = require('./util/js'); |
|
|
var bufferUtil = require('./util/buffer'); |
|
|
var bufferUtil = require('./util/buffer'); |
|
@ -35,16 +36,16 @@ function HDPublicKey(arg) { |
|
|
} |
|
|
} |
|
|
if (arg) { |
|
|
if (arg) { |
|
|
if (_.isString(arg) || bufferUtil.isBuffer(arg)) { |
|
|
if (_.isString(arg) || bufferUtil.isBuffer(arg)) { |
|
|
if (HDPublicKey.isValidSerialized(arg)) { |
|
|
var error = HDPublicKey.getSerializedError(arg); |
|
|
|
|
|
if (!error) { |
|
|
return this._buildFromSerialized(arg); |
|
|
return this._buildFromSerialized(arg); |
|
|
} else if (jsUtil.isValidJson(arg)) { |
|
|
} else if (jsUtil.isValidJson(arg)) { |
|
|
return this._buildFromJson(arg); |
|
|
return this._buildFromJson(arg); |
|
|
} else { |
|
|
} else { |
|
|
var error = HDPublicKey.getSerializedError(arg); |
|
|
if (error instanceof HDPublicKey.Error.ArgumentIsPrivateExtended) { |
|
|
if (error === HDPublicKey.Errors.ArgumentIsPrivateExtended) { |
|
|
|
|
|
return new HDPrivateKey(arg).hdPublicKey; |
|
|
return new HDPrivateKey(arg).hdPublicKey; |
|
|
} |
|
|
} |
|
|
throw new Error(error); |
|
|
throw error; |
|
|
} |
|
|
} |
|
|
} else { |
|
|
} else { |
|
|
if (_.isObject(arg)) { |
|
|
if (_.isObject(arg)) { |
|
@ -54,11 +55,11 @@ function HDPublicKey(arg) { |
|
|
return this._buildFromObject(arg); |
|
|
return this._buildFromObject(arg); |
|
|
} |
|
|
} |
|
|
} else { |
|
|
} else { |
|
|
throw new Error(HDPublicKey.Errors.UnrecognizedArgument); |
|
|
throw new HDPublicKey.Error.UnrecognizedArgument(arg); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} else { |
|
|
} else { |
|
|
throw new Error(HDPublicKey.Errors.MustSupplyArgument); |
|
|
throw new HDPublicKey.Error.MustSupplyArgument(); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -89,13 +90,13 @@ HDPublicKey.prototype.derive = function (arg, hardened) { |
|
|
} else if (_.isString(arg)) { |
|
|
} else if (_.isString(arg)) { |
|
|
return this._deriveFromString(arg); |
|
|
return this._deriveFromString(arg); |
|
|
} else { |
|
|
} else { |
|
|
throw new Error(HDPublicKey.Errors.InvalidDerivationArgument); |
|
|
throw new HDPublicKey.Error.InvalidDerivationArgument(arg); |
|
|
} |
|
|
} |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
HDPublicKey.prototype._deriveWithNumber = function (index, hardened) { |
|
|
HDPublicKey.prototype._deriveWithNumber = function (index, hardened) { |
|
|
if (hardened || index >= HDPublicKey.Hardened) { |
|
|
if (hardened || index >= HDPublicKey.Hardened) { |
|
|
throw new Error(HDPublicKey.Errors.InvalidIndexCantDeriveHardened); |
|
|
throw new HDPublicKey.Error.InvalidIndexCantDeriveHardened(); |
|
|
} |
|
|
} |
|
|
var cached = HDKeyCache.get(this.xpubkey, index, hardened); |
|
|
var cached = HDKeyCache.get(this.xpubkey, index, hardened); |
|
|
if (cached) { |
|
|
if (cached) { |
|
@ -131,7 +132,7 @@ HDPublicKey.prototype._deriveFromString = function (path) { |
|
|
return this; |
|
|
return this; |
|
|
} |
|
|
} |
|
|
if (!_.contains(HDPublicKey.RootElementAlias, steps[0])) { |
|
|
if (!_.contains(HDPublicKey.RootElementAlias, steps[0])) { |
|
|
throw new Error(HDPublicKey.Errors.InvalidPath); |
|
|
throw new HDPublicKey.Error.InvalidPath(path); |
|
|
} |
|
|
} |
|
|
steps = steps.slice(1); |
|
|
steps = steps.slice(1); |
|
|
|
|
|
|
|
@ -154,7 +155,7 @@ HDPublicKey.prototype._deriveFromString = function (path) { |
|
|
* @return {boolean} |
|
|
* @return {boolean} |
|
|
*/ |
|
|
*/ |
|
|
HDPublicKey.isValidSerialized = function (data, network) { |
|
|
HDPublicKey.isValidSerialized = function (data, network) { |
|
|
return !HDPublicKey.getSerializedError(data, network); |
|
|
return _.isNull(HDPublicKey.getSerializedError(data, network)); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
@ -164,24 +165,24 @@ HDPublicKey.isValidSerialized = function (data, network) { |
|
|
* @param {string|Buffer} data - the serialized private key |
|
|
* @param {string|Buffer} data - the serialized private key |
|
|
* @param {string|Network=} network - optional, if present, checks that the |
|
|
* @param {string|Network=} network - optional, if present, checks that the |
|
|
* network provided matches the network serialized. |
|
|
* network provided matches the network serialized. |
|
|
* @return {HDPublicKey.Errors|null} |
|
|
* @return {HDPublicKey.Error|null} |
|
|
*/ |
|
|
*/ |
|
|
HDPublicKey.getSerializedError = function (data, network) { |
|
|
HDPublicKey.getSerializedError = function (data, network) { |
|
|
/* jshint maxcomplexity: 10 */ |
|
|
/* jshint maxcomplexity: 10 */ |
|
|
/* jshint maxstatements: 20 */ |
|
|
/* jshint maxstatements: 20 */ |
|
|
if (!(_.isString(data) || bufferUtil.isBuffer(data))) { |
|
|
if (!(_.isString(data) || bufferUtil.isBuffer(data))) { |
|
|
return HDPublicKey.Errors.InvalidArgument; |
|
|
return new HDPublicKey.Error.InvalidArgument('expected buffer or string'); |
|
|
} |
|
|
} |
|
|
if (!Base58.validCharacters(data)) { |
|
|
if (!Base58.validCharacters(data)) { |
|
|
return HDPublicKey.Errors.InvalidB58Char; |
|
|
return new HDPublicKey.Error.InvalidB58Char('(unknown)', data); |
|
|
} |
|
|
} |
|
|
try { |
|
|
try { |
|
|
data = Base58Check.decode(data); |
|
|
data = Base58Check.decode(data); |
|
|
} catch (e) { |
|
|
} catch (e) { |
|
|
return HDPublicKey.Errors.InvalidB58Checksum; |
|
|
return new HDPublicKey.Error.InvalidB58Checksum(data); |
|
|
} |
|
|
} |
|
|
if (data.length !== 78) { |
|
|
if (data.length !== HDPublicKey.DataSize) { |
|
|
return HDPublicKey.Errors.InvalidLength; |
|
|
return new HDPublicKey.Error.InvalidLength(data); |
|
|
} |
|
|
} |
|
|
if (!_.isUndefined(network)) { |
|
|
if (!_.isUndefined(network)) { |
|
|
var error = HDPublicKey._validateNetwork(data, network); |
|
|
var error = HDPublicKey._validateNetwork(data, network); |
|
@ -191,19 +192,19 @@ HDPublicKey.getSerializedError = function (data, network) { |
|
|
} |
|
|
} |
|
|
network = Network.get(network) || Network.defaultNetwork; |
|
|
network = Network.get(network) || Network.defaultNetwork; |
|
|
if (bufferUtil.integerFromBuffer(data.slice(0, 4)) === network.xprivkey) { |
|
|
if (bufferUtil.integerFromBuffer(data.slice(0, 4)) === network.xprivkey) { |
|
|
return HDPublicKey.Errors.ArgumentIsPrivateExtended; |
|
|
return new HDPublicKey.Error.ArgumentIsPrivateExtended(); |
|
|
} |
|
|
} |
|
|
return null; |
|
|
return null; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
HDPublicKey._validateNetwork = function (data, network) { |
|
|
HDPublicKey._validateNetwork = function (data, networkArg) { |
|
|
network = Network.get(network); |
|
|
var network = Network.get(networkArg); |
|
|
if (!network) { |
|
|
if (!network) { |
|
|
return HDPublicKey.Errors.InvalidNetworkArgument; |
|
|
return new HDPublicKey.Error.InvalidNetworkArgument(networkArg); |
|
|
} |
|
|
} |
|
|
var version = data.slice(HDPublicKey.VersionStart, HDPublicKey.VersionEnd); |
|
|
var version = data.slice(HDPublicKey.VersionStart, HDPublicKey.VersionEnd); |
|
|
if (bufferUtil.integerFromBuffer(version) !== network.xpubkey) { |
|
|
if (bufferUtil.integerFromBuffer(version) !== network.xpubkey) { |
|
|
return HDPublicKey.Errors.InvalidNetwork; |
|
|
return new HDPublicKey.Error.InvalidNetwork(version); |
|
|
} |
|
|
} |
|
|
return null; |
|
|
return null; |
|
|
}; |
|
|
}; |
|
@ -288,7 +289,7 @@ HDPublicKey.prototype._buildFromBuffers = function (arg) { |
|
|
arg.checksum = checksum; |
|
|
arg.checksum = checksum; |
|
|
} else { |
|
|
} else { |
|
|
if (arg.checksum.toString('hex') !== checksum.toString('hex')) { |
|
|
if (arg.checksum.toString('hex') !== checksum.toString('hex')) { |
|
|
throw new Error(HDPublicKey.Errors.InvalidB58Checksum); |
|
|
throw new HDPublicKey.Error.InvalidB58Checksum(concat, checksum); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -385,6 +386,7 @@ HDPublicKey.ChainCodeSize = 32; |
|
|
HDPublicKey.PublicKeySize = 33; |
|
|
HDPublicKey.PublicKeySize = 33; |
|
|
HDPublicKey.CheckSumSize = 4; |
|
|
HDPublicKey.CheckSumSize = 4; |
|
|
|
|
|
|
|
|
|
|
|
HDPublicKey.DataSize = 78; |
|
|
HDPublicKey.SerializedByteSize = 82; |
|
|
HDPublicKey.SerializedByteSize = 82; |
|
|
|
|
|
|
|
|
HDPublicKey.VersionStart = 0; |
|
|
HDPublicKey.VersionStart = 0; |
|
@ -402,25 +404,78 @@ HDPublicKey.PublicKeyEnd = HDPublicKey.PublicKeyStart + HDPublicKey.Pu |
|
|
HDPublicKey.ChecksumStart = HDPublicKey.PublicKeyEnd; |
|
|
HDPublicKey.ChecksumStart = HDPublicKey.PublicKeyEnd; |
|
|
HDPublicKey.ChecksumEnd = HDPublicKey.ChecksumStart + HDPublicKey.CheckSumSize; |
|
|
HDPublicKey.ChecksumEnd = HDPublicKey.ChecksumStart + HDPublicKey.CheckSumSize; |
|
|
|
|
|
|
|
|
|
|
|
assert(HDPublicKey.PublicKeyEnd === HDPublicKey.DataSize); |
|
|
assert(HDPublicKey.ChecksumEnd === HDPublicKey.SerializedByteSize); |
|
|
assert(HDPublicKey.ChecksumEnd === HDPublicKey.SerializedByteSize); |
|
|
|
|
|
|
|
|
HDPublicKey.Errors = {}; |
|
|
HDPublicKey.Error = function() { |
|
|
HDPublicKey.Errors.ArgumentIsPrivateExtended = 'Argument starts with xpriv..., it\'s a private key'; |
|
|
Error.apply(this, arguments); |
|
|
HDPublicKey.Errors.InvalidArgument = 'Invalid argument, expected string or Buffer'; |
|
|
}; |
|
|
HDPublicKey.Errors.InvalidB58Char = 'Invalid Base 58 character'; |
|
|
inherits(HDPublicKey.Error, Error); |
|
|
HDPublicKey.Errors.InvalidB58Checksum = 'Invalid Base 58 checksum'; |
|
|
|
|
|
HDPublicKey.Errors.InvalidChildIndex = 'Invalid Child Index - must be a number'; |
|
|
|
|
|
HDPublicKey.Errors.InvalidConstant = 'Unrecognized xpubkey version'; |
|
|
|
|
|
HDPublicKey.Errors.InvalidDepth = 'Invalid depth parameter - must be a number'; |
|
|
|
|
|
HDPublicKey.Errors.InvalidDerivationArgument = 'Invalid argument, expected number and boolean or string'; |
|
|
|
|
|
HDPublicKey.Errors.InvalidEntropyArg = 'Invalid argument: entropy must be an hexa string or binary buffer'; |
|
|
|
|
|
HDPublicKey.Errors.InvalidLength = 'Invalid length for xpubkey format'; |
|
|
|
|
|
HDPublicKey.Errors.InvalidNetwork = 'Unexpected version for network'; |
|
|
|
|
|
HDPublicKey.Errors.InvalidNetworkArgument = 'Network argument must be \'livenet\' or \'testnet\''; |
|
|
|
|
|
HDPublicKey.Errors.InvalidParentFingerPrint = 'Invalid Parent Fingerprint - must be a number'; |
|
|
|
|
|
HDPublicKey.Errors.InvalidPath = 'Invalid path for derivation: must start with "m"'; |
|
|
|
|
|
HDPublicKey.Errors.MustSupplyArgument = 'Must supply an argument for the constructor'; |
|
|
|
|
|
HDPublicKey.Errors.UnrecognizedArgument = 'Creating a HDPublicKey requires a string, a buffer, a json, or an object'; |
|
|
|
|
|
|
|
|
|
|
|
module.exports = HDPublicKey; |
|
|
HDPublicKey.Error.InvalidArgument = function() { |
|
|
|
|
|
HDPublicKey.Error.apply(this, arguments); |
|
|
|
|
|
this.message = 'Invalid argument'; |
|
|
|
|
|
}; |
|
|
|
|
|
inherits(HDPublicKey.Error.InvalidArgument, HDPublicKey.Error); |
|
|
|
|
|
|
|
|
|
|
|
HDPublicKey.Error.ArgumentIsPrivateExtended = function() { |
|
|
|
|
|
HDPublicKey.Error.InvalidArgument.apply(this, arguments); |
|
|
|
|
|
this.message = 'Argument starts with xpriv..., it\'s a private key'; |
|
|
|
|
|
}; |
|
|
|
|
|
inherits(HDPublicKey.Error.ArgumentIsPrivateExtended, HDPublicKey.Error.InvalidArgument); |
|
|
|
|
|
|
|
|
|
|
|
HDPublicKey.Error.InvalidB58Char = function() { |
|
|
|
|
|
HDPublicKey.Error.InvalidArgument.apply(this, arguments); |
|
|
|
|
|
this.message = 'Invalid Base 58 character'; |
|
|
|
|
|
}; |
|
|
|
|
|
inherits(HDPublicKey.Error.InvalidB58Char, HDPublicKey.Error.InvalidArgument); |
|
|
|
|
|
|
|
|
|
|
|
HDPublicKey.Error.InvalidB58Checksum = function() { |
|
|
|
|
|
HDPublicKey.Error.InvalidArgument.apply(this, arguments); |
|
|
|
|
|
this.message = 'Invalid Base 58 checksum'; |
|
|
|
|
|
}; |
|
|
|
|
|
inherits(HDPublicKey.Error.InvalidB58Checksum, HDPublicKey.Error.InvalidArgument); |
|
|
|
|
|
|
|
|
|
|
|
HDPublicKey.Error.InvalidDerivationArgument = function() { |
|
|
|
|
|
HDPublicKey.Error.InvalidArgument.apply(this, arguments); |
|
|
|
|
|
this.message = 'Invalid argument, expected number and boolean or string'; |
|
|
|
|
|
}; |
|
|
|
|
|
inherits(HDPublicKey.Error.InvalidDerivationArgument, HDPublicKey.Error.InvalidArgument); |
|
|
|
|
|
|
|
|
|
|
|
HDPublicKey.Error.InvalidLength = function() { |
|
|
|
|
|
HDPublicKey.Error.InvalidArgument.apply(this, arguments); |
|
|
|
|
|
this.message = 'Invalid length for xpubkey format'; |
|
|
|
|
|
}; |
|
|
|
|
|
inherits(HDPublicKey.Error.InvalidLength, HDPublicKey.Error.InvalidArgument); |
|
|
|
|
|
|
|
|
|
|
|
HDPublicKey.Error.InvalidNetwork = function() { |
|
|
|
|
|
HDPublicKey.Error.InvalidArgument.apply(this, arguments); |
|
|
|
|
|
this.message = 'Unexpected version for network'; |
|
|
|
|
|
}; |
|
|
|
|
|
inherits(HDPublicKey.Error.InvalidNetwork, HDPublicKey.Error.InvalidArgument); |
|
|
|
|
|
|
|
|
|
|
|
HDPublicKey.Error.InvalidNetworkArgument = function() { |
|
|
|
|
|
HDPublicKey.Error.InvalidArgument.apply(this, arguments); |
|
|
|
|
|
this.message = 'Network argument must be \'livenet\' or \'testnet\''; |
|
|
|
|
|
}; |
|
|
|
|
|
inherits(HDPublicKey.Error.InvalidNetworkArgument, HDPublicKey.Error.InvalidArgument); |
|
|
|
|
|
|
|
|
|
|
|
HDPublicKey.Error.InvalidPath = function() { |
|
|
|
|
|
HDPublicKey.Error.InvalidArgument.apply(this, arguments); |
|
|
|
|
|
this.message = 'Invalid path for derivation: must start with "m"'; |
|
|
|
|
|
}; |
|
|
|
|
|
inherits(HDPublicKey.Error.InvalidPath, HDPublicKey.Error.InvalidArgument); |
|
|
|
|
|
|
|
|
|
|
|
HDPublicKey.Error.MustSupplyArgument = function() { |
|
|
|
|
|
HDPublicKey.Error.InvalidArgument.apply(this, arguments); |
|
|
|
|
|
this.message = 'Must supply an argument for the constructor'; |
|
|
|
|
|
}; |
|
|
|
|
|
inherits(HDPublicKey.Error.MustSupplyArgument, HDPublicKey.Error.InvalidArgument); |
|
|
|
|
|
|
|
|
|
|
|
HDPublicKey.Error.UnrecognizedArgument = function() { |
|
|
|
|
|
HDPublicKey.Error.InvalidArgument.apply(this, arguments); |
|
|
|
|
|
this.message = 'Creating a HDPublicKey requires a string, a buffer, a json, or an object'; |
|
|
|
|
|
}; |
|
|
|
|
|
inherits(HDPublicKey.Error.UnrecognizedArgument, HDPublicKey.Error.InvalidArgument); |
|
|
|
|
|
|
|
|
|
|
|
module.exports = HDPublicKey; |
|
|