hd and ec refactor.
This commit is contained in:
parent
6690991acb
commit
3cea8323b0
@ -119,15 +119,16 @@ ec.rand = function rand(min, max) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
ec.verify = function verify(msg, sig, key, historical, high) {
|
ec.verify = function verify(msg, sig, key, historical, high) {
|
||||||
if (!Buffer.isBuffer(sig))
|
if (key.getPublicKey)
|
||||||
return false;
|
key = key.getPublicKey();
|
||||||
|
|
||||||
|
assert(Buffer.isBuffer(msg));
|
||||||
|
assert(Buffer.isBuffer(sig));
|
||||||
|
assert(Buffer.isBuffer(key));
|
||||||
|
|
||||||
if (sig.length === 0)
|
if (sig.length === 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (key.getPublicKey)
|
|
||||||
key = key.getPublicKey();
|
|
||||||
|
|
||||||
if (key.length === 0)
|
if (key.length === 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -150,14 +151,14 @@ ec.verify = function verify(msg, sig, key, historical, high) {
|
|||||||
|
|
||||||
return secp256k1.verify(msg, sig, key);
|
return secp256k1.verify(msg, sig, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make elliptic mimic secp256k1's
|
// Make elliptic mimic secp256k1's
|
||||||
// failure with high S values.
|
// failure with high S values.
|
||||||
if (!high && !ec.isLowS(sig))
|
if (!high && !ec.isLowS(sig))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return ec.elliptic.verify(msg, sig, key);
|
return ec.elliptic.verify(msg, sig, key);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// if (!ec.publicKeyVerify(key))
|
|
||||||
// bcoin.debug('Public key is invalid.');
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -294,9 +295,6 @@ ec.isLowS = function isLowS(sig) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Technically a negative S value is low,
|
|
||||||
// but we don't want to ever use negative
|
|
||||||
// S values in bitcoin.
|
|
||||||
if (sig.s.cmpn(0) <= 0)
|
if (sig.s.cmpn(0) <= 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|||||||
@ -359,14 +359,14 @@ HD.isExtended = function isExtended(data) {
|
|||||||
HD.parsePath = function parsePath(path, max) {
|
HD.parsePath = function parsePath(path, max) {
|
||||||
var parts = path.split('/');
|
var parts = path.split('/');
|
||||||
var root = parts.shift();
|
var root = parts.shift();
|
||||||
var indexes = [];
|
var result = [];
|
||||||
var i, hardened, index;
|
var i, hardened, index;
|
||||||
|
|
||||||
if (max == null)
|
if (max == null)
|
||||||
max = constants.hd.MAX_INDEX;
|
max = constants.hd.MAX_INDEX;
|
||||||
|
|
||||||
if (constants.hd.PATH_ROOTS.indexOf(path) !== -1)
|
if (constants.hd.PATH_ROOTS.indexOf(path) !== -1)
|
||||||
return indexes;
|
return result;
|
||||||
|
|
||||||
if (constants.hd.PATH_ROOTS.indexOf(root) === -1)
|
if (constants.hd.PATH_ROOTS.indexOf(root) === -1)
|
||||||
throw new Error('Bad path root.');
|
throw new Error('Bad path root.');
|
||||||
@ -378,21 +378,21 @@ HD.parsePath = function parsePath(path, max) {
|
|||||||
if (hardened)
|
if (hardened)
|
||||||
index = index.slice(0, -1);
|
index = index.slice(0, -1);
|
||||||
|
|
||||||
index = +index;
|
if (!/^\d+$/.test(index))
|
||||||
|
|
||||||
if (!(index >= 0))
|
|
||||||
throw new Error('Non-number path index.');
|
throw new Error('Non-number path index.');
|
||||||
|
|
||||||
|
index = +index;
|
||||||
|
|
||||||
if (hardened)
|
if (hardened)
|
||||||
index += constants.hd.HARDENED;
|
index += constants.hd.HARDENED;
|
||||||
|
|
||||||
if (!(index >= 0 && index < max))
|
if (!(index >= 0 && index < max))
|
||||||
throw new Error('Index out of range.');
|
throw new Error('Index out of range.');
|
||||||
|
|
||||||
indexes.push(index);
|
result.push(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
return indexes;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -496,15 +496,16 @@ HDPrivateKey.prototype.__defineGetter__('xpubkey', function() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
HDPrivateKey.prototype.derive = function derive(index, hardened) {
|
HDPrivateKey.prototype.derive = function derive(index, hardened) {
|
||||||
var cached, p, data, hash, leftPart, chainCode, privateKey, child;
|
var p, id, data, hash, left, chainCode, privateKey, child;
|
||||||
|
|
||||||
if (typeof index === 'string')
|
if (typeof index === 'string')
|
||||||
return this.derivePath(index);
|
return this.derivePath(index);
|
||||||
|
|
||||||
cached = HD.cache.get(this.xprivkey + '/' + index);
|
id = this.xprivkey + '/' + index;
|
||||||
|
child = HD.cache.get(id);
|
||||||
|
|
||||||
if (cached)
|
if (child)
|
||||||
return cached;
|
return child;
|
||||||
|
|
||||||
hardened = index >= constants.hd.HARDENED ? true : hardened;
|
hardened = index >= constants.hd.HARDENED ? true : hardened;
|
||||||
if (index < constants.hd.HARDENED && hardened)
|
if (index < constants.hd.HARDENED && hardened)
|
||||||
@ -527,18 +528,16 @@ HDPrivateKey.prototype.derive = function derive(index, hardened) {
|
|||||||
data = p.render();
|
data = p.render();
|
||||||
|
|
||||||
hash = utils.hmac('sha512', data, this.chainCode);
|
hash = utils.hmac('sha512', data, this.chainCode);
|
||||||
leftPart = new bn(hash.slice(0, 32));
|
left = new bn(hash.slice(0, 32));
|
||||||
chainCode = hash.slice(32, 64);
|
chainCode = hash.slice(32, 64);
|
||||||
|
|
||||||
privateKey = leftPart
|
privateKey = left
|
||||||
.add(new bn(this.privateKey))
|
.add(new bn(this.privateKey))
|
||||||
.mod(ec.elliptic.curve.n)
|
.mod(ec.elliptic.curve.n)
|
||||||
.toBuffer('be', 32);
|
.toBuffer('be', 32);
|
||||||
|
|
||||||
if (!this.fingerPrint) {
|
if (!this.fingerPrint)
|
||||||
this.fingerPrint = utils.ripesha(this.publicKey)
|
this.fingerPrint = utils.ripesha(this.publicKey).slice(0, 4);
|
||||||
.slice(0, constants.hd.PARENT_FINGERPRINT_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
child = new HDPrivateKey({
|
child = new HDPrivateKey({
|
||||||
network: this.network,
|
network: this.network,
|
||||||
@ -549,7 +548,7 @@ HDPrivateKey.prototype.derive = function derive(index, hardened) {
|
|||||||
privateKey: privateKey
|
privateKey: privateKey
|
||||||
});
|
});
|
||||||
|
|
||||||
HD.cache.set(this.xprivkey + '/' + index, child);
|
HD.cache.set(id, child);
|
||||||
|
|
||||||
return child;
|
return child;
|
||||||
};
|
};
|
||||||
@ -702,9 +701,6 @@ HDPrivateKey.prototype.derivePath = function derivePath(path) {
|
|||||||
HDPrivateKey.parseSeed = function parseSeed(seed, network) {
|
HDPrivateKey.parseSeed = function parseSeed(seed, network) {
|
||||||
var hash, chainCode, privateKey;
|
var hash, chainCode, privateKey;
|
||||||
|
|
||||||
if (!seed)
|
|
||||||
seed = {};
|
|
||||||
|
|
||||||
assert(Buffer.isBuffer(seed));
|
assert(Buffer.isBuffer(seed));
|
||||||
|
|
||||||
if (seed.length < constants.hd.MIN_ENTROPY
|
if (seed.length < constants.hd.MIN_ENTROPY
|
||||||
@ -759,6 +755,8 @@ HDPrivateKey.fromMnemonic = function fromMnemonic(mnemonic, network) {
|
|||||||
if (mnemonic.seed || mnemonic.phrase || mnemonic.entropy)
|
if (mnemonic.seed || mnemonic.phrase || mnemonic.entropy)
|
||||||
return HDPrivateKey.fromSeed(mnemonic.toSeed(), network);
|
return HDPrivateKey.fromSeed(mnemonic.toSeed(), network);
|
||||||
|
|
||||||
|
// Very unlikely, but not impossible
|
||||||
|
// to get an invalid private key.
|
||||||
for (;;) {
|
for (;;) {
|
||||||
try {
|
try {
|
||||||
key = HDPrivateKey.fromSeed(mnemonic.toSeed(), network);
|
key = HDPrivateKey.fromSeed(mnemonic.toSeed(), network);
|
||||||
@ -1083,16 +1081,17 @@ HDPublicKey.prototype.__defineGetter__('xpubkey', function() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
HDPublicKey.prototype.derive = function derive(index, hardened) {
|
HDPublicKey.prototype.derive = function derive(index, hardened) {
|
||||||
var cached, p, data, hash, leftPart, chainCode;
|
var p, id, data, hash, left, chainCode;
|
||||||
var publicPoint, point, publicKey, child;
|
var publicPoint, point, publicKey, child;
|
||||||
|
|
||||||
if (typeof index === 'string')
|
if (typeof index === 'string')
|
||||||
return this.derivePath(index);
|
return this.derivePath(index);
|
||||||
|
|
||||||
cached = HD.cache.get(this.xpubkey + '/' + index);
|
id = this.xpubkey + '/' + index;
|
||||||
|
child = HD.cache.get(id);
|
||||||
|
|
||||||
if (cached)
|
if (child)
|
||||||
return cached;
|
return child;
|
||||||
|
|
||||||
if (index >= constants.hd.HARDENED || hardened)
|
if (index >= constants.hd.HARDENED || hardened)
|
||||||
throw new Error('Index out of range.');
|
throw new Error('Index out of range.');
|
||||||
@ -1106,18 +1105,16 @@ HDPublicKey.prototype.derive = function derive(index, hardened) {
|
|||||||
data = p.render();
|
data = p.render();
|
||||||
|
|
||||||
hash = utils.hmac('sha512', data, this.chainCode);
|
hash = utils.hmac('sha512', data, this.chainCode);
|
||||||
leftPart = new bn(hash.slice(0, 32));
|
left = new bn(hash.slice(0, 32));
|
||||||
chainCode = hash.slice(32, 64);
|
chainCode = hash.slice(32, 64);
|
||||||
|
|
||||||
publicPoint = ec.elliptic.curve.decodePoint(this.publicKey);
|
publicPoint = ec.elliptic.curve.decodePoint(this.publicKey);
|
||||||
point = ec.elliptic.curve.g.mul(leftPart).add(publicPoint);
|
point = ec.elliptic.curve.g.mul(left).add(publicPoint);
|
||||||
publicKey = new Buffer(point.encode('array', true));
|
publicKey = new Buffer(point.encode('array', true));
|
||||||
assert(publicKey.length === 33);
|
assert(publicKey.length === 33);
|
||||||
|
|
||||||
if (!this.fingerPrint) {
|
if (!this.fingerPrint)
|
||||||
this.fingerPrint = utils.ripesha(this.publicKey)
|
this.fingerPrint = utils.ripesha(this.publicKey).slice(0, 4);
|
||||||
.slice(0, constants.hd.PARENT_FINGERPRINT_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
child = new HDPublicKey({
|
child = new HDPublicKey({
|
||||||
network: this.network,
|
network: this.network,
|
||||||
@ -1128,7 +1125,7 @@ HDPublicKey.prototype.derive = function derive(index, hardened) {
|
|||||||
publicKey: publicKey
|
publicKey: publicKey
|
||||||
});
|
});
|
||||||
|
|
||||||
HD.cache.set(this.xpubkey + '/' + index, child);
|
HD.cache.set(id, child);
|
||||||
|
|
||||||
return child;
|
return child;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -515,10 +515,9 @@ exports.rejectByVal = utils.revMap(exports.reject);
|
|||||||
|
|
||||||
exports.hd = {
|
exports.hd = {
|
||||||
HARDENED: 0x80000000,
|
HARDENED: 0x80000000,
|
||||||
MAX_INDEX: 2 * 0x80000000,
|
MAX_INDEX: 0x100000000,
|
||||||
MIN_ENTROPY: 128 / 8,
|
MIN_ENTROPY: 128 / 8,
|
||||||
MAX_ENTROPY: 512 / 8,
|
MAX_ENTROPY: 512 / 8,
|
||||||
PARENT_FINGERPRINT_SIZE: 4,
|
|
||||||
PATH_ROOTS: ['m', 'M', 'm\'', 'M\'']
|
PATH_ROOTS: ['m', 'M', 'm\'', 'M\'']
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user