WNafUtilities.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. using System;
  3. namespace Org.BouncyCastle.Math.EC.Multiplier
  4. {
  5. public abstract class WNafUtilities
  6. {
  7. public static readonly string PRECOMP_NAME = "bc_wnaf";
  8. private static readonly int[] DEFAULT_WINDOW_SIZE_CUTOFFS = new int[]{ 13, 41, 121, 337, 897, 2305 };
  9. private static readonly byte[] EMPTY_BYTES = new byte[0];
  10. private static readonly int[] EMPTY_INTS = new int[0];
  11. private static readonly ECPoint[] EMPTY_POINTS = new ECPoint[0];
  12. public static int[] GenerateCompactNaf(BigInteger k)
  13. {
  14. if ((k.BitLength >> 16) != 0)
  15. throw new ArgumentException("must have bitlength < 2^16", "k");
  16. if (k.SignValue == 0)
  17. return EMPTY_INTS;
  18. BigInteger _3k = k.ShiftLeft(1).Add(k);
  19. int bits = _3k.BitLength;
  20. int[] naf = new int[bits >> 1];
  21. BigInteger diff = _3k.Xor(k);
  22. int highBit = bits - 1, length = 0, zeroes = 0;
  23. for (int i = 1; i < highBit; ++i)
  24. {
  25. if (!diff.TestBit(i))
  26. {
  27. ++zeroes;
  28. continue;
  29. }
  30. int digit = k.TestBit(i) ? -1 : 1;
  31. naf[length++] = (digit << 16) | zeroes;
  32. zeroes = 1;
  33. ++i;
  34. }
  35. naf[length++] = (1 << 16) | zeroes;
  36. if (naf.Length > length)
  37. {
  38. naf = Trim(naf, length);
  39. }
  40. return naf;
  41. }
  42. public static int[] GenerateCompactWindowNaf(int width, BigInteger k)
  43. {
  44. if (width == 2)
  45. {
  46. return GenerateCompactNaf(k);
  47. }
  48. if (width < 2 || width > 16)
  49. throw new ArgumentException("must be in the range [2, 16]", "width");
  50. if ((k.BitLength >> 16) != 0)
  51. throw new ArgumentException("must have bitlength < 2^16", "k");
  52. if (k.SignValue == 0)
  53. return EMPTY_INTS;
  54. int[] wnaf = new int[k.BitLength / width + 1];
  55. // 2^width and a mask and sign bit set accordingly
  56. int pow2 = 1 << width;
  57. int mask = pow2 - 1;
  58. int sign = pow2 >> 1;
  59. bool carry = false;
  60. int length = 0, pos = 0;
  61. while (pos <= k.BitLength)
  62. {
  63. if (k.TestBit(pos) == carry)
  64. {
  65. ++pos;
  66. continue;
  67. }
  68. k = k.ShiftRight(pos);
  69. int digit = k.IntValue & mask;
  70. if (carry)
  71. {
  72. ++digit;
  73. }
  74. carry = (digit & sign) != 0;
  75. if (carry)
  76. {
  77. digit -= pow2;
  78. }
  79. int zeroes = length > 0 ? pos - 1 : pos;
  80. wnaf[length++] = (digit << 16) | zeroes;
  81. pos = width;
  82. }
  83. // Reduce the WNAF array to its actual length
  84. if (wnaf.Length > length)
  85. {
  86. wnaf = Trim(wnaf, length);
  87. }
  88. return wnaf;
  89. }
  90. public static byte[] GenerateJsf(BigInteger g, BigInteger h)
  91. {
  92. int digits = System.Math.Max(g.BitLength, h.BitLength) + 1;
  93. byte[] jsf = new byte[digits];
  94. BigInteger k0 = g, k1 = h;
  95. int j = 0, d0 = 0, d1 = 0;
  96. int offset = 0;
  97. while ((d0 | d1) != 0 || k0.BitLength > offset || k1.BitLength > offset)
  98. {
  99. int n0 = ((int)((uint)k0.IntValue >> offset) + d0) & 7;
  100. int n1 = ((int)((uint)k1.IntValue >> offset) + d1) & 7;
  101. int u0 = n0 & 1;
  102. if (u0 != 0)
  103. {
  104. u0 -= (n0 & 2);
  105. if ((n0 + u0) == 4 && (n1 & 3) == 2)
  106. {
  107. u0 = -u0;
  108. }
  109. }
  110. int u1 = n1 & 1;
  111. if (u1 != 0)
  112. {
  113. u1 -= (n1 & 2);
  114. if ((n1 + u1) == 4 && (n0 & 3) == 2)
  115. {
  116. u1 = -u1;
  117. }
  118. }
  119. if ((d0 << 1) == 1 + u0)
  120. {
  121. d0 ^= 1;
  122. }
  123. if ((d1 << 1) == 1 + u1)
  124. {
  125. d1 ^= 1;
  126. }
  127. if (++offset == 30)
  128. {
  129. offset = 0;
  130. k0 = k0.ShiftRight(30);
  131. k1 = k1.ShiftRight(30);
  132. }
  133. jsf[j++] = (byte)((u0 << 4) | (u1 & 0xF));
  134. }
  135. // Reduce the JSF array to its actual length
  136. if (jsf.Length > j)
  137. {
  138. jsf = Trim(jsf, j);
  139. }
  140. return jsf;
  141. }
  142. public static byte[] GenerateNaf(BigInteger k)
  143. {
  144. if (k.SignValue == 0)
  145. return EMPTY_BYTES;
  146. BigInteger _3k = k.ShiftLeft(1).Add(k);
  147. int digits = _3k.BitLength - 1;
  148. byte[] naf = new byte[digits];
  149. BigInteger diff = _3k.Xor(k);
  150. for (int i = 1; i < digits; ++i)
  151. {
  152. if (diff.TestBit(i))
  153. {
  154. naf[i - 1] = (byte)(k.TestBit(i) ? -1 : 1);
  155. ++i;
  156. }
  157. }
  158. naf[digits - 1] = 1;
  159. return naf;
  160. }
  161. /**
  162. * Computes the Window NAF (non-adjacent Form) of an integer.
  163. * @param width The width <code>w</code> of the Window NAF. The width is
  164. * defined as the minimal number <code>w</code>, such that for any
  165. * <code>w</code> consecutive digits in the resulting representation, at
  166. * most one is non-zero.
  167. * @param k The integer of which the Window NAF is computed.
  168. * @return The Window NAF of the given width, such that the following holds:
  169. * <code>k = &amp;sum;<sub>i=0</sub><sup>l-1</sup> k<sub>i</sub>2<sup>i</sup>
  170. * </code>, where the <code>k<sub>i</sub></code> denote the elements of the
  171. * returned <code>byte[]</code>.
  172. */
  173. public static byte[] GenerateWindowNaf(int width, BigInteger k)
  174. {
  175. if (width == 2)
  176. {
  177. return GenerateNaf(k);
  178. }
  179. if (width < 2 || width > 8)
  180. throw new ArgumentException("must be in the range [2, 8]", "width");
  181. if (k.SignValue == 0)
  182. return EMPTY_BYTES;
  183. byte[] wnaf = new byte[k.BitLength + 1];
  184. // 2^width and a mask and sign bit set accordingly
  185. int pow2 = 1 << width;
  186. int mask = pow2 - 1;
  187. int sign = pow2 >> 1;
  188. bool carry = false;
  189. int length = 0, pos = 0;
  190. while (pos <= k.BitLength)
  191. {
  192. if (k.TestBit(pos) == carry)
  193. {
  194. ++pos;
  195. continue;
  196. }
  197. k = k.ShiftRight(pos);
  198. int digit = k.IntValue & mask;
  199. if (carry)
  200. {
  201. ++digit;
  202. }
  203. carry = (digit & sign) != 0;
  204. if (carry)
  205. {
  206. digit -= pow2;
  207. }
  208. length += (length > 0) ? pos - 1 : pos;
  209. wnaf[length++] = (byte)digit;
  210. pos = width;
  211. }
  212. // Reduce the WNAF array to its actual length
  213. if (wnaf.Length > length)
  214. {
  215. wnaf = Trim(wnaf, length);
  216. }
  217. return wnaf;
  218. }
  219. public static int GetNafWeight(BigInteger k)
  220. {
  221. if (k.SignValue == 0)
  222. return 0;
  223. BigInteger _3k = k.ShiftLeft(1).Add(k);
  224. BigInteger diff = _3k.Xor(k);
  225. return diff.BitCount;
  226. }
  227. public static WNafPreCompInfo GetWNafPreCompInfo(ECPoint p)
  228. {
  229. return GetWNafPreCompInfo(p.Curve.GetPreCompInfo(p, PRECOMP_NAME));
  230. }
  231. public static WNafPreCompInfo GetWNafPreCompInfo(PreCompInfo preCompInfo)
  232. {
  233. if ((preCompInfo != null) && (preCompInfo is WNafPreCompInfo))
  234. {
  235. return (WNafPreCompInfo)preCompInfo;
  236. }
  237. return new WNafPreCompInfo();
  238. }
  239. /**
  240. * Determine window width to use for a scalar multiplication of the given size.
  241. *
  242. * @param bits the bit-length of the scalar to multiply by
  243. * @return the window size to use
  244. */
  245. public static int GetWindowSize(int bits)
  246. {
  247. return GetWindowSize(bits, DEFAULT_WINDOW_SIZE_CUTOFFS);
  248. }
  249. /**
  250. * Determine window width to use for a scalar multiplication of the given size.
  251. *
  252. * @param bits the bit-length of the scalar to multiply by
  253. * @param windowSizeCutoffs a monotonically increasing list of bit sizes at which to increment the window width
  254. * @return the window size to use
  255. */
  256. public static int GetWindowSize(int bits, int[] windowSizeCutoffs)
  257. {
  258. int w = 0;
  259. for (; w < windowSizeCutoffs.Length; ++w)
  260. {
  261. if (bits < windowSizeCutoffs[w])
  262. {
  263. break;
  264. }
  265. }
  266. return w + 2;
  267. }
  268. public static ECPoint MapPointWithPrecomp(ECPoint p, int width, bool includeNegated,
  269. ECPointMap pointMap)
  270. {
  271. ECCurve c = p.Curve;
  272. WNafPreCompInfo wnafPreCompP = Precompute(p, width, includeNegated);
  273. ECPoint q = pointMap.Map(p);
  274. WNafPreCompInfo wnafPreCompQ = GetWNafPreCompInfo(c.GetPreCompInfo(q, PRECOMP_NAME));
  275. ECPoint twiceP = wnafPreCompP.Twice;
  276. if (twiceP != null)
  277. {
  278. ECPoint twiceQ = pointMap.Map(twiceP);
  279. wnafPreCompQ.Twice = twiceQ;
  280. }
  281. ECPoint[] preCompP = wnafPreCompP.PreComp;
  282. ECPoint[] preCompQ = new ECPoint[preCompP.Length];
  283. for (int i = 0; i < preCompP.Length; ++i)
  284. {
  285. preCompQ[i] = pointMap.Map(preCompP[i]);
  286. }
  287. wnafPreCompQ.PreComp = preCompQ;
  288. if (includeNegated)
  289. {
  290. ECPoint[] preCompNegQ = new ECPoint[preCompQ.Length];
  291. for (int i = 0; i < preCompNegQ.Length; ++i)
  292. {
  293. preCompNegQ[i] = preCompQ[i].Negate();
  294. }
  295. wnafPreCompQ.PreCompNeg = preCompNegQ;
  296. }
  297. c.SetPreCompInfo(q, PRECOMP_NAME, wnafPreCompQ);
  298. return q;
  299. }
  300. public static WNafPreCompInfo Precompute(ECPoint p, int width, bool includeNegated)
  301. {
  302. ECCurve c = p.Curve;
  303. WNafPreCompInfo wnafPreCompInfo = GetWNafPreCompInfo(c.GetPreCompInfo(p, PRECOMP_NAME));
  304. int iniPreCompLen = 0, reqPreCompLen = 1 << System.Math.Max(0, width - 2);
  305. ECPoint[] preComp = wnafPreCompInfo.PreComp;
  306. if (preComp == null)
  307. {
  308. preComp = EMPTY_POINTS;
  309. }
  310. else
  311. {
  312. iniPreCompLen = preComp.Length;
  313. }
  314. if (iniPreCompLen < reqPreCompLen)
  315. {
  316. preComp = ResizeTable(preComp, reqPreCompLen);
  317. if (reqPreCompLen == 1)
  318. {
  319. preComp[0] = p.Normalize();
  320. }
  321. else
  322. {
  323. int curPreCompLen = iniPreCompLen;
  324. if (curPreCompLen == 0)
  325. {
  326. preComp[0] = p;
  327. curPreCompLen = 1;
  328. }
  329. ECFieldElement iso = null;
  330. if (reqPreCompLen == 2)
  331. {
  332. preComp[1] = p.ThreeTimes();
  333. }
  334. else
  335. {
  336. ECPoint twiceP = wnafPreCompInfo.Twice, last = preComp[curPreCompLen - 1];
  337. if (twiceP == null)
  338. {
  339. twiceP = preComp[0].Twice();
  340. wnafPreCompInfo.Twice = twiceP;
  341. /*
  342. * For Fp curves with Jacobian projective coordinates, use a (quasi-)isomorphism
  343. * where 'twiceP' is "affine", so that the subsequent additions are cheaper. This
  344. * also requires scaling the initial point's X, Y coordinates, and reversing the
  345. * isomorphism as part of the subsequent normalization.
  346. *
  347. * NOTE: The correctness of this optimization depends on:
  348. * 1) additions do not use the curve's A, B coefficients.
  349. * 2) no special cases (i.e. Q +/- Q) when calculating 1P, 3P, 5P, ...
  350. */
  351. if (ECAlgorithms.IsFpCurve(c) && c.FieldSize >= 64)
  352. {
  353. switch (c.CoordinateSystem)
  354. {
  355. case ECCurve.COORD_JACOBIAN:
  356. case ECCurve.COORD_JACOBIAN_CHUDNOVSKY:
  357. case ECCurve.COORD_JACOBIAN_MODIFIED:
  358. {
  359. iso = twiceP.GetZCoord(0);
  360. twiceP = c.CreatePoint(twiceP.XCoord.ToBigInteger(),
  361. twiceP.YCoord.ToBigInteger());
  362. ECFieldElement iso2 = iso.Square(), iso3 = iso2.Multiply(iso);
  363. last = last.ScaleX(iso2).ScaleY(iso3);
  364. if (iniPreCompLen == 0)
  365. {
  366. preComp[0] = last;
  367. }
  368. break;
  369. }
  370. }
  371. }
  372. }
  373. while (curPreCompLen < reqPreCompLen)
  374. {
  375. /*
  376. * Compute the new ECPoints for the precomputation array. The values 1, 3,
  377. * 5, ..., 2^(width-1)-1 times p are computed
  378. */
  379. preComp[curPreCompLen++] = last = last.Add(twiceP);
  380. }
  381. }
  382. /*
  383. * Having oft-used operands in affine form makes operations faster.
  384. */
  385. c.NormalizeAll(preComp, iniPreCompLen, reqPreCompLen - iniPreCompLen, iso);
  386. }
  387. }
  388. wnafPreCompInfo.PreComp = preComp;
  389. if (includeNegated)
  390. {
  391. ECPoint[] preCompNeg = wnafPreCompInfo.PreCompNeg;
  392. int pos;
  393. if (preCompNeg == null)
  394. {
  395. pos = 0;
  396. preCompNeg = new ECPoint[reqPreCompLen];
  397. }
  398. else
  399. {
  400. pos = preCompNeg.Length;
  401. if (pos < reqPreCompLen)
  402. {
  403. preCompNeg = ResizeTable(preCompNeg, reqPreCompLen);
  404. }
  405. }
  406. while (pos < reqPreCompLen)
  407. {
  408. preCompNeg[pos] = preComp[pos].Negate();
  409. ++pos;
  410. }
  411. wnafPreCompInfo.PreCompNeg = preCompNeg;
  412. }
  413. c.SetPreCompInfo(p, PRECOMP_NAME, wnafPreCompInfo);
  414. return wnafPreCompInfo;
  415. }
  416. private static byte[] Trim(byte[] a, int length)
  417. {
  418. byte[] result = new byte[length];
  419. Array.Copy(a, 0, result, 0, result.Length);
  420. return result;
  421. }
  422. private static int[] Trim(int[] a, int length)
  423. {
  424. int[] result = new int[length];
  425. Array.Copy(a, 0, result, 0, result.Length);
  426. return result;
  427. }
  428. private static ECPoint[] ResizeTable(ECPoint[] a, int length)
  429. {
  430. ECPoint[] result = new ECPoint[length];
  431. Array.Copy(a, 0, result, 0, a.Length);
  432. return result;
  433. }
  434. }
  435. }
  436. #endif