ECAlgorithms.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using BestHTTP.SecureProtocol.Org.BouncyCastle.Math.EC.Endo;
  5. using BestHTTP.SecureProtocol.Org.BouncyCastle.Math.EC.Multiplier;
  6. using BestHTTP.SecureProtocol.Org.BouncyCastle.Math.Field;
  7. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Math.EC
  8. {
  9. public class ECAlgorithms
  10. {
  11. public static bool IsF2mCurve(ECCurve c)
  12. {
  13. return IsF2mField(c.Field);
  14. }
  15. public static bool IsF2mField(IFiniteField field)
  16. {
  17. return field.Dimension > 1 && field.Characteristic.Equals(BigInteger.Two)
  18. && field is IPolynomialExtensionField;
  19. }
  20. public static bool IsFpCurve(ECCurve c)
  21. {
  22. return IsFpField(c.Field);
  23. }
  24. public static bool IsFpField(IFiniteField field)
  25. {
  26. return field.Dimension == 1;
  27. }
  28. public static ECPoint SumOfMultiplies(ECPoint[] ps, BigInteger[] ks)
  29. {
  30. if (ps == null || ks == null || ps.Length != ks.Length || ps.Length < 1)
  31. throw new ArgumentException("point and scalar arrays should be non-null, and of equal, non-zero, length");
  32. int count = ps.Length;
  33. switch (count)
  34. {
  35. case 1:
  36. return ps[0].Multiply(ks[0]);
  37. case 2:
  38. return SumOfTwoMultiplies(ps[0], ks[0], ps[1], ks[1]);
  39. default:
  40. break;
  41. }
  42. ECPoint p = ps[0];
  43. ECCurve c = p.Curve;
  44. ECPoint[] imported = new ECPoint[count];
  45. imported[0] = p;
  46. for (int i = 1; i < count; ++i)
  47. {
  48. imported[i] = ImportPoint(c, ps[i]);
  49. }
  50. GlvEndomorphism glvEndomorphism = c.GetEndomorphism() as GlvEndomorphism;
  51. if (glvEndomorphism != null)
  52. {
  53. return ImplCheckResult(ImplSumOfMultipliesGlv(imported, ks, glvEndomorphism));
  54. }
  55. return ImplCheckResult(ImplSumOfMultiplies(imported, ks));
  56. }
  57. public static ECPoint SumOfTwoMultiplies(ECPoint P, BigInteger a, ECPoint Q, BigInteger b)
  58. {
  59. ECCurve cp = P.Curve;
  60. Q = ImportPoint(cp, Q);
  61. // Point multiplication for Koblitz curves (using WTNAF) beats Shamir's trick
  62. {
  63. AbstractF2mCurve f2mCurve = cp as AbstractF2mCurve;
  64. if (f2mCurve != null && f2mCurve.IsKoblitz)
  65. {
  66. return ImplCheckResult(P.Multiply(a).Add(Q.Multiply(b)));
  67. }
  68. }
  69. GlvEndomorphism glvEndomorphism = cp.GetEndomorphism() as GlvEndomorphism;
  70. if (glvEndomorphism != null)
  71. {
  72. return ImplCheckResult(
  73. ImplSumOfMultipliesGlv(new ECPoint[] { P, Q }, new BigInteger[] { a, b }, glvEndomorphism));
  74. }
  75. return ImplCheckResult(ImplShamirsTrickWNaf(P, a, Q, b));
  76. }
  77. /*
  78. * "Shamir's Trick", originally due to E. G. Straus
  79. * (Addition chains of vectors. American Mathematical Monthly,
  80. * 71(7):806-808, Aug./Sept. 1964)
  81. *
  82. * Input: The points P, Q, scalar k = (km?, ... , k1, k0)
  83. * and scalar l = (lm?, ... , l1, l0).
  84. * Output: R = k * P + l * Q.
  85. * 1: Z <- P + Q
  86. * 2: R <- O
  87. * 3: for i from m-1 down to 0 do
  88. * 4: R <- R + R {point doubling}
  89. * 5: if (ki = 1) and (li = 0) then R <- R + P end if
  90. * 6: if (ki = 0) and (li = 1) then R <- R + Q end if
  91. * 7: if (ki = 1) and (li = 1) then R <- R + Z end if
  92. * 8: end for
  93. * 9: return R
  94. */
  95. public static ECPoint ShamirsTrick(ECPoint P, BigInteger k, ECPoint Q, BigInteger l)
  96. {
  97. ECCurve cp = P.Curve;
  98. Q = ImportPoint(cp, Q);
  99. return ImplCheckResult(ImplShamirsTrickJsf(P, k, Q, l));
  100. }
  101. public static ECPoint ImportPoint(ECCurve c, ECPoint p)
  102. {
  103. ECCurve cp = p.Curve;
  104. if (!c.Equals(cp))
  105. throw new ArgumentException("Point must be on the same curve");
  106. return c.ImportPoint(p);
  107. }
  108. public static void MontgomeryTrick(ECFieldElement[] zs, int off, int len)
  109. {
  110. MontgomeryTrick(zs, off, len, null);
  111. }
  112. public static void MontgomeryTrick(ECFieldElement[] zs, int off, int len, ECFieldElement scale)
  113. {
  114. /*
  115. * Uses the "Montgomery Trick" to invert many field elements, with only a single actual
  116. * field inversion. See e.g. the paper:
  117. * "Fast Multi-scalar Multiplication Methods on Elliptic Curves with Precomputation Strategy Using Montgomery Trick"
  118. * by Katsuyuki Okeya, Kouichi Sakurai.
  119. */
  120. ECFieldElement[] c = new ECFieldElement[len];
  121. c[0] = zs[off];
  122. int i = 0;
  123. while (++i < len)
  124. {
  125. c[i] = c[i - 1].Multiply(zs[off + i]);
  126. }
  127. --i;
  128. if (scale != null)
  129. {
  130. c[i] = c[i].Multiply(scale);
  131. }
  132. ECFieldElement u = c[i].Invert();
  133. while (i > 0)
  134. {
  135. int j = off + i--;
  136. ECFieldElement tmp = zs[j];
  137. zs[j] = c[i].Multiply(u);
  138. u = u.Multiply(tmp);
  139. }
  140. zs[off] = u;
  141. }
  142. /**
  143. * Simple shift-and-add multiplication. Serves as reference implementation
  144. * to verify (possibly faster) implementations, and for very small scalars.
  145. *
  146. * @param p
  147. * The point to multiply.
  148. * @param k
  149. * The multiplier.
  150. * @return The result of the point multiplication <code>kP</code>.
  151. */
  152. public static ECPoint ReferenceMultiply(ECPoint p, BigInteger k)
  153. {
  154. BigInteger x = k.Abs();
  155. ECPoint q = p.Curve.Infinity;
  156. int t = x.BitLength;
  157. if (t > 0)
  158. {
  159. if (x.TestBit(0))
  160. {
  161. q = p;
  162. }
  163. for (int i = 1; i < t; i++)
  164. {
  165. p = p.Twice();
  166. if (x.TestBit(i))
  167. {
  168. q = q.Add(p);
  169. }
  170. }
  171. }
  172. return k.SignValue < 0 ? q.Negate() : q;
  173. }
  174. public static ECPoint ValidatePoint(ECPoint p)
  175. {
  176. if (!p.IsValid())
  177. throw new InvalidOperationException("Invalid point");
  178. return p;
  179. }
  180. public static ECPoint CleanPoint(ECCurve c, ECPoint p)
  181. {
  182. ECCurve cp = p.Curve;
  183. if (!c.Equals(cp))
  184. throw new ArgumentException("Point must be on the same curve", "p");
  185. return c.DecodePoint(p.GetEncoded(false));
  186. }
  187. internal static ECPoint ImplCheckResult(ECPoint p)
  188. {
  189. if (!p.IsValidPartial())
  190. throw new InvalidOperationException("Invalid result");
  191. return p;
  192. }
  193. internal static ECPoint ImplShamirsTrickJsf(ECPoint P, BigInteger k, ECPoint Q, BigInteger l)
  194. {
  195. ECCurve curve = P.Curve;
  196. ECPoint infinity = curve.Infinity;
  197. // TODO conjugate co-Z addition (ZADDC) can return both of these
  198. ECPoint PaddQ = P.Add(Q);
  199. ECPoint PsubQ = P.Subtract(Q);
  200. ECPoint[] points = new ECPoint[] { Q, PsubQ, P, PaddQ };
  201. curve.NormalizeAll(points);
  202. ECPoint[] table = new ECPoint[] {
  203. points[3].Negate(), points[2].Negate(), points[1].Negate(),
  204. points[0].Negate(), infinity, points[0],
  205. points[1], points[2], points[3] };
  206. byte[] jsf = WNafUtilities.GenerateJsf(k, l);
  207. ECPoint R = infinity;
  208. int i = jsf.Length;
  209. while (--i >= 0)
  210. {
  211. int jsfi = jsf[i];
  212. // NOTE: The shifting ensures the sign is extended correctly
  213. int kDigit = ((jsfi << 24) >> 28), lDigit = ((jsfi << 28) >> 28);
  214. int index = 4 + (kDigit * 3) + lDigit;
  215. R = R.TwicePlus(table[index]);
  216. }
  217. return R;
  218. }
  219. internal static ECPoint ImplShamirsTrickWNaf(ECPoint P, BigInteger k,
  220. ECPoint Q, BigInteger l)
  221. {
  222. bool negK = k.SignValue < 0, negL = l.SignValue < 0;
  223. k = k.Abs();
  224. l = l.Abs();
  225. int widthP = System.Math.Max(2, System.Math.Min(16, WNafUtilities.GetWindowSize(k.BitLength)));
  226. int widthQ = System.Math.Max(2, System.Math.Min(16, WNafUtilities.GetWindowSize(l.BitLength)));
  227. WNafPreCompInfo infoP = WNafUtilities.Precompute(P, widthP, true);
  228. WNafPreCompInfo infoQ = WNafUtilities.Precompute(Q, widthQ, true);
  229. ECPoint[] preCompP = negK ? infoP.PreCompNeg : infoP.PreComp;
  230. ECPoint[] preCompQ = negL ? infoQ.PreCompNeg : infoQ.PreComp;
  231. ECPoint[] preCompNegP = negK ? infoP.PreComp : infoP.PreCompNeg;
  232. ECPoint[] preCompNegQ = negL ? infoQ.PreComp : infoQ.PreCompNeg;
  233. byte[] wnafP = WNafUtilities.GenerateWindowNaf(widthP, k);
  234. byte[] wnafQ = WNafUtilities.GenerateWindowNaf(widthQ, l);
  235. return ImplShamirsTrickWNaf(preCompP, preCompNegP, wnafP, preCompQ, preCompNegQ, wnafQ);
  236. }
  237. internal static ECPoint ImplShamirsTrickWNaf(ECPoint P, BigInteger k, ECPointMap pointMapQ, BigInteger l)
  238. {
  239. bool negK = k.SignValue < 0, negL = l.SignValue < 0;
  240. k = k.Abs();
  241. l = l.Abs();
  242. int width = System.Math.Max(2, System.Math.Min(16, WNafUtilities.GetWindowSize(System.Math.Max(k.BitLength, l.BitLength))));
  243. ECPoint Q = WNafUtilities.MapPointWithPrecomp(P, width, true, pointMapQ);
  244. WNafPreCompInfo infoP = WNafUtilities.GetWNafPreCompInfo(P);
  245. WNafPreCompInfo infoQ = WNafUtilities.GetWNafPreCompInfo(Q);
  246. ECPoint[] preCompP = negK ? infoP.PreCompNeg : infoP.PreComp;
  247. ECPoint[] preCompQ = negL ? infoQ.PreCompNeg : infoQ.PreComp;
  248. ECPoint[] preCompNegP = negK ? infoP.PreComp : infoP.PreCompNeg;
  249. ECPoint[] preCompNegQ = negL ? infoQ.PreComp : infoQ.PreCompNeg;
  250. byte[] wnafP = WNafUtilities.GenerateWindowNaf(width, k);
  251. byte[] wnafQ = WNafUtilities.GenerateWindowNaf(width, l);
  252. return ImplShamirsTrickWNaf(preCompP, preCompNegP, wnafP, preCompQ, preCompNegQ, wnafQ);
  253. }
  254. private static ECPoint ImplShamirsTrickWNaf(ECPoint[] preCompP, ECPoint[] preCompNegP, byte[] wnafP,
  255. ECPoint[] preCompQ, ECPoint[] preCompNegQ, byte[] wnafQ)
  256. {
  257. int len = System.Math.Max(wnafP.Length, wnafQ.Length);
  258. ECCurve curve = preCompP[0].Curve;
  259. ECPoint infinity = curve.Infinity;
  260. ECPoint R = infinity;
  261. int zeroes = 0;
  262. for (int i = len - 1; i >= 0; --i)
  263. {
  264. int wiP = i < wnafP.Length ? (int)(sbyte)wnafP[i] : 0;
  265. int wiQ = i < wnafQ.Length ? (int)(sbyte)wnafQ[i] : 0;
  266. if ((wiP | wiQ) == 0)
  267. {
  268. ++zeroes;
  269. continue;
  270. }
  271. ECPoint r = infinity;
  272. if (wiP != 0)
  273. {
  274. int nP = System.Math.Abs(wiP);
  275. ECPoint[] tableP = wiP < 0 ? preCompNegP : preCompP;
  276. r = r.Add(tableP[nP >> 1]);
  277. }
  278. if (wiQ != 0)
  279. {
  280. int nQ = System.Math.Abs(wiQ);
  281. ECPoint[] tableQ = wiQ < 0 ? preCompNegQ : preCompQ;
  282. r = r.Add(tableQ[nQ >> 1]);
  283. }
  284. if (zeroes > 0)
  285. {
  286. R = R.TimesPow2(zeroes);
  287. zeroes = 0;
  288. }
  289. R = R.TwicePlus(r);
  290. }
  291. if (zeroes > 0)
  292. {
  293. R = R.TimesPow2(zeroes);
  294. }
  295. return R;
  296. }
  297. internal static ECPoint ImplSumOfMultiplies(ECPoint[] ps, BigInteger[] ks)
  298. {
  299. int count = ps.Length;
  300. bool[] negs = new bool[count];
  301. WNafPreCompInfo[] infos = new WNafPreCompInfo[count];
  302. byte[][] wnafs = new byte[count][];
  303. for (int i = 0; i < count; ++i)
  304. {
  305. BigInteger ki = ks[i]; negs[i] = ki.SignValue < 0; ki = ki.Abs();
  306. int width = System.Math.Max(2, System.Math.Min(16, WNafUtilities.GetWindowSize(ki.BitLength)));
  307. infos[i] = WNafUtilities.Precompute(ps[i], width, true);
  308. wnafs[i] = WNafUtilities.GenerateWindowNaf(width, ki);
  309. }
  310. return ImplSumOfMultiplies(negs, infos, wnafs);
  311. }
  312. internal static ECPoint ImplSumOfMultipliesGlv(ECPoint[] ps, BigInteger[] ks, GlvEndomorphism glvEndomorphism)
  313. {
  314. BigInteger n = ps[0].Curve.Order;
  315. int len = ps.Length;
  316. BigInteger[] abs = new BigInteger[len << 1];
  317. for (int i = 0, j = 0; i < len; ++i)
  318. {
  319. BigInteger[] ab = glvEndomorphism.DecomposeScalar(ks[i].Mod(n));
  320. abs[j++] = ab[0];
  321. abs[j++] = ab[1];
  322. }
  323. ECPointMap pointMap = glvEndomorphism.PointMap;
  324. if (glvEndomorphism.HasEfficientPointMap)
  325. {
  326. return ECAlgorithms.ImplSumOfMultiplies(ps, pointMap, abs);
  327. }
  328. ECPoint[] pqs = new ECPoint[len << 1];
  329. for (int i = 0, j = 0; i < len; ++i)
  330. {
  331. ECPoint p = ps[i], q = pointMap.Map(p);
  332. pqs[j++] = p;
  333. pqs[j++] = q;
  334. }
  335. return ECAlgorithms.ImplSumOfMultiplies(pqs, abs);
  336. }
  337. internal static ECPoint ImplSumOfMultiplies(ECPoint[] ps, ECPointMap pointMap, BigInteger[] ks)
  338. {
  339. int halfCount = ps.Length, fullCount = halfCount << 1;
  340. bool[] negs = new bool[fullCount];
  341. WNafPreCompInfo[] infos = new WNafPreCompInfo[fullCount];
  342. byte[][] wnafs = new byte[fullCount][];
  343. for (int i = 0; i < halfCount; ++i)
  344. {
  345. int j0 = i << 1, j1 = j0 + 1;
  346. BigInteger kj0 = ks[j0]; negs[j0] = kj0.SignValue < 0; kj0 = kj0.Abs();
  347. BigInteger kj1 = ks[j1]; negs[j1] = kj1.SignValue < 0; kj1 = kj1.Abs();
  348. int width = System.Math.Max(2, System.Math.Min(16, WNafUtilities.GetWindowSize(System.Math.Max(kj0.BitLength, kj1.BitLength))));
  349. ECPoint P = ps[i], Q = WNafUtilities.MapPointWithPrecomp(P, width, true, pointMap);
  350. infos[j0] = WNafUtilities.GetWNafPreCompInfo(P);
  351. infos[j1] = WNafUtilities.GetWNafPreCompInfo(Q);
  352. wnafs[j0] = WNafUtilities.GenerateWindowNaf(width, kj0);
  353. wnafs[j1] = WNafUtilities.GenerateWindowNaf(width, kj1);
  354. }
  355. return ImplSumOfMultiplies(negs, infos, wnafs);
  356. }
  357. private static ECPoint ImplSumOfMultiplies(bool[] negs, WNafPreCompInfo[] infos, byte[][] wnafs)
  358. {
  359. int len = 0, count = wnafs.Length;
  360. for (int i = 0; i < count; ++i)
  361. {
  362. len = System.Math.Max(len, wnafs[i].Length);
  363. }
  364. ECCurve curve = infos[0].PreComp[0].Curve;
  365. ECPoint infinity = curve.Infinity;
  366. ECPoint R = infinity;
  367. int zeroes = 0;
  368. for (int i = len - 1; i >= 0; --i)
  369. {
  370. ECPoint r = infinity;
  371. for (int j = 0; j < count; ++j)
  372. {
  373. byte[] wnaf = wnafs[j];
  374. int wi = i < wnaf.Length ? (int)(sbyte)wnaf[i] : 0;
  375. if (wi != 0)
  376. {
  377. int n = System.Math.Abs(wi);
  378. WNafPreCompInfo info = infos[j];
  379. ECPoint[] table = (wi < 0 == negs[j]) ? info.PreComp : info.PreCompNeg;
  380. r = r.Add(table[n >> 1]);
  381. }
  382. }
  383. if (r == infinity)
  384. {
  385. ++zeroes;
  386. continue;
  387. }
  388. if (zeroes > 0)
  389. {
  390. R = R.TimesPow2(zeroes);
  391. zeroes = 0;
  392. }
  393. R = R.TwicePlus(r);
  394. }
  395. if (zeroes > 0)
  396. {
  397. R = R.TimesPow2(zeroes);
  398. }
  399. return R;
  400. }
  401. }
  402. }
  403. #pragma warning restore
  404. #endif