refactor keypair and hd.

This commit is contained in:
Christopher Jeffrey 2016-02-23 19:08:42 -08:00
parent 0f40d78f9e
commit 30db808930
7 changed files with 96 additions and 150 deletions

View File

@ -174,14 +174,6 @@ Address.prototype.getPrivateKey = function getPrivateKey(enc) {
return this.key.getPrivateKey(enc);
};
Address.toSecret = function toSecret(privateKey, compressed) {
return bcoin.keypair.toSecret(privateKey, compressed);
};
Address.fromSecret = function fromSecret(privateKey) {
return bcoin.keypair.fromSecret(privateKey);
};
Address.prototype.getScript = function getScript() {
var redeem;
@ -565,6 +557,11 @@ Address.getType = function getType(addr) {
};
Address.prototype.toJSON = function toJSON(passphrase) {
var key = this.key;
if (!(key instanceof bcoin.keypair))
key = new bcoin.keypair({ privateKey: key.getPrivateKey() });
return {
v: 1,
name: 'address',
@ -575,7 +572,7 @@ Address.prototype.toJSON = function toJSON(passphrase) {
index: this.index,
path: this.path,
address: this.getAddress(),
key: this.key.toJSON(passphrase),
key: key.toJSON(passphrase),
type: this.type,
redeem: this.redeem ? utils.toHex(this.redeem) : null,
keys: this.keys.map(utils.toBase58),

View File

@ -15,21 +15,29 @@ var ec = exports;
* EC
*/
ec.generate = function generate(options) {
var key, priv, pub;
ec.generatePrivateKey = function generatePrivateKey() {
var key, priv;
if (bcoin.secp256k1 && bcoin.crypto) {
do {
priv = bcoin.crypto.randomBytes(32);
} while (!bcoin.secp256k1.privateKeyVerify(priv));
pub = bcoin.secp256k1.publicKeyCreate(priv, true);
} else {
key = bcoin.ecdsa.genKeyPair();
priv = new Buffer(key.getPrivate().toArray('be', 32));
pub = new Buffer(key.getPublic(true, 'array'));
}
return { privateKey: priv, publicKey: pub };
return priv;
};
ec.publicKeyCreate = function publicKeyCreate(priv, compressed) {
assert(Buffer.isBuffer(priv));
if (bcoin.ecdsa.secp256k1)
return bcoin.secp256k1.publicKeyCreate(priv, compressed);
priv = bcoin.ecdsa.keyPair({ priv: priv }).getPublic(compressed, 'array');
return new Buffer(priv);
};
ec.random = function random(size) {
@ -43,15 +51,15 @@ bn.prototype.toBuffer = function toBuffer(order, size) {
};
ec.verify = function verify(msg, sig, key, historical) {
if (key.getPublicKey)
key = key.getPublicKey();
if (!Buffer.isBuffer(sig))
return false;
if (sig.length === 0)
return false;
if (key.getPublicKey)
key = key.getPublicKey();
// Attempt to normalize the signature
// length before passing to elliptic.
// Note: We only do this for historical data!
@ -61,7 +69,7 @@ ec.verify = function verify(msg, sig, key, historical) {
try {
if (bcoin.secp256k1) {
// secp256k1 fails on low s values. This is
// secp256k1 fails on high s values. This is
// bad for verifying historical data.
if (historical)
sig = ec.toLowS(sig);
@ -92,9 +100,10 @@ ec.verify = function verify(msg, sig, key, historical) {
ec.sign = function sign(msg, key) {
var sig;
if (bcoin.secp256k1) {
if (key.getPrivateKey)
key = key.getPrivateKey();
if (bcoin.secp256k1) {
// Sign message
sig = bcoin.secp256k1.sign(msg, key);
@ -105,7 +114,7 @@ ec.sign = function sign(msg, key) {
sig = bcoin.secp256k1.signatureExport(sig);
} else {
// Sign message and ensure low S value
sig = bcoin.ecdsa.sign(msg, key.privatePoint, { canonical: true });
sig = bcoin.ecdsa.sign(msg, key, { canonical: true });
// Convert to DER array
sig = new Buffer(sig.toDER());

View File

@ -62,8 +62,6 @@ var EventEmitter = require('events').EventEmitter;
var english = require('../../etc/english.json');
var ec = elliptic.curves.secp256k1;
/**
* HD Seeds
*/
@ -109,6 +107,14 @@ function HD(options) {
return new HDPrivateKey(options);
}
HD.generate = function generate(privateKey, entropy) {
return HDPrivateKey.generate(privateKey, entropy);
};
HD.fromSeed = function fromSeed(options) {
return HDPrivateKey.fromSeed(options);
};
/**
* HD Private Key
*/
@ -122,8 +128,7 @@ function HDPrivateKey(options) {
assert(!(options instanceof HDPrivateKey));
assert(!(options instanceof HDPublicKey));
if (!options)
options = { seed: bcoin.hd.seed() };
assert(options);
if (HDPrivateKey.isExtended(options))
options = { xkey: options };
@ -137,23 +142,6 @@ function HDPrivateKey(options) {
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
|| options.mnemonic) {
options.seed = bcoin.hd.seed(options);
}
if (options.seed
&& typeof options.seed === 'object'
&& !Buffer.isBuffer(options.seed)
&& !(options.seed instanceof bcoin.hd.seed)) {
options.seed = bcoin.hd.seed(options.seed);
}
this.network = options.network || network.type;
if (options.seed) {
@ -161,8 +149,6 @@ function HDPrivateKey(options) {
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;
}
@ -612,20 +598,20 @@ HDPrivateKey.prototype._seed = function _seed(seed) {
};
};
HDPrivateKey.prototype._generate = function _generate(privateKey, entropy) {
if (!privateKey)
privateKey = bcoin.ec.generate().privateKey;
HDPrivateKey.fromSeed = function fromSeed(options) {
var seed = (options instanceof HDSeed) ? options : new HDSeed(options);
return new HDPrivateKey({ seed: seed });
};
if (utils.isHex(privateKey))
privateKey = new Buffer(privateKey, 'hex');
else if (utils.isBase58(privateKey))
privateKey = bcoin.keypair._fromSecret(privateKey).privateKey;
HDPrivateKey._generate = function _generate(privateKey, entropy) {
if (!privateKey)
privateKey = bcoin.ec.generatePrivateKey();
if (!entropy)
entropy = bcoin.ec.random(32);
return {
version: network[this.network].prefixes.xprivkey,
version: null,
depth: 0,
parentFingerPrint: 0,
childIndex: 0,
@ -635,6 +621,16 @@ HDPrivateKey.prototype._generate = function _generate(privateKey, entropy) {
};
};
HDPrivateKey.generate = function generate(privateKey, entropy) {
return new HDPrivateKey(HDPrivateKey._generate(privateKey, entropy));
};
HDPrivateKey.prototype._generate = function _generate(privateKey, entropy) {
var data = HDPrivateKey._generate(privateKey, entropy);
data.version = network[this.network].prefixes.xprivkey;
return data;
};
HDPrivateKey.prototype._unbuild = function _unbuild(xkey) {
var raw = utils.fromBase58(xkey);
var data = {};
@ -672,7 +668,7 @@ HDPrivateKey.prototype._unbuild = function _unbuild(xkey) {
HDPrivateKey.prototype._build = function _build(data) {
var sequence = new Buffer(82);
var off = 0;
var checksum, xprivkey, key, privateKey, publicKey, size, fingerPrint;
var checksum, xprivkey, privateKey, publicKey, size, fingerPrint;
off += utils.copy(data.version, sequence, off);
off += utils.copy(data.depth, sequence, off);
@ -688,8 +684,7 @@ HDPrivateKey.prototype._build = function _build(data) {
xprivkey = utils.toBase58(sequence);
key = bcoin.keypair({ privateKey: data.privateKey });
publicKey = key.getPublicKey();
publicKey = bcoin.ec.publicKeyCreate(data.privateKey, true);
size = constants.hd.parentFingerPrintSize;
fingerPrint = utils.ripesha(publicKey).slice(0, size);
@ -704,7 +699,6 @@ HDPrivateKey.prototype._build = function _build(data) {
this.fingerPrint = fingerPrint;
this.publicKey = publicKey;
this.key = key;
this.hdPrivateKey = this;
this.xprivkey = xprivkey;
@ -758,7 +752,7 @@ HDPrivateKey.prototype.derive = function derive(index, hardened) {
privateKey = new Buffer(leftPart
.add(new bn(this.privateKey))
.mod(ec.curve.n)
.mod(bcoin.ecdsa.curve.n)
.toArray('be', 32));
child = new HDPrivateKey({
@ -911,11 +905,8 @@ HDPrivateKey._fromJSON = function _fromJSON(json, passphrase) {
HDPrivateKey.fromJSON = function fromJSON(json, passphrase) {
json = HDPrivateKey._fromJSON(json, passphrase);
if (json.seed) {
return new HDPrivateKey({
seed: new HDSeed(json.seed)
});
}
if (json.seed)
return HDPrivateKey.fromSeed(json.seed);
if (json.xprivkey) {
return new HDPrivateKey({
@ -1078,7 +1069,6 @@ HDPublicKey.prototype._build = function _build(data) {
this.fingerPrint = fingerPrint;
this.privateKey = null;
this.key = data.key || bcoin.keypair({ publicKey: this.publicKey });
this.hdPublicKey = this;
this.xpubkey = xpubkey;
@ -1088,8 +1078,9 @@ HDPublicKey.prototype._build = function _build(data) {
};
HDPublicKey.prototype.derive = function derive(index, hardened) {
var cached, data, hash, leftPart, chainCode, key, point, publicKey, child;
var off = 0;
var cached, data, hash, leftPart, chainCode;
var publicPoint, point, publicKey, child;
if (typeof index === 'string')
return this.deriveString(index);
@ -1113,9 +1104,9 @@ HDPublicKey.prototype.derive = function derive(index, hardened) {
leftPart = new bn(hash.slice(0, 32));
chainCode = hash.slice(32, 64);
key = bcoin.keypair({ publicKey: this.publicKey });
point = ec.curve.g.mul(leftPart).add(key.publicPoint);
publicKey = bcoin.keypair({ publicKey: point }).getPublicKey();
publicPoint = bcoin.ecdsa.curve.decodePoint(this.publicKey);
point = bcoin.ecdsa.curve.g.mul(leftPart).add(publicPoint);
publicKey = new Buffer(point.encode('array', true));
child = new HDPublicKey({
network: this.network,
@ -1165,14 +1156,14 @@ HDPublicKey.prototype.deriveString = function deriveString(path) {
*/
[HDPrivateKey, HDPublicKey].forEach(function(HD) {
HD.prototype.getPublicKey = function getPublicKey() {
return bcoin.keypair.prototype.getPublicKey.apply(this, arguments);
};
HD.prototype.getPrivateKey = function getPrivateKey() {
return bcoin.keypair.prototype.getPrivateKey.apply(this, arguments);
};
HD.prototype.getPublicKey = function getPublicKey() {
return bcoin.keypair.prototype.getPublicKey.apply(this, arguments);
};
HD.prototype.sign = function sign() {
return this.key.sign.apply(this.key, arguments);
};
@ -1181,19 +1172,11 @@ HDPublicKey.prototype.deriveString = function deriveString(path) {
return this.key.verify.apply(this.key, arguments);
};
HD.prototype.__defineGetter__('publicPoint', function() {
return this.key.publicPoint;
});
HD.prototype.__defineGetter__('privatePoint', function() {
return this.key.privatePoint;
});
HD.prototype.compressed = true;
});
HDPrivateKey.prototype.toSecret = function toSecret() {
return bcoin.keypair.toSecret(this.privateKey, this.compressed);
return bcoin.keypair.toSecret.call(this);
};
HDPrivateKey.fromSecret = function fromSecret(privateKey) {

View File

@ -28,90 +28,56 @@ function KeyPair(options) {
if (!options.privateKey && !options.publicKey)
throw new Error('No options for keypair');
assert(!options.privateKey || Buffer.isBuffer(options.privateKey));
assert(!options.publicKey || Buffer.isBuffer(options.publicKey));
this.privateKey = options.privateKey;
this.publicKey = options.publicKey;
}
KeyPair.prototype.__defineGetter__('key', function() {
if (!this._key) {
this._key = bcoin.ecdsa.keyPair({
priv: this.options.privateKey,
pub: this.options.publicKey
});
}
return this._key;
});
KeyPair.prototype.__defineGetter__('privatePoint', function() {
if (!this._privatePoint)
this._privatePoint = this.key.getPrivate();
return this._privatePoint;
});
KeyPair.prototype.__defineGetter__('publicPoint', function() {
if (!this._publicPoint)
this._publicPoint = this.key.getPublic();
return this._publicPoint;
});
KeyPair.prototype.__defineGetter__('privateKey', function() {
return this.getPrivateKey();
});
KeyPair.prototype.__defineGetter__('publicKey', function() {
return this.getPublicKey();
});
KeyPair.generate = function() {
return new KeyPair(bcoin.ec.generate());
return new KeyPair({ privateKey: bcoin.ec.generatePrivateKey() });
};
KeyPair.prototype.sign = function sign(msg) {
return bcoin.ec.sign(msg, this);
return bcoin.ec.sign(msg, this.getPrivateKey());
};
KeyPair.prototype.verify = function verify(msg, sig) {
return bcoin.ec.verify(msg, sig, this);
return bcoin.ec.verify(msg, sig, this.getPublicKey());
};
KeyPair.prototype.getPrivateKey = function getPrivateKey(enc) {
var privateKey;
if (!this._privateKey) {
privateKey = this.privatePoint;
if (!privateKey)
return;
privateKey = new Buffer(privateKey.toArray('be', 32));
this._privateKey = privateKey;
}
privateKey = this._privateKey;
if (!this.privateKey)
return;
if (enc === 'base58')
return KeyPair.toSecret(privateKey, this.compressed);
return this.toSecret();
if (enc === 'hex')
return utils.toHex(privateKey);
return utils.toHex(this.privateKey);
return privateKey;
return this.privateKey;
};
KeyPair.prototype.getPublicKey = function getPublicKey(enc) {
var publicKey;
if (!this.publicKey) {
if (!this.privateKey)
return;
if (!this._publicKey)
this._publicKey = new Buffer(this.key.getPublic(this.compressed, 'array'));
publicKey = this._publicKey;
this.publicKey = bcoin.ec.publicKeyCreate(
this.privateKey, this.compressed
);
}
if (enc === 'base58')
return utils.toBase58(publicKey);
return utils.toBase58(this.publicKey);
if (enc === 'hex')
return utils.toHex(publicKey);
return utils.toHex(this.publicKey);
return publicKey;
return this.publicKey;
};
KeyPair.prototype.toSecret = function toSecret() {
@ -161,14 +127,6 @@ KeyPair.fromSecret = function fromSecret(privateKey) {
return new KeyPair(KeyPair._fromSecret(privateKey));
};
KeyPair.verify = function verify(msg, sig, key) {
return bcoin.ec.verify(msg, sig, key);
};
KeyPair.sign = function sign(msg, key) {
return bcoin.ec.sign(msg, key);
};
KeyPair.prototype.toJSON = function toJSON(passphrase) {
var json = {
v: 1,

View File

@ -41,7 +41,7 @@ function Wallet(options) {
}
if (!options.master)
options.master = bcoin.hd.privateKey();
options.master = bcoin.hd.fromSeed();
this.options = options;
this.db = options.db || new bcoin.walletdb({ type: 'file' });
@ -355,8 +355,7 @@ Wallet.prototype.deriveAddress = function deriveAddress(change, index) {
key = this.accountKey.derive(data.path);
options = {
key: key.key,
compressed: key.compressed,
key: key,
change: data.change,
index: data.index,
path: data.path,

View File

@ -86,7 +86,7 @@ describe('HD', function() {
});
it('should deserialize and reserialize', function() {
var key = bcoin.hd.priv();
var key = bcoin.hd.fromSeed();
assert.equal(bcoin.hd.fromJSON(key.toJSON()).xprivkey, key.xprivkey);
});

View File

@ -52,7 +52,7 @@ describe('Wallet', function() {
m: 1,
n: 2
});
var k2 = bcoin.hd.priv().deriveAccount44(0).hdPublicKey;
var k2 = bcoin.hd.fromSeed().deriveAccount44(0).hdPublicKey;
w.addKey(k2);
// Input transcation