Add public key
This commit is contained in:
parent
ad74b549a1
commit
950ea6ed1a
3
index.js
3
index.js
|
@ -22,7 +22,8 @@ bitcore.encoding.Varint = require('./lib/encoding/varint');
|
|||
bitcore.Address = require('./lib/address');
|
||||
bitcore.Block = require('./lib/block');
|
||||
bitcore.Blockheader = require('./lib/blockheader');
|
||||
bitcore.HDPrivateKey = require('./lib/hdprivkey.js');
|
||||
bitcore.HDPrivateKey = require('./lib/hdprivatekey.js');
|
||||
bitcore.HDPublicKey = require('./lib/hdpublickey.js');
|
||||
bitcore.Networks = require('./lib/networks');
|
||||
bitcore.Opcode = require('./lib/opcode');
|
||||
bitcore.PrivateKey = require('./lib/privatekey');
|
||||
|
|
320
lib/bip32.js
320
lib/bip32.js
|
@ -1,320 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
var Base58Check = require('./encoding/base58check');
|
||||
var networks = require('./networks');
|
||||
var Hash = require('./crypto/hash');
|
||||
var Point = require('./crypto/point');
|
||||
var Random = require('./crypto/random');
|
||||
var BN = require('./crypto/bn');
|
||||
var PublicKey = require('./publickey');
|
||||
var PrivateKey = require('./privatekey');
|
||||
|
||||
var BIP32 = function BIP32(obj) {
|
||||
if (!(this instanceof BIP32))
|
||||
return new BIP32(obj);
|
||||
if (typeof obj === 'string') {
|
||||
var str = obj;
|
||||
this.fromString(str);
|
||||
} else if (obj ) {
|
||||
this.set(obj);
|
||||
}
|
||||
};
|
||||
|
||||
BIP32.prototype.set = function(obj) {
|
||||
this.version = typeof obj.version !== 'undefined' ? obj.version : this.version;
|
||||
this.depth = typeof obj.depth !== 'undefined' ? obj.depth : this.depth;
|
||||
this.parentfingerprint = obj.parentfingerprint || this.parentfingerprint;
|
||||
this.childindex = obj.childindex || this.childindex;
|
||||
this.chaincode = obj.chaincode || this.chaincode;
|
||||
this.hasprivkey = typeof obj.hasprivkey !== 'undefined' ? obj.hasprivkey : this.hasprivkey;
|
||||
this.pubkeyhash = obj.pubkeyhash || this.pubkeyhash;
|
||||
this.xpubkey = obj.xpubkey || this.xpubkey;
|
||||
this.xprivkey = obj.xprivkey || this.xprivkey;
|
||||
return this;
|
||||
};
|
||||
|
||||
BIP32.prototype.fromRandom = function(networkstr) {
|
||||
if (!networkstr)
|
||||
networkstr = 'mainnet';
|
||||
this.version = networks[networkstr].xprivkey;
|
||||
this.depth = 0x00;
|
||||
this.parentfingerprint = new Buffer([0, 0, 0, 0]);
|
||||
this.childindex = new Buffer([0, 0, 0, 0]);
|
||||
this.chaincode = Random.getRandomBuffer(32);
|
||||
this.privkey = PrivateKey.fromRandom();
|
||||
this.pubkey = PublicKey.fromPrivateKey(this.privkey);
|
||||
this.hasprivkey = true;
|
||||
this.pubkeyhash = Hash.sha256ripemd160(this.pubkey.toBuffer());
|
||||
this.buildxpubkey();
|
||||
this.buildxprivkey();
|
||||
};
|
||||
|
||||
BIP32.prototype.fromString = function(str) {
|
||||
var bytes = Base58Check.decode(str);
|
||||
this.initFromBytes(bytes);
|
||||
return this;
|
||||
};
|
||||
|
||||
BIP32.prototype.fromSeed = function(bytes, networkstr) {
|
||||
if (!networkstr)
|
||||
networkstr = 'mainnet';
|
||||
|
||||
if (!Buffer.isBuffer(bytes))
|
||||
throw new Error('bytes must be a buffer');
|
||||
if (bytes.length < 128 / 8)
|
||||
throw new Error('Need more than 128 bytes of entropy');
|
||||
if (bytes.length > 512 / 8)
|
||||
throw new Error('More than 512 bytes of entropy is nonstandard');
|
||||
var hash = Hash.sha512hmac(bytes, new Buffer('Bitcoin seed'));
|
||||
|
||||
this.depth = 0x00;
|
||||
this.parentfingerprint = new Buffer([0, 0, 0, 0]);
|
||||
this.childindex = new Buffer([0, 0, 0, 0]);
|
||||
this.chaincode = hash.slice(32, 64);
|
||||
this.version = networks[networkstr].xprivkey;
|
||||
this.privkey = new PrivateKey(BN().fromBuffer(hash.slice(0, 32)));
|
||||
this.pubkey = PublicKey.fromPrivateKey(this.privkey);
|
||||
this.hasprivkey = true;
|
||||
this.pubkeyhash = Hash.sha256ripemd160(this.pubkey.toBuffer());
|
||||
|
||||
this.buildxpubkey();
|
||||
this.buildxprivkey();
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
BIP32.prototype.initFromBytes = function(bytes) {
|
||||
// Both pub and private extended keys are 78 bytes
|
||||
if (bytes.length != 78)
|
||||
throw new Error('not enough data');
|
||||
|
||||
this.version = bytes.slice(0, 4).readUInt32BE(0);
|
||||
this.depth = bytes.slice(4, 5).readUInt8(0);
|
||||
this.parentfingerprint = bytes.slice(5, 9);
|
||||
this.childindex = bytes.slice(9, 13).readUInt32BE(0);
|
||||
this.chaincode = bytes.slice(13, 45);
|
||||
|
||||
var keyBytes = bytes.slice(45, 78);
|
||||
|
||||
var isPrivate =
|
||||
(this.version == networks.mainnet.xprivkey ||
|
||||
this.version == networks.testnet.xprivkey);
|
||||
|
||||
var isPublic =
|
||||
(this.version == networks.mainnet.xpubkey ||
|
||||
this.version == networks.testnet.xpubkey);
|
||||
|
||||
if (isPrivate && keyBytes[0] == 0) {
|
||||
this.privkey = new PrivateKey(BN().fromBuffer(keyBytes.slice(1, 33)));
|
||||
this.pubkey = PublicKey.fromPrivateKey(this.privkey);
|
||||
this.pubkeyhash = Hash.sha256ripemd160(this.pubkey.toBuffer());
|
||||
this.hasprivkey = true;
|
||||
} else if (isPublic && (keyBytes[0] == 0x02 || keyBytes[0] == 0x03)) {
|
||||
this.pubkey = PublicKey.fromDER(keyBytes);
|
||||
this.pubkeyhash = Hash.sha256ripemd160(this.pubkey.toBuffer());
|
||||
this.hasprivkey = false;
|
||||
} else {
|
||||
throw new Error('Invalid key');
|
||||
}
|
||||
|
||||
this.buildxpubkey();
|
||||
this.buildxprivkey();
|
||||
};
|
||||
|
||||
BIP32.prototype.buildxpubkey = function() {
|
||||
this.xpubkey = new Buffer([]);
|
||||
|
||||
var v = null;
|
||||
switch (this.version) {
|
||||
case networks.mainnet.xpubkey:
|
||||
case networks.mainnet.xprivkey:
|
||||
v = networks.mainnet.xpubkey;
|
||||
break;
|
||||
case networks.testnet.xpubkey:
|
||||
case networks.testnet.xprivkey:
|
||||
v = networks.testnet.xpubkey;
|
||||
break;
|
||||
default:
|
||||
throw new Error('Unknown version');
|
||||
}
|
||||
|
||||
// Version
|
||||
this.xpubkey = Buffer.concat([
|
||||
new Buffer([v >> 24]),
|
||||
new Buffer([(v >> 16) & 0xff]),
|
||||
new Buffer([(v >> 8) & 0xff]),
|
||||
new Buffer([v & 0xff]),
|
||||
new Buffer([this.depth]),
|
||||
this.parentfingerprint,
|
||||
new Buffer([this.childindex >>> 24]),
|
||||
new Buffer([(this.childindex >>> 16) & 0xff]),
|
||||
new Buffer([(this.childindex >>> 8) & 0xff]),
|
||||
new Buffer([this.childindex & 0xff]),
|
||||
this.chaincode,
|
||||
this.pubkey.toBuffer()
|
||||
]);
|
||||
};
|
||||
|
||||
BIP32.prototype.xpubkeyString = function(format) {
|
||||
if (format === undefined || format === 'base58') {
|
||||
return Base58Check.encode(this.xpubkey);
|
||||
} else if (format === 'hex') {
|
||||
return this.xpubkey.toString('hex');
|
||||
} else {
|
||||
throw new Error('bad format');
|
||||
}
|
||||
}
|
||||
|
||||
BIP32.prototype.buildxprivkey = function() {
|
||||
if (!this.hasprivkey) return;
|
||||
this.xprivkey = new Buffer([]);
|
||||
|
||||
var v = this.version;
|
||||
|
||||
this.xprivkey = Buffer.concat([
|
||||
new Buffer([v >> 24]),
|
||||
new Buffer([(v >> 16) & 0xff]),
|
||||
new Buffer([(v >> 8) & 0xff]),
|
||||
new Buffer([v & 0xff]),
|
||||
new Buffer([this.depth]),
|
||||
this.parentfingerprint,
|
||||
new Buffer([this.childindex >>> 24]),
|
||||
new Buffer([(this.childindex >>> 16) & 0xff]),
|
||||
new Buffer([(this.childindex >>> 8) & 0xff]),
|
||||
new Buffer([this.childindex & 0xff]),
|
||||
this.chaincode,
|
||||
new Buffer([0]),
|
||||
this.privkey.bn.toBuffer({size: 32})
|
||||
]);
|
||||
}
|
||||
|
||||
BIP32.prototype.xprivkeyString = function(format) {
|
||||
if (format === undefined || format === 'base58') {
|
||||
return Base58Check.encode(this.xprivkey);
|
||||
} else if (format === 'hex') {
|
||||
return this.xprivkey.toString('hex');
|
||||
} else {
|
||||
throw new Error('bad format');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BIP32.prototype.derive = function(path) {
|
||||
var e = path.split('/');
|
||||
|
||||
// Special cases:
|
||||
if (path == 'm' || path == 'M' || path == 'm\'' || path == 'M\'')
|
||||
return this;
|
||||
|
||||
var bip32 = this;
|
||||
for (var i in e) {
|
||||
var c = e[i];
|
||||
|
||||
if (i == 0) {
|
||||
if (c != 'm') throw new Error('invalid path');
|
||||
continue;
|
||||
}
|
||||
|
||||
if (parseInt(c.replace("'", "")).toString() !== c.replace("'", ""))
|
||||
throw new Error('invalid path');
|
||||
|
||||
var usePrivate = (c.length > 1) && (c[c.length - 1] == '\'');
|
||||
var childindex = parseInt(usePrivate ? c.slice(0, c.length - 1) : c) & 0x7fffffff;
|
||||
|
||||
if (usePrivate)
|
||||
childindex += 0x80000000;
|
||||
|
||||
bip32 = bip32.deriveChild(childindex);
|
||||
}
|
||||
|
||||
return bip32;
|
||||
};
|
||||
|
||||
BIP32.prototype.deriveChild = function(i) {
|
||||
if (typeof i !== 'number')
|
||||
throw new Error('i must be a number');
|
||||
|
||||
var ib = [];
|
||||
ib.push((i >> 24) & 0xff);
|
||||
ib.push((i >> 16) & 0xff);
|
||||
ib.push((i >> 8) & 0xff);
|
||||
ib.push(i & 0xff);
|
||||
ib = new Buffer(ib);
|
||||
|
||||
var usePrivate = (i & 0x80000000) != 0;
|
||||
|
||||
var isPrivate =
|
||||
(this.version == networks.mainnet.xprivkey ||
|
||||
this.version == networks.testnet.xprivkey);
|
||||
|
||||
if (usePrivate && (!this.hasprivkey || !isPrivate))
|
||||
throw new Error('Cannot do private key derivation without private key');
|
||||
|
||||
var ret = null;
|
||||
if (this.hasprivkey) {
|
||||
var data = null;
|
||||
|
||||
if (usePrivate) {
|
||||
data = Buffer.concat([new Buffer([0]), this.privkey.bn.toBuffer({size: 32}), ib]);
|
||||
} else {
|
||||
data = Buffer.concat([this.pubkey.toBuffer({size: 32}), ib]);
|
||||
}
|
||||
|
||||
var hash = Hash.sha512hmac(data, this.chaincode);
|
||||
var il = BN().fromBuffer(hash.slice(0, 32), {size: 32});
|
||||
var ir = hash.slice(32, 64);
|
||||
|
||||
// ki = IL + kpar (mod n).
|
||||
var k = il.add(this.privkey.bn).mod(Point.getN());
|
||||
|
||||
ret = new BIP32();
|
||||
ret.chaincode = ir;
|
||||
|
||||
ret.privkey = new PrivateKey(k);
|
||||
ret.pubkey = PublicKey.fromPrivateKey(ret.privkey);
|
||||
ret.hasprivkey = true;
|
||||
|
||||
} else {
|
||||
var data = Buffer.concat([this.pubkey.toBuffer(), ib]);
|
||||
var hash = Hash.sha512hmac(data, this.chaincode);
|
||||
var il = BN().fromBuffer(hash.slice(0, 32));
|
||||
var ir = hash.slice(32, 64);
|
||||
|
||||
// Ki = (IL + kpar)*G = IL*G + Kpar
|
||||
var ilG = Point.getG().mul(il);
|
||||
var Kpar = this.pubkey.point;
|
||||
var Ki = ilG.add(Kpar);
|
||||
var newpub = PublicKey.fromPoint(Ki);
|
||||
|
||||
ret = new BIP32();
|
||||
ret.chaincode = ir;
|
||||
|
||||
ret.pubkey = newpub;
|
||||
ret.hasprivkey = false;
|
||||
}
|
||||
|
||||
ret.childindex = i;
|
||||
ret.parentfingerprint = this.pubkeyhash.slice(0, 4);
|
||||
ret.version = this.version;
|
||||
ret.depth = this.depth + 1;
|
||||
|
||||
ret.pubkeyhash = Hash.sha256ripemd160(ret.pubkey.toBuffer());
|
||||
|
||||
ret.buildxpubkey();
|
||||
ret.buildxprivkey();
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
BIP32.prototype.toString = function() {
|
||||
var isPrivate =
|
||||
(this.version == networks.mainnet.xprivkey ||
|
||||
this.version == networks.testnet.xprivkey);
|
||||
|
||||
if (isPrivate)
|
||||
return this.xprivkeyString();
|
||||
else
|
||||
return this.xpubkeyString();
|
||||
};
|
||||
|
||||
module.exports = BIP32;
|
|
@ -58,10 +58,13 @@ HDPrivateKey.prototype.derive = function(arg, hardened) {
|
|||
}
|
||||
};
|
||||
|
||||
HDPrivateKey.prototype._deriveWithNumber = function deriveWithNumber(index, hardened) {
|
||||
HDPrivateKey.prototype._deriveWithNumber = function(index, hardened) {
|
||||
if (index >= HDPrivateKey.Hardened) {
|
||||
hardened = true;
|
||||
}
|
||||
if (index < HDPrivateKey.Hardened && hardened) {
|
||||
index += HDPrivateKey.Hardened;
|
||||
}
|
||||
|
||||
var indexBuffer = util.integerAsBuffer(index);
|
||||
var data;
|
||||
|
@ -75,7 +78,6 @@ HDPrivateKey.prototype._deriveWithNumber = function deriveWithNumber(index, hard
|
|||
var chainCode = hash.slice(32, 64);
|
||||
|
||||
var privateKey = leftPart.add(this.privateKey.toBigNumber()).mod(Point.getN()).toBuffer({size: 32});
|
||||
console.log(privateKey);
|
||||
|
||||
return new HDPrivateKey({
|
||||
network: this.network,
|
||||
|
@ -87,7 +89,7 @@ HDPrivateKey.prototype._deriveWithNumber = function deriveWithNumber(index, hard
|
|||
});
|
||||
};
|
||||
|
||||
HDPrivateKey.prototype._deriveFromString = function deriveFromString(path) {
|
||||
HDPrivateKey.prototype._deriveFromString = function(path) {
|
||||
var steps = path.split('/');
|
||||
|
||||
// Special cases:
|
||||
|
@ -101,9 +103,9 @@ HDPrivateKey.prototype._deriveFromString = function deriveFromString(path) {
|
|||
|
||||
var result = this;
|
||||
for (var step in steps) {
|
||||
var index = parseInt(step);
|
||||
var hardened = step !== index.toString();
|
||||
result = result.derive(index, hardened);
|
||||
var index = parseInt(steps[step]);
|
||||
var hardened = steps[step] !== index.toString();
|
||||
result = result._deriveWithNumber(index, hardened);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
@ -117,7 +119,7 @@ HDPrivateKey.prototype._deriveFromString = function deriveFromString(path) {
|
|||
* network provided matches the network serialized.
|
||||
* @return {boolean}
|
||||
*/
|
||||
HDPrivateKey.isValidSerialized = function isValidSerialized(data, network) {
|
||||
HDPrivateKey.isValidSerialized = function(data, network) {
|
||||
return !HDPrivateKey.getSerializedError(data, network);
|
||||
};
|
||||
|
||||
|
@ -130,7 +132,7 @@ HDPrivateKey.isValidSerialized = function isValidSerialized(data, network) {
|
|||
* network provided matches the network serialized.
|
||||
* @return {HDPrivateKey.Errors|null}
|
||||
*/
|
||||
HDPrivateKey.getSerializedError = function getSerializedError(data, network) {
|
||||
HDPrivateKey.getSerializedError = function(data, network) {
|
||||
/* jshint maxcomplexity: 10 */
|
||||
if (!(_.isString(data) || buffer.Buffer.isBuffer(data))) {
|
||||
return HDPrivateKey.Errors.InvalidArgument;
|
||||
|
@ -155,7 +157,7 @@ HDPrivateKey.getSerializedError = function getSerializedError(data, network) {
|
|||
return null;
|
||||
};
|
||||
|
||||
HDPrivateKey._validateNetwork = function validateNetwork(data, network) {
|
||||
HDPrivateKey._validateNetwork = function(data, network) {
|
||||
network = Network.get(network);
|
||||
if (!network) {
|
||||
return HDPrivateKey.Errors.InvalidNetworkArgument;
|
||||
|
@ -167,17 +169,17 @@ HDPrivateKey._validateNetwork = function validateNetwork(data, network) {
|
|||
return null;
|
||||
};
|
||||
|
||||
HDPrivateKey.prototype._buildFromJson = function buildFromJson(arg) {
|
||||
HDPrivateKey.prototype._buildFromJson = function(arg) {
|
||||
return this._buildFromObject(JSON.parse(arg));
|
||||
};
|
||||
|
||||
HDPrivateKey.prototype._buildFromObject = function buildFromObject(arg) {
|
||||
HDPrivateKey.prototype._buildFromObject = function(arg) {
|
||||
// TODO: Type validation
|
||||
var buffers = {
|
||||
version: util.integerAsBuffer(Network.get(arg.network).xprivkey),
|
||||
depth: util.integerAsSingleByteBuffer(arg.depth),
|
||||
parentFingerPrint: util.integerAsBuffer(arg.parentFingerPrint),
|
||||
childIndex: util.integerAsBuffer(arg.childIndex),
|
||||
parentFingerPrint: _.isNumber(arg.parentFingerPrint) ? util.integerAsBuffer(arg.parentFingerPrint) : arg.parentFingerPrint,
|
||||
childIndex: _.isNumber(arg.childIndex) ? util.integerAsBuffer(arg.childIndex) : arg.childIndex,
|
||||
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
|
||||
|
@ -185,7 +187,7 @@ HDPrivateKey.prototype._buildFromObject = function buildFromObject(arg) {
|
|||
return this._buildFromBuffers(buffers);
|
||||
};
|
||||
|
||||
HDPrivateKey.prototype._buildFromSerialized = function buildFromSerialized(arg) {
|
||||
HDPrivateKey.prototype._buildFromSerialized = function(arg) {
|
||||
var decoded = Base58Check.decode(arg);
|
||||
var buffers = {
|
||||
version: decoded.slice(HDPrivateKey.VersionStart, HDPrivateKey.VersionEnd),
|
||||
|
@ -201,11 +203,11 @@ HDPrivateKey.prototype._buildFromSerialized = function buildFromSerialized(arg)
|
|||
return this._buildFromBuffers(buffers);
|
||||
};
|
||||
|
||||
HDPrivateKey.prototype._generateRandomly = function generateRandomly(network) {
|
||||
return HDPrivateKey.fromSeed(Random.getRandomBytes(64), network);
|
||||
HDPrivateKey.prototype._generateRandomly = function(network) {
|
||||
return HDPrivateKey.fromSeed(Random.getRandomBuffer(64), network);
|
||||
};
|
||||
|
||||
HDPrivateKey.fromSeed = function fromSeed(hexa, network) {
|
||||
HDPrivateKey.fromSeed = function(hexa, network) {
|
||||
/* jshint maxcomplexity: 8 */
|
||||
|
||||
if (util.isHexaString(hexa)) {
|
||||
|
@ -248,20 +250,17 @@ HDPrivateKey.fromSeed = function fromSeed(hexa, network) {
|
|||
* representation
|
||||
* @return {HDPrivateKey} this
|
||||
*/
|
||||
HDPrivateKey.prototype._buildFromBuffers = function buildFromBuffers(arg) {
|
||||
HDPrivateKey.prototype._buildFromBuffers = function(arg) {
|
||||
/* jshint maxcomplexity: 8 */
|
||||
/* jshint maxstatements: 20 */
|
||||
|
||||
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
|
||||
];
|
||||
console.log(arg.privateKey);
|
||||
console.log(sequence);
|
||||
if (!arg.checksum || !arg.checksum.length) {
|
||||
arg.checksum = Base58Check.checksum(buffer.Buffer.concat(sequence));
|
||||
} else {
|
||||
|
@ -271,24 +270,25 @@ HDPrivateKey.prototype._buildFromBuffers = function buildFromBuffers(arg) {
|
|||
}
|
||||
|
||||
if (!arg.xprivkey) {
|
||||
sequence.push(arg.checksum);
|
||||
this.xprivkey = Base58.encode(buffer.Buffer.concat(sequence));
|
||||
this.xprivkey = Base58Check.encode(buffer.Buffer.concat(sequence));
|
||||
} else {
|
||||
this.xprivkey = arg.xprivkey;
|
||||
}
|
||||
|
||||
// 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(util.hexToBuffer(this.publicKey.toString()));
|
||||
this.depth = util.integerFromSingleByteBuffer(arg.depth);
|
||||
this.privateKey = new PrivateKey(BN().fromBuffer(arg.privateKey));
|
||||
this.publicKey = this.privateKey.toPublicKey();
|
||||
|
||||
this.fingerPrint = Hash.sha256ripemd160(this.publicKey.toBuffer()).slice(0, HDPrivateKey.ParentFingerPrintSize);
|
||||
|
||||
var HDPublicKey = require('./hdpublickey');
|
||||
this.hdPublicKey = new HDPublicKey(this);
|
||||
this.xpubkey = this.hdPublicKey.xpubkey;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
HDPrivateKey._validateBufferArguments = function validateBufferArguments(arg) {
|
||||
HDPrivateKey._validateBufferArguments = function(arg) {
|
||||
var checkBuffer = function(name, size) {
|
||||
var buff = arg[name];
|
||||
assert(buffer.Buffer.isBuffer(buff), name + ' argument is not a buffer');
|
||||
|
@ -308,14 +308,14 @@ HDPrivateKey._validateBufferArguments = function validateBufferArguments(arg) {
|
|||
}
|
||||
};
|
||||
|
||||
HDPrivateKey.prototype.toString = function toString() {
|
||||
HDPrivateKey.prototype.toString = function() {
|
||||
return this.xprivkey;
|
||||
};
|
||||
|
||||
HDPrivateKey.prototype.toObject = function toObject() {
|
||||
HDPrivateKey.prototype.toObject = function() {
|
||||
return {
|
||||
network: Network.get(util.integerFromBuffer(this._buffers.version)),
|
||||
depth: util.integerFromBuffer(this._buffers.depth),
|
||||
network: Network.get(util.integerFromBuffer(this._buffers.version)).name,
|
||||
depth: util.integerFromSingleByteBuffer(this._buffers.depth),
|
||||
fingerPrint: this.fingerPrint,
|
||||
parentFingerPrint: util.integerFromBuffer(this._buffers.parentFingerPrint),
|
||||
childIndex: util.integerFromBuffer(this._buffers.childIndex),
|
||||
|
@ -326,7 +326,7 @@ HDPrivateKey.prototype.toObject = function toObject() {
|
|||
};
|
||||
};
|
||||
|
||||
HDPrivateKey.prototype.toJson = function toJson() {
|
||||
HDPrivateKey.prototype.toJson = function() {
|
||||
return JSON.stringify(this.toObject());
|
||||
};
|
||||
|
|
@ -0,0 +1,399 @@
|
|||
'use strict';
|
||||
|
||||
var _ = require('lodash');
|
||||
var BN = require('./crypto/bn');
|
||||
var Base58 = require('./encoding/base58');
|
||||
var Base58Check = require('./encoding/base58check');
|
||||
var Hash = require('./crypto/hash');
|
||||
var HDPrivateKey = require('./hdprivatekey');
|
||||
var Network = require('./networks');
|
||||
var Point = require('./crypto/point');
|
||||
var PublicKey = require('./publickey');
|
||||
var Random = require('./crypto/random');
|
||||
|
||||
var assert = require('assert');
|
||||
var buffer = require('buffer');
|
||||
var util = require('./util');
|
||||
|
||||
var MINIMUM_ENTROPY_BITS = 128;
|
||||
var BITS_TO_BYTES = 1/8;
|
||||
var MAXIMUM_ENTROPY_BITS = 512;
|
||||
|
||||
|
||||
function HDPublicKey(arg) {
|
||||
/* jshint maxcomplexity: 12 */
|
||||
/* jshint maxstatements: 20 */
|
||||
if (arg instanceof HDPublicKey) {
|
||||
return arg;
|
||||
}
|
||||
if (!(this instanceof HDPublicKey)) {
|
||||
return new HDPublicKey(arg);
|
||||
}
|
||||
if (arg) {
|
||||
if (_.isString(arg) || buffer.Buffer.isBuffer(arg)) {
|
||||
if (HDPublicKey.isValidSerialized(arg)) {
|
||||
this._buildFromSerialized(arg);
|
||||
} else {
|
||||
var error = HDPublicKey.getSerializedError(arg);
|
||||
if (error === HDPublicKey.Errors.ArgumentIsPrivateExtended) {
|
||||
return new HDPrivateKey(arg).hdPublicKey;
|
||||
}
|
||||
throw new Error(error);
|
||||
}
|
||||
} else {
|
||||
if (_.isObject(arg)) {
|
||||
if (arg instanceof HDPrivateKey) {
|
||||
this._buildFromPrivate(arg);
|
||||
} else {
|
||||
this._buildFromObject(arg);
|
||||
}
|
||||
} else if (util.isValidJson(arg)) {
|
||||
this._buildFromJson(arg);
|
||||
} else {
|
||||
throw new Error(HDPublicKey.Errors.UnrecognizedArgument);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this._generateRandomly();
|
||||
}
|
||||
}
|
||||
|
||||
HDPublicKey.prototype.derive = function (arg, hardened) {
|
||||
if (_.isNumber(arg)) {
|
||||
return this._deriveWithNumber(arg, hardened);
|
||||
} else if (_.isString(arg)) {
|
||||
return this._deriveFromString(arg);
|
||||
} else {
|
||||
throw new Error(HDPublicKey.Errors.InvalidDerivationArgument);
|
||||
}
|
||||
};
|
||||
|
||||
HDPublicKey.prototype._deriveWithNumber = function (index, hardened) {
|
||||
if (hardened || index >= HDPublicKey.Hardened) {
|
||||
throw new Error(HDPublicKey.Errors.InvalidIndexCantDeriveHardened);
|
||||
}
|
||||
|
||||
var indexBuffer = util.integerAsBuffer(index);
|
||||
var data = buffer.Buffer.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);
|
||||
|
||||
var publicKey = PublicKey.fromPoint(Point.getG().mul(leftPart).add(this.publicKey.point));
|
||||
|
||||
return new HDPublicKey({
|
||||
network: this.network,
|
||||
depth: this.depth + 1,
|
||||
parentFingerPrint: this.fingerPrint,
|
||||
childIndex: index,
|
||||
chainCode: chainCode,
|
||||
publicKey: publicKey
|
||||
});
|
||||
};
|
||||
|
||||
HDPublicKey.prototype._deriveFromString = function (path) {
|
||||
/* jshint maxcomplexity: 8 */
|
||||
var steps = path.split('/');
|
||||
|
||||
// Special cases:
|
||||
if (_.contains(HDPublicKey.RootElementAlias, path)) {
|
||||
return this;
|
||||
}
|
||||
if (!_.contains(HDPublicKey.RootElementAlias, steps[0])) {
|
||||
throw new Error(HDPublicKey.Errors.InvalidPath);
|
||||
}
|
||||
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;
|
||||
};
|
||||
|
||||
/**
|
||||
* Verifies that a given serialized private key in base58 with checksum format
|
||||
* is valid.
|
||||
*
|
||||
* @param {string|Buffer} data - the serialized private key
|
||||
* @param {string|Network=} network - optional, if present, checks that the
|
||||
* network provided matches the network serialized.
|
||||
* @return {boolean}
|
||||
*/
|
||||
HDPublicKey.isValidSerialized = function (data, network) {
|
||||
return !HDPublicKey.getSerializedError(data, network);
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks what's the error that causes the validation of a serialized private key
|
||||
* in base58 with checksum to fail.
|
||||
*
|
||||
* @param {string|Buffer} data - the serialized private key
|
||||
* @param {string|Network=} network - optional, if present, checks that the
|
||||
* network provided matches the network serialized.
|
||||
* @return {HDPublicKey.Errors|null}
|
||||
*/
|
||||
HDPublicKey.getSerializedError = function (data, network) {
|
||||
/* jshint maxcomplexity: 10 */
|
||||
network = Network.get(network) || Network.defaultNetwork;
|
||||
if (!(_.isString(data) || buffer.Buffer.isBuffer(data))) {
|
||||
return HDPublicKey.Errors.InvalidArgument;
|
||||
}
|
||||
if (!Base58.validCharacters(data)) {
|
||||
return HDPublicKey.Errors.InvalidB58Char;
|
||||
}
|
||||
try {
|
||||
data = Base58Check.decode(data);
|
||||
} catch (e) {
|
||||
return HDPublicKey.Errors.InvalidB58Checksum;
|
||||
}
|
||||
if (data.length !== 78) {
|
||||
return HDPublicKey.Errors.InvalidLength;
|
||||
}
|
||||
if (util.integerFromBuffer(data.slice(0, 4)) === network.xprivkey) {
|
||||
return HDPublicKey.Errors.ArgumentIsPrivateExtended;
|
||||
}
|
||||
if (!_.isUndefined(network)) {
|
||||
var error = HDPublicKey._validateNetwork(data, network);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
HDPublicKey._validateNetwork = function (data, network) {
|
||||
network = Network.get(network);
|
||||
if (!network) {
|
||||
return HDPublicKey.Errors.InvalidNetworkArgument;
|
||||
}
|
||||
var version = data.slice(HDPublicKey.VersionStart, HDPublicKey.VersionEnd);
|
||||
if (util.integerFromBuffer(version) !== network.xpubkey) {
|
||||
return HDPublicKey.Errors.InvalidNetwork;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
HDPublicKey.prototype._buildFromJson = function (arg) {
|
||||
return this._buildFromObject(JSON.parse(arg));
|
||||
};
|
||||
|
||||
HDPublicKey.prototype._buildFromPrivate = function (arg) {
|
||||
var args = _.clone(arg._buffers);
|
||||
var point = Point.getG().mul(BN().fromBuffer(args.privateKey));
|
||||
args.publicKey = util.pointToCompressed(point);
|
||||
args.version = util.integerAsBuffer(Network.get(util.integerFromBuffer(args.version)).xpubkey);
|
||||
args.privateKey = undefined;
|
||||
args.checksum = undefined;
|
||||
args.xprivkey = undefined;
|
||||
return this._buildFromBuffers(args);
|
||||
};
|
||||
|
||||
HDPublicKey.prototype._buildFromObject = function (arg) {
|
||||
/* jshint maxcomplexity: 8 */
|
||||
// TODO: Type validation
|
||||
var buffers = {
|
||||
version: util.integerAsBuffer(Network.get(arg.network).xpubkey),
|
||||
depth: util.integerAsSingleByteBuffer(arg.depth),
|
||||
parentFingerPrint: _.isNumber(arg.parentFingerPrint) ? util.integerAsBuffer(arg.parentFingerPrint) : arg.parentFingerPrint,
|
||||
childIndex: util.integerAsBuffer(arg.childIndex),
|
||||
chainCode: _.isString(arg.chainCode) ? util.hexToBuffer(arg.chainCode) : arg.chainCode,
|
||||
publicKey: _.isString(arg.publicKey) ? util.hexToBuffer(arg.publicKey) :
|
||||
buffer.Buffer.isBuffer(arg.publicKey) ? arg.publicKey : arg.publicKey.toBuffer(),
|
||||
checksum: arg.checksum && arg.checksum.length ? util.integerAsBuffer(arg.checksum) : undefined
|
||||
};
|
||||
return this._buildFromBuffers(buffers);
|
||||
};
|
||||
|
||||
HDPublicKey.prototype._buildFromSerialized = function (arg) {
|
||||
var decoded = Base58Check.decode(arg);
|
||||
var buffers = {
|
||||
version: decoded.slice(HDPublicKey.VersionStart, HDPublicKey.VersionEnd),
|
||||
depth: decoded.slice(HDPublicKey.DepthStart, HDPublicKey.DepthEnd),
|
||||
parentFingerPrint: decoded.slice(HDPublicKey.ParentFingerPrintStart,
|
||||
HDPublicKey.ParentFingerPrintEnd),
|
||||
childIndex: decoded.slice(HDPublicKey.ChildIndexStart, HDPublicKey.ChildIndexEnd),
|
||||
chainCode: decoded.slice(HDPublicKey.ChainCodeStart, HDPublicKey.ChainCodeEnd),
|
||||
publicKey: decoded.slice(HDPublicKey.PublicKeyStart, HDPublicKey.PublicKeyEnd),
|
||||
checksum: decoded.slice(HDPublicKey.ChecksumStart, HDPublicKey.ChecksumEnd),
|
||||
xpubkey: arg
|
||||
};
|
||||
return this._buildFromBuffers(buffers);
|
||||
};
|
||||
|
||||
HDPublicKey.prototype._generateRandomly = function (network) {
|
||||
return HDPublicKey.fromSeed(Random.getRandomBytes(64), network);
|
||||
};
|
||||
|
||||
HDPublicKey.fromSeed = function (hexa, network) {
|
||||
/* jshint maxcomplexity: 8 */
|
||||
|
||||
if (util.isHexaString(hexa)) {
|
||||
hexa = util.hexToBuffer(hexa);
|
||||
}
|
||||
if (!Buffer.isBuffer(hexa)) {
|
||||
throw new Error(HDPublicKey.InvalidEntropyArg);
|
||||
}
|
||||
if (hexa.length < MINIMUM_ENTROPY_BITS * BITS_TO_BYTES) {
|
||||
throw new Error(HDPublicKey.NotEnoughEntropy);
|
||||
}
|
||||
if (hexa.length > MAXIMUM_ENTROPY_BITS * BITS_TO_BYTES) {
|
||||
throw new Error('More than 512 bytes of entropy is nonstandard');
|
||||
}
|
||||
var hash = Hash.sha512hmac(hexa, new buffer.Buffer('Bitcoin seed'));
|
||||
|
||||
return new HDPublicKey({
|
||||
network: Network.get(network) || Network.livenet,
|
||||
depth: 0,
|
||||
parentFingerPrint: 0,
|
||||
childIndex: 0,
|
||||
publicKey: hash.slice(0, 32),
|
||||
chainCode: hash.slice(32, 64)
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Receives a object with buffers in all the properties and populates the
|
||||
* internal structure
|
||||
*
|
||||
* @param {Object} arg
|
||||
* @param {buffer.Buffer} arg.version
|
||||
* @param {buffer.Buffer} arg.depth
|
||||
* @param {buffer.Buffer} arg.parentFingerPrint
|
||||
* @param {buffer.Buffer} arg.childIndex
|
||||
* @param {buffer.Buffer} arg.chainCode
|
||||
* @param {buffer.Buffer} arg.publicKey
|
||||
* @param {buffer.Buffer} arg.checksum
|
||||
* @param {string=} arg.xpubkey - if set, don't recalculate the base58
|
||||
* representation
|
||||
* @return {HDPublicKey} this
|
||||
*/
|
||||
HDPublicKey.prototype._buildFromBuffers = function (arg) {
|
||||
/* jshint maxcomplexity: 8 */
|
||||
|
||||
HDPublicKey._validateBufferArguments(arg);
|
||||
this._buffers = arg;
|
||||
|
||||
var sequence = [
|
||||
arg.version, arg.depth, arg.parentFingerPrint, arg.childIndex, arg.chainCode,
|
||||
arg.publicKey
|
||||
];
|
||||
if (!arg.checksum || !arg.checksum.length) {
|
||||
arg.checksum = Base58Check.checksum(buffer.Buffer.concat(sequence));
|
||||
} else {
|
||||
if (arg.checksum.toString() !== sequence.toString()) {
|
||||
throw new Error(HDPublicKey.Errors.InvalidB58Checksum);
|
||||
}
|
||||
}
|
||||
|
||||
if (!arg.xpubkey) {
|
||||
this.xpubkey = Base58Check.encode(buffer.Buffer.concat(sequence));
|
||||
} else {
|
||||
this.xpubkey = arg.xpubkey;
|
||||
}
|
||||
|
||||
this.network = Network.get(util.integerFromBuffer(arg.version));
|
||||
this.depth = util.integerFromSingleByteBuffer(arg.depth);
|
||||
this.publicKey = PublicKey.fromString(arg.publicKey);
|
||||
this.fingerPrint = Hash.sha256ripemd160(this.publicKey.toBuffer()).slice(0, HDPublicKey.ParentFingerPrintSize);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
HDPublicKey._validateBufferArguments = function (arg) {
|
||||
var checkBuffer = function(name, size) {
|
||||
var buff = arg[name];
|
||||
assert(buffer.Buffer.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
|
||||
);
|
||||
};
|
||||
checkBuffer('version', HDPublicKey.VersionSize);
|
||||
checkBuffer('depth', HDPublicKey.DepthSize);
|
||||
checkBuffer('parentFingerPrint', HDPublicKey.ParentFingerPrintSize);
|
||||
checkBuffer('childIndex', HDPublicKey.ChildIndexSize);
|
||||
checkBuffer('chainCode', HDPublicKey.ChainCodeSize);
|
||||
checkBuffer('publicKey', HDPublicKey.PublicKeySize);
|
||||
if (arg.checksum && arg.checksum.length) {
|
||||
checkBuffer('checksum', HDPublicKey.CheckSumSize);
|
||||
}
|
||||
};
|
||||
|
||||
HDPublicKey.prototype.toString = function () {
|
||||
return this.xpubkey;
|
||||
};
|
||||
|
||||
HDPublicKey.prototype.toObject = function () {
|
||||
return {
|
||||
network: Network.get(util.integerFromBuffer(this._buffers.version)),
|
||||
depth: util.integerFromSingleByteBuffer(this._buffers.depth),
|
||||
fingerPrint: util.integerFromBuffer(this.fingerPrint),
|
||||
parentFingerPrint: util.integerFromBuffer(this._buffers.parentFingerPrint),
|
||||
childIndex: util.integerFromBuffer(this._buffers.childIndex),
|
||||
chainCode: util.bufferToHex(this._buffers.chainCode),
|
||||
publicKey: this.publicKey.toString(),
|
||||
checksum: util.integerFromBuffer(this._buffers.checksum),
|
||||
xpubkey: this.xpubkey
|
||||
};
|
||||
};
|
||||
|
||||
HDPublicKey.prototype.toJson = function () {
|
||||
return JSON.stringify(this.toObject());
|
||||
};
|
||||
|
||||
HDPublicKey.DefaultDepth = 0;
|
||||
HDPublicKey.DefaultFingerprint = 0;
|
||||
HDPublicKey.DefaultChildIndex = 0;
|
||||
HDPublicKey.DefaultNetwork = Network.livenet;
|
||||
HDPublicKey.Hardened = 0x80000000;
|
||||
HDPublicKey.RootElementAlias = ['m', 'M', 'm\'', 'M\''];
|
||||
|
||||
HDPublicKey.VersionSize = 4;
|
||||
HDPublicKey.DepthSize = 1;
|
||||
HDPublicKey.ParentFingerPrintSize = 4;
|
||||
HDPublicKey.ChildIndexSize = 4;
|
||||
HDPublicKey.ChainCodeSize = 32;
|
||||
HDPublicKey.PublicKeySize = 33;
|
||||
HDPublicKey.CheckSumSize = 4;
|
||||
|
||||
HDPublicKey.SerializedByteSize = 82;
|
||||
|
||||
HDPublicKey.VersionStart = 0;
|
||||
HDPublicKey.VersionEnd = HDPublicKey.VersionStart + HDPublicKey.VersionSize;
|
||||
HDPublicKey.DepthStart = HDPublicKey.VersionEnd;
|
||||
HDPublicKey.DepthEnd = HDPublicKey.DepthStart + HDPublicKey.DepthSize;
|
||||
HDPublicKey.ParentFingerPrintStart = HDPublicKey.DepthEnd;
|
||||
HDPublicKey.ParentFingerPrintEnd = HDPublicKey.ParentFingerPrintStart + HDPublicKey.ParentFingerPrintSize;
|
||||
HDPublicKey.ChildIndexStart = HDPublicKey.ParentFingerPrintEnd;
|
||||
HDPublicKey.ChildIndexEnd = HDPublicKey.ChildIndexStart + HDPublicKey.ChildIndexSize;
|
||||
HDPublicKey.ChainCodeStart = HDPublicKey.ChildIndexEnd;
|
||||
HDPublicKey.ChainCodeEnd = HDPublicKey.ChainCodeStart + HDPublicKey.ChainCodeSize;
|
||||
HDPublicKey.PublicKeyStart = HDPublicKey.ChainCodeEnd;
|
||||
HDPublicKey.PublicKeyEnd = HDPublicKey.PublicKeyStart + HDPublicKey.PublicKeySize;
|
||||
HDPublicKey.ChecksumStart = HDPublicKey.PublicKeyEnd;
|
||||
HDPublicKey.ChecksumEnd = HDPublicKey.ChecksumStart + HDPublicKey.CheckSumSize;
|
||||
|
||||
assert(HDPublicKey.ChecksumEnd === HDPublicKey.SerializedByteSize);
|
||||
|
||||
HDPublicKey.Errors = {};
|
||||
HDPublicKey.Errors.ArgumentIsPrivateExtended = 'Argument starts with xpriv..., it\'s a private key';
|
||||
HDPublicKey.Errors.InvalidArgument = 'Invalid argument, expected string or Buffer';
|
||||
HDPublicKey.Errors.InvalidB58Char = 'Invalid Base 58 character';
|
||||
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.UnrecognizedArgument = 'Creating a HDPublicKey requires a string, a buffer, a json, or an object';
|
||||
|
||||
module.exports = HDPublicKey;
|
||||
|
|
@ -66,6 +66,7 @@ function getNetwork(arg) {
|
|||
* @namespace Network
|
||||
*/
|
||||
module.exports = {
|
||||
defaultNetwork: livenet,
|
||||
livenet: livenet,
|
||||
testnet: testnet,
|
||||
mainnet: livenet,
|
||||
|
|
|
@ -8,12 +8,6 @@ var base58check = require('./encoding/base58check');
|
|||
var Address = require('./address');
|
||||
var PublicKey = require('./publickey');
|
||||
|
||||
var assert = require('assert');
|
||||
|
||||
var COMPRESSED_LENGTH = 34;
|
||||
var UNCOMPRESSED_LENGTH = 33;
|
||||
var RAW_LENGTH = 32;
|
||||
|
||||
/**
|
||||
*
|
||||
* Instantiate a PrivateKey from a BN, Buffer and WIF.
|
||||
|
@ -44,10 +38,9 @@ var PrivateKey = function PrivateKey(data, network, compressed) {
|
|||
return new PrivateKey(data, network, compressed);
|
||||
}
|
||||
|
||||
network = network || 'livenet';
|
||||
var info = {
|
||||
compressed: typeof(compressed) !== 'undefined' ? compressed : true,
|
||||
network: network
|
||||
network: network || 'mainnet'
|
||||
};
|
||||
|
||||
// detect type of data
|
||||
|
@ -67,6 +60,9 @@ var PrivateKey = function PrivateKey(data, network, compressed) {
|
|||
if (!info.bn.lt(Point.getN())) {
|
||||
throw new TypeError('Number must be less than N');
|
||||
}
|
||||
if (typeof(networks[info.network]) === 'undefined') {
|
||||
throw new TypeError('Must specify the network ("mainnet" or "testnet")');
|
||||
}
|
||||
if (typeof(info.compressed) !== 'boolean') {
|
||||
throw new TypeError('Must specify whether the corresponding public key is compressed or not (true or false)');
|
||||
}
|
||||
|
@ -74,7 +70,6 @@ var PrivateKey = function PrivateKey(data, network, compressed) {
|
|||
this.bn = info.bn;
|
||||
this.compressed = info.compressed;
|
||||
this.network = info.network;
|
||||
this.publicKey = this.toPublicKey();
|
||||
|
||||
return this;
|
||||
|
||||
|
@ -109,29 +104,37 @@ PrivateKey._getRandomBN = function(){
|
|||
* @private
|
||||
*/
|
||||
PrivateKey._transformBuffer = function(buf, network, compressed) {
|
||||
/* jshint maxcomplexity: 8 */
|
||||
|
||||
var info = {};
|
||||
|
||||
|
||||
info.compressed = false;
|
||||
if (buf.length === COMPRESSED_LENGTH && buf[COMPRESSED_LENGTH-1] === 1) {
|
||||
if (buf.length === 1 + 32 + 1 && buf[1 + 32 + 1 - 1] === 1) {
|
||||
info.compressed = true;
|
||||
assert(buf[0] === networks.get(network).privatekey, 'Network version mismatch');
|
||||
} else if (buf.length === RAW_LENGTH || buf.length === UNCOMPRESSED_LENGTH) {
|
||||
if (buf.length === UNCOMPRESSED_LENGTH) {
|
||||
assert(buf[0] === networks.get(network).privatekey, 'Network version mismatch');
|
||||
buf = buf.slice(1, RAW_LENGTH);
|
||||
}
|
||||
} else if (buf.length === 1 + 32) {
|
||||
info.compressed = false;
|
||||
} else {
|
||||
throw new Error('Length of buffer must be 32 to 34 (plain, uncompressed, or compressed)');
|
||||
throw new Error('Length of buffer must be 33 (uncompressed) or 34 (compressed)');
|
||||
}
|
||||
|
||||
if (buf[0] === networks.mainnet.privatekey) {
|
||||
info.network = 'mainnet';
|
||||
} else if (buf[0] === networks.testnet.privatekey) {
|
||||
info.network = 'testnet';
|
||||
} else {
|
||||
throw new Error('Invalid network');
|
||||
}
|
||||
|
||||
if (network && networks.get(info.network) !== networks.get(network)) {
|
||||
throw TypeError('Private key network mismatch');
|
||||
}
|
||||
|
||||
if (typeof(compressed) !== 'undefined' && info.compressed !== compressed){
|
||||
throw TypeError('Private key compression mismatch');
|
||||
}
|
||||
info.bn = BN.fromBuffer(buf);
|
||||
|
||||
info.bn = BN.fromBuffer(buf.slice(1, 32 + 1));
|
||||
|
||||
return info;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -70,7 +70,6 @@ var PublicKey = function PublicKey(data, compressed) {
|
|||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* Internal function to transform a private key into a public key point
|
||||
*
|
||||
* @param {PrivateKey} privkey - An instance of PrivateKey
|
||||
|
@ -89,7 +88,6 @@ PublicKey._transformPrivateKey = function(privkey) {
|
|||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* Internal function to transform DER into a public key point
|
||||
*
|
||||
* @param {Buffer} buf - An hex encoded buffer
|
||||
|
|
16
lib/util.js
16
lib/util.js
|
@ -44,11 +44,27 @@ module.exports = {
|
|||
integerFromBuffer: function integerFromBuffer(buffer) {
|
||||
return buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
|
||||
},
|
||||
integerFromSingleByteBuffer: function integerFromBuffer(buffer) {
|
||||
return buffer[0];
|
||||
},
|
||||
bufferToHex: function bufferToHex(buffer) {
|
||||
return buffer.toString('hex');
|
||||
},
|
||||
hexToBuffer: function hexToBuffer(string) {
|
||||
assert(isHexa(string));
|
||||
return new buffer.Buffer(string, 'hex');
|
||||
},
|
||||
pointToCompressed: function pointToCompressed(point) {
|
||||
var xbuf = point.getX().toBuffer({size: 32});
|
||||
var ybuf = point.getY().toBuffer({size: 32});
|
||||
|
||||
var prefix;
|
||||
var odd = ybuf[ybuf.length - 1] % 2;
|
||||
if (odd) {
|
||||
prefix = new Buffer([0x03]);
|
||||
} else {
|
||||
prefix = new Buffer([0x02]);
|
||||
}
|
||||
return buffer.Buffer.concat([prefix, xbuf]);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -15,7 +15,7 @@ var bitcore = require('..');
|
|||
var HDPrivateKey = bitcore.HDPrivateKey;
|
||||
var HDPublicKey = bitcore.HDPublicKey;
|
||||
|
||||
describe.only('BIP32 compliance', function() {
|
||||
describe('BIP32 compliance', function() {
|
||||
|
||||
it('should initialize test vector 1 from the extended public key', function() {
|
||||
new HDPublicKey(vector1_m_public).xpubkey.should.equal(vector1_m_public);
|
||||
|
@ -44,8 +44,8 @@ describe.only('BIP32 compliance', function() {
|
|||
});
|
||||
|
||||
it("should get m/0' ext. private key from test vector 1", function() {
|
||||
var privateKey = new HDPrivateKey(vector1_m_private);
|
||||
privateKey.derive("m/0'").xprivkey.should.equal(vector1_m0h_private);
|
||||
var privateKey = new HDPrivateKey(vector1_m_private).derive("m/0'");
|
||||
privateKey.xprivkey.should.equal(vector1_m0h_private);
|
||||
});
|
||||
|
||||
it("should get m/0' ext. public key from test vector 1", function() {
|
||||
|
@ -64,8 +64,8 @@ describe.only('BIP32 compliance', function() {
|
|||
});
|
||||
|
||||
it("should get m/0'/1 ext. public key from m/0' public key from test vector 1", function() {
|
||||
var derivedPublic = HDPrivateKey(vector1_m_private).derive("m/0'").hdPublicKey;
|
||||
derivedPublic.derive("m/1").xpubkey.should.equal(vector1_m0h1_public);
|
||||
var derivedPublic = HDPrivateKey(vector1_m_private).derive("m/0'").hdPublicKey.derive("m/1");
|
||||
derivedPublic.xpubkey.should.equal(vector1_m0h1_public);
|
||||
});
|
||||
|
||||
it("should get m/0'/1/2' ext. private key from test vector 1", function() {
|
||||
|
@ -130,7 +130,7 @@ describe.only('BIP32 compliance', function() {
|
|||
});
|
||||
|
||||
it("should get m/0 ext. public key from m public key from test vector 2", function() {
|
||||
HDPrivateKey(vector2_m_private).hdPublicKey.derive(0).should.equal(vector2_m0_public);
|
||||
HDPrivateKey(vector2_m_private).hdPublicKey.derive(0).xpubkey.should.equal(vector2_m0_public);
|
||||
});
|
||||
|
||||
it("should get m/0/2147483647h ext. private key from test vector 2", function() {
|
||||
|
|
Loading…
Reference in New Issue