react / wstein / node_modules / browserify / node_modules / crypto-browserify / node_modules / browserify-sign / node_modules / elliptic / lib / elliptic / curve / short.js
80621 views'use strict';12var curve = require('../curve');3var elliptic = require('../../elliptic');4var bn = require('bn.js');5var inherits = require('inherits');6var Base = curve.base;78var assert = elliptic.utils.assert;910function ShortCurve(conf) {11Base.call(this, 'short', conf);1213this.a = new bn(conf.a, 16).toRed(this.red);14this.b = new bn(conf.b, 16).toRed(this.red);15this.tinv = this.two.redInvm();1617this.zeroA = this.a.fromRed().cmpn(0) === 0;18this.threeA = this.a.fromRed().sub(this.p).cmpn(-3) === 0;1920// If the curve is endomorphic, precalculate beta and lambda21this.endo = this._getEndomorphism(conf);22this._endoWnafT1 = new Array(4);23this._endoWnafT2 = new Array(4);24}25inherits(ShortCurve, Base);26module.exports = ShortCurve;2728ShortCurve.prototype._getEndomorphism = function _getEndomorphism(conf) {29// No efficient endomorphism30if (!this.zeroA || !this.g || !this.n || this.p.modn(3) !== 1)31return;3233// Compute beta and lambda, that lambda * P = (beta * Px; Py)34var beta;35var lambda;36if (conf.beta) {37beta = new bn(conf.beta, 16).toRed(this.red);38} else {39var betas = this._getEndoRoots(this.p);40// Choose the smallest beta41beta = betas[0].cmp(betas[1]) < 0 ? betas[0] : betas[1];42beta = beta.toRed(this.red);43}44if (conf.lambda) {45lambda = new bn(conf.lambda, 16);46} else {47// Choose the lambda that is matching selected beta48var lambdas = this._getEndoRoots(this.n);49if (this.g.mul(lambdas[0]).x.cmp(this.g.x.redMul(beta)) === 0) {50lambda = lambdas[0];51} else {52lambda = lambdas[1];53assert(this.g.mul(lambda).x.cmp(this.g.x.redMul(beta)) === 0);54}55}5657// Get basis vectors, used for balanced length-two representation58var basis;59if (conf.basis) {60basis = conf.basis.map(function(vec) {61return {62a: new bn(vec.a, 16),63b: new bn(vec.b, 16)64};65});66} else {67basis = this._getEndoBasis(lambda);68}6970return {71beta: beta,72lambda: lambda,73basis: basis74};75};7677ShortCurve.prototype._getEndoRoots = function _getEndoRoots(num) {78// Find roots of for x^2 + x + 1 in F79// Root = (-1 +- Sqrt(-3)) / 280//81var red = num === this.p ? this.red : bn.mont(num);82var tinv = new bn(2).toRed(red).redInvm();83var ntinv = tinv.redNeg();8485var s = new bn(3).toRed(red).redNeg().redSqrt().redMul(tinv);8687var l1 = ntinv.redAdd(s).fromRed();88var l2 = ntinv.redSub(s).fromRed();89return [ l1, l2 ];90};9192ShortCurve.prototype._getEndoBasis = function _getEndoBasis(lambda) {93// aprxSqrt >= sqrt(this.n)94var aprxSqrt = this.n.shrn(Math.floor(this.n.bitLength() / 2));9596// 3.7497// Run EGCD, until r(L + 1) < aprxSqrt98var u = lambda;99var v = this.n.clone();100var x1 = new bn(1);101var y1 = new bn(0);102var x2 = new bn(0);103var y2 = new bn(1);104105// NOTE: all vectors are roots of: a + b * lambda = 0 (mod n)106var a0;107var b0;108// First vector109var a1;110var b1;111// Second vector112var a2;113var b2;114115var prevR;116var i = 0;117var r;118var x;119while (u.cmpn(0) !== 0) {120var q = v.div(u);121r = v.sub(q.mul(u));122x = x2.sub(q.mul(x1));123var y = y2.sub(q.mul(y1));124125if (!a1 && r.cmp(aprxSqrt) < 0) {126a0 = prevR.neg();127b0 = x1;128a1 = r.neg();129b1 = x;130} else if (a1 && ++i === 2) {131break;132}133prevR = r;134135v = u;136u = r;137x2 = x1;138x1 = x;139y2 = y1;140y1 = y;141}142a2 = r.neg();143b2 = x;144145var len1 = a1.sqr().add(b1.sqr());146var len2 = a2.sqr().add(b2.sqr());147if (len2.cmp(len1) >= 0) {148a2 = a0;149b2 = b0;150}151152// Normalize signs153if (a1.sign) {154a1 = a1.neg();155b1 = b1.neg();156}157if (a2.sign) {158a2 = a2.neg();159b2 = b2.neg();160}161162return [163{ a: a1, b: b1 },164{ a: a2, b: b2 }165];166};167168ShortCurve.prototype._endoSplit = function _endoSplit(k) {169var basis = this.endo.basis;170var v1 = basis[0];171var v2 = basis[1];172173var c1 = v2.b.mul(k).divRound(this.n);174var c2 = v1.b.neg().mul(k).divRound(this.n);175176var p1 = c1.mul(v1.a);177var p2 = c2.mul(v2.a);178var q1 = c1.mul(v1.b);179var q2 = c2.mul(v2.b);180181// Calculate answer182var k1 = k.sub(p1).sub(p2);183var k2 = q1.add(q2).neg();184return { k1: k1, k2: k2 };185};186187ShortCurve.prototype.pointFromX = function pointFromX(odd, x) {188x = new bn(x, 16);189if (!x.red)190x = x.toRed(this.red);191192var y2 = x.redSqr().redMul(x).redIAdd(x.redMul(this.a)).redIAdd(this.b);193var y = y2.redSqrt();194195// XXX Is there any way to tell if the number is odd without converting it196// to non-red form?197var isOdd = y.fromRed().isOdd();198if (odd && !isOdd || !odd && isOdd)199y = y.redNeg();200201return this.point(x, y);202};203204ShortCurve.prototype.validate = function validate(point) {205if (point.inf)206return true;207208var x = point.x;209var y = point.y;210211var ax = this.a.redMul(x);212var rhs = x.redSqr().redMul(x).redIAdd(ax).redIAdd(this.b);213return y.redSqr().redISub(rhs).cmpn(0) === 0;214};215216ShortCurve.prototype._endoWnafMulAdd =217function _endoWnafMulAdd(points, coeffs) {218var npoints = this._endoWnafT1;219var ncoeffs = this._endoWnafT2;220for (var i = 0; i < points.length; i++) {221var split = this._endoSplit(coeffs[i]);222var p = points[i];223var beta = p._getBeta();224225if (split.k1.sign) {226split.k1.sign = !split.k1.sign;227p = p.neg(true);228}229if (split.k2.sign) {230split.k2.sign = !split.k2.sign;231beta = beta.neg(true);232}233234npoints[i * 2] = p;235npoints[i * 2 + 1] = beta;236ncoeffs[i * 2] = split.k1;237ncoeffs[i * 2 + 1] = split.k2;238}239var res = this._wnafMulAdd(1, npoints, ncoeffs, i * 2);240241// Clean-up references to points and coefficients242for (var j = 0; j < i * 2; j++) {243npoints[j] = null;244ncoeffs[j] = null;245}246return res;247};248249function Point(curve, x, y, isRed) {250Base.BasePoint.call(this, curve, 'affine');251if (x === null && y === null) {252this.x = null;253this.y = null;254this.inf = true;255} else {256this.x = new bn(x, 16);257this.y = new bn(y, 16);258// Force redgomery representation when loading from JSON259if (isRed) {260this.x.forceRed(this.curve.red);261this.y.forceRed(this.curve.red);262}263if (!this.x.red)264this.x = this.x.toRed(this.curve.red);265if (!this.y.red)266this.y = this.y.toRed(this.curve.red);267this.inf = false;268}269}270inherits(Point, Base.BasePoint);271272ShortCurve.prototype.point = function point(x, y, isRed) {273return new Point(this, x, y, isRed);274};275276ShortCurve.prototype.pointFromJSON = function pointFromJSON(obj, red) {277return Point.fromJSON(this, obj, red);278};279280Point.prototype._getBeta = function _getBeta() {281if (!this.curve.endo)282return;283284var pre = this.precomputed;285if (pre && pre.beta)286return pre.beta;287288var beta = this.curve.point(this.x.redMul(this.curve.endo.beta), this.y);289if (pre) {290var curve = this.curve;291var endoMul = function(p) {292return curve.point(p.x.redMul(curve.endo.beta), p.y);293};294pre.beta = beta;295beta.precomputed = {296beta: null,297naf: pre.naf && {298wnd: pre.naf.wnd,299points: pre.naf.points.map(endoMul)300},301doubles: pre.doubles && {302step: pre.doubles.step,303points: pre.doubles.points.map(endoMul)304}305};306}307return beta;308};309310Point.prototype.toJSON = function toJSON() {311if (!this.precomputed)312return [ this.x, this.y ];313314return [ this.x, this.y, this.precomputed && {315doubles: this.precomputed.doubles && {316step: this.precomputed.doubles.step,317points: this.precomputed.doubles.points.slice(1)318},319naf: this.precomputed.naf && {320wnd: this.precomputed.naf.wnd,321points: this.precomputed.naf.points.slice(1)322}323} ];324};325326Point.fromJSON = function fromJSON(curve, obj, red) {327if (typeof obj === 'string')328obj = JSON.parse(obj);329var res = curve.point(obj[0], obj[1], red);330if (!obj[2])331return res;332333function obj2point(obj) {334return curve.point(obj[0], obj[1], red);335}336337var pre = obj[2];338res.precomputed = {339beta: null,340doubles: pre.doubles && {341step: pre.doubles.step,342points: [ res ].concat(pre.doubles.points.map(obj2point))343},344naf: pre.naf && {345wnd: pre.naf.wnd,346points: [ res ].concat(pre.naf.points.map(obj2point))347}348};349return res;350};351352Point.prototype.inspect = function inspect() {353if (this.isInfinity())354return '<EC Point Infinity>';355return '<EC Point x: ' + this.x.fromRed().toString(16, 2) +356' y: ' + this.y.fromRed().toString(16, 2) + '>';357};358359Point.prototype.isInfinity = function isInfinity() {360return this.inf;361};362363Point.prototype.add = function add(p) {364// O + P = P365if (this.inf)366return p;367368// P + O = P369if (p.inf)370return this;371372// P + P = 2P373if (this.eq(p))374return this.dbl();375376// P + (-P) = O377if (this.neg().eq(p))378return this.curve.point(null, null);379380// P + Q = O381if (this.x.cmp(p.x) === 0)382return this.curve.point(null, null);383384var c = this.y.redSub(p.y);385if (c.cmpn(0) !== 0)386c = c.redMul(this.x.redSub(p.x).redInvm());387var nx = c.redSqr().redISub(this.x).redISub(p.x);388var ny = c.redMul(this.x.redSub(nx)).redISub(this.y);389return this.curve.point(nx, ny);390};391392Point.prototype.dbl = function dbl() {393if (this.inf)394return this;395396// 2P = O397var ys1 = this.y.redAdd(this.y);398if (ys1.cmpn(0) === 0)399return this.curve.point(null, null);400401var a = this.curve.a;402403var x2 = this.x.redSqr();404var dyinv = ys1.redInvm();405var c = x2.redAdd(x2).redIAdd(x2).redIAdd(a).redMul(dyinv);406407var nx = c.redSqr().redISub(this.x.redAdd(this.x));408var ny = c.redMul(this.x.redSub(nx)).redISub(this.y);409return this.curve.point(nx, ny);410};411412Point.prototype.getX = function getX() {413return this.x.fromRed();414};415416Point.prototype.getY = function getY() {417return this.y.fromRed();418};419420Point.prototype.mul = function mul(k) {421k = new bn(k, 16);422423if (this.precomputed && this.precomputed.doubles)424return this.curve._fixedNafMul(this, k);425else if (this.curve.endo)426return this.curve._endoWnafMulAdd([ this ], [ k ]);427else428return this.curve._wnafMul(this, k);429};430431Point.prototype.mulAdd = function mulAdd(k1, p2, k2) {432var points = [ this, p2 ];433var coeffs = [ k1, k2 ];434if (this.curve.endo)435return this.curve._endoWnafMulAdd(points, coeffs);436else437return this.curve._wnafMulAdd(1, points, coeffs, 2);438};439440Point.prototype.eq = function eq(p) {441return this === p ||442this.inf === p.inf &&443(this.inf || this.x.cmp(p.x) === 0 && this.y.cmp(p.y) === 0);444};445446Point.prototype.neg = function neg(_precompute) {447if (this.inf)448return this;449450var res = this.curve.point(this.x, this.y.redNeg());451if (_precompute && this.precomputed) {452var pre = this.precomputed;453var negate = function(p) {454return p.neg();455};456res.precomputed = {457naf: pre.naf && {458wnd: pre.naf.wnd,459points: pre.naf.points.map(negate)460},461doubles: pre.doubles && {462step: pre.doubles.step,463points: pre.doubles.points.map(negate)464}465};466}467return res;468};469470Point.prototype.toJ = function toJ() {471if (this.inf)472return this.curve.jpoint(null, null, null);473474var res = this.curve.jpoint(this.x, this.y, this.curve.one);475return res;476};477478function JPoint(curve, x, y, z) {479Base.BasePoint.call(this, curve, 'jacobian');480if (x === null && y === null && z === null) {481this.x = this.curve.one;482this.y = this.curve.one;483this.z = new bn(0);484} else {485this.x = new bn(x, 16);486this.y = new bn(y, 16);487this.z = new bn(z, 16);488}489if (!this.x.red)490this.x = this.x.toRed(this.curve.red);491if (!this.y.red)492this.y = this.y.toRed(this.curve.red);493if (!this.z.red)494this.z = this.z.toRed(this.curve.red);495496this.zOne = this.z === this.curve.one;497}498inherits(JPoint, Base.BasePoint);499500ShortCurve.prototype.jpoint = function jpoint(x, y, z) {501return new JPoint(this, x, y, z);502};503504JPoint.prototype.toP = function toP() {505if (this.isInfinity())506return this.curve.point(null, null);507508var zinv = this.z.redInvm();509var zinv2 = zinv.redSqr();510var ax = this.x.redMul(zinv2);511var ay = this.y.redMul(zinv2).redMul(zinv);512513return this.curve.point(ax, ay);514};515516JPoint.prototype.neg = function neg() {517return this.curve.jpoint(this.x, this.y.redNeg(), this.z);518};519520JPoint.prototype.add = function add(p) {521// O + P = P522if (this.isInfinity())523return p;524525// P + O = P526if (p.isInfinity())527return this;528529// 12M + 4S + 7A530var pz2 = p.z.redSqr();531var z2 = this.z.redSqr();532var u1 = this.x.redMul(pz2);533var u2 = p.x.redMul(z2);534var s1 = this.y.redMul(pz2.redMul(p.z));535var s2 = p.y.redMul(z2.redMul(this.z));536537var h = u1.redSub(u2);538var r = s1.redSub(s2);539if (h.cmpn(0) === 0) {540if (r.cmpn(0) !== 0)541return this.curve.jpoint(null, null, null);542else543return this.dbl();544}545546var h2 = h.redSqr();547var h3 = h2.redMul(h);548var v = u1.redMul(h2);549550var nx = r.redSqr().redIAdd(h3).redISub(v).redISub(v);551var ny = r.redMul(v.redISub(nx)).redISub(s1.redMul(h3));552var nz = this.z.redMul(p.z).redMul(h);553554return this.curve.jpoint(nx, ny, nz);555};556557JPoint.prototype.mixedAdd = function mixedAdd(p) {558// O + P = P559if (this.isInfinity())560return p.toJ();561562// P + O = P563if (p.isInfinity())564return this;565566// 8M + 3S + 7A567var z2 = this.z.redSqr();568var u1 = this.x;569var u2 = p.x.redMul(z2);570var s1 = this.y;571var s2 = p.y.redMul(z2).redMul(this.z);572573var h = u1.redSub(u2);574var r = s1.redSub(s2);575if (h.cmpn(0) === 0) {576if (r.cmpn(0) !== 0)577return this.curve.jpoint(null, null, null);578else579return this.dbl();580}581582var h2 = h.redSqr();583var h3 = h2.redMul(h);584var v = u1.redMul(h2);585586var nx = r.redSqr().redIAdd(h3).redISub(v).redISub(v);587var ny = r.redMul(v.redISub(nx)).redISub(s1.redMul(h3));588var nz = this.z.redMul(h);589590return this.curve.jpoint(nx, ny, nz);591};592593JPoint.prototype.dblp = function dblp(pow) {594if (pow === 0)595return this;596if (this.isInfinity())597return this;598if (!pow)599return this.dbl();600601if (this.curve.zeroA || this.curve.threeA) {602var r = this;603for (var i = 0; i < pow; i++)604r = r.dbl();605return r;606}607608// 1M + 2S + 1A + N * (4S + 5M + 8A)609// N = 1 => 6M + 6S + 9A610var a = this.curve.a;611var tinv = this.curve.tinv;612613var jx = this.x;614var jy = this.y;615var jz = this.z;616var jz4 = jz.redSqr().redSqr();617618// Reuse results619var jyd = jy.redAdd(jy);620for (var i = 0; i < pow; i++) {621var jx2 = jx.redSqr();622var jyd2 = jyd.redSqr();623var jyd4 = jyd2.redSqr();624var c = jx2.redAdd(jx2).redIAdd(jx2).redIAdd(a.redMul(jz4));625626var t1 = jx.redMul(jyd2);627var nx = c.redSqr().redISub(t1.redAdd(t1));628var t2 = t1.redISub(nx);629var dny = c.redMul(t2);630dny = dny.redIAdd(dny).redISub(jyd4);631var nz = jyd.redMul(jz);632if (i + 1 < pow)633jz4 = jz4.redMul(jyd4);634635jx = nx;636jz = nz;637jyd = dny;638}639640return this.curve.jpoint(jx, jyd.redMul(tinv), jz);641};642643JPoint.prototype.dbl = function dbl() {644if (this.isInfinity())645return this;646647if (this.curve.zeroA)648return this._zeroDbl();649else if (this.curve.threeA)650return this._threeDbl();651else652return this._dbl();653};654655JPoint.prototype._zeroDbl = function _zeroDbl() {656var nx;657var ny;658var nz;659// Z = 1660if (this.zOne) {661// hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html662// #doubling-mdbl-2007-bl663// 1M + 5S + 14A664665// XX = X1^2666var xx = this.x.redSqr();667// YY = Y1^2668var yy = this.y.redSqr();669// YYYY = YY^2670var yyyy = yy.redSqr();671// S = 2 * ((X1 + YY)^2 - XX - YYYY)672var s = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy);673s = s.redIAdd(s);674// M = 3 * XX + a; a = 0675var m = xx.redAdd(xx).redIAdd(xx);676// T = M ^ 2 - 2*S677var t = m.redSqr().redISub(s).redISub(s);678679// 8 * YYYY680var yyyy8 = yyyy.redIAdd(yyyy);681yyyy8 = yyyy8.redIAdd(yyyy8);682yyyy8 = yyyy8.redIAdd(yyyy8);683684// X3 = T685nx = t;686// Y3 = M * (S - T) - 8 * YYYY687ny = m.redMul(s.redISub(t)).redISub(yyyy8);688// Z3 = 2*Y1689nz = this.y.redAdd(this.y);690} else {691// hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html692// #doubling-dbl-2009-l693// 2M + 5S + 13A694695// A = X1^2696var a = this.x.redSqr();697// B = Y1^2698var b = this.y.redSqr();699// C = B^2700var c = b.redSqr();701// D = 2 * ((X1 + B)^2 - A - C)702var d = this.x.redAdd(b).redSqr().redISub(a).redISub(c);703d = d.redIAdd(d);704// E = 3 * A705var e = a.redAdd(a).redIAdd(a);706// F = E^2707var f = e.redSqr();708709// 8 * C710var c8 = c.redIAdd(c);711c8 = c8.redIAdd(c8);712c8 = c8.redIAdd(c8);713714// X3 = F - 2 * D715nx = f.redISub(d).redISub(d);716// Y3 = E * (D - X3) - 8 * C717ny = e.redMul(d.redISub(nx)).redISub(c8);718// Z3 = 2 * Y1 * Z1719nz = this.y.redMul(this.z);720nz = nz.redIAdd(nz);721}722723return this.curve.jpoint(nx, ny, nz);724};725726JPoint.prototype._threeDbl = function _threeDbl() {727var nx;728var ny;729var nz;730// Z = 1731if (this.zOne) {732// hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html733// #doubling-mdbl-2007-bl734// 1M + 5S + 15A735736// XX = X1^2737var xx = this.x.redSqr();738// YY = Y1^2739var yy = this.y.redSqr();740// YYYY = YY^2741var yyyy = yy.redSqr();742// S = 2 * ((X1 + YY)^2 - XX - YYYY)743var s = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy);744s = s.redIAdd(s);745// M = 3 * XX + a746var m = xx.redAdd(xx).redIAdd(xx).redIAdd(this.curve.a);747// T = M^2 - 2 * S748var t = m.redSqr().redISub(s).redISub(s);749// X3 = T750nx = t;751// Y3 = M * (S - T) - 8 * YYYY752var yyyy8 = yyyy.redIAdd(yyyy);753yyyy8 = yyyy8.redIAdd(yyyy8);754yyyy8 = yyyy8.redIAdd(yyyy8);755ny = m.redMul(s.redISub(t)).redISub(yyyy8);756// Z3 = 2 * Y1757nz = this.y.redAdd(this.y);758} else {759// hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b760// 3M + 5S761762// delta = Z1^2763var delta = this.z.redSqr();764// gamma = Y1^2765var gamma = this.y.redSqr();766// beta = X1 * gamma767var beta = this.x.redMul(gamma);768// alpha = 3 * (X1 - delta) * (X1 + delta)769var alpha = this.x.redSub(delta).redMul(this.x.redAdd(delta));770alpha = alpha.redAdd(alpha).redIAdd(alpha);771// X3 = alpha^2 - 8 * beta772var beta4 = beta.redIAdd(beta);773beta4 = beta4.redIAdd(beta4);774var beta8 = beta4.redAdd(beta4);775nx = alpha.redSqr().redISub(beta8);776// Z3 = (Y1 + Z1)^2 - gamma - delta777nz = this.y.redAdd(this.z).redSqr().redISub(gamma).redISub(delta);778// Y3 = alpha * (4 * beta - X3) - 8 * gamma^2779var ggamma8 = gamma.redSqr();780ggamma8 = ggamma8.redIAdd(ggamma8);781ggamma8 = ggamma8.redIAdd(ggamma8);782ggamma8 = ggamma8.redIAdd(ggamma8);783ny = alpha.redMul(beta4.redISub(nx)).redISub(ggamma8);784}785786return this.curve.jpoint(nx, ny, nz);787};788789JPoint.prototype._dbl = function _dbl() {790var a = this.curve.a;791792// 4M + 6S + 10A793var jx = this.x;794var jy = this.y;795var jz = this.z;796var jz4 = jz.redSqr().redSqr();797798var jx2 = jx.redSqr();799var jy2 = jy.redSqr();800801var c = jx2.redAdd(jx2).redIAdd(jx2).redIAdd(a.redMul(jz4));802803var jxd4 = jx.redAdd(jx);804jxd4 = jxd4.redIAdd(jxd4);805var t1 = jxd4.redMul(jy2);806var nx = c.redSqr().redISub(t1.redAdd(t1));807var t2 = t1.redISub(nx);808809var jyd8 = jy2.redSqr();810jyd8 = jyd8.redIAdd(jyd8);811jyd8 = jyd8.redIAdd(jyd8);812jyd8 = jyd8.redIAdd(jyd8);813var ny = c.redMul(t2).redISub(jyd8);814var nz = jy.redAdd(jy).redMul(jz);815816return this.curve.jpoint(nx, ny, nz);817};818819JPoint.prototype.trpl = function trpl() {820if (!this.curve.zeroA)821return this.dbl().add(this);822823// hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#tripling-tpl-2007-bl824// 5M + 10S + ...825826// XX = X1^2827var xx = this.x.redSqr();828// YY = Y1^2829var yy = this.y.redSqr();830// ZZ = Z1^2831var zz = this.z.redSqr();832// YYYY = YY^2833var yyyy = yy.redSqr();834// M = 3 * XX + a * ZZ2; a = 0835var m = xx.redAdd(xx).redIAdd(xx);836// MM = M^2837var mm = m.redSqr();838// E = 6 * ((X1 + YY)^2 - XX - YYYY) - MM839var e = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy);840e = e.redIAdd(e);841e = e.redAdd(e).redIAdd(e);842e = e.redISub(mm);843// EE = E^2844var ee = e.redSqr();845// T = 16*YYYY846var t = yyyy.redIAdd(yyyy);847t = t.redIAdd(t);848t = t.redIAdd(t);849t = t.redIAdd(t);850// U = (M + E)^2 - MM - EE - T851var u = m.redIAdd(e).redSqr().redISub(mm).redISub(ee).redISub(t);852// X3 = 4 * (X1 * EE - 4 * YY * U)853var yyu4 = yy.redMul(u);854yyu4 = yyu4.redIAdd(yyu4);855yyu4 = yyu4.redIAdd(yyu4);856var nx = this.x.redMul(ee).redISub(yyu4);857nx = nx.redIAdd(nx);858nx = nx.redIAdd(nx);859// Y3 = 8 * Y1 * (U * (T - U) - E * EE)860var ny = this.y.redMul(u.redMul(t.redISub(u)).redISub(e.redMul(ee)));861ny = ny.redIAdd(ny);862ny = ny.redIAdd(ny);863ny = ny.redIAdd(ny);864// Z3 = (Z1 + E)^2 - ZZ - EE865var nz = this.z.redAdd(e).redSqr().redISub(zz).redISub(ee);866867return this.curve.jpoint(nx, ny, nz);868};869870JPoint.prototype.mul = function mul(k, kbase) {871k = new bn(k, kbase);872873return this.curve._wnafMul(this, k);874};875876JPoint.prototype.eq = function eq(p) {877if (p.type === 'affine')878return this.eq(p.toJ());879880if (this === p)881return true;882883// x1 * z2^2 == x2 * z1^2884var z2 = this.z.redSqr();885var pz2 = p.z.redSqr();886if (this.x.redMul(pz2).redISub(p.x.redMul(z2)).cmpn(0) !== 0)887return false;888889// y1 * z2^3 == y2 * z1^3890var z3 = z2.redMul(this.z);891var pz3 = pz2.redMul(p.z);892return this.y.redMul(pz3).redISub(p.y.redMul(z3)).cmpn(0) === 0;893};894895JPoint.prototype.inspect = function inspect() {896if (this.isInfinity())897return '<EC JPoint Infinity>';898return '<EC JPoint x: ' + this.x.toString(16, 2) +899' y: ' + this.y.toString(16, 2) +900' z: ' + this.z.toString(16, 2) + '>';901};902903JPoint.prototype.isInfinity = function isInfinity() {904// XXX This code assumes that zero is always zero in red905return this.z.cmpn(0) === 0;906};907908909