use libsecp256k1 for hd derivation.

This commit is contained in:
Christopher Jeffrey 2016-07-13 16:27:56 -07:00
parent 350c76d49b
commit 850b16fa7d
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
2 changed files with 70 additions and 29 deletions

View File

@ -134,6 +134,52 @@ ec.publicKeyConvert = function publicKeyConvert(key, compressed) {
return new Buffer(point.encode('array', compressed)); return new Buffer(point.encode('array', compressed));
}; };
/**
* ((tweak + key) % n)
* @param {Buffer} privateKey
* @param {Buffer} tweak
* @returns {Buffer} privateKey
*/
ec.privateKeyTweakAdd = function privateKeyTweakAdd(privateKey, tweak) {
if (secp256k1)
return secp256k1.privateKeyTweakAdd(privateKey, tweak);
privateKey = new bn(tweak)
.add(new bn(privateKey))
.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.');
return privateKey;
};
/**
* ((g * tweak) + key)
* @param {Buffer} publicKey
* @param {Buffer} tweak
* @returns {Buffer} publicKey
*/
ec.publicKeyTweakAdd = function publicKeyTweakAdd(publicKey, tweak, compressed) {
var point;
if (secp256k1)
return secp256k1.publicKeyTweakAdd(publicKey, tweak, compressed);
point = ec.decodePoint(publicKey);
point = ec.curve.g.mul(new bn(tweak)).add(point);
publicKey = new Buffer(point.encode('array', compressed));
if (!ec.publicKeyVerify(publicKey))
throw new Error('Public key is invalid.');
return publicKey;
};
/** /**
* Create an ecdh. * Create an ecdh.
* @param {Buffer} pub * @param {Buffer} pub

View File

@ -945,7 +945,7 @@ HDPrivateKey.prototype.__defineGetter__('xpubkey', function() {
*/ */
HDPrivateKey.prototype.derive = function derive(index, hardened) { HDPrivateKey.prototype.derive = function derive(index, hardened) {
var p, id, data, hash, left, chainCode, privateKey, child; var p, id, data, hash, left, right, privateKey, child;
if (typeof index === 'string') if (typeof index === 'string')
return this.derivePath(index); return this.derivePath(index);
@ -981,17 +981,14 @@ 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);
left = new bn(hash.slice(0, 32)); left = hash.slice(0, 32);
chainCode = hash.slice(32, 64); right = hash.slice(32, 64);
privateKey = left try {
.add(new bn(this.privateKey)) privateKey = ec.privateKeyTweakAdd(this.privateKey, left);
.mod(ec.curve.n) } catch (e) {
.toArrayLike(Buffer, 'be', 32); return this.derive(index + 1);
}
// Only a 1 in 2^127 chance of happening.
if (!ec.privateKeyVerify(privateKey))
throw new Error('Private key is invalid.');
if (!this.fingerPrint) if (!this.fingerPrint)
this.fingerPrint = utils.hash160(this.publicKey).slice(0, 4); this.fingerPrint = utils.hash160(this.publicKey).slice(0, 4);
@ -1001,7 +998,7 @@ HDPrivateKey.prototype.derive = function derive(index, hardened) {
child.depth = this.depth + 1; child.depth = this.depth + 1;
child.parentFingerPrint = this.fingerPrint; child.parentFingerPrint = this.fingerPrint;
child.childIndex = index; child.childIndex = index;
child.chainCode = chainCode; child.chainCode = right;
child.privateKey = privateKey; child.privateKey = privateKey;
child.publicKey = ec.publicKeyCreate(privateKey, true); child.publicKey = ec.publicKeyCreate(privateKey, true);
@ -1179,7 +1176,7 @@ HDPrivateKey.prototype.equal = function equal(obj) {
*/ */
HDPrivateKey.prototype.fromSeed = function fromSeed(seed, network) { HDPrivateKey.prototype.fromSeed = function fromSeed(seed, network) {
var hash, chainCode, privateKey; var hash, left, right;
assert(Buffer.isBuffer(seed)); assert(Buffer.isBuffer(seed));
@ -1190,19 +1187,19 @@ HDPrivateKey.prototype.fromSeed = function fromSeed(seed, network) {
hash = utils.hmac('sha512', seed, 'Bitcoin seed'); hash = utils.hmac('sha512', seed, 'Bitcoin seed');
privateKey = hash.slice(0, 32); left = hash.slice(0, 32);
chainCode = hash.slice(32, 64); right = hash.slice(32, 64);
// Only a 1 in 2^127 chance of happening. // Only a 1 in 2^127 chance of happening.
if (!ec.privateKeyVerify(privateKey)) if (!ec.privateKeyVerify(left))
throw new Error('Master private key is invalid.'); throw new Error('Master private key is invalid.');
this.network = bcoin.network.get(network); this.network = bcoin.network.get(network);
this.depth = 0; this.depth = 0;
this.parentFingerPrint = new Buffer([0, 0, 0, 0]); this.parentFingerPrint = new Buffer([0, 0, 0, 0]);
this.childIndex = 0; this.childIndex = 0;
this.chainCode = chainCode; this.chainCode = right;
this.privateKey = privateKey; this.privateKey = left;
this.publicKey = ec.publicKeyCreate(this.privateKey, true); this.publicKey = ec.publicKeyCreate(this.privateKey, true);
return this; return this;
@ -1597,7 +1594,7 @@ HDPublicKey.prototype.__defineGetter__('xpubkey', function() {
*/ */
HDPublicKey.prototype.derive = function derive(index, hardened) { HDPublicKey.prototype.derive = function derive(index, hardened) {
var p, id, data, hash, left, chainCode, point, publicKey, child; var p, id, data, hash, left, right, publicKey, child;
if (typeof index === 'string') if (typeof index === 'string')
return this.derivePath(index); return this.derivePath(index);
@ -1623,16 +1620,14 @@ 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);
left = new bn(hash.slice(0, 32)); left = hash.slice(0, 32);
chainCode = hash.slice(32, 64); right = hash.slice(32, 64);
point = ec.decodePoint(this.publicKey); try {
point = ec.curve.g.mul(left).add(point); publicKey = ec.publicKeyTweakAdd(this.publicKey, left, true);
publicKey = new Buffer(point.encode('array', true)); } catch (e) {
assert(publicKey.length === 33); return this.derive(index + 1);
}
if (!ec.publicKeyVerify(publicKey))
throw new Error('Public key is invalid.');
if (!this.fingerPrint) if (!this.fingerPrint)
this.fingerPrint = utils.hash160(this.publicKey).slice(0, 4); this.fingerPrint = utils.hash160(this.publicKey).slice(0, 4);
@ -1642,7 +1637,7 @@ HDPublicKey.prototype.derive = function derive(index, hardened) {
child.depth = this.depth + 1; child.depth = this.depth + 1;
child.parentFingerPrint = this.fingerPrint; child.parentFingerPrint = this.fingerPrint;
child.childIndex = index; child.childIndex = index;
child.chainCode = chainCode; child.chainCode = right;
child.publicKey = publicKey; child.publicKey = publicKey;
HD.cache.set(id, child); HD.cache.set(id, child);