short.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938
  1. 'use strict';
  2. var curve = require('../curve');
  3. var elliptic = require('../../elliptic');
  4. var BN = require('bn.js');
  5. var inherits = require('inherits');
  6. var Base = curve.base;
  7. var assert = elliptic.utils.assert;
  8. function ShortCurve(conf) {
  9. Base.call(this, 'short', conf);
  10. this.a = new BN(conf.a, 16).toRed(this.red);
  11. this.b = new BN(conf.b, 16).toRed(this.red);
  12. this.tinv = this.two.redInvm();
  13. this.zeroA = this.a.fromRed().cmpn(0) === 0;
  14. this.threeA = this.a.fromRed().sub(this.p).cmpn(-3) === 0;
  15. // If the curve is endomorphic, precalculate beta and lambda
  16. this.endo = this._getEndomorphism(conf);
  17. this._endoWnafT1 = new Array(4);
  18. this._endoWnafT2 = new Array(4);
  19. }
  20. inherits(ShortCurve, Base);
  21. module.exports = ShortCurve;
  22. ShortCurve.prototype._getEndomorphism = function _getEndomorphism(conf) {
  23. // No efficient endomorphism
  24. if (!this.zeroA || !this.g || !this.n || this.p.modn(3) !== 1)
  25. return;
  26. // Compute beta and lambda, that lambda * P = (beta * Px; Py)
  27. var beta;
  28. var lambda;
  29. if (conf.beta) {
  30. beta = new BN(conf.beta, 16).toRed(this.red);
  31. } else {
  32. var betas = this._getEndoRoots(this.p);
  33. // Choose the smallest beta
  34. beta = betas[0].cmp(betas[1]) < 0 ? betas[0] : betas[1];
  35. beta = beta.toRed(this.red);
  36. }
  37. if (conf.lambda) {
  38. lambda = new BN(conf.lambda, 16);
  39. } else {
  40. // Choose the lambda that is matching selected beta
  41. var lambdas = this._getEndoRoots(this.n);
  42. if (this.g.mul(lambdas[0]).x.cmp(this.g.x.redMul(beta)) === 0) {
  43. lambda = lambdas[0];
  44. } else {
  45. lambda = lambdas[1];
  46. assert(this.g.mul(lambda).x.cmp(this.g.x.redMul(beta)) === 0);
  47. }
  48. }
  49. // Get basis vectors, used for balanced length-two representation
  50. var basis;
  51. if (conf.basis) {
  52. basis = conf.basis.map(function(vec) {
  53. return {
  54. a: new BN(vec.a, 16),
  55. b: new BN(vec.b, 16)
  56. };
  57. });
  58. } else {
  59. basis = this._getEndoBasis(lambda);
  60. }
  61. return {
  62. beta: beta,
  63. lambda: lambda,
  64. basis: basis
  65. };
  66. };
  67. ShortCurve.prototype._getEndoRoots = function _getEndoRoots(num) {
  68. // Find roots of for x^2 + x + 1 in F
  69. // Root = (-1 +- Sqrt(-3)) / 2
  70. //
  71. var red = num === this.p ? this.red : BN.mont(num);
  72. var tinv = new BN(2).toRed(red).redInvm();
  73. var ntinv = tinv.redNeg();
  74. var s = new BN(3).toRed(red).redNeg().redSqrt().redMul(tinv);
  75. var l1 = ntinv.redAdd(s).fromRed();
  76. var l2 = ntinv.redSub(s).fromRed();
  77. return [ l1, l2 ];
  78. };
  79. ShortCurve.prototype._getEndoBasis = function _getEndoBasis(lambda) {
  80. // aprxSqrt >= sqrt(this.n)
  81. var aprxSqrt = this.n.ushrn(Math.floor(this.n.bitLength() / 2));
  82. // 3.74
  83. // Run EGCD, until r(L + 1) < aprxSqrt
  84. var u = lambda;
  85. var v = this.n.clone();
  86. var x1 = new BN(1);
  87. var y1 = new BN(0);
  88. var x2 = new BN(0);
  89. var y2 = new BN(1);
  90. // NOTE: all vectors are roots of: a + b * lambda = 0 (mod n)
  91. var a0;
  92. var b0;
  93. // First vector
  94. var a1;
  95. var b1;
  96. // Second vector
  97. var a2;
  98. var b2;
  99. var prevR;
  100. var i = 0;
  101. var r;
  102. var x;
  103. while (u.cmpn(0) !== 0) {
  104. var q = v.div(u);
  105. r = v.sub(q.mul(u));
  106. x = x2.sub(q.mul(x1));
  107. var y = y2.sub(q.mul(y1));
  108. if (!a1 && r.cmp(aprxSqrt) < 0) {
  109. a0 = prevR.neg();
  110. b0 = x1;
  111. a1 = r.neg();
  112. b1 = x;
  113. } else if (a1 && ++i === 2) {
  114. break;
  115. }
  116. prevR = r;
  117. v = u;
  118. u = r;
  119. x2 = x1;
  120. x1 = x;
  121. y2 = y1;
  122. y1 = y;
  123. }
  124. a2 = r.neg();
  125. b2 = x;
  126. var len1 = a1.sqr().add(b1.sqr());
  127. var len2 = a2.sqr().add(b2.sqr());
  128. if (len2.cmp(len1) >= 0) {
  129. a2 = a0;
  130. b2 = b0;
  131. }
  132. // Normalize signs
  133. if (a1.negative) {
  134. a1 = a1.neg();
  135. b1 = b1.neg();
  136. }
  137. if (a2.negative) {
  138. a2 = a2.neg();
  139. b2 = b2.neg();
  140. }
  141. return [
  142. { a: a1, b: b1 },
  143. { a: a2, b: b2 }
  144. ];
  145. };
  146. ShortCurve.prototype._endoSplit = function _endoSplit(k) {
  147. var basis = this.endo.basis;
  148. var v1 = basis[0];
  149. var v2 = basis[1];
  150. var c1 = v2.b.mul(k).divRound(this.n);
  151. var c2 = v1.b.neg().mul(k).divRound(this.n);
  152. var p1 = c1.mul(v1.a);
  153. var p2 = c2.mul(v2.a);
  154. var q1 = c1.mul(v1.b);
  155. var q2 = c2.mul(v2.b);
  156. // Calculate answer
  157. var k1 = k.sub(p1).sub(p2);
  158. var k2 = q1.add(q2).neg();
  159. return { k1: k1, k2: k2 };
  160. };
  161. ShortCurve.prototype.pointFromX = function pointFromX(x, odd) {
  162. x = new BN(x, 16);
  163. if (!x.red)
  164. x = x.toRed(this.red);
  165. var y2 = x.redSqr().redMul(x).redIAdd(x.redMul(this.a)).redIAdd(this.b);
  166. var y = y2.redSqrt();
  167. if (y.redSqr().redSub(y2).cmp(this.zero) !== 0)
  168. throw new Error('invalid point');
  169. // XXX Is there any way to tell if the number is odd without converting it
  170. // to non-red form?
  171. var isOdd = y.fromRed().isOdd();
  172. if (odd && !isOdd || !odd && isOdd)
  173. y = y.redNeg();
  174. return this.point(x, y);
  175. };
  176. ShortCurve.prototype.validate = function validate(point) {
  177. if (point.inf)
  178. return true;
  179. var x = point.x;
  180. var y = point.y;
  181. var ax = this.a.redMul(x);
  182. var rhs = x.redSqr().redMul(x).redIAdd(ax).redIAdd(this.b);
  183. return y.redSqr().redISub(rhs).cmpn(0) === 0;
  184. };
  185. ShortCurve.prototype._endoWnafMulAdd =
  186. function _endoWnafMulAdd(points, coeffs, jacobianResult) {
  187. var npoints = this._endoWnafT1;
  188. var ncoeffs = this._endoWnafT2;
  189. for (var i = 0; i < points.length; i++) {
  190. var split = this._endoSplit(coeffs[i]);
  191. var p = points[i];
  192. var beta = p._getBeta();
  193. if (split.k1.negative) {
  194. split.k1.ineg();
  195. p = p.neg(true);
  196. }
  197. if (split.k2.negative) {
  198. split.k2.ineg();
  199. beta = beta.neg(true);
  200. }
  201. npoints[i * 2] = p;
  202. npoints[i * 2 + 1] = beta;
  203. ncoeffs[i * 2] = split.k1;
  204. ncoeffs[i * 2 + 1] = split.k2;
  205. }
  206. var res = this._wnafMulAdd(1, npoints, ncoeffs, i * 2, jacobianResult);
  207. // Clean-up references to points and coefficients
  208. for (var j = 0; j < i * 2; j++) {
  209. npoints[j] = null;
  210. ncoeffs[j] = null;
  211. }
  212. return res;
  213. };
  214. function Point(curve, x, y, isRed) {
  215. Base.BasePoint.call(this, curve, 'affine');
  216. if (x === null && y === null) {
  217. this.x = null;
  218. this.y = null;
  219. this.inf = true;
  220. } else {
  221. this.x = new BN(x, 16);
  222. this.y = new BN(y, 16);
  223. // Force redgomery representation when loading from JSON
  224. if (isRed) {
  225. this.x.forceRed(this.curve.red);
  226. this.y.forceRed(this.curve.red);
  227. }
  228. if (!this.x.red)
  229. this.x = this.x.toRed(this.curve.red);
  230. if (!this.y.red)
  231. this.y = this.y.toRed(this.curve.red);
  232. this.inf = false;
  233. }
  234. }
  235. inherits(Point, Base.BasePoint);
  236. ShortCurve.prototype.point = function point(x, y, isRed) {
  237. return new Point(this, x, y, isRed);
  238. };
  239. ShortCurve.prototype.pointFromJSON = function pointFromJSON(obj, red) {
  240. return Point.fromJSON(this, obj, red);
  241. };
  242. Point.prototype._getBeta = function _getBeta() {
  243. if (!this.curve.endo)
  244. return;
  245. var pre = this.precomputed;
  246. if (pre && pre.beta)
  247. return pre.beta;
  248. var beta = this.curve.point(this.x.redMul(this.curve.endo.beta), this.y);
  249. if (pre) {
  250. var curve = this.curve;
  251. var endoMul = function(p) {
  252. return curve.point(p.x.redMul(curve.endo.beta), p.y);
  253. };
  254. pre.beta = beta;
  255. beta.precomputed = {
  256. beta: null,
  257. naf: pre.naf && {
  258. wnd: pre.naf.wnd,
  259. points: pre.naf.points.map(endoMul)
  260. },
  261. doubles: pre.doubles && {
  262. step: pre.doubles.step,
  263. points: pre.doubles.points.map(endoMul)
  264. }
  265. };
  266. }
  267. return beta;
  268. };
  269. Point.prototype.toJSON = function toJSON() {
  270. if (!this.precomputed)
  271. return [ this.x, this.y ];
  272. return [ this.x, this.y, this.precomputed && {
  273. doubles: this.precomputed.doubles && {
  274. step: this.precomputed.doubles.step,
  275. points: this.precomputed.doubles.points.slice(1)
  276. },
  277. naf: this.precomputed.naf && {
  278. wnd: this.precomputed.naf.wnd,
  279. points: this.precomputed.naf.points.slice(1)
  280. }
  281. } ];
  282. };
  283. Point.fromJSON = function fromJSON(curve, obj, red) {
  284. if (typeof obj === 'string')
  285. obj = JSON.parse(obj);
  286. var res = curve.point(obj[0], obj[1], red);
  287. if (!obj[2])
  288. return res;
  289. function obj2point(obj) {
  290. return curve.point(obj[0], obj[1], red);
  291. }
  292. var pre = obj[2];
  293. res.precomputed = {
  294. beta: null,
  295. doubles: pre.doubles && {
  296. step: pre.doubles.step,
  297. points: [ res ].concat(pre.doubles.points.map(obj2point))
  298. },
  299. naf: pre.naf && {
  300. wnd: pre.naf.wnd,
  301. points: [ res ].concat(pre.naf.points.map(obj2point))
  302. }
  303. };
  304. return res;
  305. };
  306. Point.prototype.inspect = function inspect() {
  307. if (this.isInfinity())
  308. return '<EC Point Infinity>';
  309. return '<EC Point x: ' + this.x.fromRed().toString(16, 2) +
  310. ' y: ' + this.y.fromRed().toString(16, 2) + '>';
  311. };
  312. Point.prototype.isInfinity = function isInfinity() {
  313. return this.inf;
  314. };
  315. Point.prototype.add = function add(p) {
  316. // O + P = P
  317. if (this.inf)
  318. return p;
  319. // P + O = P
  320. if (p.inf)
  321. return this;
  322. // P + P = 2P
  323. if (this.eq(p))
  324. return this.dbl();
  325. // P + (-P) = O
  326. if (this.neg().eq(p))
  327. return this.curve.point(null, null);
  328. // P + Q = O
  329. if (this.x.cmp(p.x) === 0)
  330. return this.curve.point(null, null);
  331. var c = this.y.redSub(p.y);
  332. if (c.cmpn(0) !== 0)
  333. c = c.redMul(this.x.redSub(p.x).redInvm());
  334. var nx = c.redSqr().redISub(this.x).redISub(p.x);
  335. var ny = c.redMul(this.x.redSub(nx)).redISub(this.y);
  336. return this.curve.point(nx, ny);
  337. };
  338. Point.prototype.dbl = function dbl() {
  339. if (this.inf)
  340. return this;
  341. // 2P = O
  342. var ys1 = this.y.redAdd(this.y);
  343. if (ys1.cmpn(0) === 0)
  344. return this.curve.point(null, null);
  345. var a = this.curve.a;
  346. var x2 = this.x.redSqr();
  347. var dyinv = ys1.redInvm();
  348. var c = x2.redAdd(x2).redIAdd(x2).redIAdd(a).redMul(dyinv);
  349. var nx = c.redSqr().redISub(this.x.redAdd(this.x));
  350. var ny = c.redMul(this.x.redSub(nx)).redISub(this.y);
  351. return this.curve.point(nx, ny);
  352. };
  353. Point.prototype.getX = function getX() {
  354. return this.x.fromRed();
  355. };
  356. Point.prototype.getY = function getY() {
  357. return this.y.fromRed();
  358. };
  359. Point.prototype.mul = function mul(k) {
  360. k = new BN(k, 16);
  361. if (this._hasDoubles(k))
  362. return this.curve._fixedNafMul(this, k);
  363. else if (this.curve.endo)
  364. return this.curve._endoWnafMulAdd([ this ], [ k ]);
  365. else
  366. return this.curve._wnafMul(this, k);
  367. };
  368. Point.prototype.mulAdd = function mulAdd(k1, p2, k2) {
  369. var points = [ this, p2 ];
  370. var coeffs = [ k1, k2 ];
  371. if (this.curve.endo)
  372. return this.curve._endoWnafMulAdd(points, coeffs);
  373. else
  374. return this.curve._wnafMulAdd(1, points, coeffs, 2);
  375. };
  376. Point.prototype.jmulAdd = function jmulAdd(k1, p2, k2) {
  377. var points = [ this, p2 ];
  378. var coeffs = [ k1, k2 ];
  379. if (this.curve.endo)
  380. return this.curve._endoWnafMulAdd(points, coeffs, true);
  381. else
  382. return this.curve._wnafMulAdd(1, points, coeffs, 2, true);
  383. };
  384. Point.prototype.eq = function eq(p) {
  385. return this === p ||
  386. this.inf === p.inf &&
  387. (this.inf || this.x.cmp(p.x) === 0 && this.y.cmp(p.y) === 0);
  388. };
  389. Point.prototype.neg = function neg(_precompute) {
  390. if (this.inf)
  391. return this;
  392. var res = this.curve.point(this.x, this.y.redNeg());
  393. if (_precompute && this.precomputed) {
  394. var pre = this.precomputed;
  395. var negate = function(p) {
  396. return p.neg();
  397. };
  398. res.precomputed = {
  399. naf: pre.naf && {
  400. wnd: pre.naf.wnd,
  401. points: pre.naf.points.map(negate)
  402. },
  403. doubles: pre.doubles && {
  404. step: pre.doubles.step,
  405. points: pre.doubles.points.map(negate)
  406. }
  407. };
  408. }
  409. return res;
  410. };
  411. Point.prototype.toJ = function toJ() {
  412. if (this.inf)
  413. return this.curve.jpoint(null, null, null);
  414. var res = this.curve.jpoint(this.x, this.y, this.curve.one);
  415. return res;
  416. };
  417. function JPoint(curve, x, y, z) {
  418. Base.BasePoint.call(this, curve, 'jacobian');
  419. if (x === null && y === null && z === null) {
  420. this.x = this.curve.one;
  421. this.y = this.curve.one;
  422. this.z = new BN(0);
  423. } else {
  424. this.x = new BN(x, 16);
  425. this.y = new BN(y, 16);
  426. this.z = new BN(z, 16);
  427. }
  428. if (!this.x.red)
  429. this.x = this.x.toRed(this.curve.red);
  430. if (!this.y.red)
  431. this.y = this.y.toRed(this.curve.red);
  432. if (!this.z.red)
  433. this.z = this.z.toRed(this.curve.red);
  434. this.zOne = this.z === this.curve.one;
  435. }
  436. inherits(JPoint, Base.BasePoint);
  437. ShortCurve.prototype.jpoint = function jpoint(x, y, z) {
  438. return new JPoint(this, x, y, z);
  439. };
  440. JPoint.prototype.toP = function toP() {
  441. if (this.isInfinity())
  442. return this.curve.point(null, null);
  443. var zinv = this.z.redInvm();
  444. var zinv2 = zinv.redSqr();
  445. var ax = this.x.redMul(zinv2);
  446. var ay = this.y.redMul(zinv2).redMul(zinv);
  447. return this.curve.point(ax, ay);
  448. };
  449. JPoint.prototype.neg = function neg() {
  450. return this.curve.jpoint(this.x, this.y.redNeg(), this.z);
  451. };
  452. JPoint.prototype.add = function add(p) {
  453. // O + P = P
  454. if (this.isInfinity())
  455. return p;
  456. // P + O = P
  457. if (p.isInfinity())
  458. return this;
  459. // 12M + 4S + 7A
  460. var pz2 = p.z.redSqr();
  461. var z2 = this.z.redSqr();
  462. var u1 = this.x.redMul(pz2);
  463. var u2 = p.x.redMul(z2);
  464. var s1 = this.y.redMul(pz2.redMul(p.z));
  465. var s2 = p.y.redMul(z2.redMul(this.z));
  466. var h = u1.redSub(u2);
  467. var r = s1.redSub(s2);
  468. if (h.cmpn(0) === 0) {
  469. if (r.cmpn(0) !== 0)
  470. return this.curve.jpoint(null, null, null);
  471. else
  472. return this.dbl();
  473. }
  474. var h2 = h.redSqr();
  475. var h3 = h2.redMul(h);
  476. var v = u1.redMul(h2);
  477. var nx = r.redSqr().redIAdd(h3).redISub(v).redISub(v);
  478. var ny = r.redMul(v.redISub(nx)).redISub(s1.redMul(h3));
  479. var nz = this.z.redMul(p.z).redMul(h);
  480. return this.curve.jpoint(nx, ny, nz);
  481. };
  482. JPoint.prototype.mixedAdd = function mixedAdd(p) {
  483. // O + P = P
  484. if (this.isInfinity())
  485. return p.toJ();
  486. // P + O = P
  487. if (p.isInfinity())
  488. return this;
  489. // 8M + 3S + 7A
  490. var z2 = this.z.redSqr();
  491. var u1 = this.x;
  492. var u2 = p.x.redMul(z2);
  493. var s1 = this.y;
  494. var s2 = p.y.redMul(z2).redMul(this.z);
  495. var h = u1.redSub(u2);
  496. var r = s1.redSub(s2);
  497. if (h.cmpn(0) === 0) {
  498. if (r.cmpn(0) !== 0)
  499. return this.curve.jpoint(null, null, null);
  500. else
  501. return this.dbl();
  502. }
  503. var h2 = h.redSqr();
  504. var h3 = h2.redMul(h);
  505. var v = u1.redMul(h2);
  506. var nx = r.redSqr().redIAdd(h3).redISub(v).redISub(v);
  507. var ny = r.redMul(v.redISub(nx)).redISub(s1.redMul(h3));
  508. var nz = this.z.redMul(h);
  509. return this.curve.jpoint(nx, ny, nz);
  510. };
  511. JPoint.prototype.dblp = function dblp(pow) {
  512. if (pow === 0)
  513. return this;
  514. if (this.isInfinity())
  515. return this;
  516. if (!pow)
  517. return this.dbl();
  518. if (this.curve.zeroA || this.curve.threeA) {
  519. var r = this;
  520. for (var i = 0; i < pow; i++)
  521. r = r.dbl();
  522. return r;
  523. }
  524. // 1M + 2S + 1A + N * (4S + 5M + 8A)
  525. // N = 1 => 6M + 6S + 9A
  526. var a = this.curve.a;
  527. var tinv = this.curve.tinv;
  528. var jx = this.x;
  529. var jy = this.y;
  530. var jz = this.z;
  531. var jz4 = jz.redSqr().redSqr();
  532. // Reuse results
  533. var jyd = jy.redAdd(jy);
  534. for (var i = 0; i < pow; i++) {
  535. var jx2 = jx.redSqr();
  536. var jyd2 = jyd.redSqr();
  537. var jyd4 = jyd2.redSqr();
  538. var c = jx2.redAdd(jx2).redIAdd(jx2).redIAdd(a.redMul(jz4));
  539. var t1 = jx.redMul(jyd2);
  540. var nx = c.redSqr().redISub(t1.redAdd(t1));
  541. var t2 = t1.redISub(nx);
  542. var dny = c.redMul(t2);
  543. dny = dny.redIAdd(dny).redISub(jyd4);
  544. var nz = jyd.redMul(jz);
  545. if (i + 1 < pow)
  546. jz4 = jz4.redMul(jyd4);
  547. jx = nx;
  548. jz = nz;
  549. jyd = dny;
  550. }
  551. return this.curve.jpoint(jx, jyd.redMul(tinv), jz);
  552. };
  553. JPoint.prototype.dbl = function dbl() {
  554. if (this.isInfinity())
  555. return this;
  556. if (this.curve.zeroA)
  557. return this._zeroDbl();
  558. else if (this.curve.threeA)
  559. return this._threeDbl();
  560. else
  561. return this._dbl();
  562. };
  563. JPoint.prototype._zeroDbl = function _zeroDbl() {
  564. var nx;
  565. var ny;
  566. var nz;
  567. // Z = 1
  568. if (this.zOne) {
  569. // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html
  570. // #doubling-mdbl-2007-bl
  571. // 1M + 5S + 14A
  572. // XX = X1^2
  573. var xx = this.x.redSqr();
  574. // YY = Y1^2
  575. var yy = this.y.redSqr();
  576. // YYYY = YY^2
  577. var yyyy = yy.redSqr();
  578. // S = 2 * ((X1 + YY)^2 - XX - YYYY)
  579. var s = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy);
  580. s = s.redIAdd(s);
  581. // M = 3 * XX + a; a = 0
  582. var m = xx.redAdd(xx).redIAdd(xx);
  583. // T = M ^ 2 - 2*S
  584. var t = m.redSqr().redISub(s).redISub(s);
  585. // 8 * YYYY
  586. var yyyy8 = yyyy.redIAdd(yyyy);
  587. yyyy8 = yyyy8.redIAdd(yyyy8);
  588. yyyy8 = yyyy8.redIAdd(yyyy8);
  589. // X3 = T
  590. nx = t;
  591. // Y3 = M * (S - T) - 8 * YYYY
  592. ny = m.redMul(s.redISub(t)).redISub(yyyy8);
  593. // Z3 = 2*Y1
  594. nz = this.y.redAdd(this.y);
  595. } else {
  596. // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html
  597. // #doubling-dbl-2009-l
  598. // 2M + 5S + 13A
  599. // A = X1^2
  600. var a = this.x.redSqr();
  601. // B = Y1^2
  602. var b = this.y.redSqr();
  603. // C = B^2
  604. var c = b.redSqr();
  605. // D = 2 * ((X1 + B)^2 - A - C)
  606. var d = this.x.redAdd(b).redSqr().redISub(a).redISub(c);
  607. d = d.redIAdd(d);
  608. // E = 3 * A
  609. var e = a.redAdd(a).redIAdd(a);
  610. // F = E^2
  611. var f = e.redSqr();
  612. // 8 * C
  613. var c8 = c.redIAdd(c);
  614. c8 = c8.redIAdd(c8);
  615. c8 = c8.redIAdd(c8);
  616. // X3 = F - 2 * D
  617. nx = f.redISub(d).redISub(d);
  618. // Y3 = E * (D - X3) - 8 * C
  619. ny = e.redMul(d.redISub(nx)).redISub(c8);
  620. // Z3 = 2 * Y1 * Z1
  621. nz = this.y.redMul(this.z);
  622. nz = nz.redIAdd(nz);
  623. }
  624. return this.curve.jpoint(nx, ny, nz);
  625. };
  626. JPoint.prototype._threeDbl = function _threeDbl() {
  627. var nx;
  628. var ny;
  629. var nz;
  630. // Z = 1
  631. if (this.zOne) {
  632. // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html
  633. // #doubling-mdbl-2007-bl
  634. // 1M + 5S + 15A
  635. // XX = X1^2
  636. var xx = this.x.redSqr();
  637. // YY = Y1^2
  638. var yy = this.y.redSqr();
  639. // YYYY = YY^2
  640. var yyyy = yy.redSqr();
  641. // S = 2 * ((X1 + YY)^2 - XX - YYYY)
  642. var s = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy);
  643. s = s.redIAdd(s);
  644. // M = 3 * XX + a
  645. var m = xx.redAdd(xx).redIAdd(xx).redIAdd(this.curve.a);
  646. // T = M^2 - 2 * S
  647. var t = m.redSqr().redISub(s).redISub(s);
  648. // X3 = T
  649. nx = t;
  650. // Y3 = M * (S - T) - 8 * YYYY
  651. var yyyy8 = yyyy.redIAdd(yyyy);
  652. yyyy8 = yyyy8.redIAdd(yyyy8);
  653. yyyy8 = yyyy8.redIAdd(yyyy8);
  654. ny = m.redMul(s.redISub(t)).redISub(yyyy8);
  655. // Z3 = 2 * Y1
  656. nz = this.y.redAdd(this.y);
  657. } else {
  658. // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b
  659. // 3M + 5S
  660. // delta = Z1^2
  661. var delta = this.z.redSqr();
  662. // gamma = Y1^2
  663. var gamma = this.y.redSqr();
  664. // beta = X1 * gamma
  665. var beta = this.x.redMul(gamma);
  666. // alpha = 3 * (X1 - delta) * (X1 + delta)
  667. var alpha = this.x.redSub(delta).redMul(this.x.redAdd(delta));
  668. alpha = alpha.redAdd(alpha).redIAdd(alpha);
  669. // X3 = alpha^2 - 8 * beta
  670. var beta4 = beta.redIAdd(beta);
  671. beta4 = beta4.redIAdd(beta4);
  672. var beta8 = beta4.redAdd(beta4);
  673. nx = alpha.redSqr().redISub(beta8);
  674. // Z3 = (Y1 + Z1)^2 - gamma - delta
  675. nz = this.y.redAdd(this.z).redSqr().redISub(gamma).redISub(delta);
  676. // Y3 = alpha * (4 * beta - X3) - 8 * gamma^2
  677. var ggamma8 = gamma.redSqr();
  678. ggamma8 = ggamma8.redIAdd(ggamma8);
  679. ggamma8 = ggamma8.redIAdd(ggamma8);
  680. ggamma8 = ggamma8.redIAdd(ggamma8);
  681. ny = alpha.redMul(beta4.redISub(nx)).redISub(ggamma8);
  682. }
  683. return this.curve.jpoint(nx, ny, nz);
  684. };
  685. JPoint.prototype._dbl = function _dbl() {
  686. var a = this.curve.a;
  687. // 4M + 6S + 10A
  688. var jx = this.x;
  689. var jy = this.y;
  690. var jz = this.z;
  691. var jz4 = jz.redSqr().redSqr();
  692. var jx2 = jx.redSqr();
  693. var jy2 = jy.redSqr();
  694. var c = jx2.redAdd(jx2).redIAdd(jx2).redIAdd(a.redMul(jz4));
  695. var jxd4 = jx.redAdd(jx);
  696. jxd4 = jxd4.redIAdd(jxd4);
  697. var t1 = jxd4.redMul(jy2);
  698. var nx = c.redSqr().redISub(t1.redAdd(t1));
  699. var t2 = t1.redISub(nx);
  700. var jyd8 = jy2.redSqr();
  701. jyd8 = jyd8.redIAdd(jyd8);
  702. jyd8 = jyd8.redIAdd(jyd8);
  703. jyd8 = jyd8.redIAdd(jyd8);
  704. var ny = c.redMul(t2).redISub(jyd8);
  705. var nz = jy.redAdd(jy).redMul(jz);
  706. return this.curve.jpoint(nx, ny, nz);
  707. };
  708. JPoint.prototype.trpl = function trpl() {
  709. if (!this.curve.zeroA)
  710. return this.dbl().add(this);
  711. // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#tripling-tpl-2007-bl
  712. // 5M + 10S + ...
  713. // XX = X1^2
  714. var xx = this.x.redSqr();
  715. // YY = Y1^2
  716. var yy = this.y.redSqr();
  717. // ZZ = Z1^2
  718. var zz = this.z.redSqr();
  719. // YYYY = YY^2
  720. var yyyy = yy.redSqr();
  721. // M = 3 * XX + a * ZZ2; a = 0
  722. var m = xx.redAdd(xx).redIAdd(xx);
  723. // MM = M^2
  724. var mm = m.redSqr();
  725. // E = 6 * ((X1 + YY)^2 - XX - YYYY) - MM
  726. var e = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy);
  727. e = e.redIAdd(e);
  728. e = e.redAdd(e).redIAdd(e);
  729. e = e.redISub(mm);
  730. // EE = E^2
  731. var ee = e.redSqr();
  732. // T = 16*YYYY
  733. var t = yyyy.redIAdd(yyyy);
  734. t = t.redIAdd(t);
  735. t = t.redIAdd(t);
  736. t = t.redIAdd(t);
  737. // U = (M + E)^2 - MM - EE - T
  738. var u = m.redIAdd(e).redSqr().redISub(mm).redISub(ee).redISub(t);
  739. // X3 = 4 * (X1 * EE - 4 * YY * U)
  740. var yyu4 = yy.redMul(u);
  741. yyu4 = yyu4.redIAdd(yyu4);
  742. yyu4 = yyu4.redIAdd(yyu4);
  743. var nx = this.x.redMul(ee).redISub(yyu4);
  744. nx = nx.redIAdd(nx);
  745. nx = nx.redIAdd(nx);
  746. // Y3 = 8 * Y1 * (U * (T - U) - E * EE)
  747. var ny = this.y.redMul(u.redMul(t.redISub(u)).redISub(e.redMul(ee)));
  748. ny = ny.redIAdd(ny);
  749. ny = ny.redIAdd(ny);
  750. ny = ny.redIAdd(ny);
  751. // Z3 = (Z1 + E)^2 - ZZ - EE
  752. var nz = this.z.redAdd(e).redSqr().redISub(zz).redISub(ee);
  753. return this.curve.jpoint(nx, ny, nz);
  754. };
  755. JPoint.prototype.mul = function mul(k, kbase) {
  756. k = new BN(k, kbase);
  757. return this.curve._wnafMul(this, k);
  758. };
  759. JPoint.prototype.eq = function eq(p) {
  760. if (p.type === 'affine')
  761. return this.eq(p.toJ());
  762. if (this === p)
  763. return true;
  764. // x1 * z2^2 == x2 * z1^2
  765. var z2 = this.z.redSqr();
  766. var pz2 = p.z.redSqr();
  767. if (this.x.redMul(pz2).redISub(p.x.redMul(z2)).cmpn(0) !== 0)
  768. return false;
  769. // y1 * z2^3 == y2 * z1^3
  770. var z3 = z2.redMul(this.z);
  771. var pz3 = pz2.redMul(p.z);
  772. return this.y.redMul(pz3).redISub(p.y.redMul(z3)).cmpn(0) === 0;
  773. };
  774. JPoint.prototype.eqXToP = function eqXToP(x) {
  775. var zs = this.z.redSqr();
  776. var rx = x.toRed(this.curve.red).redMul(zs);
  777. if (this.x.cmp(rx) === 0)
  778. return true;
  779. var xc = x.clone();
  780. var t = this.curve.redN.redMul(zs);
  781. for (;;) {
  782. xc.iadd(this.curve.n);
  783. if (xc.cmp(this.curve.p) >= 0)
  784. return false;
  785. rx.redIAdd(t);
  786. if (this.x.cmp(rx) === 0)
  787. return true;
  788. }
  789. return false;
  790. };
  791. JPoint.prototype.inspect = function inspect() {
  792. if (this.isInfinity())
  793. return '<EC JPoint Infinity>';
  794. return '<EC JPoint x: ' + this.x.toString(16, 2) +
  795. ' y: ' + this.y.toString(16, 2) +
  796. ' z: ' + this.z.toString(16, 2) + '>';
  797. };
  798. JPoint.prototype.isInfinity = function isInfinity() {
  799. // XXX This code assumes that zero is always zero in red
  800. return this.z.cmpn(0) === 0;
  801. };