hd option parsing and network.
This commit is contained in:
parent
88c131c7b3
commit
60abff853a
163
lib/bcoin/hd.js
163
lib/bcoin/hd.js
@ -124,30 +124,24 @@ function HDPrivateKey(options) {
|
||||
assert(!(options instanceof HDPrivateKey));
|
||||
assert(!(options instanceof HDPublicKey));
|
||||
|
||||
if (options instanceof bcoin.hd.seed)
|
||||
options = { seed: options };
|
||||
|
||||
if (options) {
|
||||
if (options.xprivkey)
|
||||
options.xkey = options.xprivkey;
|
||||
if (options.xpubkey)
|
||||
options.xkey = options.xpubkey;
|
||||
}
|
||||
|
||||
if (options) {
|
||||
if (HDPublicKey.isExtended(options) || HDPublicKey.isExtended(options.xkey))
|
||||
return new HDPublicKey(options);
|
||||
}
|
||||
|
||||
if (!options)
|
||||
options = { seed: bcoin.hd.seed() };
|
||||
|
||||
// if (!options)
|
||||
// options = this._generate();
|
||||
|
||||
if (HDPrivateKey.isExtended(options))
|
||||
options = { xkey: options };
|
||||
|
||||
if (options.xpubkey)
|
||||
options.xkey = options.xpubkey;
|
||||
|
||||
if (options.xprivkey)
|
||||
options.xkey = options.xprivkey;
|
||||
|
||||
if (HDPublicKey.isExtended(options.xkey))
|
||||
return new HDPublicKey(options);
|
||||
|
||||
if (options instanceof bcoin.hd.seed)
|
||||
options = { seed: options };
|
||||
|
||||
if (options.passphrase !== undefined
|
||||
|| options.bits
|
||||
|| options.entropy
|
||||
@ -162,16 +156,21 @@ function HDPrivateKey(options) {
|
||||
options.seed = bcoin.hd.seed(options.seed);
|
||||
}
|
||||
|
||||
this.network = options.network || network.type;
|
||||
|
||||
if (options.seed) {
|
||||
this.seed = options.seed;
|
||||
data = this._seed(options.seed);
|
||||
} else if (options.xkey) {
|
||||
data = this._unbuild(options.xkey);
|
||||
} else if (options.privateKey) {
|
||||
data = this._generate(options.privateKey, options.chainCode);
|
||||
} else {
|
||||
data = options;
|
||||
data = options.data;
|
||||
}
|
||||
assert(data);
|
||||
|
||||
data = this._normalize(data, network.prefixes.xprivkey);
|
||||
data = this._normalize(data);
|
||||
|
||||
this.data = data;
|
||||
|
||||
@ -199,7 +198,7 @@ HDPrivateKey.prototype.scan44 = function scan44(options, txByAddress, callback)
|
||||
coinType = options.coinType;
|
||||
|
||||
if (coinType == null)
|
||||
coinType = network.type === 'main' ? 0 : 1;
|
||||
coinType = network[this.network].type === 'main' ? 0 : 1;
|
||||
|
||||
assert(utils.isFinite(coinType));
|
||||
|
||||
@ -240,6 +239,8 @@ HDPrivateKey.prototype.scan44 = function scan44(options, txByAddress, callback)
|
||||
if (txs) {
|
||||
if (typeof txs === 'boolean')
|
||||
result = txs;
|
||||
else if (typeof txs === 'number')
|
||||
result = txs > 0;
|
||||
else if (Array.isArray(txs))
|
||||
result = txs.length > 0;
|
||||
else
|
||||
@ -300,7 +301,7 @@ HDPrivateKey.prototype.deriveAccount44 = function deriveAccount44(options) {
|
||||
}
|
||||
|
||||
if (coinType == null)
|
||||
coinType = network.type === 'main' ? 0 : 1;
|
||||
coinType = network[this.network].type === 'main' ? 0 : 1;
|
||||
|
||||
assert(utils.isFinite(coinType));
|
||||
assert(utils.isFinite(accountIndex));
|
||||
@ -387,6 +388,8 @@ HDPrivateKey.prototype.scan45 = function scan45(options, txByAddress, callback)
|
||||
if (txs) {
|
||||
if (typeof txs === 'boolean')
|
||||
result = txs;
|
||||
else if (typeof txs === 'number')
|
||||
result = txs > 0;
|
||||
else if (Array.isArray(txs))
|
||||
result = txs.length > 0;
|
||||
else
|
||||
@ -500,7 +503,7 @@ HDPrivateKey.getPath = function getPath(options) {
|
||||
purpose = 44;
|
||||
|
||||
if (coinType == null)
|
||||
coinType = network.type === 'main' ? 0 : 1;
|
||||
coinType = network[this.network].type === 'main' ? 0 : 1;
|
||||
|
||||
if (chain == null)
|
||||
chain = options.change ? 1 : 0;
|
||||
@ -519,10 +522,12 @@ HDPrivateKey.isExtended = function isExtended(data) {
|
||||
return data.indexOf('xprv') === 0 || data.indexOf('tprv') === 0;
|
||||
};
|
||||
|
||||
HDPrivateKey.prototype._normalize = function _normalize(data, version) {
|
||||
data.version = version || network.prefixes.xprivkey;
|
||||
data.privateKey = data.privateKey || data.priv;
|
||||
data.publicKey = data.publicKey || data.pub;
|
||||
HDPrivateKey.prototype._normalize = function _normalize(data) {
|
||||
if (!data.version) {
|
||||
data.version = (this instanceof HDPrivateKey)
|
||||
? network[this.network].prefixes.xprivkey
|
||||
: network[this.network].prefixes.xpubkey;
|
||||
}
|
||||
|
||||
// version = uint_32be
|
||||
if (typeof data.version === 'string')
|
||||
@ -581,6 +586,8 @@ HDPrivateKey.prototype._normalize = function _normalize(data, version) {
|
||||
};
|
||||
|
||||
HDPrivateKey.prototype._seed = function _seed(seed) {
|
||||
var hash;
|
||||
|
||||
if (seed instanceof HDSeed)
|
||||
seed = seed.seed;
|
||||
|
||||
@ -592,10 +599,10 @@ HDPrivateKey.prototype._seed = function _seed(seed) {
|
||||
throw new Error('entropy not in range');
|
||||
}
|
||||
|
||||
var hash = utils.sha512hmac(seed, 'Bitcoin seed');
|
||||
hash = utils.sha512hmac(seed, 'Bitcoin seed');
|
||||
|
||||
return {
|
||||
version: null,
|
||||
version: network[this.network].prefixes.xprivkey,
|
||||
depth: 0,
|
||||
parentFingerPrint: 0,
|
||||
childIndex: 0,
|
||||
@ -605,7 +612,7 @@ HDPrivateKey.prototype._seed = function _seed(seed) {
|
||||
};
|
||||
};
|
||||
|
||||
HDPrivateKey.prototype._generate = function _generate(privateKey) {
|
||||
HDPrivateKey.prototype._generate = function _generate(privateKey, entropy) {
|
||||
if (!privateKey)
|
||||
privateKey = bcoin.ecdsa.genKeyPair().getPrivate().toArray();
|
||||
|
||||
@ -614,12 +621,15 @@ HDPrivateKey.prototype._generate = function _generate(privateKey) {
|
||||
else if (utils.isBase58(privateKey))
|
||||
privateKey = bcoin.keypair.fromSecret(privateKey).getPrivate().toArray();
|
||||
|
||||
if (!entropy)
|
||||
entropy = elliptic.rand(32);
|
||||
|
||||
return {
|
||||
version: null,
|
||||
version: network[this.network].prefixes.xprivkey,
|
||||
depth: 0,
|
||||
parentFingerPrint: 0,
|
||||
childIndex: 0,
|
||||
chainCode: elliptic.rand(32),
|
||||
chainCode: entropy,
|
||||
privateKey: privateKey,
|
||||
checksum: null
|
||||
};
|
||||
@ -651,6 +661,11 @@ HDPrivateKey.prototype._unbuild = function _unbuild(xkey) {
|
||||
if (data.checksum !== utils.readU32BE(hash, 0))
|
||||
throw new Error('checksum mismatch');
|
||||
|
||||
if (data.version === network.main.prefixes.xprivkey)
|
||||
this.network = 'main';
|
||||
else
|
||||
this.network = 'testnet';
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
@ -693,21 +708,25 @@ HDPrivateKey.prototype._build = function _build(data) {
|
||||
this.publicKey = publicKey;
|
||||
|
||||
this.hdPublicKey = new HDPublicKey({
|
||||
version: this.version,
|
||||
depth: this.depth,
|
||||
parentFingerPrint: this.parentFingerPrint,
|
||||
childIndex: this.childIndex,
|
||||
chainCode: this.chainCode,
|
||||
checksum: this.checksum,
|
||||
publicKey: this.publicKey
|
||||
network: this.network,
|
||||
data: {
|
||||
version: network[this.network].prefixes.xpubkey,
|
||||
depth: this.depth,
|
||||
parentFingerPrint: this.parentFingerPrint,
|
||||
childIndex: this.childIndex,
|
||||
chainCode: this.chainCode,
|
||||
checksum: this.checksum,
|
||||
publicKey: this.publicKey
|
||||
}
|
||||
});
|
||||
this.hdPrivateKey = this;
|
||||
|
||||
this.xpubkey = this.hdPublicKey.xpubkey;
|
||||
this.pair = bcoin.ecdsa.keyPair({ priv: this.privateKey });
|
||||
};
|
||||
|
||||
HDPrivateKey.prototype.derive = function derive(index, hardened) {
|
||||
var cached, data, hash, leftPart, chainCode, privateKey;
|
||||
var cached, data, hash, leftPart, chainCode, privateKey, child;
|
||||
|
||||
if (typeof index === 'string')
|
||||
return this.deriveString(index);
|
||||
@ -734,14 +753,17 @@ HDPrivateKey.prototype.derive = function derive(index, hardened) {
|
||||
.mod(ec.curve.n)
|
||||
.toArray('be', 32);
|
||||
|
||||
var child = new HDPrivateKey({
|
||||
version: this.version,
|
||||
depth: new bn(this.depth).toNumber() + 1,
|
||||
parentFingerPrint: this.fingerPrint,
|
||||
childIndex: index,
|
||||
chainCode: chainCode,
|
||||
privateKey: privateKey,
|
||||
checksum: null
|
||||
child = new HDPrivateKey({
|
||||
network: this.network,
|
||||
data: {
|
||||
version: this.version,
|
||||
depth: new bn(this.depth).toNumber() + 1,
|
||||
parentFingerPrint: this.fingerPrint,
|
||||
childIndex: index,
|
||||
chainCode: chainCode,
|
||||
privateKey: privateKey,
|
||||
checksum: null
|
||||
}
|
||||
});
|
||||
|
||||
cache.set(this.xprivkey, index, child);
|
||||
@ -894,22 +916,26 @@ function HDPublicKey(options) {
|
||||
assert(!(options instanceof HDPrivateKey));
|
||||
assert(!(options instanceof HDPublicKey));
|
||||
|
||||
assert(!options.xprivkey);
|
||||
if (HDPublicKey.isExtended(options))
|
||||
options = { xkey: options };
|
||||
|
||||
if (options.xprivkey)
|
||||
options.xkey = options.xprivkey;
|
||||
|
||||
if (options.xpubkey)
|
||||
options.xkey = options.xpubkey;
|
||||
|
||||
if (HDPublicKey.isExtended(options))
|
||||
options = { xkey: options };
|
||||
|
||||
if (HDPrivateKey.isExtended(options) || HDPrivateKey.isExtended(options.xkey))
|
||||
if (HDPrivateKey.isExtended(options.xkey))
|
||||
throw new Error('Cannot pass xprivkey into HDPublicKey');
|
||||
|
||||
this.network = options.network || network.type;
|
||||
|
||||
data = options.xkey
|
||||
? this._unbuild(options.xkey)
|
||||
: options;
|
||||
: options.data;
|
||||
assert(data);
|
||||
|
||||
data = this._normalize(data, network.prefixes.xpubkey);
|
||||
data = this._normalize(data);
|
||||
|
||||
this.data = data;
|
||||
|
||||
@ -977,6 +1003,11 @@ HDPublicKey.prototype._unbuild = function _unbuild(xkey) {
|
||||
if (data.checksum !== utils.readU32BE(hash, 0))
|
||||
throw new Error('checksum mismatch');
|
||||
|
||||
if (data.version === network.main.prefixes.xpubkey)
|
||||
this.network = 'main';
|
||||
else
|
||||
this.network = 'testnet';
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
@ -1015,6 +1046,7 @@ HDPublicKey.prototype._build = function _build(data) {
|
||||
this.publicKey = publicKey;
|
||||
this.checksum = null;
|
||||
|
||||
this.hdPublicKey = this;
|
||||
this.xpubkey = xpubkey;
|
||||
this.fingerPrint = fingerPrint;
|
||||
|
||||
@ -1023,7 +1055,7 @@ HDPublicKey.prototype._build = function _build(data) {
|
||||
};
|
||||
|
||||
HDPublicKey.prototype.derive = function derive(index, hardened) {
|
||||
var cached, data, hash, leftPart, chainCode, pair, point, publicKey;
|
||||
var cached, data, hash, leftPart, chainCode, pair, point, publicKey, child;
|
||||
|
||||
if (typeof index === 'string')
|
||||
return this.deriveString(index);
|
||||
@ -1048,14 +1080,17 @@ HDPublicKey.prototype.derive = function derive(index, hardened) {
|
||||
point = ec.curve.g.mul(leftPart).add(pair.pub);
|
||||
publicKey = bcoin.ecdsa.keyPair({ pub: point }).getPublic(true, 'array');
|
||||
|
||||
var child = new HDPublicKey({
|
||||
version: this.version,
|
||||
depth: new bn(this.depth).toNumber() + 1,
|
||||
parentFingerPrint: this.fingerPrint,
|
||||
childIndex: index,
|
||||
chainCode: chainCode,
|
||||
publicKey: publicKey,
|
||||
checksum: null
|
||||
child = new HDPublicKey({
|
||||
network: this.network,
|
||||
data: {
|
||||
version: this.version,
|
||||
depth: new bn(this.depth).toNumber() + 1,
|
||||
parentFingerPrint: this.fingerPrint,
|
||||
childIndex: index,
|
||||
chainCode: chainCode,
|
||||
publicKey: publicKey,
|
||||
checksum: null
|
||||
}
|
||||
});
|
||||
|
||||
cache.set(this.xpubkey, index, child);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user