Merge pull request #183 from dcousens/ecconst
EC constants and bitShifts
This commit is contained in:
commit
e4aac0f2de
4 changed files with 58 additions and 43 deletions
64
src/ec.js
64
src/ec.js
|
@ -5,6 +5,10 @@
|
||||||
var assert = require('assert')
|
var assert = require('assert')
|
||||||
var BigInteger = require('bigi')
|
var BigInteger = require('bigi')
|
||||||
|
|
||||||
|
// constants
|
||||||
|
var TWO = BigInteger.valueOf(2)
|
||||||
|
var THREE = BigInteger.valueOf(3)
|
||||||
|
|
||||||
function ECFieldElementFp(q,x) {
|
function ECFieldElementFp(q,x) {
|
||||||
this.x = x;
|
this.x = x;
|
||||||
// TODO if(x.compareTo(q) >= 0) error
|
// TODO if(x.compareTo(q) >= 0) error
|
||||||
|
@ -94,15 +98,15 @@ function pointFpEquals(other) {
|
||||||
var u, v;
|
var u, v;
|
||||||
// u = Y2 * Z1 - Y1 * Z2
|
// u = Y2 * Z1 - Y1 * Z2
|
||||||
u = other.y.toBigInteger().multiply(this.z).subtract(this.y.toBigInteger().multiply(other.z)).mod(this.curve.q);
|
u = other.y.toBigInteger().multiply(this.z).subtract(this.y.toBigInteger().multiply(other.z)).mod(this.curve.q);
|
||||||
if(!u.equals(BigInteger.ZERO)) return false;
|
if (u.signum() !== 0) return false;
|
||||||
// v = X2 * Z1 - X1 * Z2
|
// v = X2 * Z1 - X1 * Z2
|
||||||
v = other.x.toBigInteger().multiply(this.z).subtract(this.x.toBigInteger().multiply(other.z)).mod(this.curve.q);
|
v = other.x.toBigInteger().multiply(this.z).subtract(this.x.toBigInteger().multiply(other.z)).mod(this.curve.q);
|
||||||
return v.equals(BigInteger.ZERO);
|
return v.signum() === 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function pointFpIsInfinity() {
|
function pointFpIsInfinity() {
|
||||||
if((this.x == null) && (this.y == null)) return true;
|
if ((this.x == null) && (this.y == null)) return true;
|
||||||
return this.z.equals(BigInteger.ZERO) && !this.y.toBigInteger().equals(BigInteger.ZERO);
|
return this.z.signum() === 0 && this.y.toBigInteger().signum() !== 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function pointFpNegate() {
|
function pointFpNegate() {
|
||||||
|
@ -118,14 +122,13 @@ function pointFpAdd(b) {
|
||||||
// v = X2 * Z1 - X1 * Z2
|
// v = X2 * Z1 - X1 * Z2
|
||||||
var v = b.x.toBigInteger().multiply(this.z).subtract(this.x.toBigInteger().multiply(b.z)).mod(this.curve.q);
|
var v = b.x.toBigInteger().multiply(this.z).subtract(this.x.toBigInteger().multiply(b.z)).mod(this.curve.q);
|
||||||
|
|
||||||
if(BigInteger.ZERO.equals(v)) {
|
if(v.signum() === 0) {
|
||||||
if(BigInteger.ZERO.equals(u)) {
|
if(u.signum() === 0) {
|
||||||
return this.twice(); // this == b, so double
|
return this.twice(); // this == b, so double
|
||||||
}
|
}
|
||||||
return this.curve.getInfinity(); // this = -b, so infinity
|
return this.curve.getInfinity(); // this = -b, so infinity
|
||||||
}
|
}
|
||||||
|
|
||||||
var THREE = new BigInteger("3");
|
|
||||||
var x1 = this.x.toBigInteger();
|
var x1 = this.x.toBigInteger();
|
||||||
var y1 = this.y.toBigInteger();
|
var y1 = this.y.toBigInteger();
|
||||||
var x2 = b.x.toBigInteger();
|
var x2 = b.x.toBigInteger();
|
||||||
|
@ -148,10 +151,8 @@ function pointFpAdd(b) {
|
||||||
|
|
||||||
function pointFpTwice() {
|
function pointFpTwice() {
|
||||||
if(this.isInfinity()) return this;
|
if(this.isInfinity()) return this;
|
||||||
if(this.y.toBigInteger().signum() == 0) return this.curve.getInfinity();
|
if(this.y.toBigInteger().signum() === 0) return this.curve.getInfinity();
|
||||||
|
|
||||||
// TODO: optimized handling of constants
|
|
||||||
var THREE = new BigInteger("3");
|
|
||||||
var x1 = this.x.toBigInteger();
|
var x1 = this.x.toBigInteger();
|
||||||
var y1 = this.y.toBigInteger();
|
var y1 = this.y.toBigInteger();
|
||||||
|
|
||||||
|
@ -161,16 +162,16 @@ function pointFpTwice() {
|
||||||
|
|
||||||
// w = 3 * x1^2 + a * z1^2
|
// w = 3 * x1^2 + a * z1^2
|
||||||
var w = x1.square().multiply(THREE);
|
var w = x1.square().multiply(THREE);
|
||||||
if(!BigInteger.ZERO.equals(a)) {
|
if(a.signum() !== 0) {
|
||||||
w = w.add(this.z.square().multiply(a));
|
w = w.add(this.z.square().multiply(a));
|
||||||
}
|
}
|
||||||
w = w.mod(this.curve.q);
|
w = w.mod(this.curve.q);
|
||||||
// x3 = 2 * y1 * z1 * (w^2 - 8 * x1 * y1^2 * z1)
|
// x3 = 2 * y1 * z1 * (w^2 - 8 * x1 * y1^2 * z1)
|
||||||
var x3 = w.square().subtract(x1.shiftLeft(3).multiply(y1sqz1)).shiftLeft(1).multiply(y1z1).mod(this.curve.q);
|
var x3 = w.square().subtract(x1.shiftLeft(3).multiply(y1sqz1)).shiftLeft(1).multiply(y1z1).mod(this.curve.q);
|
||||||
// y3 = 4 * y1^2 * z1 * (3 * w * x1 - 2 * y1^2 * z1) - w^3
|
// y3 = 4 * y1^2 * z1 * (3 * w * x1 - 2 * y1^2 * z1) - w^3
|
||||||
var y3 = w.multiply(THREE).multiply(x1).subtract(y1sqz1.shiftLeft(1)).shiftLeft(2).multiply(y1sqz1).subtract(w.square().multiply(w)).mod(this.curve.q);
|
var y3 = w.multiply(THREE).multiply(x1).subtract(y1sqz1.shiftLeft(1)).shiftLeft(2).multiply(y1sqz1).subtract(w.pow(3)).mod(this.curve.q);
|
||||||
// z3 = 8 * (y1 * z1)^3
|
// z3 = 8 * (y1 * z1)^3
|
||||||
var z3 = y1z1.square().multiply(y1z1).shiftLeft(3).mod(this.curve.q);
|
var z3 = y1z1.pow(3).shiftLeft(3).mod(this.curve.q);
|
||||||
|
|
||||||
return new ECPointFp(this.curve, this.curve.fromBigInteger(x3), this.curve.fromBigInteger(y3), z3);
|
return new ECPointFp(this.curve, this.curve.fromBigInteger(x3), this.curve.fromBigInteger(y3), z3);
|
||||||
}
|
}
|
||||||
|
@ -179,10 +180,10 @@ function pointFpTwice() {
|
||||||
// TODO: modularize the multiplication algorithm
|
// TODO: modularize the multiplication algorithm
|
||||||
function pointFpMultiply(k) {
|
function pointFpMultiply(k) {
|
||||||
if(this.isInfinity()) return this;
|
if(this.isInfinity()) return this;
|
||||||
if(k.signum() == 0) return this.curve.getInfinity();
|
if(k.signum() === 0) return this.curve.getInfinity()
|
||||||
|
|
||||||
var e = k;
|
var e = k;
|
||||||
var h = e.multiply(new BigInteger("3"));
|
var h = e.multiply(THREE)
|
||||||
|
|
||||||
var neg = this.negate();
|
var neg = this.negate();
|
||||||
var R = this;
|
var R = this;
|
||||||
|
@ -327,8 +328,6 @@ ECPointFp.prototype.getEncoded = function(compressed) {
|
||||||
return buffer
|
return buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
var SEVEN = BigInteger.valueOf(7)
|
|
||||||
|
|
||||||
ECPointFp.decodeFrom = function (curve, buffer) {
|
ECPointFp.decodeFrom = function (curve, buffer) {
|
||||||
var type = buffer.readUInt8(0)
|
var type = buffer.readUInt8(0)
|
||||||
var compressed = type !== 0x04
|
var compressed = type !== 0x04
|
||||||
|
@ -340,14 +339,18 @@ ECPointFp.decodeFrom = function (curve, buffer) {
|
||||||
assert(type === 0x02 || type === 0x03, 'Invalid sequence tag')
|
assert(type === 0x02 || type === 0x03, 'Invalid sequence tag')
|
||||||
|
|
||||||
var isYEven = (type === 0x02)
|
var isYEven = (type === 0x02)
|
||||||
|
var a = curve.getA().toBigInteger()
|
||||||
|
var b = curve.getB().toBigInteger()
|
||||||
var p = curve.getQ()
|
var p = curve.getQ()
|
||||||
|
|
||||||
// We precalculate (p + 1) / 4 where p is the field order
|
// We precalculate (p + 1) / 4 where p is the field order
|
||||||
var P_OVER_FOUR = p.add(BigInteger.ONE).shiftRight(2)
|
if (!curve.P_OVER_FOUR) {
|
||||||
|
curve.P_OVER_FOUR = p.add(BigInteger.ONE).shiftRight(2)
|
||||||
|
}
|
||||||
|
|
||||||
// Convert x to point
|
// Convert x to point
|
||||||
var alpha = x.square().multiply(x).add(SEVEN).mod(p)
|
var alpha = x.pow(3).add(a.multiply(x)).add(b).mod(p)
|
||||||
var beta = alpha.modPow(P_OVER_FOUR, p)
|
var beta = alpha.modPow(curve.P_OVER_FOUR, p)
|
||||||
|
|
||||||
// If beta is even, but y isn't, or vice versa, then convert it,
|
// If beta is even, but y isn't, or vice versa, then convert it,
|
||||||
// otherwise we're done and y == beta.
|
// otherwise we're done and y == beta.
|
||||||
|
@ -392,17 +395,17 @@ ECPointFp.prototype.add2D = function (b) {
|
||||||
|
|
||||||
ECPointFp.prototype.twice2D = function () {
|
ECPointFp.prototype.twice2D = function () {
|
||||||
if (this.isInfinity()) return this;
|
if (this.isInfinity()) return this;
|
||||||
if (this.y.toBigInteger().signum() == 0) {
|
if (this.y.toBigInteger().signum() === 0) {
|
||||||
// if y1 == 0, then (x1, y1) == (x1, -y1)
|
// if y1 == 0, then (x1, y1) == (x1, -y1)
|
||||||
// and hence this = -this and thus 2(x1, y1) == infinity
|
// and hence this = -this and thus 2(x1, y1) == infinity
|
||||||
return this.curve.getInfinity();
|
return this.curve.getInfinity();
|
||||||
}
|
}
|
||||||
|
|
||||||
var TWO = this.curve.fromBigInteger(BigInteger.valueOf(2));
|
var FpTWO = this.curve.fromBigInteger(TWO);
|
||||||
var THREE = this.curve.fromBigInteger(BigInteger.valueOf(3));
|
var FpTHREE = this.curve.fromBigInteger(THREE)
|
||||||
var gamma = this.x.square().multiply(THREE).add(this.curve.a).divide(this.y.multiply(TWO));
|
var gamma = this.x.square().multiply(FpTHREE).add(this.curve.a).divide(this.y.multiply(FpTWO));
|
||||||
|
|
||||||
var x3 = gamma.square().subtract(this.x.multiply(TWO));
|
var x3 = gamma.square().subtract(this.x.multiply(FpTWO));
|
||||||
var y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y);
|
var y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y);
|
||||||
|
|
||||||
return new ECPointFp(this.curve, x3, y3);
|
return new ECPointFp(this.curve, x3, y3);
|
||||||
|
@ -410,10 +413,10 @@ ECPointFp.prototype.twice2D = function () {
|
||||||
|
|
||||||
ECPointFp.prototype.multiply2D = function (k) {
|
ECPointFp.prototype.multiply2D = function (k) {
|
||||||
if(this.isInfinity()) return this;
|
if(this.isInfinity()) return this;
|
||||||
if(k.signum() == 0) return this.curve.getInfinity();
|
if (k.signum() === 0) return this.curve.getInfinity()
|
||||||
|
|
||||||
var e = k;
|
var e = k;
|
||||||
var h = e.multiply(new BigInteger("3"));
|
var h = e.multiply(THREE)
|
||||||
|
|
||||||
var neg = this.negate();
|
var neg = this.negate();
|
||||||
var R = this;
|
var R = this;
|
||||||
|
@ -438,10 +441,9 @@ ECPointFp.prototype.isOnCurve = function () {
|
||||||
var y = this.getY().toBigInteger();
|
var y = this.getY().toBigInteger();
|
||||||
var a = this.curve.getA().toBigInteger();
|
var a = this.curve.getA().toBigInteger();
|
||||||
var b = this.curve.getB().toBigInteger();
|
var b = this.curve.getB().toBigInteger();
|
||||||
var n = this.curve.getQ();
|
var p = this.curve.getQ()
|
||||||
var lhs = y.multiply(y).mod(n);
|
var lhs = y.square().mod(p)
|
||||||
var rhs = x.multiply(x).multiply(x)
|
var rhs = x.pow(3).add(a.multiply(x)).add(b).mod(p)
|
||||||
.add(a.multiply(x)).add(b).mod(n);
|
|
||||||
return lhs.equals(rhs);
|
return lhs.equals(rhs);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
19
src/ecdsa.js
19
src/ecdsa.js
|
@ -6,8 +6,6 @@ var ecparams = sec("secp256k1")
|
||||||
var BigInteger = require('bigi')
|
var BigInteger = require('bigi')
|
||||||
var ECPointFp = require('./ec').ECPointFp
|
var ECPointFp = require('./ec').ECPointFp
|
||||||
|
|
||||||
var P_OVER_FOUR = null
|
|
||||||
|
|
||||||
function implShamirsTrick(P, k, Q, l) {
|
function implShamirsTrick(P, k, Q, l) {
|
||||||
var m = Math.max(k.bitLength(), l.bitLength())
|
var m = Math.max(k.bitLength(), l.bitLength())
|
||||||
var Z = P.add2D(Q)
|
var Z = P.add2D(Q)
|
||||||
|
@ -75,9 +73,9 @@ var ecdsa = {
|
||||||
var s = k.modInverse(n).multiply(e.add(D.multiply(r))).mod(n)
|
var s = k.modInverse(n).multiply(e.add(D.multiply(r))).mod(n)
|
||||||
assert.notEqual(s.signum(), 0, 'Invalid S value')
|
assert.notEqual(s.signum(), 0, 'Invalid S value')
|
||||||
|
|
||||||
var N_OVER_TWO = n.divide(BigInteger.valueOf(2))
|
var N_OVER_TWO = n.shiftRight(1)
|
||||||
|
|
||||||
// Make 's' value 'low' as per bip62
|
// enforce low S values, see bip62: 'low s values in signatures'
|
||||||
if (s.compareTo(N_OVER_TWO) > 0) {
|
if (s.compareTo(N_OVER_TWO) > 0) {
|
||||||
s = n.subtract(s)
|
s = n.subtract(s)
|
||||||
}
|
}
|
||||||
|
@ -124,7 +122,6 @@ var ecdsa = {
|
||||||
}
|
}
|
||||||
|
|
||||||
var c = s.modInverse(n)
|
var c = s.modInverse(n)
|
||||||
|
|
||||||
var u1 = e.multiply(c).mod(n)
|
var u1 = e.multiply(c).mod(n)
|
||||||
var u2 = r.multiply(c).mod(n)
|
var u2 = r.multiply(c).mod(n)
|
||||||
|
|
||||||
|
@ -257,23 +254,23 @@ var ecdsa = {
|
||||||
var a = curve.getA().toBigInteger()
|
var a = curve.getA().toBigInteger()
|
||||||
var b = curve.getB().toBigInteger()
|
var b = curve.getB().toBigInteger()
|
||||||
|
|
||||||
// We precalculate (p + 1) / 4 where p is if the field order
|
// We precalculate (p + 1) / 4 where p is the field order
|
||||||
if (!P_OVER_FOUR) {
|
if (!curve.P_OVER_FOUR) {
|
||||||
P_OVER_FOUR = p.add(BigInteger.ONE).divide(BigInteger.valueOf(4))
|
curve.P_OVER_FOUR = p.add(BigInteger.ONE).shiftRight(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1.1 Compute x
|
// 1.1 Compute x
|
||||||
var x = isSecondKey ? r.add(n) : r
|
var x = isSecondKey ? r.add(n) : r
|
||||||
|
|
||||||
// 1.3 Convert x to point
|
// 1.3 Convert x to point
|
||||||
var alpha = x.multiply(x).multiply(x).add(a.multiply(x)).add(b).mod(p)
|
var alpha = x.pow(3).add(a.multiply(x)).add(b).mod(p)
|
||||||
var beta = alpha.modPow(P_OVER_FOUR, p)
|
var beta = alpha.modPow(curve.P_OVER_FOUR, p)
|
||||||
|
|
||||||
// If beta is even, but y isn't, or vice versa, then convert it,
|
// If beta is even, but y isn't, or vice versa, then convert it,
|
||||||
// otherwise we're done and y == beta.
|
// otherwise we're done and y == beta.
|
||||||
var y = (beta.isEven() ^ isYEven) ? p.subtract(beta) : beta
|
var y = (beta.isEven() ^ isYEven) ? p.subtract(beta) : beta
|
||||||
|
|
||||||
// 1.4 Check that nR is at infinity
|
// 1.4 Check that nR isn't at infinity
|
||||||
var R = new ECPointFp(curve, curve.fromBigInteger(x), curve.fromBigInteger(y))
|
var R = new ECPointFp(curve, curve.fromBigInteger(x), curve.fromBigInteger(y))
|
||||||
R.validate()
|
R.validate()
|
||||||
|
|
||||||
|
|
15
test/ec.js
15
test/ec.js
|
@ -64,6 +64,21 @@ describe('ec', function() {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('supports other curves', function() {
|
||||||
|
var f = fixtures.valid.ECPointFp[1]
|
||||||
|
var ecparams2 = sec('secp256r1')
|
||||||
|
var curve = ecparams2.getCurve()
|
||||||
|
|
||||||
|
var D = BigInteger.ONE
|
||||||
|
var Q = ecparams2.getG().multiply(D)
|
||||||
|
|
||||||
|
var buffer = Q.getEncoded(true)
|
||||||
|
var decoded = ECPointFp.decodeFrom(curve, buffer)
|
||||||
|
|
||||||
|
assert(Q.equals(decoded.Q))
|
||||||
|
assert(decoded.compressed, true)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -59,7 +59,8 @@ describe('ecdsa', function() {
|
||||||
var psig = ecdsa.parseSig(signature)
|
var psig = ecdsa.parseSig(signature)
|
||||||
|
|
||||||
// See BIP62 for more information
|
// See BIP62 for more information
|
||||||
assert(psig.s.compareTo(ecparams.getN().divide(BigInteger.valueOf(2))) <= 0)
|
var N_OVER_TWO = ecparams.getN().shiftRight(1)
|
||||||
|
assert(psig.s.compareTo(N_OVER_TWO) <= 0)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue