ecc.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. sjcl.ecc = {};
  2. /**
  3. * Represents a point on a curve in affine coordinates.
  4. * @constructor
  5. * @param {sjcl.ecc.curve} curve The curve that this point lies on.
  6. * @param {bigInt} x The x coordinate.
  7. * @param {bigInt} y The y coordinate.
  8. */
  9. sjcl.ecc.point = function(curve,x,y) {
  10. if (x === undefined) {
  11. this.isIdentity = true;
  12. } else {
  13. this.x = x;
  14. this.y = y;
  15. this.isIdentity = false;
  16. }
  17. this.curve = curve;
  18. };
  19. sjcl.ecc.point.prototype = {
  20. toJac: function() {
  21. return new sjcl.ecc.pointJac(this.curve, this.x, this.y, new this.curve.field(1));
  22. },
  23. mult: function(k) {
  24. return this.toJac().mult(k, this).toAffine();
  25. },
  26. /**
  27. * Multiply this point by k, added to affine2*k2, and return the answer in Jacobian coordinates.
  28. * @param {bigInt} k The coefficient to multiply this by.
  29. * @param {bigInt} k2 The coefficient to multiply affine2 this by.
  30. * @param {sjcl.ecc.point} affine The other point in affine coordinates.
  31. * @return {sjcl.ecc.pointJac} The result of the multiplication and addition, in Jacobian coordinates.
  32. */
  33. mult2: function(k, k2, affine2) {
  34. return this.toJac().mult2(k, this, k2, affine2).toAffine();
  35. },
  36. multiples: function() {
  37. var m, i, j;
  38. if (this._multiples === undefined) {
  39. j = this.toJac().doubl();
  40. m = this._multiples = [new sjcl.ecc.point(this.curve), this, j.toAffine()];
  41. for (i=3; i<16; i++) {
  42. j = j.add(this);
  43. m.push(j.toAffine());
  44. }
  45. }
  46. return this._multiples;
  47. },
  48. isValid: function() {
  49. return this.y.square().equals(this.curve.b.add(this.x.mul(this.curve.a.add(this.x.square()))));
  50. },
  51. toBits: function() {
  52. return sjcl.bitArray.concat(this.x.toBits(), this.y.toBits());
  53. }
  54. };
  55. /**
  56. * Represents a point on a curve in Jacobian coordinates. Coordinates can be specified as bigInts or strings (which
  57. * will be converted to bigInts).
  58. *
  59. * @constructor
  60. * @param {bigInt/string} x The x coordinate.
  61. * @param {bigInt/string} y The y coordinate.
  62. * @param {bigInt/string} z The z coordinate.
  63. * @param {sjcl.ecc.curve} curve The curve that this point lies on.
  64. */
  65. sjcl.ecc.pointJac = function(curve, x, y, z) {
  66. if (x === undefined) {
  67. this.isIdentity = true;
  68. } else {
  69. this.x = x;
  70. this.y = y;
  71. this.z = z;
  72. this.isIdentity = false;
  73. }
  74. this.curve = curve;
  75. };
  76. sjcl.ecc.pointJac.prototype = {
  77. /**
  78. * Adds S and T and returns the result in Jacobian coordinates. Note that S must be in Jacobian coordinates and T must be in affine coordinates.
  79. * @param {sjcl.ecc.pointJac} S One of the points to add, in Jacobian coordinates.
  80. * @param {sjcl.ecc.point} T The other point to add, in affine coordinates.
  81. * @return {sjcl.ecc.pointJac} The sum of the two points, in Jacobian coordinates.
  82. */
  83. add: function(T) {
  84. var S = this;
  85. if (S.curve !== T.curve) {
  86. throw("sjcl.ecc.add(): Points must be on the same curve to add them!");
  87. }
  88. if (S.isIdentity) {
  89. return T.toJac();
  90. } else if (T.isIdentity) {
  91. return S;
  92. }
  93. var
  94. sz2 = S.z.square(),
  95. c = T.x.mul(sz2).subM(S.x);
  96. if (c.equals(0)) {
  97. if (S.y.equals(T.y.mul(sz2.mul(S.z)))) {
  98. // same point
  99. return S.doubl();
  100. } else {
  101. // inverses
  102. return new sjcl.ecc.pointJac(S.curve);
  103. }
  104. }
  105. var
  106. d = T.y.mul(sz2.mul(S.z)).subM(S.y),
  107. c2 = c.square(),
  108. x1 = d.square(),
  109. x2 = c.square().mul(c).addM( S.x.add(S.x).mul(c2) ),
  110. x = x1.subM(x2),
  111. y1 = S.x.mul(c2).subM(x).mul(d),
  112. y2 = S.y.mul(c.square().mul(c)),
  113. y = y1.subM(y2),
  114. z = S.z.mul(c);
  115. //return new sjcl.ecc.pointJac(this.curve,x,y,z);
  116. var U = new sjcl.ecc.pointJac(this.curve,x,y,z);
  117. if (!U.isValid()) { throw "FOOOOOOOO"; }
  118. return U;
  119. },
  120. /**
  121. * doubles this point.
  122. * @return {sjcl.ecc.pointJac} The doubled point.
  123. */
  124. doubl: function() {
  125. if (this.isIdentity) { return this; }
  126. var
  127. y2 = this.y.square(),
  128. a = y2.mul(this.x.mul(4)),
  129. b = y2.square().mul(8),
  130. z2 = this.z.square(),
  131. c = this.x.sub(z2).mul(3).mul(this.x.add(z2)),
  132. x = c.square().subM(a).subM(a),
  133. y = a.sub(x).mul(c).subM(b),
  134. z = this.y.add(this.y).mul(this.z);
  135. return new sjcl.ecc.pointJac(this.curve, x, y, z);
  136. },
  137. /**
  138. * Returns a copy of this point converted to affine coordinates.
  139. * @return {sjcl.ecc.point} The converted point.
  140. */
  141. toAffine: function() {
  142. if (this.isIdentity || this.z.equals(0)) {
  143. return new sjcl.ecc.point(this.curve);
  144. }
  145. var zi = this.z.inverse(), zi2 = zi.square();
  146. return new sjcl.ecc.point(this.curve, this.x.mul(zi2).fullReduce(), this.y.mul(zi2.mul(zi)).fullReduce());
  147. },
  148. /**
  149. * Multiply this point by k and return the answer in Jacobian coordinates.
  150. * @param {bigInt} k The coefficient to multiply by.
  151. * @param {sjcl.ecc.point} affine This point in affine coordinates.
  152. * @return {sjcl.ecc.pointJac} The result of the multiplication, in Jacobian coordinates.
  153. */
  154. mult: function(k, affine) {
  155. if (typeof(k) == "number") {
  156. k = [k];
  157. } else if (k.limbs !== undefined) {
  158. k = k.normalize().limbs;
  159. }
  160. var i, j, out = new sjcl.ecc.point(this.curve).toJac(), multiples = affine.multiples();
  161. for (i=k.length-1; i>=0; i--) {
  162. for (j=sjcl.bn.prototype.radix-4; j>=0; j-=4) {
  163. out = out.doubl().doubl().doubl().doubl().add(multiples[k[i]>>j & 0xF]);
  164. }
  165. }
  166. return out;
  167. },
  168. /**
  169. * Multiply this point by k, added to affine2*k2, and return the answer in Jacobian coordinates.
  170. * @param {bigInt} k The coefficient to multiply this by.
  171. * @param {sjcl.ecc.point} affine This point in affine coordinates.
  172. * @param {bigInt} k2 The coefficient to multiply affine2 this by.
  173. * @param {sjcl.ecc.point} affine The other point in affine coordinates.
  174. * @return {sjcl.ecc.pointJac} The result of the multiplication and addition, in Jacobian coordinates.
  175. */
  176. mult2: function(k1, affine, k2, affine2) {
  177. if (typeof(k1) == "number") {
  178. k1 = [k1];
  179. } else if (k1.limbs !== undefined) {
  180. k1 = k1.normalize().limbs;
  181. }
  182. if (typeof(k2) == "number") {
  183. k2 = [k2];
  184. } else if (k2.limbs !== undefined) {
  185. k2 = k2.normalize().limbs;
  186. }
  187. var i, j, out = new sjcl.ecc.point(this.curve).toJac(), m1 = affine.multiples(),
  188. m2 = affine2.multiples(), l1, l2;
  189. for (i=Math.max(k1.length,k2.length)-1; i>=0; i--) {
  190. l1 = k1[i] | 0;
  191. l2 = k2[i] | 0;
  192. for (j=sjcl.bn.prototype.radix-4; j>=0; j-=4) {
  193. out = out.doubl().doubl().doubl().doubl().add(m1[l1>>j & 0xF]).add(m2[l2>>j & 0xF]);
  194. }
  195. }
  196. return out;
  197. },
  198. isValid: function() {
  199. var z2 = this.z.square(), z4 = z2.square(), z6 = z4.mul(z2);
  200. return this.y.square().equals(
  201. this.curve.b.mul(z6).add(this.x.mul(
  202. this.curve.a.mul(z4).add(this.x.square()))));
  203. }
  204. };
  205. /**
  206. * Construct an elliptic curve. Most users will not use this and instead start with one of the NIST curves defined below.
  207. *
  208. * @constructor
  209. * @param {bigInt} p The prime modulus.
  210. * @param {bigInt} r The prime order of the curve.
  211. * @param {bigInt} a The constant a in the equation of the curve y^2 = x^3 + ax + b (for NIST curves, a is always -3).
  212. * @param {bigInt} x The x coordinate of a base point of the curve.
  213. * @param {bigInt} y The y coordinate of a base point of the curve.
  214. */
  215. sjcl.ecc.curve = function(field, r, a, b, x, y) {
  216. this.field = field;
  217. this.r = field.prototype.modulus.sub(r);
  218. this.a = new field(a);
  219. this.b = new field(b);
  220. this.G = new sjcl.ecc.point(this, new field(x), new field(y));
  221. };
  222. sjcl.ecc.curve.prototype.fromBits = function (bits) {
  223. var w = sjcl.bitArray, l = this.field.prototype.exponent + 7 & -8;
  224. p = new sjcl.ecc.point(this, this.field.fromBits(w.bitSlice(bits, 0, l)),
  225. this.field.fromBits(w.bitSlice(bits, l, 2*l)));
  226. if (!p.isValid()) {
  227. throw new sjcl.exception.corrupt("not on the curve!");
  228. }
  229. return p;
  230. };
  231. sjcl.ecc.curves = {
  232. c192: new sjcl.ecc.curve(
  233. sjcl.bn.prime.p192,
  234. "0x662107c8eb94364e4b2dd7ce",
  235. -3,
  236. "0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1",
  237. "0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012",
  238. "0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811"),
  239. c224: new sjcl.ecc.curve(
  240. sjcl.bn.prime.p224,
  241. "0xe95c1f470fc1ec22d6baa3a3d5c4",
  242. -3,
  243. "0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4",
  244. "0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21",
  245. "0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34"),
  246. c256: new sjcl.ecc.curve(
  247. sjcl.bn.prime.p256,
  248. "0x4319055358e8617b0c46353d039cdaae",
  249. -3,
  250. "0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b",
  251. "0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
  252. "0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5"),
  253. c384: new sjcl.ecc.curve(
  254. sjcl.bn.prime.p384,
  255. "0x389cb27e0bc8d21fa7e5f24cb74f58851313e696333ad68c",
  256. -3,
  257. "0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef",
  258. "0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7",
  259. "0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f")
  260. };
  261. /* Diffie-Hellman-like public-key system */
  262. sjcl.ecc._dh = function(cn) {
  263. sjcl.ecc[cn] = {
  264. publicKey: function(curve, point) {
  265. this._curve = curve;
  266. if (point instanceof Array) {
  267. this._point = curve.fromBits(point);
  268. } else {
  269. this._point = point;
  270. }
  271. },
  272. secretKey: function(curve, exponent) {
  273. this._curve = curve;
  274. this._exponent = exponent;
  275. },
  276. generateKeys: function(curve, paranoia) {
  277. if (typeof curve == "number") {
  278. curve = sjcl.ecc.curves['c'+curve];
  279. if (curve === undefined) {
  280. throw new sjcl.exception.invalid("no such curve");
  281. }
  282. }
  283. var sec = sjcl.bn.random(curve.r, paranoia), pub = curve.G.mult(sec);
  284. return { pub: new sjcl.ecc[cn].publicKey(curve, pub),
  285. sec: new sjcl.ecc[cn].secretKey(curve, sec) };
  286. }
  287. };
  288. };
  289. sjcl.ecc._dh("elGamal");
  290. sjcl.ecc.elGamal.publicKey.prototype = {
  291. kem: function(paranoia) {
  292. var sec = sjcl.bn.random(this._curve.r, paranoia),
  293. tag = this._curve.G.mult(sec).toBits(),
  294. key = sjcl.hash.sha256.hash(this._point.mult(sec).toBits());
  295. return { key: key, tag: tag };
  296. }
  297. };
  298. sjcl.ecc.elGamal.secretKey.prototype = {
  299. unkem: function(tag) {
  300. return sjcl.hash.sha256.hash(this._curve.fromBits(tag).mult(this._exponent).toBits());
  301. }
  302. };
  303. sjcl.ecc._dh("dsa");
  304. sjcl.ecc.dsa.secretKey.prototype = {
  305. sign: function(hash, paranoia) {
  306. var R = this._curve.r,
  307. l = R.bitLength(),
  308. k = kkkk = sjcl.bn.random(R.sub(1), paranoia).add(1),
  309. r = this._curve.G.mult(k).x.mod(R),
  310. s = sjcl.bn.fromBits(hash).add(r.mul(this._exponent)).inverseMod(R).mul(kkkk).mod(R);
  311. return sjcl.bitArray.concat(r.toBits(l), s.toBits(l));
  312. }
  313. };
  314. sjcl.ecc.dsa.publicKey.prototype = {
  315. verify: function(hash, rs) {
  316. var w = sjcl.bitArray,
  317. R = this._curve.r,
  318. l = R.bitLength(),
  319. r = sjcl.bn.fromBits(w.bitSlice(rs,0,l)),
  320. s = sjcl.bn.fromBits(w.bitSlice(rs,l,2*l)),
  321. hG = sjcl.bn.fromBits(hash).mul(s).mod(R),
  322. hA = r.mul(s).mod(R),
  323. r2 = this._curve.G.mult2(hG, hA, this._point).x,
  324. corrupt = sjcl.exception.corrupt;
  325. if (r.equals(0) || s.equals(0) || r.greaterEquals(R) || s.greaterEquals(R) || !r2.equals(r)) {
  326. throw (new corrupt("signature didn't check out"));
  327. }
  328. return true;
  329. }
  330. }