'use strict';
|
|
var BN = require('bn.js');
|
var inherits = require('inherits');
|
var Base = require('./base');
|
|
var utils = require('../utils');
|
|
function MontCurve(conf) {
|
Base.call(this, 'mont', conf);
|
|
this.a = new BN(conf.a, 16).toRed(this.red);
|
this.b = new BN(conf.b, 16).toRed(this.red);
|
this.i4 = new BN(4).toRed(this.red).redInvm();
|
this.two = new BN(2).toRed(this.red);
|
this.a24 = this.i4.redMul(this.a.redAdd(this.two));
|
}
|
inherits(MontCurve, Base);
|
module.exports = MontCurve;
|
|
MontCurve.prototype.validate = function validate(point) {
|
var x = point.normalize().x;
|
var x2 = x.redSqr();
|
var rhs = x2.redMul(x).redAdd(x2.redMul(this.a)).redAdd(x);
|
var y = rhs.redSqrt();
|
|
return y.redSqr().cmp(rhs) === 0;
|
};
|
|
function Point(curve, x, z) {
|
Base.BasePoint.call(this, curve, 'projective');
|
if (x === null && z === null) {
|
this.x = this.curve.one;
|
this.z = this.curve.zero;
|
} else {
|
this.x = new BN(x, 16);
|
this.z = new BN(z, 16);
|
if (!this.x.red)
|
this.x = this.x.toRed(this.curve.red);
|
if (!this.z.red)
|
this.z = this.z.toRed(this.curve.red);
|
}
|
}
|
inherits(Point, Base.BasePoint);
|
|
MontCurve.prototype.decodePoint = function decodePoint(bytes, enc) {
|
return this.point(utils.toArray(bytes, enc), 1);
|
};
|
|
MontCurve.prototype.point = function point(x, z) {
|
return new Point(this, x, z);
|
};
|
|
MontCurve.prototype.pointFromJSON = function pointFromJSON(obj) {
|
return Point.fromJSON(this, obj);
|
};
|
|
Point.prototype.precompute = function precompute() {
|
// No-op
|
};
|
|
Point.prototype._encode = function _encode() {
|
return this.getX().toArray('be', this.curve.p.byteLength());
|
};
|
|
Point.fromJSON = function fromJSON(curve, obj) {
|
return new Point(curve, obj[0], obj[1] || curve.one);
|
};
|
|
Point.prototype.inspect = function inspect() {
|
if (this.isInfinity())
|
return '<EC Point Infinity>';
|
return '<EC Point x: ' + this.x.fromRed().toString(16, 2) +
|
' z: ' + this.z.fromRed().toString(16, 2) + '>';
|
};
|
|
Point.prototype.isInfinity = function isInfinity() {
|
// XXX This code assumes that zero is always zero in red
|
return this.z.cmpn(0) === 0;
|
};
|
|
Point.prototype.dbl = function dbl() {
|
// http://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html#doubling-dbl-1987-m-3
|
// 2M + 2S + 4A
|
|
// A = X1 + Z1
|
var a = this.x.redAdd(this.z);
|
// AA = A^2
|
var aa = a.redSqr();
|
// B = X1 - Z1
|
var b = this.x.redSub(this.z);
|
// BB = B^2
|
var bb = b.redSqr();
|
// C = AA - BB
|
var c = aa.redSub(bb);
|
// X3 = AA * BB
|
var nx = aa.redMul(bb);
|
// Z3 = C * (BB + A24 * C)
|
var nz = c.redMul(bb.redAdd(this.curve.a24.redMul(c)));
|
return this.curve.point(nx, nz);
|
};
|
|
Point.prototype.add = function add() {
|
throw new Error('Not supported on Montgomery curve');
|
};
|
|
Point.prototype.diffAdd = function diffAdd(p, diff) {
|
// http://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html#diffadd-dadd-1987-m-3
|
// 4M + 2S + 6A
|
|
// A = X2 + Z2
|
var a = this.x.redAdd(this.z);
|
// B = X2 - Z2
|
var b = this.x.redSub(this.z);
|
// C = X3 + Z3
|
var c = p.x.redAdd(p.z);
|
// D = X3 - Z3
|
var d = p.x.redSub(p.z);
|
// DA = D * A
|
var da = d.redMul(a);
|
// CB = C * B
|
var cb = c.redMul(b);
|
// X5 = Z1 * (DA + CB)^2
|
var nx = diff.z.redMul(da.redAdd(cb).redSqr());
|
// Z5 = X1 * (DA - CB)^2
|
var nz = diff.x.redMul(da.redISub(cb).redSqr());
|
return this.curve.point(nx, nz);
|
};
|
|
Point.prototype.mul = function mul(k) {
|
var t = k.clone();
|
var a = this; // (N / 2) * Q + Q
|
var b = this.curve.point(null, null); // (N / 2) * Q
|
var c = this; // Q
|
|
for (var bits = []; t.cmpn(0) !== 0; t.iushrn(1))
|
bits.push(t.andln(1));
|
|
for (var i = bits.length - 1; i >= 0; i--) {
|
if (bits[i] === 0) {
|
// N * Q + Q = ((N / 2) * Q + Q)) + (N / 2) * Q
|
a = a.diffAdd(b, c);
|
// N * Q = 2 * ((N / 2) * Q + Q))
|
b = b.dbl();
|
} else {
|
// N * Q = ((N / 2) * Q + Q) + ((N / 2) * Q)
|
b = a.diffAdd(b, c);
|
// N * Q + Q = 2 * ((N / 2) * Q + Q)
|
a = a.dbl();
|
}
|
}
|
return b;
|
};
|
|
Point.prototype.mulAdd = function mulAdd() {
|
throw new Error('Not supported on Montgomery curve');
|
};
|
|
Point.prototype.jumlAdd = function jumlAdd() {
|
throw new Error('Not supported on Montgomery curve');
|
};
|
|
Point.prototype.eq = function eq(other) {
|
return this.getX().cmp(other.getX()) === 0;
|
};
|
|
Point.prototype.normalize = function normalize() {
|
this.x = this.x.redMul(this.z.redInvm());
|
this.z = this.curve.one;
|
return this;
|
};
|
|
Point.prototype.getX = function getX() {
|
// Normalize coordinates
|
this.normalize();
|
|
return this.x.fromRed();
|
};
|