|
|
@ -16,8 +16,8 @@ var errors = bitcoreErrors; |
|
|
|
var hdErrors = bitcoreErrors.HDPublicKey; |
|
|
|
var assert = require('assert'); |
|
|
|
|
|
|
|
var jsUtil = require('./util/js'); |
|
|
|
var bufferUtil = require('./util/buffer'); |
|
|
|
var JSUtil = require('./util/js'); |
|
|
|
var BufferUtil = require('./util/buffer'); |
|
|
|
|
|
|
|
/** |
|
|
|
* The representation of an hierarchically derived public key. |
|
|
@ -37,12 +37,12 @@ function HDPublicKey(arg) { |
|
|
|
return new HDPublicKey(arg); |
|
|
|
} |
|
|
|
if (arg) { |
|
|
|
if (_.isString(arg) || bufferUtil.isBuffer(arg)) { |
|
|
|
if (_.isString(arg) || BufferUtil.isBuffer(arg)) { |
|
|
|
var error = HDPublicKey.getSerializedError(arg); |
|
|
|
if (!error) { |
|
|
|
return this._buildFromSerialized(arg); |
|
|
|
} else if (jsUtil.isValidJson(arg)) { |
|
|
|
return this._buildFromJson(arg); |
|
|
|
} else if (JSUtil.isValidJSON(arg)) { |
|
|
|
return this._buildFromJSON(arg); |
|
|
|
} else { |
|
|
|
if (error instanceof hdErrors.ArgumentIsPrivateExtended) { |
|
|
|
return new HDPrivateKey(arg).hdPublicKey; |
|
|
@ -105,8 +105,8 @@ HDPublicKey.prototype._deriveWithNumber = function (index, hardened) { |
|
|
|
return cached; |
|
|
|
} |
|
|
|
|
|
|
|
var indexBuffer = bufferUtil.integerAsBuffer(index); |
|
|
|
var data = bufferUtil.concat([this.publicKey.toBuffer(), indexBuffer]); |
|
|
|
var indexBuffer = BufferUtil.integerAsBuffer(index); |
|
|
|
var 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 chainCode = hash.slice(32, 64); |
|
|
@ -172,7 +172,7 @@ HDPublicKey.isValidSerialized = function (data, network) { |
|
|
|
HDPublicKey.getSerializedError = function (data, network) { |
|
|
|
/* jshint maxcomplexity: 10 */ |
|
|
|
/* jshint maxstatements: 20 */ |
|
|
|
if (!(_.isString(data) || bufferUtil.isBuffer(data))) { |
|
|
|
if (!(_.isString(data) || BufferUtil.isBuffer(data))) { |
|
|
|
return new hdErrors.UnrecognizedArgument('expected buffer or string'); |
|
|
|
} |
|
|
|
if (!Base58.validCharacters(data)) { |
|
|
@ -193,7 +193,7 @@ HDPublicKey.getSerializedError = function (data, network) { |
|
|
|
} |
|
|
|
} |
|
|
|
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 new hdErrors.ArgumentIsPrivateExtended(); |
|
|
|
} |
|
|
|
return null; |
|
|
@ -205,13 +205,13 @@ HDPublicKey._validateNetwork = function (data, networkArg) { |
|
|
|
return new errors.InvalidNetworkArgument(networkArg); |
|
|
|
} |
|
|
|
var version = data.slice(HDPublicKey.VersionStart, HDPublicKey.VersionEnd); |
|
|
|
if (bufferUtil.integerFromBuffer(version) !== network.xpubkey) { |
|
|
|
if (BufferUtil.integerFromBuffer(version) !== network.xpubkey) { |
|
|
|
return new errors.InvalidNetwork(version); |
|
|
|
} |
|
|
|
return null; |
|
|
|
}; |
|
|
|
|
|
|
|
HDPublicKey.prototype._buildFromJson = function (arg) { |
|
|
|
HDPublicKey.prototype._buildFromJSON = function (arg) { |
|
|
|
return this._buildFromObject(JSON.parse(arg)); |
|
|
|
}; |
|
|
|
|
|
|
@ -219,7 +219,7 @@ HDPublicKey.prototype._buildFromPrivate = function (arg) { |
|
|
|
var args = _.clone(arg._buffers); |
|
|
|
var point = Point.getG().mul(BN().fromBuffer(args.privateKey)); |
|
|
|
args.publicKey = Point.pointToCompressed(point); |
|
|
|
args.version = bufferUtil.integerAsBuffer(Network.get(bufferUtil.integerFromBuffer(args.version)).xpubkey); |
|
|
|
args.version = BufferUtil.integerAsBuffer(Network.get(BufferUtil.integerFromBuffer(args.version)).xpubkey); |
|
|
|
args.privateKey = undefined; |
|
|
|
args.checksum = undefined; |
|
|
|
args.xprivkey = undefined; |
|
|
@ -230,14 +230,14 @@ HDPublicKey.prototype._buildFromObject = function (arg) { |
|
|
|
/* jshint maxcomplexity: 10 */ |
|
|
|
// TODO: Type validation
|
|
|
|
var buffers = { |
|
|
|
version: arg.network ? bufferUtil.integerAsBuffer(Network.get(arg.network).xpubkey) : arg.version, |
|
|
|
depth: bufferUtil.integerAsSingleByteBuffer(arg.depth), |
|
|
|
parentFingerPrint: _.isNumber(arg.parentFingerPrint) ? bufferUtil.integerAsBuffer(arg.parentFingerPrint) : arg.parentFingerPrint, |
|
|
|
childIndex: bufferUtil.integerAsBuffer(arg.childIndex), |
|
|
|
chainCode: _.isString(arg.chainCode) ? bufferUtil.hexToBuffer(arg.chainCode) : arg.chainCode, |
|
|
|
publicKey: _.isString(arg.publicKey) ? bufferUtil.hexToBuffer(arg.publicKey) : |
|
|
|
bufferUtil.isBuffer(arg.publicKey) ? arg.publicKey : arg.publicKey.toBuffer(), |
|
|
|
checksum: _.isNumber(arg.checksum) ? bufferUtil.integerAsBuffer(arg.checksum) : arg.checksum |
|
|
|
version: arg.network ? BufferUtil.integerAsBuffer(Network.get(arg.network).xpubkey) : arg.version, |
|
|
|
depth: BufferUtil.integerAsSingleByteBuffer(arg.depth), |
|
|
|
parentFingerPrint: _.isNumber(arg.parentFingerPrint) ? BufferUtil.integerAsBuffer(arg.parentFingerPrint) : arg.parentFingerPrint, |
|
|
|
childIndex: BufferUtil.integerAsBuffer(arg.childIndex), |
|
|
|
chainCode: _.isString(arg.chainCode) ? BufferUtil.hexToBuffer(arg.chainCode) : arg.chainCode, |
|
|
|
publicKey: _.isString(arg.publicKey) ? BufferUtil.hexToBuffer(arg.publicKey) : |
|
|
|
BufferUtil.isBuffer(arg.publicKey) ? arg.publicKey : arg.publicKey.toBuffer(), |
|
|
|
checksum: _.isNumber(arg.checksum) ? BufferUtil.integerAsBuffer(arg.checksum) : arg.checksum |
|
|
|
}; |
|
|
|
return this._buildFromBuffers(buffers); |
|
|
|
}; |
|
|
@ -289,7 +289,7 @@ HDPublicKey.prototype._buildFromBuffers = function (arg) { |
|
|
|
arg.version, arg.depth, arg.parentFingerPrint, arg.childIndex, arg.chainCode, |
|
|
|
arg.publicKey |
|
|
|
]; |
|
|
|
var concat = bufferUtil.concat(sequence); |
|
|
|
var concat = BufferUtil.concat(sequence); |
|
|
|
var checksum = Base58Check.checksum(concat); |
|
|
|
if (!arg.checksum || !arg.checksum.length) { |
|
|
|
arg.checksum = checksum; |
|
|
@ -302,7 +302,7 @@ HDPublicKey.prototype._buildFromBuffers = function (arg) { |
|
|
|
var xpubkey; |
|
|
|
|
|
|
|
if (!arg.xpubkey) { |
|
|
|
xpubkey = Base58Check.encode(bufferUtil.concat(sequence)); |
|
|
|
xpubkey = Base58Check.encode(BufferUtil.concat(sequence)); |
|
|
|
} else { |
|
|
|
xpubkey = arg.xpubkey; |
|
|
|
} |
|
|
@ -311,10 +311,10 @@ HDPublicKey.prototype._buildFromBuffers = function (arg) { |
|
|
|
var size = HDPublicKey.ParentFingerPrintSize; |
|
|
|
var fingerPrint = Hash.sha256ripemd160(publicKey.toBuffer()).slice(0, size); |
|
|
|
|
|
|
|
jsUtil.defineImmutable(this, { |
|
|
|
JSUtil.defineImmutable(this, { |
|
|
|
xpubkey: xpubkey, |
|
|
|
network: Network.get(bufferUtil.integerFromBuffer(arg.version)), |
|
|
|
depth: bufferUtil.integerFromSingleByteBuffer(arg.depth), |
|
|
|
network: Network.get(BufferUtil.integerFromBuffer(arg.version)), |
|
|
|
depth: BufferUtil.integerFromSingleByteBuffer(arg.depth), |
|
|
|
publicKey: publicKey, |
|
|
|
fingerPrint: fingerPrint |
|
|
|
}); |
|
|
@ -325,7 +325,7 @@ HDPublicKey.prototype._buildFromBuffers = function (arg) { |
|
|
|
HDPublicKey._validateBufferArguments = function (arg) { |
|
|
|
var checkBuffer = function(name, size) { |
|
|
|
var buff = arg[name]; |
|
|
|
assert(bufferUtil.isBuffer(buff), name + ' argument is not a buffer, it\'s ' + typeof buff); |
|
|
|
assert(BufferUtil.isBuffer(buff), name + ' argument is not a buffer, it\'s ' + typeof buff); |
|
|
|
assert( |
|
|
|
buff.length === size, |
|
|
|
name + ' has not the expected size: found ' + buff.length + ', expected ' + size |
|
|
@ -362,34 +362,24 @@ HDPublicKey.prototype.toString = function () { |
|
|
|
* * childIndex: index with which this key was derived |
|
|
|
* * chainCode: string in hexa encoding used for derivation |
|
|
|
* * publicKey: string, hexa encoded, in compressed key format |
|
|
|
* * checksum: bufferUtil.integerFromBuffer(this._buffers.checksum), |
|
|
|
* * checksum: BufferUtil.integerFromBuffer(this._buffers.checksum), |
|
|
|
* * xpubkey: the string with the base58 representation of this extended key |
|
|
|
* * checksum: the base58 checksum of xpubkey |
|
|
|
*/ |
|
|
|
HDPublicKey.prototype.toObject = function () { |
|
|
|
HDPublicKey.prototype.toJSON = function () { |
|
|
|
return { |
|
|
|
network: Network.get(bufferUtil.integerFromBuffer(this._buffers.version)).name, |
|
|
|
depth: bufferUtil.integerFromSingleByteBuffer(this._buffers.depth), |
|
|
|
fingerPrint: bufferUtil.integerFromBuffer(this.fingerPrint), |
|
|
|
parentFingerPrint: bufferUtil.integerFromBuffer(this._buffers.parentFingerPrint), |
|
|
|
childIndex: bufferUtil.integerFromBuffer(this._buffers.childIndex), |
|
|
|
chainCode: bufferUtil.bufferToHex(this._buffers.chainCode), |
|
|
|
network: Network.get(BufferUtil.integerFromBuffer(this._buffers.version)).name, |
|
|
|
depth: BufferUtil.integerFromSingleByteBuffer(this._buffers.depth), |
|
|
|
fingerPrint: BufferUtil.integerFromBuffer(this.fingerPrint), |
|
|
|
parentFingerPrint: BufferUtil.integerFromBuffer(this._buffers.parentFingerPrint), |
|
|
|
childIndex: BufferUtil.integerFromBuffer(this._buffers.childIndex), |
|
|
|
chainCode: BufferUtil.bufferToHex(this._buffers.chainCode), |
|
|
|
publicKey: this.publicKey.toString(), |
|
|
|
checksum: bufferUtil.integerFromBuffer(this._buffers.checksum), |
|
|
|
checksum: BufferUtil.integerFromBuffer(this._buffers.checksum), |
|
|
|
xpubkey: this.xpubkey |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
/** |
|
|
|
* Returns the JSON representation of this key's <tt>toObject</tt> result |
|
|
|
* |
|
|
|
* @see {HDPublicKey#toObject} |
|
|
|
* @return {string} |
|
|
|
*/ |
|
|
|
HDPublicKey.prototype.toJson = function () { |
|
|
|
return JSON.stringify(this.toObject()); |
|
|
|
}; |
|
|
|
|
|
|
|
HDPublicKey.Hardened = 0x80000000; |
|
|
|
HDPublicKey.RootElementAlias = ['m', 'M']; |
|
|
|
|
|
|
|