|
|
@ -5,9 +5,9 @@ var BN = require('./crypto/bn'); |
|
|
|
var Base58 = require('./encoding/base58'); |
|
|
|
var Base58Check = require('./encoding/base58check'); |
|
|
|
var Hash = require('./crypto/hash'); |
|
|
|
var Network = require('./network'); |
|
|
|
var Network = require('./networks'); |
|
|
|
var Point = require('./crypto/point'); |
|
|
|
var PrivateKey = require('./privkey'); |
|
|
|
var PrivateKey = require('./privatekey'); |
|
|
|
var Random = require('./crypto/random'); |
|
|
|
|
|
|
|
var assert = require('assert'); |
|
|
@ -15,7 +15,7 @@ var buffer = require('buffer'); |
|
|
|
var util = require('./util'); |
|
|
|
|
|
|
|
var MINIMUM_ENTROPY_BITS = 128; |
|
|
|
var BITS_TO_BYTES = 128; |
|
|
|
var BITS_TO_BYTES = 1/8; |
|
|
|
var MAXIMUM_ENTROPY_BITS = 512; |
|
|
|
|
|
|
|
|
|
|
@ -24,21 +24,21 @@ function HDPrivateKey(arg) { |
|
|
|
if (arg instanceof HDPrivateKey) { |
|
|
|
return arg; |
|
|
|
} |
|
|
|
if (!this instanceof HDPrivateKey) { |
|
|
|
if (!(this instanceof HDPrivateKey)) { |
|
|
|
return new HDPrivateKey(arg); |
|
|
|
} |
|
|
|
if (arg) { |
|
|
|
if (_.isString(arg) || buffer.Buffer.isBuffer(arg)) { |
|
|
|
if (HDPrivateKey.isValidSerialized(arg)) { |
|
|
|
this._buildFromSerialized(arg); |
|
|
|
} else if (util.isValidJson(arg)) { |
|
|
|
this._buildFromJson(arg); |
|
|
|
} else { |
|
|
|
throw new Error(HDPrivateKey.Errors.UnrecognizedArgument); |
|
|
|
throw new Error(HDPrivateKey.getSerializedError(arg)); |
|
|
|
} |
|
|
|
} else { |
|
|
|
if (_.isObject(arg)) { |
|
|
|
this._buildFromObject(arg); |
|
|
|
} else if (util.isValidJson(arg)) { |
|
|
|
this._buildFromJson(arg); |
|
|
|
} else { |
|
|
|
throw new Error(HDPrivateKey.Errors.UnrecognizedArgument); |
|
|
|
} |
|
|
@ -70,11 +70,12 @@ HDPrivateKey.prototype._deriveWithNumber = function deriveWithNumber(index, hard |
|
|
|
} else { |
|
|
|
data = buffer.Buffer.concat([this.publicKey.toBuffer(), indexBuffer]); |
|
|
|
} |
|
|
|
var hash = Hash.sha512hmac(data, this.chainCode); |
|
|
|
var hash = Hash.sha512hmac(data, this._buffers.chainCode); |
|
|
|
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()); |
|
|
|
var privateKey = leftPart.add(this.privateKey.toBigNumber()).mod(Point.getN()).toBuffer({size: 32}); |
|
|
|
console.log(privateKey); |
|
|
|
|
|
|
|
return new HDPrivateKey({ |
|
|
|
network: this.network, |
|
|
@ -134,13 +135,12 @@ HDPrivateKey.getSerializedError = function getSerializedError(data, network) { |
|
|
|
if (!(_.isString(data) || buffer.Buffer.isBuffer(data))) { |
|
|
|
return HDPrivateKey.Errors.InvalidArgument; |
|
|
|
} |
|
|
|
if (_.isString(data)) { |
|
|
|
data = new buffer.Buffer(data); |
|
|
|
} |
|
|
|
if (!Base58.validCharacters(data)) { |
|
|
|
return HDPrivateKey.Errors.InvalidB58Char; |
|
|
|
} |
|
|
|
if (!Base58Check.validChecksum(data)) { |
|
|
|
try { |
|
|
|
data = Base58Check.decode(data); |
|
|
|
} catch (e) { |
|
|
|
return HDPrivateKey.Errors.InvalidB58Checksum; |
|
|
|
} |
|
|
|
if (data.length !== 78) { |
|
|
@ -175,12 +175,12 @@ HDPrivateKey.prototype._buildFromObject = function buildFromObject(arg) { |
|
|
|
// TODO: Type validation
|
|
|
|
var buffers = { |
|
|
|
version: util.integerAsBuffer(Network.get(arg.network).xprivkey), |
|
|
|
depth: util.integerAsBuffer(arg.depth), |
|
|
|
depth: util.integerAsSingleByteBuffer(arg.depth), |
|
|
|
parentFingerPrint: util.integerAsBuffer(arg.parentFingerPrint), |
|
|
|
childIndex: util.integerAsBuffer(arg.childIndex), |
|
|
|
chainCode: util.integerAsBuffer(arg.chainCode), |
|
|
|
privateKey: util.hexToBuffer(arg.privateKey), |
|
|
|
checksum: util.integerAsBuffer(arg.checksum) |
|
|
|
chainCode: _.isString(arg.chainCode) ? util.hexToBuffer(arg.chainCode) : arg.chainCode, |
|
|
|
privateKey: _.isString(arg.privateKey) ? util.hexToBuffer(arg.privateKey) : arg.privateKey, |
|
|
|
checksum: arg.checksum && arg.checksum.length ? util.integerAsBuffer(arg.checksum) : undefined |
|
|
|
}; |
|
|
|
return this._buildFromBuffers(buffers); |
|
|
|
}; |
|
|
@ -196,7 +196,7 @@ HDPrivateKey.prototype._buildFromSerialized = function buildFromSerialized(arg) |
|
|
|
chainCode: decoded.slice(HDPrivateKey.ChainCodeStart, HDPrivateKey.ChainCodeEnd), |
|
|
|
privateKey: decoded.slice(HDPrivateKey.PrivateKeyStart, HDPrivateKey.PrivateKeyEnd), |
|
|
|
checksum: decoded.slice(HDPrivateKey.ChecksumStart, HDPrivateKey.ChecksumEnd), |
|
|
|
xprivkey: decoded.toString() |
|
|
|
xprivkey: arg |
|
|
|
}; |
|
|
|
return this._buildFromBuffers(buffers); |
|
|
|
}; |
|
|
@ -227,8 +227,8 @@ HDPrivateKey.fromSeed = function fromSeed(hexa, network) { |
|
|
|
depth: 0, |
|
|
|
parentFingerPrint: 0, |
|
|
|
childIndex: 0, |
|
|
|
chainCode: hash.slice(32, 64), |
|
|
|
privateKey: hash.slice(0, 32) |
|
|
|
privateKey: hash.slice(0, 32), |
|
|
|
chainCode: hash.slice(32, 64) |
|
|
|
}); |
|
|
|
}; |
|
|
|
|
|
|
@ -249,16 +249,21 @@ HDPrivateKey.fromSeed = function fromSeed(hexa, network) { |
|
|
|
* @return {HDPrivateKey} this |
|
|
|
*/ |
|
|
|
HDPrivateKey.prototype._buildFromBuffers = function buildFromBuffers(arg) { |
|
|
|
/* jshint maxcomplexity: 8 */ |
|
|
|
|
|
|
|
console.log(arg.privateKey); |
|
|
|
HDPrivateKey._validateBufferArguments(arg); |
|
|
|
this._buffers = arg; |
|
|
|
console.log(arg.privateKey); |
|
|
|
|
|
|
|
var sequence = [ |
|
|
|
arg.version, arg.depth, arg.parentFingerPrint, arg.childIndex, arg.chainCode, |
|
|
|
util.emptyBuffer(1), arg.privateKey, |
|
|
|
util.emptyBuffer(1), arg.privateKey |
|
|
|
]; |
|
|
|
if (!arg.checksum) { |
|
|
|
arg.checksum = Base58Check.checksum(sequence); |
|
|
|
console.log(arg.privateKey); |
|
|
|
console.log(sequence); |
|
|
|
if (!arg.checksum || !arg.checksum.length) { |
|
|
|
arg.checksum = Base58Check.checksum(buffer.Buffer.concat(sequence)); |
|
|
|
} else { |
|
|
|
if (arg.checksum.toString() !== sequence.toString()) { |
|
|
|
throw new Error(HDPrivateKey.Errors.InvalidB58Checksum); |
|
|
@ -275,29 +280,32 @@ HDPrivateKey.prototype._buildFromBuffers = function buildFromBuffers(arg) { |
|
|
|
// TODO:
|
|
|
|
// * Instantiate associated HDPublicKey
|
|
|
|
|
|
|
|
this.network = Network.get(util.integerFromBuffer(arg.version)); |
|
|
|
this.privateKey = new PrivateKey(arg.privateKey); |
|
|
|
this.publicKey = this.privateKey.publicKey; |
|
|
|
this.fingerPrint = Base58Check.checksum(this.publicKey._value); |
|
|
|
this.fingerPrint = Base58Check.checksum(util.hexToBuffer(this.publicKey.toString())); |
|
|
|
|
|
|
|
return this; |
|
|
|
}; |
|
|
|
|
|
|
|
HDPrivateKey._validateBufferArguments = function validateBufferArguments(arg) { |
|
|
|
var checkBuffer = function(name, size) { |
|
|
|
var buffer = arg[name]; |
|
|
|
assert(buffer.Buffer.isBuffer(buffer), name + ' argument is not a buffer'); |
|
|
|
var buff = arg[name]; |
|
|
|
assert(buffer.Buffer.isBuffer(buff), name + ' argument is not a buffer'); |
|
|
|
assert( |
|
|
|
buffer.length === size, |
|
|
|
name + ' has not the expected size: found ' + buffer.length + ', expected ' + size |
|
|
|
buff.length === size, |
|
|
|
name + ' has not the expected size: found ' + buff.length + ', expected ' + size |
|
|
|
); |
|
|
|
}; |
|
|
|
checkBuffer('version', HDPrivateKey.VersionSize); |
|
|
|
checkBuffer('depth', HDPrivateKey.DepthLength); |
|
|
|
checkBuffer('depth', HDPrivateKey.DepthSize); |
|
|
|
checkBuffer('parentFingerPrint', HDPrivateKey.ParentFingerPrintSize); |
|
|
|
checkBuffer('childIndex', HDPrivateKey.ChildIndexSize); |
|
|
|
checkBuffer('chainCode', HDPrivateKey.ChainCodeSize); |
|
|
|
checkBuffer('privateKey', HDPrivateKey.PrivateKeySize); |
|
|
|
checkBuffer('checksum', HDPrivateKey.CheckSumSize); |
|
|
|
if (arg.checksum && arg.checksum.length) { |
|
|
|
checkBuffer('checksum', HDPrivateKey.CheckSumSize); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
HDPrivateKey.prototype.toString = function toString() { |
|
|
@ -330,22 +338,31 @@ HDPrivateKey.Hardened = 0x80000000; |
|
|
|
HDPrivateKey.RootElementAlias = ['m', 'M', 'm\'', 'M\'']; |
|
|
|
|
|
|
|
HDPrivateKey.VersionSize = 4; |
|
|
|
HDPrivateKey.DepthLength = 4; |
|
|
|
HDPrivateKey.DepthSize = 1; |
|
|
|
HDPrivateKey.ParentFingerPrintSize = 4; |
|
|
|
HDPrivateKey.ChildIndexSize = 4; |
|
|
|
HDPrivateKey.ChainCodeSize = 32; |
|
|
|
HDPrivateKey.PrivateKeySize = 32; |
|
|
|
HDPrivateKey.CheckSumSize = 4; |
|
|
|
|
|
|
|
HDPrivateKey.VersionStart = 0; |
|
|
|
HDPrivateKey.VersionEnd = HDPrivateKey.DepthStart = 4; |
|
|
|
HDPrivateKey.DepthEnd = HDPrivateKey.ParentFingerPrintStart = 8; |
|
|
|
HDPrivateKey.ParentFingerPrintEnd = HDPrivateKey.ChildIndexStart = 12; |
|
|
|
HDPrivateKey.ChildIndexEnd = HDPrivateKey.ChainCodeStart = 16; |
|
|
|
HDPrivateKey.ChainCodeEnd = 32; |
|
|
|
HDPrivateKey.PrivateKeyStart = 33; |
|
|
|
HDPrivateKey.PrivateKeyEnd = HDPrivateKey.ChecksumStart = 65; |
|
|
|
HDPrivateKey.ChecksumEnd = 69; |
|
|
|
HDPrivateKey.SerializedByteSize = 82; |
|
|
|
|
|
|
|
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; |
|
|
|
|
|
|
|
assert(HDPrivateKey.ChecksumEnd === HDPrivateKey.SerializedByteSize); |
|
|
|
|
|
|
|
HDPrivateKey.Errors = {}; |
|
|
|
HDPrivateKey.Errors.InvalidArgument = 'Invalid argument, expected string or Buffer'; |
|
|
|