refactor keypair and hd.
This commit is contained in:
parent
0f40d78f9e
commit
30db808930
@ -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),
|
||||
|
||||
@ -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());
|
||||
|
||||
101
lib/bcoin/hd.js
101
lib/bcoin/hd.js
@ -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) {
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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);
|
||||
});
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user