hd refactor.
This commit is contained in:
parent
b59f6ae384
commit
4bf31f32bf
@ -38,6 +38,7 @@ ec.elliptic = elliptic.ec('secp256k1');
|
||||
/**
|
||||
* elliptic.js signature constructor.
|
||||
* @static
|
||||
* @type {Function}
|
||||
*/
|
||||
|
||||
ec.signature = require('elliptic/lib/elliptic/ec/signature');
|
||||
@ -45,10 +46,18 @@ ec.signature = require('elliptic/lib/elliptic/ec/signature');
|
||||
/**
|
||||
* elliptic.js keypair constructor.
|
||||
* @static
|
||||
* @type {Function}
|
||||
*/
|
||||
|
||||
ec.keypair = require('elliptic/lib/elliptic/ec/key');
|
||||
|
||||
/**
|
||||
* A reference to the secp256k1 curve.
|
||||
* @const {Object}
|
||||
*/
|
||||
|
||||
ec.curve = ec.elliptic.curve;
|
||||
|
||||
/**
|
||||
* Generate a private key.
|
||||
* @returns {Buffer} Private key.
|
||||
|
||||
@ -122,7 +122,7 @@ function Mnemonic(options) {
|
||||
if (!(this instanceof Mnemonic))
|
||||
return new Mnemonic(options);
|
||||
|
||||
this.bits = 128;
|
||||
this.bits = constants.hd.MIN_ENTROPY;
|
||||
this.language = 'english';
|
||||
this.entropy = null;
|
||||
this.phrase = null;
|
||||
@ -159,7 +159,8 @@ Mnemonic.prototype.fromOptions = function fromOptions(options) {
|
||||
|
||||
if (options.bits != null) {
|
||||
assert(utils.isNumber(options.bits));
|
||||
assert(options.bits >= 128);
|
||||
assert(options.bits >= constants.hd.MIN_ENTROPY);
|
||||
assert(options.bits <= constants.hd.MAX_ENTROPY);
|
||||
assert(options.bits % 32 === 0);
|
||||
this.bits = options.bits;
|
||||
}
|
||||
@ -309,12 +310,20 @@ Mnemonic.prototype.fromPhrase = function fromPhrase(phrase) {
|
||||
|
||||
words = phrase.split(/[ \u3000]+/);
|
||||
bits = words.length * 11;
|
||||
lang = Mnemonic.getLanguage(words[0]);
|
||||
ent = new Buffer(Math.ceil(bits / 8));
|
||||
wordlist = Mnemonic.getWordlist(lang);
|
||||
cbits = bits % 32;
|
||||
cbytes = Math.ceil(cbits / 8);
|
||||
bits -= cbits;
|
||||
|
||||
assert(bits >= constants.hd.MIN_ENTROPY);
|
||||
assert(bits <= constants.hd.MAX_ENTROPY);
|
||||
assert(bits % 32 === 0);
|
||||
|
||||
ent = new Buffer(Math.ceil((bits + cbits) / 8));
|
||||
ent.fill(0);
|
||||
|
||||
lang = Mnemonic.getLanguage(words[0]);
|
||||
wordlist = Mnemonic.getWordlist(lang);
|
||||
|
||||
for (i = 0; i < words.length; i++) {
|
||||
word = words[i];
|
||||
index = wordlist.indexOf(word);
|
||||
@ -331,10 +340,6 @@ Mnemonic.prototype.fromPhrase = function fromPhrase(phrase) {
|
||||
}
|
||||
}
|
||||
|
||||
// Checksum bits:
|
||||
cbits = bits % 32;
|
||||
cbytes = Math.ceil(cbits / 8);
|
||||
|
||||
entropy = ent.slice(0, ent.length - cbytes);
|
||||
ent = ent.slice(ent.length - cbytes);
|
||||
chk = utils.sha256(entropy);
|
||||
@ -348,11 +353,7 @@ Mnemonic.prototype.fromPhrase = function fromPhrase(phrase) {
|
||||
throw new Error('Invalid checksum.');
|
||||
}
|
||||
|
||||
bits -= cbits;
|
||||
|
||||
assert(bits / 8 === entropy.length);
|
||||
assert(bits >= 128);
|
||||
assert(bits % 32 === 0);
|
||||
|
||||
this.bits = bits;
|
||||
this.language = lang;
|
||||
@ -382,7 +383,8 @@ Mnemonic.fromPhrase = function fromPhrase(phrase) {
|
||||
|
||||
Mnemonic.prototype.fromEntropy = function fromEntropy(entropy, lang) {
|
||||
assert(Buffer.isBuffer(entropy));
|
||||
assert(entropy.length * 8 >= 128);
|
||||
assert(entropy.length * 8 >= constants.hd.MIN_ENTROPY);
|
||||
assert(entropy.length * 8 <= constants.hd.MAX_ENTROPY);
|
||||
assert((entropy.length * 8) % 32 === 0);
|
||||
assert(!lang || Mnemonic.languages.indexOf(lang) !== -1);
|
||||
|
||||
@ -478,6 +480,10 @@ Mnemonic.prototype.fromJSON = function fromJSON(json) {
|
||||
assert(typeof json.entropy === 'string');
|
||||
assert(typeof json.phrase === 'string');
|
||||
assert(typeof json.passphrase === 'string');
|
||||
assert(json.bits >= constants.hd.MIN_ENTROPY);
|
||||
assert(json.bits <= constants.hd.MAX_ENTROPY);
|
||||
assert(json.bits % 32 === 0);
|
||||
assert(json.bits / 8 === json.entropy.length / 2);
|
||||
|
||||
this.bits = json.bits;
|
||||
this.language = json.language;
|
||||
@ -485,10 +491,6 @@ Mnemonic.prototype.fromJSON = function fromJSON(json) {
|
||||
this.phrase = json.phrase;
|
||||
this.passphrase = json.passphrase;
|
||||
|
||||
assert(this.bits >= 128);
|
||||
assert(this.bits % 32 === 0);
|
||||
assert(this.bits / 8 === this.entropy.length);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
@ -541,7 +543,8 @@ Mnemonic.prototype.fromRaw = function fromRaw(data) {
|
||||
this.passphrase = p.readVarString('utf8');
|
||||
|
||||
assert(this.language);
|
||||
assert(this.bits >= 128);
|
||||
assert(this.bits >= constants.hd.MIN_ENTROPY);
|
||||
assert(this.bits <= constants.hd.MAX_ENTROPY);
|
||||
assert(this.bits % 32 === 0);
|
||||
|
||||
return this;
|
||||
@ -881,7 +884,6 @@ HDPrivateKey.prototype.fromOptions = function fromOptions(options) {
|
||||
this.childIndex = options.childIndex;
|
||||
this.chainCode = options.chainCode;
|
||||
this.privateKey = options.privateKey;
|
||||
|
||||
this.publicKey = ec.publicKeyCreate(options.privateKey, true);
|
||||
|
||||
if (options.mnemonic) {
|
||||
@ -983,9 +985,13 @@ HDPrivateKey.prototype.derive = function derive(index, hardened) {
|
||||
|
||||
privateKey = left
|
||||
.add(new bn(this.privateKey))
|
||||
.mod(ec.elliptic.curve.n)
|
||||
.mod(ec.curve.n)
|
||||
.toArrayLike(Buffer, 'be', 32);
|
||||
|
||||
// Only a 1 in 2^127 chance of happening.
|
||||
if (!ec.privateKeyVerify(privateKey))
|
||||
throw new Error('Private key is invalid.');
|
||||
|
||||
if (!this.fingerPrint)
|
||||
this.fingerPrint = utils.hash160(this.publicKey).slice(0, 4);
|
||||
|
||||
@ -1176,8 +1182,8 @@ HDPrivateKey.prototype.fromSeed = function fromSeed(seed, network) {
|
||||
|
||||
assert(Buffer.isBuffer(seed));
|
||||
|
||||
if (seed.length < constants.hd.MIN_ENTROPY
|
||||
|| seed.length > constants.hd.MAX_ENTROPY) {
|
||||
if (!(seed.length * 8 >= constants.hd.MIN_ENTROPY
|
||||
&& seed.length * 8 <= constants.hd.MAX_ENTROPY)) {
|
||||
throw new Error('Entropy not in range.');
|
||||
}
|
||||
|
||||
@ -1186,6 +1192,7 @@ HDPrivateKey.prototype.fromSeed = function fromSeed(seed, network) {
|
||||
privateKey = hash.slice(0, 32);
|
||||
chainCode = hash.slice(32, 64);
|
||||
|
||||
// Only a 1 in 2^127 chance of happening.
|
||||
if (!ec.privateKeyVerify(privateKey))
|
||||
throw new Error('Master private key is invalid.');
|
||||
|
||||
@ -1622,11 +1629,14 @@ HDPublicKey.prototype.derive = function derive(index, hardened) {
|
||||
left = new bn(hash.slice(0, 32));
|
||||
chainCode = hash.slice(32, 64);
|
||||
|
||||
point = ec.elliptic.curve.decodePoint(this.publicKey);
|
||||
point = ec.elliptic.curve.g.mul(left).add(point);
|
||||
point = ec.decodePoint(this.publicKey);
|
||||
point = ec.curve.g.mul(left).add(point);
|
||||
publicKey = new Buffer(point.encode('array', true));
|
||||
assert(publicKey.length === 33);
|
||||
|
||||
if (!ec.publicKeyVerify(publicKey))
|
||||
throw new Error('Public key is invalid.');
|
||||
|
||||
if (!this.fingerPrint)
|
||||
this.fingerPrint = utils.hash160(this.publicKey).slice(0, 4);
|
||||
|
||||
|
||||
@ -522,8 +522,8 @@ exports.rejectByVal = utils.revMap(exports.reject);
|
||||
exports.hd = {
|
||||
HARDENED: 0x80000000,
|
||||
MAX_INDEX: 0x100000000,
|
||||
MIN_ENTROPY: 128 / 8,
|
||||
MAX_ENTROPY: 512 / 8
|
||||
MIN_ENTROPY: 128,
|
||||
MAX_ENTROPY: 512
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -178,7 +178,7 @@ Witness.prototype.getInputType = function getInputType() {
|
||||
/**
|
||||
* "Guess" the address of the witness.
|
||||
* This method is not 100% reliable.
|
||||
* @returns {String|null}
|
||||
* @returns {Address|null}
|
||||
*/
|
||||
|
||||
Witness.prototype.getInputAddress = function getInputAddress() {
|
||||
@ -2807,7 +2807,7 @@ Script.prototype.getSize = function getSize() {
|
||||
/**
|
||||
* "Guess" the address of the input script.
|
||||
* This method is not 100% reliable.
|
||||
* @returns {Base58Address|null}
|
||||
* @returns {Address|null}
|
||||
*/
|
||||
|
||||
Script.prototype.getInputAddress = function getInputAddress() {
|
||||
@ -2818,7 +2818,7 @@ Script.prototype.getInputAddress = function getInputAddress() {
|
||||
* Get the address of the script if present. Note that
|
||||
* pubkey and multisig scripts will be treated as though
|
||||
* they are pubkeyhash and scripthashes respectively.
|
||||
* @returns {Base58Address|null}
|
||||
* @returns {Address|null}
|
||||
*/
|
||||
|
||||
Script.prototype.getAddress = function getAddress() {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user