ecdsa
This commit is contained in:
parent
1a01674532
commit
c4064cc6e1
1
index.js
1
index.js
|
@ -13,6 +13,7 @@ privsec.base58 = require('./lib/base58');
|
|||
privsec.base58check = require('./lib/base58check');
|
||||
privsec.bn = require('./lib/bn');
|
||||
privsec.constants = require('./lib/constants');
|
||||
privsec.ecdsa = require('./lib/ecdsa');
|
||||
privsec.hash = require('./lib/hash');
|
||||
privsec.key = require('./lib/key');
|
||||
privsec.point = require('./lib/point');
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
var bn = require('./bn');
|
||||
var point = require('./point');
|
||||
var Signature = require('./signature');
|
||||
var Privkey = require('./privkey');
|
||||
var Pubkey = require('./pubkey');
|
||||
var Random = require('./random');
|
||||
|
||||
var ECDSA = function(hash, key, sig, k) {
|
||||
this.hash = hash;
|
||||
this.key = key;
|
||||
this.sig = sig;
|
||||
this.k = k;
|
||||
};
|
||||
|
||||
ECDSA.prototype.sigError = function() {
|
||||
if (!Buffer.isBuffer(this.hash) || this.hash.length !== 32)
|
||||
return 'Invalid hash';
|
||||
|
||||
try {
|
||||
this.key.pubkey.validate();
|
||||
} catch (e) {
|
||||
return 'Invalid pubkey: ' + e;
|
||||
};
|
||||
|
||||
var r = this.sig.r;
|
||||
var s = this.sig.s;
|
||||
if (!(r.gt(0) && r.lt(point.getN()))
|
||||
|| !(s.gt(0) && s.lt(point.getN())))
|
||||
return 'r and s not in range';
|
||||
|
||||
var e = bn.fromBuffer(this.hash);
|
||||
var n = point.getN();
|
||||
var sinv = s.invm(n);
|
||||
var u1 = sinv.mul(e).mod(n);
|
||||
var u2 = sinv.mul(r).mod(n);
|
||||
|
||||
var p = point.getG().mulAdd(u1, this.key.pubkey.p, u2);
|
||||
if (p.isInfinity())
|
||||
return 'p is infinity';
|
||||
|
||||
if (!(p.getX().mod(n).cmp(r) === 0))
|
||||
return 'Invalid signature';
|
||||
else
|
||||
return false;
|
||||
};
|
||||
|
||||
ECDSA.prototype.randomK = function() {
|
||||
var N = point.getN();
|
||||
var k;
|
||||
do {
|
||||
k = bn.fromBuffer(Random.getRandomBuffer(32));
|
||||
} while (!(k.lt(N) && k.gt(0)));
|
||||
this.k = k;
|
||||
return this;
|
||||
};
|
||||
|
||||
ECDSA.prototype.sign = function() {
|
||||
var hash = this.hash;
|
||||
var privkey = this.key.privkey;
|
||||
var k = this.k;
|
||||
var d = privkey.n;
|
||||
|
||||
if (!hash || !privkey || !k || !d)
|
||||
throw new Error('ecdsa: invalid parameters');
|
||||
|
||||
var N = point.getN();
|
||||
var G = point.getG();
|
||||
var e = bn(hash);
|
||||
|
||||
do {
|
||||
var Q = G.mul(k);
|
||||
var r = Q.x.mod(N);
|
||||
var s = k.invm(N).mul(e.add(d.mul(r))).mod(N);
|
||||
} while (r.cmp(0) <= 0 || s.cmp(0) <= 0);
|
||||
|
||||
this.sig = new Signature(r, s);
|
||||
return this.sig;
|
||||
};
|
||||
|
||||
ECDSA.prototype.signRandomK = function() {
|
||||
var k = this.randomK();
|
||||
return this.sign();
|
||||
};
|
||||
|
||||
ECDSA.prototype.verify = function() {
|
||||
if (!this.sigError())
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
};
|
||||
|
||||
module.exports = ECDSA;
|
32
lib/key.js
32
lib/key.js
|
@ -4,42 +4,42 @@ var Random = require('./random');
|
|||
var bn = require('./bn');
|
||||
var point = require('./point');
|
||||
|
||||
function Key(priv, pub) {
|
||||
this.priv = priv;
|
||||
this.pub = pub;
|
||||
function Key(privkey, pubkey) {
|
||||
this.privkey = privkey;
|
||||
this.pubkey = pubkey;
|
||||
};
|
||||
|
||||
Key.prototype.fromRandom = function() {
|
||||
do {
|
||||
var privbuf = Random.getRandomBuffer(32);
|
||||
this.priv = new Privkey(bn(privbuf));
|
||||
var condition = this.priv.n.lt(point.getN());
|
||||
this.privkey = new Privkey(bn(privbuf));
|
||||
var condition = this.privkey.n.lt(point.getN());
|
||||
} while (!condition);
|
||||
this.priv2pub();
|
||||
this.privkey2pubkey();
|
||||
};
|
||||
|
||||
Key.prototype.fromString = function(str) {
|
||||
var obj = JSON.parse(str);
|
||||
if (obj.priv) {
|
||||
this.priv = new Privkey();
|
||||
this.priv.fromString(obj.priv);
|
||||
this.privkey = new Privkey();
|
||||
this.privkey.fromString(obj.priv);
|
||||
}
|
||||
if (obj.pub) {
|
||||
this.pub = new Pubkey();
|
||||
this.pub.fromString(obj.pub);
|
||||
this.pubkey = new Pubkey();
|
||||
this.pubkey.fromString(obj.pub);
|
||||
}
|
||||
};
|
||||
|
||||
Key.prototype.priv2pub = function() {
|
||||
this.pub = new Pubkey(point.getG().mul(this.priv.n));
|
||||
Key.prototype.privkey2pubkey = function() {
|
||||
this.pubkey = new Pubkey(point.getG().mul(this.privkey.n));
|
||||
};
|
||||
|
||||
Key.prototype.toString = function() {
|
||||
var obj = {};
|
||||
if (this.priv)
|
||||
obj.priv = this.priv.toString();
|
||||
if (this.pub)
|
||||
obj.pub = this.pub.toString();
|
||||
if (this.privkey)
|
||||
obj.priv = this.privkey.toString();
|
||||
if (this.pubkey)
|
||||
obj.pub = this.pubkey.toString();
|
||||
return JSON.stringify(obj);
|
||||
};
|
||||
|
||||
|
|
13
lib/point.js
13
lib/point.js
|
@ -29,4 +29,17 @@ Point.prototype.getY = function() {
|
|||
return bn(this._getY().toArray());
|
||||
};
|
||||
|
||||
//https://www.iacr.org/archive/pkc2003/25670211/25670211.pdf
|
||||
Point.prototype.validate = function() {
|
||||
var p2 = Point.fromX(this.getY().isOdd(), this.getX());
|
||||
if (!(p2.y.cmp(this.y) === 0))
|
||||
throw new Error('point: Invalid y value of public key');
|
||||
if (!(this.getX().gt(-1) && this.getX().lt(Point.getN()))
|
||||
||!(this.getY().gt(-1) && this.getY().lt(Point.getN())))
|
||||
throw new Error('point: Point does not lie on the curve');
|
||||
if (!(this.mul(Point.getN()).isInfinity()))
|
||||
throw new Error('point: Point times N must be infinity');
|
||||
return this;
|
||||
};
|
||||
|
||||
module.exports = Point;
|
||||
|
|
|
@ -2,6 +2,8 @@ var point = require('./point');
|
|||
var bn = require('./bn');
|
||||
|
||||
var Pubkey = function(p) {
|
||||
if (p && !p.getX() && !p.getY())
|
||||
throw new Error('pubkey: Invalid point');
|
||||
this.p = p;
|
||||
};
|
||||
|
||||
|
@ -64,4 +66,14 @@ Pubkey.prototype.toString = function() {
|
|||
return this.toDER(true).toString('hex');
|
||||
};
|
||||
|
||||
//https://www.iacr.org/archive/pkc2003/25670211/25670211.pdf
|
||||
Pubkey.prototype.validate = function() {
|
||||
if (this.p.isInfinity())
|
||||
throw new Error('point: Point cannot be equal to Infinity');
|
||||
if (this.p.eq(point(bn(0), bn(0))))
|
||||
throw new Error('point: Point cannot be equal to 0, 0');
|
||||
this.p.validate();
|
||||
return this;
|
||||
};
|
||||
|
||||
module.exports = Pubkey;
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
var ECDSA = require('../lib/ecdsa');
|
||||
var Hash = require('../lib/hash');
|
||||
var Key = require('../lib/key');
|
||||
var Privkey = require('../lib/privkey');
|
||||
var Pubkey = require('../lib/pubkey');
|
||||
var bn = require('../lib/bn');
|
||||
var point = require('../lib/point');
|
||||
var should = require('chai').should();
|
||||
|
||||
describe("ecdsa", function() {
|
||||
|
||||
it('should create a blank ecdsa', function() {
|
||||
var ecdsa = new ECDSA();
|
||||
});
|
||||
|
||||
var ecdsa = new ECDSA();
|
||||
ecdsa.hash = Hash.sha256(new Buffer('test data'));
|
||||
ecdsa.key = new Key();
|
||||
ecdsa.key.privkey = new Privkey(bn.fromBuffer(new Buffer('fee0a1f7afebf9d2a5a80c0c98a31c709681cce195cbcd06342b517970c0be1e', 'hex')));
|
||||
ecdsa.key.pubkey = new Pubkey(point(bn.fromBuffer(new Buffer('ac242d242d23be966085a2b2b893d989f824e06c9ad0395a8a52f055ba39abb2', 'hex')),
|
||||
bn.fromBuffer(new Buffer('4836ab292c105a711ed10fcfd30999c31ff7c02456147747e03e739ad527c380', 'hex'))));
|
||||
|
||||
describe('#signRandomK', function() {
|
||||
|
||||
it('should produce a signature', function() {
|
||||
ecdsa.signRandomK();
|
||||
should.exist(ecdsa.sig);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#verify', function() {
|
||||
|
||||
it('should verify a signature that was just signed', function() {
|
||||
ecdsa.signRandomK();
|
||||
ecdsa.verify().should.equal(true);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
|
@ -1,8 +1,8 @@
|
|||
var should = require('chai').should();
|
||||
var bn = require('../lib/bn');
|
||||
var point = require('../lib/point');
|
||||
var privkey = require('../lib/privkey');
|
||||
var pubkey = require('../lib/pubkey');
|
||||
var Privkey = require('../lib/privkey');
|
||||
var Pubkey = require('../lib/pubkey');
|
||||
var Key = require('../lib/key');
|
||||
|
||||
describe('key', function() {
|
||||
|
@ -13,12 +13,12 @@ describe('key', function() {
|
|||
});
|
||||
|
||||
it('should make a key with a priv and pub', function() {
|
||||
var priv = new privkey();
|
||||
var pub = new pubkey();
|
||||
var priv = new Privkey();
|
||||
var pub = new Pubkey();
|
||||
var key = new Key(priv, pub);
|
||||
should.exist(key);
|
||||
should.exist(key.priv);
|
||||
should.exist(key.pub);
|
||||
should.exist(key.privkey);
|
||||
should.exist(key.pubkey);
|
||||
});
|
||||
|
||||
describe("#fromRandom", function() {
|
||||
|
@ -26,11 +26,11 @@ describe('key', function() {
|
|||
it('should make a new priv and pub', function() {
|
||||
var key = new Key();
|
||||
key.fromRandom();
|
||||
should.exist(key.priv);
|
||||
should.exist(key.pub);
|
||||
key.priv.n.gt(bn(0)).should.equal(true);
|
||||
key.pub.p.getX().gt(bn(0)).should.equal(true);
|
||||
key.pub.p.getY().gt(bn(0)).should.equal(true);
|
||||
should.exist(key.privkey);
|
||||
should.exist(key.pubkey);
|
||||
key.privkey.n.gt(bn(0)).should.equal(true);
|
||||
key.pubkey.p.getX().gt(bn(0)).should.equal(true);
|
||||
key.pubkey.p.getY().gt(bn(0)).should.equal(true);
|
||||
});
|
||||
|
||||
});
|
||||
|
@ -40,49 +40,49 @@ describe('key', function() {
|
|||
it('should recover a key creating with toString', function() {
|
||||
var key = new Key();
|
||||
key.fromRandom();
|
||||
var priv = key.priv;
|
||||
var pub = key.pub;
|
||||
var priv = key.privkey;
|
||||
var pub = key.pubkey;
|
||||
var str = key.toString();
|
||||
key.fromString(str);
|
||||
should.exist(key.priv);
|
||||
should.exist(key.pub);
|
||||
key.priv.toString().should.equal(priv.toString());
|
||||
key.pub.toString().should.equal(pub.toString());
|
||||
should.exist(key.privkey);
|
||||
should.exist(key.pubkey);
|
||||
key.privkey.toString().should.equal(priv.toString());
|
||||
key.pubkey.toString().should.equal(pub.toString());
|
||||
});
|
||||
|
||||
it('should work with only privkey set', function() {
|
||||
it('should work with only Privkey set', function() {
|
||||
var key = new Key();
|
||||
key.fromRandom();
|
||||
key.pub = undefined;
|
||||
var priv = key.priv;
|
||||
key.pubkey = undefined;
|
||||
var priv = key.privkey;
|
||||
var str = key.toString();
|
||||
key.fromString(str);
|
||||
should.exist(key.priv);
|
||||
key.priv.toString().should.equal(priv.toString());
|
||||
should.exist(key.privkey);
|
||||
key.privkey.toString().should.equal(priv.toString());
|
||||
});
|
||||
|
||||
it('should work with only pubkey set', function() {
|
||||
it('should work with only Pubkey set', function() {
|
||||
var key = new Key();
|
||||
key.fromRandom();
|
||||
key.priv = undefined;
|
||||
var pub = key.pub;
|
||||
key.privkey = undefined;
|
||||
var pub = key.pubkey;
|
||||
var str = key.toString();
|
||||
key.fromString(str);
|
||||
should.exist(key.pub);
|
||||
key.pub.toString().should.equal(pub.toString());
|
||||
should.exist(key.pubkey);
|
||||
key.pubkey.toString().should.equal(pub.toString());
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("#priv2pub", function() {
|
||||
describe("#privkey2pubkey", function() {
|
||||
|
||||
it('should convert this known privkey to known pubkey', function() {
|
||||
it('should convert this known Privkey to known Pubkey', function() {
|
||||
var privhex = '906977a061af29276e40bf377042ffbde414e496ae2260bbf1fa9d085637bfff';
|
||||
var pubhex = '02a1633cafcc01ebfb6d78e39f687a1f0995c62fc95f51ead10a02ee0be551b5dc';
|
||||
var key = new Key();
|
||||
key.priv = new privkey(bn(new Buffer(privhex, 'hex')));
|
||||
key.priv2pub();
|
||||
key.pub.toString().should.equal(pubhex);
|
||||
key.privkey = new Privkey(bn(new Buffer(privhex, 'hex')));
|
||||
key.privkey2pubkey();
|
||||
key.pubkey.toString().should.equal(pubhex);
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -89,4 +89,24 @@ describe('point', function() {
|
|||
|
||||
});
|
||||
|
||||
describe('#validate', function() {
|
||||
|
||||
it('should validate this valid point', function() {
|
||||
var x = bn.fromBuffer(new Buffer('ac242d242d23be966085a2b2b893d989f824e06c9ad0395a8a52f055ba39abb2', 'hex'));
|
||||
var y = bn.fromBuffer(new Buffer('4836ab292c105a711ed10fcfd30999c31ff7c02456147747e03e739ad527c380', 'hex'));
|
||||
var p = point(x, y);
|
||||
should.exist(p.validate());
|
||||
});
|
||||
|
||||
it('should invalidate this invalid point', function() {
|
||||
var x = bn.fromBuffer(new Buffer('ac242d242d23be966085a2b2b893d989f824e06c9ad0395a8a52f055ba39abb2', 'hex'));
|
||||
var y = bn.fromBuffer(new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex'));
|
||||
var p = point(x, y);
|
||||
(function() {
|
||||
p.validate();
|
||||
}).should.throw('point: Invalid y value of public key');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -93,4 +93,32 @@ describe('pubkey', function() {
|
|||
|
||||
});
|
||||
|
||||
describe('#validate', function() {
|
||||
|
||||
it('should not throw an error if pubkey is valid', function() {
|
||||
var hex = '031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a';
|
||||
var pk = new pubkey();
|
||||
pk.fromString(hex);
|
||||
should.exist(pk.validate());
|
||||
});
|
||||
|
||||
it('should not throw an error if pubkey is invalid', function() {
|
||||
var hex = '041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a0000000000000000000000000000000000000000000000000000000000000000';
|
||||
var pk = new pubkey();
|
||||
pk.fromString(hex);
|
||||
(function() {
|
||||
pk.validate();
|
||||
}).should.throw('point: Invalid y value of public key');
|
||||
});
|
||||
|
||||
it('should not throw an error if pubkey is infinity', function() {
|
||||
var pk = new pubkey();
|
||||
pk.p = point.getG().mul(point.getN());
|
||||
(function() {
|
||||
pk.validate();
|
||||
}).should.throw('point: Point cannot be equal to Infinity');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue