more hd improvements.
This commit is contained in:
parent
b164984307
commit
6690991acb
@ -174,6 +174,24 @@ ec.publicKeyVerify = function publicKeyVerify(key) {
|
||||
return ec.elliptic.keyPair({ pub: key }).validate();
|
||||
};
|
||||
|
||||
/**
|
||||
* Validate a private key.
|
||||
* @param {Buffer} key
|
||||
* @returns {Boolean} True if buffer is a valid private key.
|
||||
*/
|
||||
|
||||
ec.privateKeyVerify = function privateKeyVerify(key) {
|
||||
if (secp256k1)
|
||||
return secp256k1.privateKeyVerify(key);
|
||||
|
||||
key = new bn(key);
|
||||
|
||||
if (key.cmpn(0) === 0 || key.cmp(ec.elliptic.curve.n) >= 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sign a message.
|
||||
* @param {Buffer} msg
|
||||
|
||||
@ -243,7 +243,7 @@ Mnemonic.isMnemonic = function isMnemonic(obj) {
|
||||
|
||||
function HD(options, network) {
|
||||
if (!options)
|
||||
return HD.fromSeed(null, network);
|
||||
return HD.fromMnemonic(null, network);
|
||||
return HD.fromAny(options, network);
|
||||
}
|
||||
|
||||
@ -284,6 +284,17 @@ HD.fromSeed = function fromSeed(options, network) {
|
||||
return HDPrivateKey.fromSeed(options, network);
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiate an hd private key from a mnemonic.
|
||||
* @param {Mnemonic|Object} mnemonic
|
||||
* @param {String?} network
|
||||
* @returns {HDPrivateKey}
|
||||
*/
|
||||
|
||||
HD.fromMnemonic = function fromMnemonic(options, network) {
|
||||
return HDPrivateKey.fromMnemonic(options, network);
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiate an HD key from a jsonified key object.
|
||||
* @param {Object} json - The jsonified transaction object.
|
||||
@ -323,7 +334,7 @@ HD.fromAny = function fromAny(options, network) {
|
||||
if (HDPublicKey.isExtended(xkey))
|
||||
return HDPublicKey.fromBase58(xkey);
|
||||
|
||||
return HDPrivateKey.fromSeed(options, network);
|
||||
return HDPrivateKey.fromMnemonic(options, network);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -499,6 +510,9 @@ HDPrivateKey.prototype.derive = function derive(index, hardened) {
|
||||
if (index < constants.hd.HARDENED && hardened)
|
||||
index += constants.hd.HARDENED;
|
||||
|
||||
if (!(index >= 0 && index < constants.hd.MAX_INDEX))
|
||||
throw new Error('Index out of range.');
|
||||
|
||||
p = new BufferWriter();
|
||||
|
||||
if (hardened) {
|
||||
@ -686,35 +700,33 @@ HDPrivateKey.prototype.derivePath = function derivePath(path) {
|
||||
*/
|
||||
|
||||
HDPrivateKey.parseSeed = function parseSeed(seed, network) {
|
||||
var data, hash;
|
||||
var hash, chainCode, privateKey;
|
||||
|
||||
if (!seed)
|
||||
seed = {};
|
||||
|
||||
if (Buffer.isBuffer(seed)) {
|
||||
data = seed;
|
||||
seed = null;
|
||||
} else if (seed instanceof Mnemonic) {
|
||||
data = seed.toSeed();
|
||||
} else {
|
||||
seed = new Mnemonic(seed);
|
||||
data = seed.toSeed();
|
||||
}
|
||||
assert(Buffer.isBuffer(seed));
|
||||
|
||||
if (data.length < constants.hd.MIN_ENTROPY
|
||||
|| data.length > constants.hd.MAX_ENTROPY) {
|
||||
if (seed.length < constants.hd.MIN_ENTROPY
|
||||
|| seed.length > constants.hd.MAX_ENTROPY) {
|
||||
throw new Error('Entropy not in range.');
|
||||
}
|
||||
|
||||
hash = utils.hmac('sha512', data, 'Bitcoin seed');
|
||||
hash = utils.hmac('sha512', seed, 'Bitcoin seed');
|
||||
|
||||
privateKey = hash.slice(0, 32);
|
||||
chainCode = hash.slice(32, 64);
|
||||
|
||||
if (!ec.privateKeyVerify(privateKey))
|
||||
throw new Error('Master private key is invalid.');
|
||||
|
||||
return {
|
||||
network: network,
|
||||
depth: 0,
|
||||
parentFingerPrint: new Buffer([0, 0, 0, 0]),
|
||||
childIndex: 0,
|
||||
chainCode: hash.slice(32, 64),
|
||||
privateKey: hash.slice(0, 32),
|
||||
chainCode: chainCode,
|
||||
privateKey: privateKey,
|
||||
mnemonic: seed
|
||||
};
|
||||
};
|
||||
@ -731,6 +743,40 @@ HDPrivateKey.fromSeed = function fromSeed(seed, network) {
|
||||
return new HDPrivateKey(HDPrivateKey.parseSeed(seed, network));
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiate an hd private key from a mnemonic.
|
||||
* @param {Mnemonic|Object} mnemonic
|
||||
* @param {String?} network
|
||||
* @returns {HDPrivateKey}
|
||||
*/
|
||||
|
||||
HDPrivateKey.fromMnemonic = function fromMnemonic(mnemonic, network) {
|
||||
var key;
|
||||
|
||||
if (!(mnemonic instanceof Mnemonic))
|
||||
mnemonic = new Mnemonic(mnemonic);
|
||||
|
||||
if (mnemonic.seed || mnemonic.phrase || mnemonic.entropy)
|
||||
return HDPrivateKey.fromSeed(mnemonic.toSeed(), network);
|
||||
|
||||
for (;;) {
|
||||
try {
|
||||
key = HDPrivateKey.fromSeed(mnemonic.toSeed(), network);
|
||||
} catch (e) {
|
||||
if (e.message === 'Master private key is invalid.') {
|
||||
mnemonic.seed = null;
|
||||
mnemonic.phrase = null;
|
||||
mnemonic.entropy = null;
|
||||
continue;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return key;
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate an hd private key from a key and/or entropy bytes.
|
||||
* @param {Object?} options
|
||||
@ -866,6 +912,7 @@ HDPrivateKey.prototype.toJSON = function toJSON(passphrase) {
|
||||
var json = {
|
||||
v: 1,
|
||||
name: 'hdkey',
|
||||
network: this.network,
|
||||
encrypted: false
|
||||
};
|
||||
|
||||
@ -953,7 +1000,7 @@ HDPrivateKey.fromJSON = function fromJSON(json, passphrase) {
|
||||
}
|
||||
|
||||
if (json.mnemonic)
|
||||
return HDPrivateKey.fromSeed(json.mnemonic);
|
||||
return HDPrivateKey.fromMnemonic(json.mnemonic, json.network);
|
||||
|
||||
if (json.xpubkey)
|
||||
return HDPublicKey.fromBase58(json.xprivkey);
|
||||
@ -1048,10 +1095,10 @@ HDPublicKey.prototype.derive = function derive(index, hardened) {
|
||||
return cached;
|
||||
|
||||
if (index >= constants.hd.HARDENED || hardened)
|
||||
throw new Error('Invalid index.');
|
||||
throw new Error('Index out of range.');
|
||||
|
||||
if (index < 0)
|
||||
throw new Error('Invalid path.');
|
||||
throw new Error('Index out of range.');
|
||||
|
||||
p = new BufferWriter();
|
||||
p.writeBytes(this.publicKey);
|
||||
|
||||
@ -70,7 +70,7 @@ function Wallet(options) {
|
||||
}
|
||||
|
||||
if (!options.master)
|
||||
options.master = bcoin.hd.fromSeed(null, this.network);
|
||||
options.master = bcoin.hd.fromMnemonic(null, this.network);
|
||||
|
||||
this.provider = options.provider || null;
|
||||
this.master = options.master || null;
|
||||
|
||||
@ -142,7 +142,7 @@ describe('HD', function() {
|
||||
});
|
||||
|
||||
it('should deserialize and reserialize', function() {
|
||||
var key = bcoin.hd.fromSeed();
|
||||
var key = bcoin.hd.fromMnemonic();
|
||||
assert.equal(bcoin.hd.fromJSON(key.toJSON()).xprivkey, key.xprivkey);
|
||||
});
|
||||
|
||||
|
||||
@ -20,7 +20,7 @@ describe('Mnemonic', function() {
|
||||
mnemonic.toSeed();
|
||||
assert.equal(mnemonic.phrase, phrase);
|
||||
assert.equal(mnemonic.toSeed().toString('hex'), seed.toString('hex'));
|
||||
var key = bcoin.hd.fromSeed(mnemonic);
|
||||
var key = bcoin.hd.fromMnemonic(mnemonic);
|
||||
assert.equal(key.xprivkey, xpriv);
|
||||
});
|
||||
});
|
||||
@ -37,11 +37,9 @@ describe('Mnemonic', function() {
|
||||
passphrase: passphrase
|
||||
});
|
||||
mnemonic.toSeed();
|
||||
// utils.print(new Buffer(mnemonic.phrase, 'utf8').toString('hex'));
|
||||
// utils.print(new Buffer(phrase, 'utf8').toString('hex'));
|
||||
assert.equal(mnemonic.phrase, phrase);
|
||||
assert.equal(mnemonic.toSeed().toString('hex'), seed.toString('hex'));
|
||||
var key = bcoin.hd.fromSeed(mnemonic);
|
||||
var key = bcoin.hd.fromMnemonic(mnemonic);
|
||||
assert.equal(key.xprivkey, xpriv);
|
||||
});
|
||||
});
|
||||
|
||||
@ -113,7 +113,7 @@ describe('Wallet', function() {
|
||||
m: 1,
|
||||
n: 2
|
||||
});
|
||||
var k2 = bcoin.hd.fromSeed().deriveAccount44(0).hdPublicKey;
|
||||
var k2 = bcoin.hd.fromMnemonic().deriveAccount44(0).hdPublicKey;
|
||||
w.addKey(k2);
|
||||
|
||||
// Input transcation
|
||||
|
||||
Loading…
Reference in New Issue
Block a user