f5501242ab2d76b3c93be2800ae9582891d924af8baaad265b104fe5c119e77d34a29589d59ec9b8e1f52d790de9fc38e265e6b3dda6b551c4a25f6af76495 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  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 EdwardsCurve(conf) {
  8. // NOTE: Important as we are creating point in Base.call()
  9. this.twisted = (conf.a | 0) !== 1;
  10. this.mOneA = this.twisted && (conf.a | 0) === -1;
  11. this.extended = this.mOneA;
  12. Base.call(this, 'edwards', conf);
  13. this.a = new BN(conf.a, 16).umod(this.red.m);
  14. this.a = this.a.toRed(this.red);
  15. this.c = new BN(conf.c, 16).toRed(this.red);
  16. this.c2 = this.c.redSqr();
  17. this.d = new BN(conf.d, 16).toRed(this.red);
  18. this.dd = this.d.redAdd(this.d);
  19. assert(!this.twisted || this.c.fromRed().cmpn(1) === 0);
  20. this.oneC = (conf.c | 0) === 1;
  21. }
  22. inherits(EdwardsCurve, Base);
  23. module.exports = EdwardsCurve;
  24. EdwardsCurve.prototype._mulA = function _mulA(num) {
  25. if (this.mOneA)
  26. return num.redNeg();
  27. else
  28. return this.a.redMul(num);
  29. };
  30. EdwardsCurve.prototype._mulC = function _mulC(num) {
  31. if (this.oneC)
  32. return num;
  33. else
  34. return this.c.redMul(num);
  35. };
  36. // Just for compatibility with Short curve
  37. EdwardsCurve.prototype.jpoint = function jpoint(x, y, z, t) {
  38. return this.point(x, y, z, t);
  39. };
  40. EdwardsCurve.prototype.pointFromX = function pointFromX(x, odd) {
  41. x = new BN(x, 16);
  42. if (!x.red)
  43. x = x.toRed(this.red);
  44. var x2 = x.redSqr();
  45. var rhs = this.c2.redSub(this.a.redMul(x2));
  46. var lhs = this.one.redSub(this.c2.redMul(this.d).redMul(x2));
  47. var y2 = rhs.redMul(lhs.redInvm());
  48. var y = y2.redSqrt();
  49. if (y.redSqr().redSub(y2).cmp(this.zero) !== 0)
  50. throw new Error('invalid point');
  51. var isOdd = y.fromRed().isOdd();
  52. if (odd && !isOdd || !odd && isOdd)
  53. y = y.redNeg();
  54. return this.point(x, y);
  55. };
  56. EdwardsCurve.prototype.pointFromY = function pointFromY(y, odd) {
  57. y = new BN(y, 16);
  58. if (!y.red)
  59. y = y.toRed(this.red);
  60. // x^2 = (y^2 - c^2) / (c^2 d y^2 - a)
  61. var y2 = y.redSqr();
  62. var lhs = y2.redSub(this.c2);
  63. var rhs = y2.redMul(this.d).redMul(this.c2).redSub(this.a);
  64. var x2 = lhs.redMul(rhs.redInvm());
  65. if (x2.cmp(this.zero) === 0) {
  66. if (odd)
  67. throw new Error('invalid point');
  68. else
  69. return this.point(this.zero, y);
  70. }
  71. var x = x2.redSqrt();
  72. if (x.redSqr().redSub(x2).cmp(this.zero) !== 0)
  73. throw new Error('invalid point');
  74. if (x.fromRed().isOdd() !== odd)
  75. x = x.redNeg();
  76. return this.point(x, y);
  77. };
  78. EdwardsCurve.prototype.validate = function validate(point) {
  79. if (point.isInfinity())
  80. return true;
  81. // Curve: A * X^2 + Y^2 = C^2 * (1 + D * X^2 * Y^2)
  82. point.normalize();
  83. var x2 = point.x.redSqr();
  84. var y2 = point.y.redSqr();
  85. var lhs = x2.redMul(this.a).redAdd(y2);
  86. var rhs = this.c2.redMul(this.one.redAdd(this.d.redMul(x2).redMul(y2)));
  87. return lhs.cmp(rhs) === 0;
  88. };
  89. function Point(curve, x, y, z, t) {
  90. Base.BasePoint.call(this, curve, 'projective');
  91. if (x === null && y === null && z === null) {
  92. this.x = this.curve.zero;
  93. this.y = this.curve.one;
  94. this.z = this.curve.one;
  95. this.t = this.curve.zero;
  96. this.zOne = true;
  97. } else {
  98. this.x = new BN(x, 16);
  99. this.y = new BN(y, 16);
  100. this.z = z ? new BN(z, 16) : this.curve.one;
  101. this.t = t && new BN(t, 16);
  102. if (!this.x.red)
  103. this.x = this.x.toRed(this.curve.red);
  104. if (!this.y.red)
  105. this.y = this.y.toRed(this.curve.red);
  106. if (!this.z.red)
  107. this.z = this.z.toRed(this.curve.red);
  108. if (this.t && !this.t.red)
  109. this.t = this.t.toRed(this.curve.red);
  110. this.zOne = this.z === this.curve.one;
  111. // Use extended coordinates
  112. if (this.curve.extended && !this.t) {
  113. this.t = this.x.redMul(this.y);
  114. if (!this.zOne)
  115. this.t = this.t.redMul(this.z.redInvm());
  116. }
  117. }
  118. }
  119. inherits(Point, Base.BasePoint);
  120. EdwardsCurve.prototype.pointFromJSON = function pointFromJSON(obj) {
  121. return Point.fromJSON(this, obj);
  122. };
  123. EdwardsCurve.prototype.point = function point(x, y, z, t) {
  124. return new Point(this, x, y, z, t);
  125. };
  126. Point.fromJSON = function fromJSON(curve, obj) {
  127. return new Point(curve, obj[0], obj[1], obj[2]);
  128. };
  129. Point.prototype.inspect = function inspect() {
  130. if (this.isInfinity())
  131. return '<EC Point Infinity>';
  132. return '<EC Point x: ' + this.x.fromRed().toString(16, 2) +
  133. ' y: ' + this.y.fromRed().toString(16, 2) +
  134. ' z: ' + this.z.fromRed().toString(16, 2) + '>';
  135. };
  136. Point.prototype.isInfinity = function isInfinity() {
  137. // XXX This code assumes that zero is always zero in red
  138. return this.x.cmpn(0) === 0 &&
  139. (this.y.cmp(this.z) === 0 ||
  140. (this.zOne && this.y.cmp(this.curve.c) === 0));
  141. };
  142. Point.prototype._extDbl = function _extDbl() {
  143. // hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html
  144. // #doubling-dbl-2008-hwcd
  145. // 4M + 4S
  146. // A = X1^2
  147. var a = this.x.redSqr();
  148. // B = Y1^2
  149. var b = this.y.redSqr();
  150. // C = 2 * Z1^2
  151. var c = this.z.redSqr();
  152. c = c.redIAdd(c);
  153. // D = a * A
  154. var d = this.curve._mulA(a);
  155. // E = (X1 + Y1)^2 - A - B
  156. var e = this.x.redAdd(this.y).redSqr().redISub(a).redISub(b);
  157. // G = D + B
  158. var g = d.redAdd(b);
  159. // F = G - C
  160. var f = g.redSub(c);
  161. // H = D - B
  162. var h = d.redSub(b);
  163. // X3 = E * F
  164. var nx = e.redMul(f);
  165. // Y3 = G * H
  166. var ny = g.redMul(h);
  167. // T3 = E * H
  168. var nt = e.redMul(h);
  169. // Z3 = F * G
  170. var nz = f.redMul(g);
  171. return this.curve.point(nx, ny, nz, nt);
  172. };
  173. Point.prototype._projDbl = function _projDbl() {
  174. // hyperelliptic.org/EFD/g1p/auto-twisted-projective.html
  175. // #doubling-dbl-2008-bbjlp
  176. // #doubling-dbl-2007-bl
  177. // and others
  178. // Generally 3M + 4S or 2M + 4S
  179. // B = (X1 + Y1)^2
  180. var b = this.x.redAdd(this.y).redSqr();
  181. // C = X1^2
  182. var c = this.x.redSqr();
  183. // D = Y1^2
  184. var d = this.y.redSqr();
  185. var nx;
  186. var ny;
  187. var nz;
  188. var e;
  189. var h;
  190. var j;
  191. if (this.curve.twisted) {
  192. // E = a * C
  193. e = this.curve._mulA(c);
  194. // F = E + D
  195. var f = e.redAdd(d);
  196. if (this.zOne) {
  197. // X3 = (B - C - D) * (F - 2)
  198. nx = b.redSub(c).redSub(d).redMul(f.redSub(this.curve.two));
  199. // Y3 = F * (E - D)
  200. ny = f.redMul(e.redSub(d));
  201. // Z3 = F^2 - 2 * F
  202. nz = f.redSqr().redSub(f).redSub(f);
  203. } else {
  204. // H = Z1^2
  205. h = this.z.redSqr();
  206. // J = F - 2 * H
  207. j = f.redSub(h).redISub(h);
  208. // X3 = (B-C-D)*J
  209. nx = b.redSub(c).redISub(d).redMul(j);
  210. // Y3 = F * (E - D)
  211. ny = f.redMul(e.redSub(d));
  212. // Z3 = F * J
  213. nz = f.redMul(j);
  214. }
  215. } else {
  216. // E = C + D
  217. e = c.redAdd(d);
  218. // H = (c * Z1)^2
  219. h = this.curve._mulC(this.z).redSqr();
  220. // J = E - 2 * H
  221. j = e.redSub(h).redSub(h);
  222. // X3 = c * (B - E) * J
  223. nx = this.curve._mulC(b.redISub(e)).redMul(j);
  224. // Y3 = c * E * (C - D)
  225. ny = this.curve._mulC(e).redMul(c.redISub(d));
  226. // Z3 = E * J
  227. nz = e.redMul(j);
  228. }
  229. return this.curve.point(nx, ny, nz);
  230. };
  231. Point.prototype.dbl = function dbl() {
  232. if (this.isInfinity())
  233. return this;
  234. // Double in extended coordinates
  235. if (this.curve.extended)
  236. return this._extDbl();
  237. else
  238. return this._projDbl();
  239. };
  240. Point.prototype._extAdd = function _extAdd(p) {
  241. // hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html
  242. // #addition-add-2008-hwcd-3
  243. // 8M
  244. // A = (Y1 - X1) * (Y2 - X2)
  245. var a = this.y.redSub(this.x).redMul(p.y.redSub(p.x));
  246. // B = (Y1 + X1) * (Y2 + X2)
  247. var b = this.y.redAdd(this.x).redMul(p.y.redAdd(p.x));
  248. // C = T1 * k * T2
  249. var c = this.t.redMul(this.curve.dd).redMul(p.t);
  250. // D = Z1 * 2 * Z2
  251. var d = this.z.redMul(p.z.redAdd(p.z));
  252. // E = B - A
  253. var e = b.redSub(a);
  254. // F = D - C
  255. var f = d.redSub(c);
  256. // G = D + C
  257. var g = d.redAdd(c);
  258. // H = B + A
  259. var h = b.redAdd(a);
  260. // X3 = E * F
  261. var nx = e.redMul(f);
  262. // Y3 = G * H
  263. var ny = g.redMul(h);
  264. // T3 = E * H
  265. var nt = e.redMul(h);
  266. // Z3 = F * G
  267. var nz = f.redMul(g);
  268. return this.curve.point(nx, ny, nz, nt);
  269. };
  270. Point.prototype._projAdd = function _projAdd(p) {
  271. // hyperelliptic.org/EFD/g1p/auto-twisted-projective.html
  272. // #addition-add-2008-bbjlp
  273. // #addition-add-2007-bl
  274. // 10M + 1S
  275. // A = Z1 * Z2
  276. var a = this.z.redMul(p.z);
  277. // B = A^2
  278. var b = a.redSqr();
  279. // C = X1 * X2
  280. var c = this.x.redMul(p.x);
  281. // D = Y1 * Y2
  282. var d = this.y.redMul(p.y);
  283. // E = d * C * D
  284. var e = this.curve.d.redMul(c).redMul(d);
  285. // F = B - E
  286. var f = b.redSub(e);
  287. // G = B + E
  288. var g = b.redAdd(e);
  289. // X3 = A * F * ((X1 + Y1) * (X2 + Y2) - C - D)
  290. var tmp = this.x.redAdd(this.y).redMul(p.x.redAdd(p.y)).redISub(c).redISub(d);
  291. var nx = a.redMul(f).redMul(tmp);
  292. var ny;
  293. var nz;
  294. if (this.curve.twisted) {
  295. // Y3 = A * G * (D - a * C)
  296. ny = a.redMul(g).redMul(d.redSub(this.curve._mulA(c)));
  297. // Z3 = F * G
  298. nz = f.redMul(g);
  299. } else {
  300. // Y3 = A * G * (D - C)
  301. ny = a.redMul(g).redMul(d.redSub(c));
  302. // Z3 = c * F * G
  303. nz = this.curve._mulC(f).redMul(g);
  304. }
  305. return this.curve.point(nx, ny, nz);
  306. };
  307. Point.prototype.add = function add(p) {
  308. if (this.isInfinity())
  309. return p;
  310. if (p.isInfinity())
  311. return this;
  312. if (this.curve.extended)
  313. return this._extAdd(p);
  314. else
  315. return this._projAdd(p);
  316. };
  317. Point.prototype.mul = function mul(k) {
  318. if (this._hasDoubles(k))
  319. return this.curve._fixedNafMul(this, k);
  320. else
  321. return this.curve._wnafMul(this, k);
  322. };
  323. Point.prototype.mulAdd = function mulAdd(k1, p, k2) {
  324. return this.curve._wnafMulAdd(1, [ this, p ], [ k1, k2 ], 2, false);
  325. };
  326. Point.prototype.jmulAdd = function jmulAdd(k1, p, k2) {
  327. return this.curve._wnafMulAdd(1, [ this, p ], [ k1, k2 ], 2, true);
  328. };
  329. Point.prototype.normalize = function normalize() {
  330. if (this.zOne)
  331. return this;
  332. // Normalize coordinates
  333. var zi = this.z.redInvm();
  334. this.x = this.x.redMul(zi);
  335. this.y = this.y.redMul(zi);
  336. if (this.t)
  337. this.t = this.t.redMul(zi);
  338. this.z = this.curve.one;
  339. this.zOne = true;
  340. return this;
  341. };
  342. Point.prototype.neg = function neg() {
  343. return this.curve.point(this.x.redNeg(),
  344. this.y,
  345. this.z,
  346. this.t && this.t.redNeg());
  347. };
  348. Point.prototype.getX = function getX() {
  349. this.normalize();
  350. return this.x.fromRed();
  351. };
  352. Point.prototype.getY = function getY() {
  353. this.normalize();
  354. return this.y.fromRed();
  355. };
  356. Point.prototype.eq = function eq(other) {
  357. return this === other ||
  358. this.getX().cmp(other.getX()) === 0 &&
  359. this.getY().cmp(other.getY()) === 0;
  360. };
  361. Point.prototype.eqXToP = function eqXToP(x) {
  362. var rx = x.toRed(this.curve.red).redMul(this.z);
  363. if (this.x.cmp(rx) === 0)
  364. return true;
  365. var xc = x.clone();
  366. var t = this.curve.redN.redMul(this.z);
  367. for (;;) {
  368. xc.iadd(this.curve.n);
  369. if (xc.cmp(this.curve.p) >= 0)
  370. return false;
  371. rx.redIAdd(t);
  372. if (this.x.cmp(rx) === 0)
  373. return true;
  374. }
  375. };
  376. // Compatibility with BaseCurve
  377. Point.prototype.toP = Point.prototype.normalize;
  378. Point.prototype.mixedAdd = Point.prototype.add;