hd refactor.
This commit is contained in:
parent
8db6e1c9a6
commit
897e4ae662
190
lib/bcoin/hd.js
190
lib/bcoin/hd.js
@ -241,10 +241,10 @@ Mnemonic.isMnemonic = function isMnemonic(obj) {
|
||||
* or {@link HDPrivateKey} options.
|
||||
*/
|
||||
|
||||
function HD(options) {
|
||||
function HD(options, network) {
|
||||
if (!options)
|
||||
return HD.fromSeed();
|
||||
return HD.fromAny(options);
|
||||
return HD.fromSeed(null, network);
|
||||
return HD.fromAny(options, network);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -264,35 +264,46 @@ HD.fromBase58 = function fromBase58(xkey) {
|
||||
* @param {Object} options
|
||||
* @param {Buffer?} options.privateKey
|
||||
* @param {Buffer?} options.entropy
|
||||
* @param {String?} networkType
|
||||
* @param {String?} network
|
||||
* @returns {HDPrivateKey}
|
||||
*/
|
||||
|
||||
HD.generate = function generate(options, networkType) {
|
||||
return HDPrivateKey.generate(options, networkType);
|
||||
HD.generate = function generate(options, network) {
|
||||
return HDPrivateKey.generate(options, network);
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate an {@link HDPrivateKey} from a seed.
|
||||
* @param {Object|Mnemonic|Buffer} options - seed,
|
||||
* mnemonic, mnemonic options.
|
||||
* @param {String?} networkType
|
||||
* @param {String?} network
|
||||
* @returns {HDPrivateKey}
|
||||
*/
|
||||
|
||||
HD.fromSeed = function fromSeed(options, networkType) {
|
||||
return HDPrivateKey.fromSeed(options, networkType);
|
||||
HD.fromSeed = function fromSeed(options, network) {
|
||||
return HDPrivateKey.fromSeed(options, network);
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiate an HD key from a jsonified key object.
|
||||
* @param {Object} json - The jsonified transaction object.
|
||||
* @param {String?} passphrase
|
||||
* @returns {HDPrivateKey}
|
||||
*/
|
||||
|
||||
HD.fromJSON = function fromJSON(json, passphrase) {
|
||||
return HDPrivateKey.fromJSON(json, passphrase);
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate an hdkey from any number of options.
|
||||
* @param {Object|Mnemonic|Buffer} options - mnemonic, mnemonic
|
||||
* options, seed, or base58 key.
|
||||
* @param {String?} networkType
|
||||
* @param {String?} network
|
||||
* @returns {HDPrivateKey|HDPublicKey}
|
||||
*/
|
||||
|
||||
HD.fromAny = function fromAny(options, networkType) {
|
||||
HD.fromAny = function fromAny(options, network) {
|
||||
var xkey;
|
||||
|
||||
assert(options, 'Options required.');
|
||||
@ -312,7 +323,7 @@ HD.fromAny = function fromAny(options, networkType) {
|
||||
if (HDPublicKey.isExtended(xkey))
|
||||
return HDPublicKey.fromBase58(xkey);
|
||||
|
||||
return HDPrivateKey.fromSeed(options, networkType);
|
||||
return HDPrivateKey.fromSeed(options, network);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -351,7 +362,6 @@ HD.isHD = function isHD(obj) {
|
||||
* @param {Object|Base58String} options
|
||||
* @param {Base58String?} options.xkey - Serialized base58 key.
|
||||
* @param {(Mnemonic|Object)?} options.mnemonic - mnemonic or mnemonic options.
|
||||
* @param {Number?} options.version
|
||||
* @param {Number?} options.depth
|
||||
* @param {Buffer?} options.parentFingerPrint
|
||||
* @param {Number?} options.childIndex
|
||||
@ -361,7 +371,6 @@ HD.isHD = function isHD(obj) {
|
||||
* @property {Base58String} xprivkey
|
||||
* @property {Base58String} xpubkey
|
||||
* @property {Mnemonic?} mnemonic
|
||||
* @property {Number} version
|
||||
* @property {Number} depth
|
||||
* @property {Buffer} parentFingerPrint
|
||||
* @property {Number} childIndex
|
||||
@ -377,11 +386,7 @@ function HDPrivateKey(options) {
|
||||
assert(options, 'No options for HD private key.');
|
||||
assert(options.depth <= 0xff, 'Depth is too high.');
|
||||
|
||||
this.network = bcoin.network.get(options.network);
|
||||
this.xprivkey = options.xprivkey;
|
||||
this.mnemonic = options.mnemonic;
|
||||
|
||||
this.version = options.version;
|
||||
this.network = bcoin.network.get(options.network).type;
|
||||
this.depth = options.depth;
|
||||
this.parentFingerPrint = options.parentFingerPrint;
|
||||
this.childIndex = options.childIndex;
|
||||
@ -391,11 +396,12 @@ function HDPrivateKey(options) {
|
||||
this.publicKey = ec.publicKeyCreate(options.privateKey, true);
|
||||
this.fingerPrint = null;
|
||||
|
||||
this.mnemonic = options.mnemonic;
|
||||
|
||||
this._xprivkey = options.xprivkey;
|
||||
|
||||
this.hdPrivateKey = this;
|
||||
this._hdPublicKey = null;
|
||||
|
||||
if (!this.xprivkey)
|
||||
this.xprivkey = HDPrivateKey.render(options);
|
||||
}
|
||||
|
||||
utils.inherits(HDPrivateKey, HD);
|
||||
@ -404,7 +410,6 @@ HDPrivateKey.prototype.__defineGetter__('hdPublicKey', function() {
|
||||
if (!this._hdPublicKey) {
|
||||
this._hdPublicKey = new HDPublicKey({
|
||||
network: this.network,
|
||||
version: this.network.prefixes.xpubkey,
|
||||
depth: this.depth,
|
||||
parentFingerPrint: this.parentFingerPrint,
|
||||
childIndex: this.childIndex,
|
||||
@ -415,6 +420,12 @@ HDPrivateKey.prototype.__defineGetter__('hdPublicKey', function() {
|
||||
return this._hdPublicKey;
|
||||
});
|
||||
|
||||
HDPrivateKey.prototype.__defineGetter__('xprivkey', function() {
|
||||
if (!this._xprivkey)
|
||||
this._xprivkey = this.toBase58();
|
||||
return this._xprivkey;
|
||||
});
|
||||
|
||||
HDPrivateKey.prototype.__defineGetter__('xpubkey', function() {
|
||||
return this.hdPublicKey.xpubkey;
|
||||
});
|
||||
@ -470,7 +481,6 @@ HDPrivateKey.prototype.derive = function derive(index, hardened) {
|
||||
|
||||
child = new HDPrivateKey({
|
||||
network: this.network,
|
||||
version: this.version,
|
||||
depth: this.depth + 1,
|
||||
parentFingerPrint: this.fingerPrint,
|
||||
childIndex: index,
|
||||
@ -505,7 +515,7 @@ HDPrivateKey.prototype.deriveAccount44 = function deriveAccount44(options) {
|
||||
}
|
||||
|
||||
if (coinType == null)
|
||||
coinType = this.network.type === 'main' ? 0 : 1;
|
||||
coinType = this.network === 'main' ? 0 : 1;
|
||||
|
||||
assert(utils.isNumber(coinType));
|
||||
assert(utils.isNumber(accountIndex));
|
||||
@ -671,13 +681,13 @@ HDPrivateKey.prototype.derivePath = function derivePath(path) {
|
||||
* Create an hd private key from a seed.
|
||||
* @param {Buffer|Mnemonic|Object} options - A seed,
|
||||
* mnemonic, or mnemonic options.
|
||||
* @param {String?} networkType
|
||||
* @param {String?} network
|
||||
* @returns {Object} A "naked" key (a
|
||||
* plain javascript object which is suitable
|
||||
* for passing to the HDPrivateKey constructor).
|
||||
*/
|
||||
|
||||
HDPrivateKey.parseSeed = function parseSeed(seed, networkType) {
|
||||
HDPrivateKey.parseSeed = function parseSeed(seed, network) {
|
||||
var data, hash;
|
||||
|
||||
if (!seed)
|
||||
@ -701,7 +711,7 @@ HDPrivateKey.parseSeed = function parseSeed(seed, networkType) {
|
||||
hash = utils.hmac('sha512', data, 'Bitcoin seed');
|
||||
|
||||
return {
|
||||
version: bcoin.network.get(networkType).prefixes.xprivkey,
|
||||
network: network,
|
||||
depth: 0,
|
||||
parentFingerPrint: new Buffer([0, 0, 0, 0]),
|
||||
childIndex: 0,
|
||||
@ -715,12 +725,12 @@ HDPrivateKey.parseSeed = function parseSeed(seed, networkType) {
|
||||
* Instantiate an hd private key from a seed.
|
||||
* @param {Buffer|Mnemonic|Object} seed - A
|
||||
* seed, mnemonic, or mnemonic options.
|
||||
* @param {String?} networkType
|
||||
* @param {String?} network
|
||||
* @returns {HDPrivateKey}
|
||||
*/
|
||||
|
||||
HDPrivateKey.fromSeed = function fromSeed(seed, networkType) {
|
||||
return new HDPrivateKey(HDPrivateKey.parseSeed(seed, networkType));
|
||||
HDPrivateKey.fromSeed = function fromSeed(seed, network) {
|
||||
return new HDPrivateKey(HDPrivateKey.parseSeed(seed, network));
|
||||
};
|
||||
|
||||
/**
|
||||
@ -728,13 +738,13 @@ HDPrivateKey.fromSeed = function fromSeed(seed, networkType) {
|
||||
* @param {Object?} options
|
||||
* @param {Buffer?} options.privateKey
|
||||
* @param {Buffer?} options.entropy
|
||||
* @param {String?} networkType
|
||||
* @param {String?} network
|
||||
* @returns {Object} A "naked" key (a
|
||||
* plain javascript object which is suitable
|
||||
* for passing to the HDPrivateKey constructor).
|
||||
*/
|
||||
|
||||
HDPrivateKey._generate = function _generate(options, networkType) {
|
||||
HDPrivateKey._generate = function _generate(options, network) {
|
||||
var privateKey, entropy;
|
||||
|
||||
if (!options)
|
||||
@ -753,7 +763,7 @@ HDPrivateKey._generate = function _generate(options, networkType) {
|
||||
entropy = ec.random(32);
|
||||
|
||||
return {
|
||||
version: bcoin.network.get(networkType).prefixes.xprivkey,
|
||||
network: network,
|
||||
depth: 0,
|
||||
parentFingerPrint: new Buffer([0, 0, 0, 0]),
|
||||
childIndex: 0,
|
||||
@ -767,12 +777,12 @@ HDPrivateKey._generate = function _generate(options, networkType) {
|
||||
* @param {Object?} options
|
||||
* @param {Buffer?} options.privateKey
|
||||
* @param {Buffer?} options.entropy
|
||||
* @param {String?} networkType
|
||||
* @param {String?} network
|
||||
* @returns {HDPrivateKey}
|
||||
*/
|
||||
|
||||
HDPrivateKey.generate = function generate(options, networkType) {
|
||||
return new HDPrivateKey(HDPrivateKey._generate(options, networkType));
|
||||
HDPrivateKey.generate = function generate(options, network) {
|
||||
return new HDPrivateKey(HDPrivateKey._generate(options, network));
|
||||
};
|
||||
|
||||
/**
|
||||
@ -781,7 +791,7 @@ HDPrivateKey.generate = function generate(options, networkType) {
|
||||
* @returns {Object}
|
||||
*/
|
||||
|
||||
HDPrivateKey.parse = function parse(xkey) {
|
||||
HDPrivateKey.parseBase58 = function parseBase58(xkey) {
|
||||
var raw = utils.fromBase58(xkey);
|
||||
var p = new BufferReader(raw, true);
|
||||
var data = {};
|
||||
@ -811,6 +821,32 @@ HDPrivateKey.parse = function parse(xkey) {
|
||||
return data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Serialize key to a base58 string.
|
||||
* @param {Network|String} network
|
||||
* @returns {Base58String}
|
||||
*/
|
||||
|
||||
HDPrivateKey.prototype.toBase58 = function toBase58(network) {
|
||||
var p = new BufferWriter();
|
||||
|
||||
if (!network)
|
||||
network = this.network;
|
||||
|
||||
network = bcoin.network.get(network);
|
||||
|
||||
p.writeU32BE(network.prefixes.xprivkey);
|
||||
p.writeU8(this.depth);
|
||||
p.writeBytes(this.parentFingerPrint);
|
||||
p.writeU32BE(this.childIndex);
|
||||
p.writeBytes(this.chainCode);
|
||||
p.writeU8(0);
|
||||
p.writeBytes(this.privateKey);
|
||||
p.writeChecksum();
|
||||
|
||||
return utils.toBase58(p.render());
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiate a transaction from a base58 string.
|
||||
* @param {Base58String} xkey
|
||||
@ -818,29 +854,10 @@ HDPrivateKey.parse = function parse(xkey) {
|
||||
*/
|
||||
|
||||
HDPrivateKey.fromBase58 = function fromBase58(xkey) {
|
||||
var data = HDPrivateKey.parse(xkey);
|
||||
var data = HDPrivateKey.parseBase58(xkey);
|
||||
return new HDPrivateKey(data);
|
||||
};
|
||||
|
||||
/**
|
||||
* Serialize key data to base58 extended key.
|
||||
* @param {Object|HDPrivateKey}
|
||||
* @returns {Base58String}
|
||||
*/
|
||||
|
||||
HDPrivateKey.render = function render(data) {
|
||||
var p = new BufferWriter();
|
||||
p.writeU32BE(data.version);
|
||||
p.writeU8(data.depth);
|
||||
p.writeBytes(data.parentFingerPrint);
|
||||
p.writeU32BE(data.childIndex);
|
||||
p.writeBytes(data.chainCode);
|
||||
p.writeU8(0);
|
||||
p.writeBytes(data.privateKey);
|
||||
p.writeChecksum();
|
||||
return utils.toBase58(p.render());
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert key to a more json-friendly object.
|
||||
* @param {String?} passphrase - Address passphrase
|
||||
@ -962,7 +979,6 @@ HDPrivateKey.isHDPrivateKey = function isHDPrivateKey(obj) {
|
||||
* @constructor
|
||||
* @param {Object|Base58String} options
|
||||
* @param {Base58String?} options.xkey - Serialized base58 key.
|
||||
* @param {Number?} options.version
|
||||
* @param {Number?} options.depth
|
||||
* @param {Buffer?} options.parentFingerPrint
|
||||
* @param {Number?} options.childIndex
|
||||
@ -970,7 +986,6 @@ HDPrivateKey.isHDPrivateKey = function isHDPrivateKey(obj) {
|
||||
* @param {Buffer?} options.publicKey
|
||||
* @property {String} network
|
||||
* @property {Base58String} xpubkey
|
||||
* @property {Number} version
|
||||
* @property {Number} depth
|
||||
* @property {Buffer} parentFingerPrint
|
||||
* @property {Number} childIndex
|
||||
@ -985,11 +1000,7 @@ function HDPublicKey(options) {
|
||||
assert(options, 'No options for HDPublicKey');
|
||||
assert(options.depth <= 0xff, 'Depth is too high.');
|
||||
|
||||
this.network = bcoin.network.get(options.network);
|
||||
this.xpubkey = options.xpubkey;
|
||||
this.xprivkey = null;
|
||||
|
||||
this.version = options.version;
|
||||
this.network = bcoin.network.get(options.network).type;
|
||||
this.depth = options.depth;
|
||||
this.parentFingerPrint = options.parentFingerPrint;
|
||||
this.childIndex = options.childIndex;
|
||||
@ -999,15 +1010,21 @@ function HDPublicKey(options) {
|
||||
this.privateKey = null;
|
||||
this.fingerPrint = null;
|
||||
|
||||
this.xprivkey = null;
|
||||
this._xpubkey = options.xpubkey;
|
||||
|
||||
this.hdPublicKey = this;
|
||||
this.hdPrivateKey = null;
|
||||
|
||||
if (!this.xpubkey)
|
||||
this.xpubkey = HDPublicKey.render(options);
|
||||
}
|
||||
|
||||
utils.inherits(HDPublicKey, HD);
|
||||
|
||||
HDPublicKey.prototype.__defineGetter__('xpubkey', function() {
|
||||
if (!this._xpubkey)
|
||||
this._xpubkey = this.toBase58();
|
||||
return this._xpubkey;
|
||||
});
|
||||
|
||||
/**
|
||||
* Derive a child key.
|
||||
* @param {Number|String} - Child index or path.
|
||||
@ -1056,7 +1073,6 @@ HDPublicKey.prototype.derive = function derive(index, hardened) {
|
||||
|
||||
child = new HDPublicKey({
|
||||
network: this.network,
|
||||
version: this.version,
|
||||
depth: this.depth + 1,
|
||||
parentFingerPrint: this.fingerPrint,
|
||||
childIndex: index,
|
||||
@ -1202,7 +1218,7 @@ HDPublicKey.isExtended = function isExtended(data) {
|
||||
* @returns {Object}
|
||||
*/
|
||||
|
||||
HDPublicKey.parse = function parse(xkey) {
|
||||
HDPublicKey.parseBase58 = function parseBase58(xkey) {
|
||||
var raw = utils.fromBase58(xkey);
|
||||
var p = new BufferReader(raw, true);
|
||||
var data = {};
|
||||
@ -1233,19 +1249,26 @@ HDPublicKey.parse = function parse(xkey) {
|
||||
|
||||
/**
|
||||
* Serialize key data to base58 extended key.
|
||||
* @param {Object|HDPublicKey}
|
||||
* @param {Network|String} network
|
||||
* @returns {Base58String}
|
||||
*/
|
||||
|
||||
HDPublicKey.render = function render(data) {
|
||||
HDPublicKey.prototype.toBase58 = function toBase58(network) {
|
||||
var p = new BufferWriter();
|
||||
p.writeU32BE(data.version);
|
||||
p.writeU8(data.depth);
|
||||
p.writeBytes(data.parentFingerPrint);
|
||||
p.writeU32BE(data.childIndex);
|
||||
p.writeBytes(data.chainCode);
|
||||
p.writeBytes(data.publicKey);
|
||||
|
||||
if (!network)
|
||||
network = this.network;
|
||||
|
||||
network = bcoin.network.get(network);
|
||||
|
||||
p.writeU32BE(network.prefixes.xpubkey);
|
||||
p.writeU8(this.depth);
|
||||
p.writeBytes(this.parentFingerPrint);
|
||||
p.writeU32BE(this.childIndex);
|
||||
p.writeBytes(this.chainCode);
|
||||
p.writeBytes(this.publicKey);
|
||||
p.writeChecksum();
|
||||
|
||||
return utils.toBase58(p.render());
|
||||
};
|
||||
|
||||
@ -1256,7 +1279,7 @@ HDPublicKey.render = function render(data) {
|
||||
*/
|
||||
|
||||
HDPublicKey.fromBase58 = function fromBase58(xkey) {
|
||||
var data = HDPublicKey.parse(xkey);
|
||||
var data = HDPublicKey.parseBase58(xkey);
|
||||
return new HDPublicKey(data);
|
||||
};
|
||||
|
||||
@ -1333,11 +1356,8 @@ HDPrivateKey.prototype.toSecret = function toSecret() {
|
||||
return KeyPair.prototype.toSecret.call(this);
|
||||
};
|
||||
|
||||
HD.mnemonic = Mnemonic;
|
||||
HD.priv = HDPrivateKey;
|
||||
HD.pub = HDPublicKey;
|
||||
HD.privateKey = HDPrivateKey;
|
||||
HD.publicKey = HDPublicKey;
|
||||
HD.fromJSON = HDPrivateKey.fromJSON;
|
||||
HD.Mnemonic = Mnemonic;
|
||||
HD.PrivateKey = HDPrivateKey;
|
||||
HD.PublicKey = HDPublicKey;
|
||||
|
||||
module.exports = HD;
|
||||
|
||||
@ -105,4 +105,8 @@ Network.get = function get(options) {
|
||||
assert(false, 'Unknown network.');
|
||||
};
|
||||
|
||||
Network.prototype.inspect = function inspect() {
|
||||
return this.type;
|
||||
};
|
||||
|
||||
module.exports = Network;
|
||||
|
||||
@ -57,18 +57,18 @@ function Wallet(options) {
|
||||
|
||||
options = utils.merge({}, options);
|
||||
|
||||
this.options = options;
|
||||
this.network = bcoin.network.get(options.network);
|
||||
|
||||
if (typeof options.master === 'string')
|
||||
options.master = { xkey: options.master };
|
||||
|
||||
if (options.master
|
||||
&& typeof options.master === 'object'
|
||||
&& !(options.master instanceof bcoin.hd)) {
|
||||
options.master = bcoin.hd.fromAny(options.master);
|
||||
options.master = bcoin.hd.fromAny(options.master, this.network);
|
||||
}
|
||||
|
||||
this.options = options;
|
||||
this.network = bcoin.network.get(options.network);
|
||||
|
||||
if (!options.master)
|
||||
options.master = bcoin.hd.fromSeed(null, this.network);
|
||||
|
||||
|
||||
@ -93,7 +93,7 @@ describe('HD', function() {
|
||||
});
|
||||
|
||||
it('should create master private key', function() {
|
||||
master = bcoin.hd.priv.fromSeed(new Buffer(seed, 'hex'));
|
||||
master = bcoin.hd.PrivateKey.fromSeed(new Buffer(seed, 'hex'));
|
||||
assert.equal(master.xprivkey, master_priv);
|
||||
assert.equal(master.xpubkey, master_pub);
|
||||
});
|
||||
@ -134,11 +134,11 @@ describe('HD', function() {
|
||||
});
|
||||
|
||||
it('should deserialize master private key', function() {
|
||||
bcoin.hd.priv.parse(master.xprivkey);
|
||||
bcoin.hd.PrivateKey.parseBase58(master.xprivkey);
|
||||
});
|
||||
|
||||
it('should deserialize master public key', function() {
|
||||
bcoin.hd.pub.parse(master.hdPublicKey.xpubkey);
|
||||
bcoin.hd.PublicKey.parseBase58(master.hdPublicKey.xpubkey);
|
||||
});
|
||||
|
||||
it('should deserialize and reserialize', function() {
|
||||
@ -162,7 +162,7 @@ describe('HD', function() {
|
||||
delete vector.seed;
|
||||
delete vector.m;
|
||||
it('should create from a seed', function() {
|
||||
master = bcoin.hd.priv.fromSeed(new Buffer(seed, 'hex'));
|
||||
master = bcoin.hd.PrivateKey.fromSeed(new Buffer(seed, 'hex'));
|
||||
equal(master.xprivkey, m.prv);
|
||||
equal(master.xpubkey, m.pub);
|
||||
});
|
||||
|
||||
@ -12,7 +12,7 @@ describe('Mnemonic', function() {
|
||||
var seed = new Buffer(data[2], 'hex');
|
||||
var xpriv = data[3];
|
||||
it('should create an english mnemonic (' + i + ')', function() {
|
||||
var mnemonic = new bcoin.hd.mnemonic({
|
||||
var mnemonic = new bcoin.hd.Mnemonic({
|
||||
language: 'english',
|
||||
entropy: entropy,
|
||||
passphrase: 'TREZOR'
|
||||
@ -31,7 +31,7 @@ describe('Mnemonic', function() {
|
||||
var passphrase = data.passphrase;
|
||||
var xpriv = data.bip32_xprv;
|
||||
it('should create a japanese mnemonic (' + i + ')', function() {
|
||||
var mnemonic = new bcoin.hd.mnemonic({
|
||||
var mnemonic = new bcoin.hd.Mnemonic({
|
||||
language: 'japanese',
|
||||
entropy: entropy,
|
||||
passphrase: passphrase
|
||||
|
||||
Loading…
Reference in New Issue
Block a user