short.js 22 KB

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