Skip to content

Commit

Permalink
key: explicit methods for priv/pub/object
Browse files Browse the repository at this point in the history
fix #21
  • Loading branch information
indutny committed Jan 16, 2015
1 parent 17dc013 commit b6ff175
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 64 deletions.
2 changes: 1 addition & 1 deletion lib/elliptic/curve/edwards.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ function EdwardsCurve(conf) {
this.mOneA = this.twisted && conf.a == -1;
this.extended = this.mOneA;

Base.call(this, 'mont', conf);
Base.call(this, 'edwards', conf);

this.a = new bn(conf.a, 16).mod(this.red.m).toRed(this.red);
this.c = new bn(conf.c, 16).toRed(this.red);
Expand Down
2 changes: 1 addition & 1 deletion lib/elliptic/curve/mont.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ MontCurve.prototype.point = function point(x, z) {

MontCurve.prototype.pointFromJSON = function pointFromJSON(obj) {
return Point.fromJSON(this, obj);
}
};

MontCurve.prototype.validate = function validate(point) {
var x = point.normalize().x;
Expand Down
29 changes: 21 additions & 8 deletions lib/elliptic/ec/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,16 @@ function EC(options) {
}
module.exports = EC;

EC.prototype.keyPair = function keyPair(priv, pub) {
return new KeyPair(this, priv, pub);
EC.prototype.keyPair = function keyPair(options) {
return new KeyPair(this, options);
};

EC.prototype.keyFromPrivate = function keyFromPrivate(priv, enc) {
return KeyPair.fromPrivate(this, priv, enc);
};

EC.prototype.keyFromPublic = function keyFromPublic(pub, enc) {
return KeyPair.fromPublic(this, pub, enc);
};

EC.prototype.genKeyPair = function genKeyPair(options) {
Expand All @@ -59,7 +67,7 @@ EC.prototype.genKeyPair = function genKeyPair(options) {
continue;

priv.iaddn(1);
return this.keyPair(priv);
return this.keyFromPrivate(priv);
} while (true);
};

Expand All @@ -73,12 +81,17 @@ EC.prototype._truncateToN = function truncateToN(msg, truncOnly) {
return msg;
};

EC.prototype.sign = function sign(msg, key, options) {
key = this.keyPair(key, 'hex');
msg = this._truncateToN(new bn(msg, 16));
EC.prototype.sign = function sign(msg, key, enc, options) {
if (typeof enc === 'object') {
options = enc;
enc = null;
}
if (!options)
options = {};

key = this.keyFromPrivate(key, enc);
msg = this._truncateToN(new bn(msg, 16));

// Zero-extend key to provide enough entropy
var bytes = this.n.byteLength();
var bkey = key.getPrivate().toArray();
Expand Down Expand Up @@ -125,9 +138,9 @@ EC.prototype.sign = function sign(msg, key, options) {
} while (true);
};

EC.prototype.verify = function verify(msg, signature, key) {
EC.prototype.verify = function verify(msg, signature, key, enc) {
msg = this._truncateToN(new bn(msg, 16));
key = this.keyPair(key, 'hex');
key = this.keyFromPublic(key, enc);
signature = new Signature(signature, 'hex');

// Perform primitive values validation
Expand Down
101 changes: 53 additions & 48 deletions lib/elliptic/ec/key.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,47 +4,39 @@ var elliptic = require('../../elliptic');
var utils = elliptic.utils;
var assert = utils.assert;

function KeyPair(ec, priv, pub) {
if (priv instanceof KeyPair)
return priv;
if (pub instanceof KeyPair)
return pub;

if (!priv) {
priv = pub;
pub = null;
}
if (priv !== null && typeof priv === 'object') {
if (priv.x) {
// KeyPair(public)
pub = priv;
priv = null;
} else if (priv.priv || priv.pub) {
// KeyPair({ priv: ..., pub: ... })
pub = priv.pub;
priv = priv.priv;
}
}

function KeyPair(ec, options) {
this.ec = ec;
this.priv = null;
this.pub = null;

// KeyPair(public, 'hex')
if (this._importPublicHex(priv, pub))
return;

if (pub === 'hex')
pub = null;

// KeyPair(priv, pub)
if (priv)
this._importPrivate(priv);
if (pub)
this._importPublic(pub);
// KeyPair(ec, { priv: ..., pub: ... })
if (options.priv)
this._importPrivate(options.priv, options.privEnc);
if (options.pub)
this._importPublic(options.pub, options.pubEnc);
}
module.exports = KeyPair;

KeyPair.fromPublic = function fromPublic(ec, pub, enc) {
if (pub instanceof KeyPair)
return pub;

return new KeyPair(ec, {
pub: pub,
pubEnc: enc
});
};

KeyPair.fromPrivate = function fromPrivate(ec, priv, enc) {
if (priv instanceof KeyPair)
return priv;

return new KeyPair(ec, {
priv: priv,
privEnc: enc
});
};

KeyPair.prototype.validate = function validate() {
var pub = this.getPublic();

Expand Down Expand Up @@ -77,14 +69,19 @@ KeyPair.prototype.getPublic = function getPublic(compact, enc) {
for (var i = x.length; i < len; i++)
x.unshift(0);

if (compact) {
var res = [ this.pub.getY().isEven() ? 0x02 : 0x03 ].concat(x);
if (this.ec.curve.type !== 'mont') {
if (compact) {
var res = [ this.pub.getY().isEven() ? 0x02 : 0x03 ].concat(x);
} else {
var y = this.pub.getY().toArray();
for (var i = y.length; i < len; i++)
y.unshift(0);
var res = [ 0x04 ].concat(x, y);
}
} else {
var y = this.pub.getY().toArray();
for (var i = y.length; i < len; i++)
y.unshift(0);
var res = [ 0x04 ].concat(x, y);
res = x;
}

return utils.encode(res, enc);
};

Expand All @@ -95,20 +92,28 @@ KeyPair.prototype.getPrivate = function getPrivate(enc) {
return this.priv;
};

KeyPair.prototype._importPrivate = function _importPrivate(key) {
KeyPair.prototype._importPrivate = function _importPrivate(key, enc) {
this.priv = new bn(key, 16);

// Ensure that the priv won't be bigger than n, otherwise we may fail
// in fixed multiplication method
this.priv = this.priv.mod(this.ec.curve.n);
};

KeyPair.prototype._importPublic = function _importPublic(key) {
this.pub = this.ec.curve.point(key.x, key.y);
};
KeyPair.prototype._importPublic = function _importPublic(key, enc) {
if (key.x || key.y) {
this.pub = this.ec.curve.point(key.x, key.y);
return;
}

KeyPair.prototype._importPublicHex = function _importPublic(key, enc) {
key = utils.toArray(key, enc);
if (this.ec.curve.type !== 'mont')
return this._importPublicShort(key);
else
return this._importPublicMont(key);
};

KeyPair.prototype._importPublicShort = function _importPublicShort(key) {
var len = this.ec.curve.p.byteLength();
if (key[0] === 0x04 && key.length - 1 === 2 * len) {
this.pub = this.ec.curve.point(
Expand All @@ -117,11 +122,11 @@ KeyPair.prototype._importPublicHex = function _importPublic(key, enc) {
} else if ((key[0] === 0x02 || key[0] === 0x03) && key.length - 1 === len) {
this.pub = this.ec.curve.pointFromX(key[0] === 0x03,
key.slice(1, 1 +len));
} else {
return false;
}
};

return true;
KeyPair.prototype._importPublicMont = function _importPublicMont(key) {
this.pub = this.ec.curve.point(key, 1);
};

// ECDH
Expand Down
6 changes: 6 additions & 0 deletions test/ecdh-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ describe('ECDH', function() {
var sh2 = s2.derive(s1.getPublic());

assert.equal(sh1.toString(16), sh2.toString(16));

var sh1 = s1.derive(ecdh.keyFromPublic(s2.getPublic('hex'), 'hex')
.getPublic());
var sh2 = s2.derive(ecdh.keyFromPublic(s1.getPublic('hex'), 'hex')
.getPublic());
assert.equal(sh1.toString(16), sh2.toString(16));
});
}

Expand Down
12 changes: 6 additions & 6 deletions test/ecdsa-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,15 @@ describe('ECDSA', function() {
assert(keys.verify(msg, signature), 'On-key verify');

// Load private key from hex
var keys = ecdsa.keyPair(keys.getPrivate('hex'), 'hex');
var keys = ecdsa.keyFromPrivate(keys.getPrivate('hex'), 'hex');
var signature = ecdsa.sign(msg, keys);
assert(ecdsa.verify(msg, signature, keys), 'hex-private verify');

// Load public key from compact hex
var keys = ecdsa.keyPair(keys.getPublic(true, 'hex'), 'hex');
var keys = ecdsa.keyFromPublic(keys.getPublic(true, 'hex'), 'hex');

// Load public key from hex
var keys = ecdsa.keyPair(keys.getPublic('hex'), 'hex');
var keys = ecdsa.keyFromPublic(keys.getPublic('hex'), 'hex');

// DER encoding
var dsign = signature.toDER('hex');
Expand All @@ -55,8 +55,8 @@ describe('ECDSA', function() {
assert(!ecdsa.verify(msg, signature, keys), 'Wrong key verify');

// Invalid private key
var keys = ecdsa.keyPair(keys.getPrivate('hex') + keys.getPrivate('hex'),
'hex');
var keys = ecdsa.keyFromPrivate(keys.getPrivate('hex') +
keys.getPrivate('hex'));
assert(!ecdsa.verify(msg, signature, keys), 'Wrong key verify');
});
}
Expand All @@ -77,7 +77,7 @@ describe('ECDSA', function() {
var sign = ecdsa.sign(dgst, opt.key);
assert.equal(sign.r.toString(16), c.r);
assert.equal(sign.s.toString(16), c.s);
assert.ok(ecdsa.keyPair(opt.pub).validate().result,
assert.ok(ecdsa.keyFromPublic(opt.pub).validate().result,
'Invalid public key');
assert.ok(ecdsa.verify(dgst, sign, opt.pub),
'Invalid signature');
Expand Down

0 comments on commit b6ff175

Please sign in to comment.