ecc.js 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. if (window.sjcl == undefined) {
  2. window.sjcl = {};
  3. }
  4. sjcl.ecc = {};
  5. /**
  6. * Represents a point on a curve in affine coordinates.
  7. * @constructor
  8. * @param {sjcl.ecc.curve} curve The curve that this point lies on.
  9. * @param {bigInt} x The x coordinate.
  10. * @param {bigInt} y The y coordinate.
  11. */
  12. sjcl.ecc.point = function(curve,x,y) {
  13. if (x === undefined) {
  14. this.isIdentity = true;
  15. } else {
  16. this.x = x;
  17. this.y = y;
  18. this.isIdentity = false;
  19. }
  20. this.curve = curve;
  21. };
  22. sjcl.ecc.point.prototype = {
  23. toJac: function() {
  24. return new sjcl.ecc.pointJac(this.curve, this.x, this.y, new this.curve.field(1));
  25. },
  26. mult: function(k) {
  27. return this.toJac().mult(k, this).toAffine();
  28. },
  29. isValid: function() {
  30. return this.y.square().equals(this.curve.b.add(this.x.mul(this.curve.a.add(this.x.square()))));
  31. },
  32. toBits: function() {
  33. return sjcl.bitArray.concat(this.x.toBits(), this.y.toBits());
  34. }
  35. };
  36. /**
  37. * Represents a point on a curve in Jacobian coordinates. Coordinates can be specified as bigInts or strings (which
  38. * will be converted to bigInts).
  39. *
  40. * @constructor
  41. * @param {bigInt/string} x The x coordinate.
  42. * @param {bigInt/string} y The y coordinate.
  43. * @param {bigInt/string} z The z coordinate.
  44. * @param {sjcl.ecc.curve} curve The curve that this point lies on.
  45. */
  46. sjcl.ecc.pointJac = function(curve, x, y, z) {
  47. if (x === undefined) {
  48. this.isIdentity = true;
  49. } else {
  50. this.x = x;
  51. this.y = y;
  52. this.z = z;
  53. this.isIdentity = false;
  54. }
  55. this.curve = curve;
  56. };
  57. sjcl.ecc.pointJac.prototype = {
  58. /**
  59. * 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.
  60. * @param {sjcl.ecc.pointJac} S One of the points to add, in Jacobian coordinates.
  61. * @param {sjcl.ecc.point} T The other point to add, in affine coordinates.
  62. * @return {sjcl.ecc.pointJac} The sum of the two points, in Jacobian coordinates.
  63. */
  64. add: function(T) {
  65. var S = this;
  66. if (S.curve !== T.curve) {
  67. throw("sjcl.ecc.add(): Points must be on the same curve to add them!");
  68. }
  69. if (S.isIdentity) {
  70. return T.toJac();
  71. } else if (T.isIdentity) {
  72. return S;
  73. }
  74. var
  75. sz2 = S.z.square(),
  76. c = T.x.mul(sz2).subM(S.x);
  77. if (c.equals(0)) {
  78. if (S.y.equals(T.y.mul(sz2.mul(S.z)))) {
  79. // same point
  80. return S.doubl();
  81. } else {
  82. // inverses
  83. return new sjcl.ecc.pointJac(S.curve);
  84. }
  85. }
  86. var
  87. d = T.y.mul(sz2.mul(S.z)).subM(S.y),
  88. c2 = c.square(),
  89. x1 = d.square(),
  90. x2 = c.square().mul(c).addM( S.x.add(S.x).mul(c2) ),
  91. x = x1.subM(x2),
  92. y1 = S.x.mul(c2).subM(x).mul(d),
  93. y2 = S.y.mul(c.square().mul(c)),
  94. y = y1.subM(y2),
  95. z = S.z.mul(c);
  96. //return new sjcl.ecc.pointJac(this.curve,x,y,z);
  97. var U = new sjcl.ecc.pointJac(this.curve,x,y,z);
  98. if (!U.isValid()) { throw "FOOOOOOOO"; }
  99. return U;
  100. },
  101. /**
  102. * doubles this point.
  103. * @return {sjcl.ecc.pointJac} The doubled point.
  104. */
  105. doubl: function() {
  106. if (this.isIdentity) { return this; }
  107. var
  108. y2 = this.y.square(),
  109. a = y2.mul(this.x.mul(4)),
  110. b = y2.square().mul(8),
  111. z2 = this.z.square(),
  112. c = this.x.sub(z2).mul(3).mul(this.x.add(z2)),
  113. x = c.square().subM(a).subM(a),
  114. y = a.sub(x).mul(c).subM(b),
  115. z = this.y.add(this.y).mul(this.z);
  116. return new sjcl.ecc.pointJac(this.curve, x, y, z);
  117. },
  118. /**
  119. * Returns a copy of this point converted to affine coordinates.
  120. * @return {sjcl.ecc.point} The converted point.
  121. */
  122. toAffine: function() {
  123. if (this.isIdentity || this.z.equals(0)) {
  124. return new sjcl.ecc.point(this.curve);
  125. }
  126. var zi = this.z.inverse(), zi2 = zi.square();
  127. return new sjcl.ecc.point(this.curve, this.x.mul(zi2), this.y.mul(zi2.mul(zi)));
  128. },
  129. /**
  130. * Multiply this point by k and return the answer in Jacobian coordinates.
  131. * @param {bigInt} k The coefficient to multiply by.
  132. * @param {sjcl.ecc.point} affine This point in affine coordinates.
  133. * @return {sjcl.ecc.pointJac} The result of the multiplication, in Jacobian coordinates.
  134. */
  135. mult: function(k, affine) {
  136. if (typeof(k) == "number") {
  137. k = [k];
  138. } else if (k.limbs !== undefined) {
  139. k = k.normalize().limbs;
  140. }
  141. var i, j, out = this, multiples, aff2;
  142. if (affine === undefined) {
  143. affine = this.toAffine();
  144. }
  145. if (affine.multiples === undefined) {
  146. j = this.doubl();
  147. affine.multiples = [new sjcl.ecc.point(this.curve), affine, j.toAffine()];
  148. for (i=3; i<16; i++) {
  149. j = j.add(affine);
  150. affine.multiples[i] = j.toAffine();
  151. }
  152. }
  153. multiples = affine.multiples;
  154. for (i=k.length-1; i>=0; i--) {
  155. for (j=bn.prototype.radix-4; j>=0; j-=4) {
  156. out = out.doubl().doubl().doubl().doubl().add(multiples[k[i]>>j & 0xF]);
  157. }
  158. }
  159. return out;
  160. },
  161. isValid: function() {
  162. var z2 = this.z.square(), z4 = z2.square(), z6 = z4.mul(z2);
  163. return this.y.square().equals(
  164. this.curve.b.mul(z6).add(this.x.mul(
  165. this.curve.a.mul(z4).add(this.x.square()))));
  166. }
  167. };
  168. /**
  169. * Construct an elliptic curve. Most users will not use this and instead start with one of the NIST curves defined below.
  170. *
  171. * @constructor
  172. * @param {bigInt} p The prime modulus.
  173. * @param {bigInt} r The prime order of the curve.
  174. * @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).
  175. * @param {bigInt} x The x coordinate of a base point of the curve.
  176. * @param {bigInt} y The y coordinate of a base point of the curve.
  177. */
  178. sjcl.ecc.curve = function(field, r, a, b, x, y) {
  179. this.field = field;
  180. this.r = field.prototype.modulus.sub(r);
  181. this.a = new field(a);
  182. this.b = new field(b);
  183. this.G = new sjcl.ecc.point(this, new field(x), new field(y));
  184. };
  185. sjcl.ecc.curve.prototype.fromBits = function (bits) {
  186. var w = sjcl.bitArray, l = this.field.prototype.exponent + 7 & -8;
  187. p = new sjcl.ecc.point(this, this.field.fromBits(w.bitSlice(bits, 0, l)),
  188. this.field.fromBits(w.bitSlice(bits, l, 2*l)));
  189. if (!p.isValid()) {
  190. throw new sjcl.exception.corrupt("not on the curve!");
  191. }
  192. return p;
  193. };
  194. sjcl.ecc.p192curve = new sjcl.ecc.curve(
  195. p192,
  196. "0x662107c8eb94364e4b2dd7ce",
  197. -3,
  198. "0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1",
  199. "0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012",
  200. "0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811");
  201. sjcl.ecc.p224curve = new sjcl.ecc.curve(
  202. p224,
  203. "0xe95c1f470fc1ec22d6baa3a3d5c4",
  204. -3,
  205. "0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4",
  206. "0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21",
  207. "0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34");
  208. sjcl.ecc.p256curve = new sjcl.ecc.curve(
  209. p256,
  210. "0x4319055358e8617b0c46353d039cdaae",
  211. -3,
  212. "0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b",
  213. "0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
  214. "0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5");
  215. sjcl.ecc.p384curve = new sjcl.ecc.curve(
  216. p384,
  217. "0x389cb27e0bc8d21fa7e5f24cb74f58851313e696333ad68c",
  218. -3,
  219. "0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef",
  220. "0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7",
  221. "0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f");
  222. sjcl.ecc.curves = {
  223. 192: sjcl.ecc.p192curve,
  224. 224: sjcl.ecc.p224curve,
  225. 256: sjcl.ecc.p256curve,
  226. 384: sjcl.ecc.p384curve
  227. };
  228. sjcl.ecc.elGamal = {
  229. publicKey: function(curve, point) {
  230. this._curve = curve;
  231. if (point instanceof Array) {
  232. this._point = curve.fromBits(point);
  233. } else {
  234. this._point = point;
  235. }
  236. },
  237. secretKey: function(curve, exponent) {
  238. this._curve = curve;
  239. this._exponent = exponent;
  240. },
  241. generateKeys: function(curve, paranoia) {
  242. if (typeof curve == "number") {
  243. curve = sjcl.ecc.curves[curve];
  244. if (curve === undefined) {
  245. throw new sjcl.exception.invalid("no such curve");
  246. }
  247. }
  248. var sec = bn.random(curve.r, paranoia), pub = curve.G.mult(sec);
  249. return { pub: new sjcl.ecc.elGamal.publicKey(curve, pub),
  250. sec: new sjcl.ecc.elGamal.secretKey(curve, sec) };
  251. }
  252. };
  253. sjcl.ecc.elGamal.publicKey.prototype = {
  254. kem: function(paranoia) {
  255. var sec = bn.random(this._curve.r, paranoia),
  256. tag = this._curve.G.mult(sec).toBits(),
  257. key = sjcl.hash.sha256.hash(this._point.mult(sec).toBits());
  258. return { key: key, tag: tag };
  259. }
  260. };
  261. sjcl.ecc.elGamal.secretKey.prototype = {
  262. unkem: function(tag) {
  263. return sjcl.hash.sha256.hash(this._curve.fromBits(tag).mult(this._exponent).toBits());
  264. }
  265. };