WNafUtilities.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  5. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Math.EC.Multiplier
  6. {
  7. public abstract class WNafUtilities
  8. {
  9. public static readonly string PRECOMP_NAME = "bc_wnaf";
  10. private static readonly int[] DEFAULT_WINDOW_SIZE_CUTOFFS = new int[]{ 13, 41, 121, 337, 897, 2305 };
  11. private static readonly int MAX_WIDTH = 16;
  12. private static readonly ECPoint[] EMPTY_POINTS = new ECPoint[0];
  13. public static void ConfigureBasepoint(ECPoint p)
  14. {
  15. ECCurve c = p.Curve;
  16. if (null == c)
  17. return;
  18. BigInteger n = c.Order;
  19. int bits = (null == n) ? c.FieldSize + 1 : n.BitLength;
  20. int confWidth = System.Math.Min(MAX_WIDTH, GetWindowSize(bits) + 3);
  21. c.Precompute(p, PRECOMP_NAME, new ConfigureBasepointCallback(c, confWidth));
  22. }
  23. public static int[] GenerateCompactNaf(BigInteger k)
  24. {
  25. if ((k.BitLength >> 16) != 0)
  26. throw new ArgumentException("must have bitlength < 2^16", "k");
  27. if (k.SignValue == 0)
  28. return Arrays.EmptyInts;
  29. BigInteger _3k = k.ShiftLeft(1).Add(k);
  30. int bits = _3k.BitLength;
  31. int[] naf = new int[bits >> 1];
  32. BigInteger diff = _3k.Xor(k);
  33. int highBit = bits - 1, length = 0, zeroes = 0;
  34. for (int i = 1; i < highBit; ++i)
  35. {
  36. if (!diff.TestBit(i))
  37. {
  38. ++zeroes;
  39. continue;
  40. }
  41. int digit = k.TestBit(i) ? -1 : 1;
  42. naf[length++] = (digit << 16) | zeroes;
  43. zeroes = 1;
  44. ++i;
  45. }
  46. naf[length++] = (1 << 16) | zeroes;
  47. if (naf.Length > length)
  48. {
  49. naf = Trim(naf, length);
  50. }
  51. return naf;
  52. }
  53. public static int[] GenerateCompactWindowNaf(int width, BigInteger k)
  54. {
  55. if (width == 2)
  56. {
  57. return GenerateCompactNaf(k);
  58. }
  59. if (width < 2 || width > 16)
  60. throw new ArgumentException("must be in the range [2, 16]", "width");
  61. if ((k.BitLength >> 16) != 0)
  62. throw new ArgumentException("must have bitlength < 2^16", "k");
  63. if (k.SignValue == 0)
  64. return Arrays.EmptyInts;
  65. int[] wnaf = new int[k.BitLength / width + 1];
  66. // 2^width and a mask and sign bit set accordingly
  67. int pow2 = 1 << width;
  68. int mask = pow2 - 1;
  69. int sign = pow2 >> 1;
  70. bool carry = false;
  71. int length = 0, pos = 0;
  72. while (pos <= k.BitLength)
  73. {
  74. if (k.TestBit(pos) == carry)
  75. {
  76. ++pos;
  77. continue;
  78. }
  79. k = k.ShiftRight(pos);
  80. int digit = k.IntValue & mask;
  81. if (carry)
  82. {
  83. ++digit;
  84. }
  85. carry = (digit & sign) != 0;
  86. if (carry)
  87. {
  88. digit -= pow2;
  89. }
  90. int zeroes = length > 0 ? pos - 1 : pos;
  91. wnaf[length++] = (digit << 16) | zeroes;
  92. pos = width;
  93. }
  94. // Reduce the WNAF array to its actual length
  95. if (wnaf.Length > length)
  96. {
  97. wnaf = Trim(wnaf, length);
  98. }
  99. return wnaf;
  100. }
  101. public static byte[] GenerateJsf(BigInteger g, BigInteger h)
  102. {
  103. int digits = System.Math.Max(g.BitLength, h.BitLength) + 1;
  104. byte[] jsf = new byte[digits];
  105. BigInteger k0 = g, k1 = h;
  106. int j = 0, d0 = 0, d1 = 0;
  107. int offset = 0;
  108. while ((d0 | d1) != 0 || k0.BitLength > offset || k1.BitLength > offset)
  109. {
  110. int n0 = ((int)((uint)k0.IntValue >> offset) + d0) & 7;
  111. int n1 = ((int)((uint)k1.IntValue >> offset) + d1) & 7;
  112. int u0 = n0 & 1;
  113. if (u0 != 0)
  114. {
  115. u0 -= (n0 & 2);
  116. if ((n0 + u0) == 4 && (n1 & 3) == 2)
  117. {
  118. u0 = -u0;
  119. }
  120. }
  121. int u1 = n1 & 1;
  122. if (u1 != 0)
  123. {
  124. u1 -= (n1 & 2);
  125. if ((n1 + u1) == 4 && (n0 & 3) == 2)
  126. {
  127. u1 = -u1;
  128. }
  129. }
  130. if ((d0 << 1) == 1 + u0)
  131. {
  132. d0 ^= 1;
  133. }
  134. if ((d1 << 1) == 1 + u1)
  135. {
  136. d1 ^= 1;
  137. }
  138. if (++offset == 30)
  139. {
  140. offset = 0;
  141. k0 = k0.ShiftRight(30);
  142. k1 = k1.ShiftRight(30);
  143. }
  144. jsf[j++] = (byte)((u0 << 4) | (u1 & 0xF));
  145. }
  146. // Reduce the JSF array to its actual length
  147. if (jsf.Length > j)
  148. {
  149. jsf = Trim(jsf, j);
  150. }
  151. return jsf;
  152. }
  153. public static byte[] GenerateNaf(BigInteger k)
  154. {
  155. if (k.SignValue == 0)
  156. return Arrays.EmptyBytes;
  157. BigInteger _3k = k.ShiftLeft(1).Add(k);
  158. int digits = _3k.BitLength - 1;
  159. byte[] naf = new byte[digits];
  160. BigInteger diff = _3k.Xor(k);
  161. for (int i = 1; i < digits; ++i)
  162. {
  163. if (diff.TestBit(i))
  164. {
  165. naf[i - 1] = (byte)(k.TestBit(i) ? -1 : 1);
  166. ++i;
  167. }
  168. }
  169. naf[digits - 1] = 1;
  170. return naf;
  171. }
  172. /**
  173. * Computes the Window NAF (non-adjacent Form) of an integer.
  174. * @param width The width <code>w</code> of the Window NAF. The width is
  175. * defined as the minimal number <code>w</code>, such that for any
  176. * <code>w</code> consecutive digits in the resulting representation, at
  177. * most one is non-zero.
  178. * @param k The integer of which the Window NAF is computed.
  179. * @return The Window NAF of the given width, such that the following holds:
  180. * <code>k = &amp;sum;<sub>i=0</sub><sup>l-1</sup> k<sub>i</sub>2<sup>i</sup>
  181. * </code>, where the <code>k<sub>i</sub></code> denote the elements of the
  182. * returned <code>byte[]</code>.
  183. */
  184. public static byte[] GenerateWindowNaf(int width, BigInteger k)
  185. {
  186. if (width == 2)
  187. {
  188. return GenerateNaf(k);
  189. }
  190. if (width < 2 || width > 8)
  191. throw new ArgumentException("must be in the range [2, 8]", "width");
  192. if (k.SignValue == 0)
  193. return Arrays.EmptyBytes;
  194. byte[] wnaf = new byte[k.BitLength + 1];
  195. // 2^width and a mask and sign bit set accordingly
  196. int pow2 = 1 << width;
  197. int mask = pow2 - 1;
  198. int sign = pow2 >> 1;
  199. bool carry = false;
  200. int length = 0, pos = 0;
  201. while (pos <= k.BitLength)
  202. {
  203. if (k.TestBit(pos) == carry)
  204. {
  205. ++pos;
  206. continue;
  207. }
  208. k = k.ShiftRight(pos);
  209. int digit = k.IntValue & mask;
  210. if (carry)
  211. {
  212. ++digit;
  213. }
  214. carry = (digit & sign) != 0;
  215. if (carry)
  216. {
  217. digit -= pow2;
  218. }
  219. length += (length > 0) ? pos - 1 : pos;
  220. wnaf[length++] = (byte)digit;
  221. pos = width;
  222. }
  223. // Reduce the WNAF array to its actual length
  224. if (wnaf.Length > length)
  225. {
  226. wnaf = Trim(wnaf, length);
  227. }
  228. return wnaf;
  229. }
  230. public static int GetNafWeight(BigInteger k)
  231. {
  232. if (k.SignValue == 0)
  233. return 0;
  234. BigInteger _3k = k.ShiftLeft(1).Add(k);
  235. BigInteger diff = _3k.Xor(k);
  236. return diff.BitCount;
  237. }
  238. public static WNafPreCompInfo GetWNafPreCompInfo(ECPoint p)
  239. {
  240. return GetWNafPreCompInfo(p.Curve.GetPreCompInfo(p, PRECOMP_NAME));
  241. }
  242. public static WNafPreCompInfo GetWNafPreCompInfo(PreCompInfo preCompInfo)
  243. {
  244. return preCompInfo as WNafPreCompInfo;
  245. }
  246. /**
  247. * Determine window width to use for a scalar multiplication of the given size.
  248. *
  249. * @param bits the bit-length of the scalar to multiply by
  250. * @return the window size to use
  251. */
  252. public static int GetWindowSize(int bits)
  253. {
  254. return GetWindowSize(bits, DEFAULT_WINDOW_SIZE_CUTOFFS, MAX_WIDTH);
  255. }
  256. /**
  257. * Determine window width to use for a scalar multiplication of the given size.
  258. *
  259. * @param bits the bit-length of the scalar to multiply by
  260. * @param maxWidth the maximum window width to return
  261. * @return the window size to use
  262. */
  263. public static int GetWindowSize(int bits, int maxWidth)
  264. {
  265. return GetWindowSize(bits, DEFAULT_WINDOW_SIZE_CUTOFFS, maxWidth);
  266. }
  267. /**
  268. * Determine window width to use for a scalar multiplication of the given size.
  269. *
  270. * @param bits the bit-length of the scalar to multiply by
  271. * @param windowSizeCutoffs a monotonically increasing list of bit sizes at which to increment the window width
  272. * @return the window size to use
  273. */
  274. public static int GetWindowSize(int bits, int[] windowSizeCutoffs)
  275. {
  276. return GetWindowSize(bits, windowSizeCutoffs, MAX_WIDTH);
  277. }
  278. /**
  279. * Determine window width to use for a scalar multiplication of the given size.
  280. *
  281. * @param bits the bit-length of the scalar to multiply by
  282. * @param windowSizeCutoffs a monotonically increasing list of bit sizes at which to increment the window width
  283. * @param maxWidth the maximum window width to return
  284. * @return the window size to use
  285. */
  286. public static int GetWindowSize(int bits, int[] windowSizeCutoffs, int maxWidth)
  287. {
  288. int w = 0;
  289. for (; w < windowSizeCutoffs.Length; ++w)
  290. {
  291. if (bits < windowSizeCutoffs[w])
  292. {
  293. break;
  294. }
  295. }
  296. return System.Math.Max(2, System.Math.Min(maxWidth, w + 2));
  297. }
  298. [Obsolete]
  299. public static ECPoint MapPointWithPrecomp(ECPoint p, int minWidth, bool includeNegated,
  300. ECPointMap pointMap)
  301. {
  302. ECCurve c = p.Curve;
  303. WNafPreCompInfo infoP = Precompute(p, minWidth, includeNegated);
  304. ECPoint q = pointMap.Map(p);
  305. c.Precompute(q, PRECOMP_NAME, new MapPointCallback(infoP, includeNegated, pointMap));
  306. return q;
  307. }
  308. public static WNafPreCompInfo Precompute(ECPoint p, int minWidth, bool includeNegated)
  309. {
  310. return (WNafPreCompInfo)p.Curve.Precompute(p, PRECOMP_NAME,
  311. new PrecomputeCallback(p, minWidth, includeNegated));
  312. }
  313. public static WNafPreCompInfo PrecomputeWithPointMap(ECPoint p, ECPointMap pointMap, WNafPreCompInfo fromWNaf,
  314. bool includeNegated)
  315. {
  316. return (WNafPreCompInfo)p.Curve.Precompute(p, PRECOMP_NAME,
  317. new PrecomputeWithPointMapCallback(p, pointMap, fromWNaf, includeNegated));
  318. }
  319. private static byte[] Trim(byte[] a, int length)
  320. {
  321. byte[] result = new byte[length];
  322. Array.Copy(a, 0, result, 0, result.Length);
  323. return result;
  324. }
  325. private static int[] Trim(int[] a, int length)
  326. {
  327. int[] result = new int[length];
  328. Array.Copy(a, 0, result, 0, result.Length);
  329. return result;
  330. }
  331. private static ECPoint[] ResizeTable(ECPoint[] a, int length)
  332. {
  333. ECPoint[] result = new ECPoint[length];
  334. Array.Copy(a, 0, result, 0, a.Length);
  335. return result;
  336. }
  337. private class ConfigureBasepointCallback
  338. : IPreCompCallback
  339. {
  340. private readonly ECCurve m_curve;
  341. private readonly int m_confWidth;
  342. internal ConfigureBasepointCallback(ECCurve curve, int confWidth)
  343. {
  344. this.m_curve = curve;
  345. this.m_confWidth = confWidth;
  346. }
  347. public PreCompInfo Precompute(PreCompInfo existing)
  348. {
  349. WNafPreCompInfo existingWNaf = existing as WNafPreCompInfo;
  350. if (null != existingWNaf && existingWNaf.ConfWidth == m_confWidth)
  351. {
  352. existingWNaf.PromotionCountdown = 0;
  353. return existingWNaf;
  354. }
  355. WNafPreCompInfo result = new WNafPreCompInfo();
  356. result.PromotionCountdown = 0;
  357. result.ConfWidth = m_confWidth;
  358. if (null != existingWNaf)
  359. {
  360. result.PreComp = existingWNaf.PreComp;
  361. result.PreCompNeg = existingWNaf.PreCompNeg;
  362. result.Twice = existingWNaf.Twice;
  363. result.Width = existingWNaf.Width;
  364. }
  365. return result;
  366. }
  367. }
  368. private class MapPointCallback
  369. : IPreCompCallback
  370. {
  371. private readonly WNafPreCompInfo m_infoP;
  372. private readonly bool m_includeNegated;
  373. private readonly ECPointMap m_pointMap;
  374. internal MapPointCallback(WNafPreCompInfo infoP, bool includeNegated, ECPointMap pointMap)
  375. {
  376. this.m_infoP = infoP;
  377. this.m_includeNegated = includeNegated;
  378. this.m_pointMap = pointMap;
  379. }
  380. public PreCompInfo Precompute(PreCompInfo existing)
  381. {
  382. WNafPreCompInfo result = new WNafPreCompInfo();
  383. result.ConfWidth = m_infoP.ConfWidth;
  384. ECPoint twiceP = m_infoP.Twice;
  385. if (null != twiceP)
  386. {
  387. ECPoint twiceQ = m_pointMap.Map(twiceP);
  388. result.Twice = twiceQ;
  389. }
  390. ECPoint[] preCompP = m_infoP.PreComp;
  391. ECPoint[] preCompQ = new ECPoint[preCompP.Length];
  392. for (int i = 0; i < preCompP.Length; ++i)
  393. {
  394. preCompQ[i] = m_pointMap.Map(preCompP[i]);
  395. }
  396. result.PreComp = preCompQ;
  397. result.Width = m_infoP.Width;
  398. if (m_includeNegated)
  399. {
  400. ECPoint[] preCompNegQ = new ECPoint[preCompQ.Length];
  401. for (int i = 0; i < preCompNegQ.Length; ++i)
  402. {
  403. preCompNegQ[i] = preCompQ[i].Negate();
  404. }
  405. result.PreCompNeg = preCompNegQ;
  406. }
  407. return result;
  408. }
  409. }
  410. private class PrecomputeCallback
  411. : IPreCompCallback
  412. {
  413. private readonly ECPoint m_p;
  414. private readonly int m_minWidth;
  415. private readonly bool m_includeNegated;
  416. internal PrecomputeCallback(ECPoint p, int minWidth, bool includeNegated)
  417. {
  418. this.m_p = p;
  419. this.m_minWidth = minWidth;
  420. this.m_includeNegated = includeNegated;
  421. }
  422. public PreCompInfo Precompute(PreCompInfo existing)
  423. {
  424. WNafPreCompInfo existingWNaf = existing as WNafPreCompInfo;
  425. int width = System.Math.Max(2, System.Math.Min(MAX_WIDTH, m_minWidth));
  426. int reqPreCompLen = 1 << (width - 2);
  427. if (CheckExisting(existingWNaf, width, reqPreCompLen, m_includeNegated))
  428. {
  429. existingWNaf.DecrementPromotionCountdown();
  430. return existingWNaf;
  431. }
  432. WNafPreCompInfo result = new WNafPreCompInfo();
  433. ECCurve c = m_p.Curve;
  434. ECPoint[] preComp = null, preCompNeg = null;
  435. ECPoint twiceP = null;
  436. if (null != existingWNaf)
  437. {
  438. int promotionCountdown = existingWNaf.DecrementPromotionCountdown();
  439. result.PromotionCountdown = promotionCountdown;
  440. int confWidth = existingWNaf.ConfWidth;
  441. result.ConfWidth = confWidth;
  442. preComp = existingWNaf.PreComp;
  443. preCompNeg = existingWNaf.PreCompNeg;
  444. twiceP = existingWNaf.Twice;
  445. }
  446. width = System.Math.Min(MAX_WIDTH, System.Math.Max(result.ConfWidth, width));
  447. reqPreCompLen = 1 << (width - 2);
  448. int iniPreCompLen = 0;
  449. if (null == preComp)
  450. {
  451. preComp = EMPTY_POINTS;
  452. }
  453. else
  454. {
  455. iniPreCompLen = preComp.Length;
  456. }
  457. if (iniPreCompLen < reqPreCompLen)
  458. {
  459. preComp = WNafUtilities.ResizeTable(preComp, reqPreCompLen);
  460. if (reqPreCompLen == 1)
  461. {
  462. preComp[0] = m_p.Normalize();
  463. }
  464. else
  465. {
  466. int curPreCompLen = iniPreCompLen;
  467. if (curPreCompLen == 0)
  468. {
  469. preComp[0] = m_p;
  470. curPreCompLen = 1;
  471. }
  472. ECFieldElement iso = null;
  473. if (reqPreCompLen == 2)
  474. {
  475. preComp[1] = m_p.ThreeTimes();
  476. }
  477. else
  478. {
  479. ECPoint isoTwiceP = twiceP, last = preComp[curPreCompLen - 1];
  480. if (null == isoTwiceP)
  481. {
  482. isoTwiceP = preComp[0].Twice();
  483. twiceP = isoTwiceP;
  484. /*
  485. * For Fp curves with Jacobian projective coordinates, use a (quasi-)isomorphism
  486. * where 'twiceP' is "affine", so that the subsequent additions are cheaper. This
  487. * also requires scaling the initial point's X, Y coordinates, and reversing the
  488. * isomorphism as part of the subsequent normalization.
  489. *
  490. * NOTE: The correctness of this optimization depends on:
  491. * 1) additions do not use the curve's A, B coefficients.
  492. * 2) no special cases (i.e. Q +/- Q) when calculating 1P, 3P, 5P, ...
  493. */
  494. if (!twiceP.IsInfinity && ECAlgorithms.IsFpCurve(c) && c.FieldSize >= 64)
  495. {
  496. switch (c.CoordinateSystem)
  497. {
  498. case ECCurve.COORD_JACOBIAN:
  499. case ECCurve.COORD_JACOBIAN_CHUDNOVSKY:
  500. case ECCurve.COORD_JACOBIAN_MODIFIED:
  501. {
  502. iso = twiceP.GetZCoord(0);
  503. isoTwiceP = c.CreatePoint(twiceP.XCoord.ToBigInteger(),
  504. twiceP.YCoord.ToBigInteger());
  505. ECFieldElement iso2 = iso.Square(), iso3 = iso2.Multiply(iso);
  506. last = last.ScaleX(iso2).ScaleY(iso3);
  507. if (iniPreCompLen == 0)
  508. {
  509. preComp[0] = last;
  510. }
  511. break;
  512. }
  513. }
  514. }
  515. }
  516. while (curPreCompLen < reqPreCompLen)
  517. {
  518. /*
  519. * Compute the new ECPoints for the precomputation array. The values 1, 3,
  520. * 5, ..., 2^(width-1)-1 times p are computed
  521. */
  522. preComp[curPreCompLen++] = last = last.Add(isoTwiceP);
  523. }
  524. }
  525. /*
  526. * Having oft-used operands in affine form makes operations faster.
  527. */
  528. c.NormalizeAll(preComp, iniPreCompLen, reqPreCompLen - iniPreCompLen, iso);
  529. }
  530. }
  531. if (m_includeNegated)
  532. {
  533. int pos;
  534. if (null == preCompNeg)
  535. {
  536. pos = 0;
  537. preCompNeg = new ECPoint[reqPreCompLen];
  538. }
  539. else
  540. {
  541. pos = preCompNeg.Length;
  542. if (pos < reqPreCompLen)
  543. {
  544. preCompNeg = WNafUtilities.ResizeTable(preCompNeg, reqPreCompLen);
  545. }
  546. }
  547. while (pos < reqPreCompLen)
  548. {
  549. preCompNeg[pos] = preComp[pos].Negate();
  550. ++pos;
  551. }
  552. }
  553. result.PreComp = preComp;
  554. result.PreCompNeg = preCompNeg;
  555. result.Twice = twiceP;
  556. result.Width = width;
  557. return result;
  558. }
  559. private bool CheckExisting(WNafPreCompInfo existingWNaf, int width, int reqPreCompLen, bool includeNegated)
  560. {
  561. return null != existingWNaf
  562. && existingWNaf.Width >= System.Math.Max(existingWNaf.ConfWidth, width)
  563. && CheckTable(existingWNaf.PreComp, reqPreCompLen)
  564. && (!includeNegated || CheckTable(existingWNaf.PreCompNeg, reqPreCompLen));
  565. }
  566. private bool CheckTable(ECPoint[] table, int reqLen)
  567. {
  568. return null != table && table.Length >= reqLen;
  569. }
  570. }
  571. private class PrecomputeWithPointMapCallback
  572. : IPreCompCallback
  573. {
  574. private readonly ECPoint m_point;
  575. private readonly ECPointMap m_pointMap;
  576. private readonly WNafPreCompInfo m_fromWNaf;
  577. private readonly bool m_includeNegated;
  578. internal PrecomputeWithPointMapCallback(ECPoint point, ECPointMap pointMap, WNafPreCompInfo fromWNaf,
  579. bool includeNegated)
  580. {
  581. this.m_point = point;
  582. this.m_pointMap = pointMap;
  583. this.m_fromWNaf = fromWNaf;
  584. this.m_includeNegated = includeNegated;
  585. }
  586. public PreCompInfo Precompute(PreCompInfo existing)
  587. {
  588. WNafPreCompInfo existingWNaf = existing as WNafPreCompInfo;
  589. int width = m_fromWNaf.Width;
  590. int reqPreCompLen = m_fromWNaf.PreComp.Length;
  591. if (CheckExisting(existingWNaf, width, reqPreCompLen, m_includeNegated))
  592. {
  593. existingWNaf.DecrementPromotionCountdown();
  594. return existingWNaf;
  595. }
  596. /*
  597. * TODO Ideally this method would support incremental calculation, but given the
  598. * existing use-cases it would be of little-to-no benefit.
  599. */
  600. WNafPreCompInfo result = new WNafPreCompInfo();
  601. result.PromotionCountdown = m_fromWNaf.PromotionCountdown;
  602. ECPoint twiceFrom = m_fromWNaf.Twice;
  603. if (null != twiceFrom)
  604. {
  605. ECPoint twice = m_pointMap.Map(twiceFrom);
  606. result.Twice = twice;
  607. }
  608. ECPoint[] preCompFrom = m_fromWNaf.PreComp;
  609. ECPoint[] preComp = new ECPoint[preCompFrom.Length];
  610. for (int i = 0; i < preCompFrom.Length; ++i)
  611. {
  612. preComp[i] = m_pointMap.Map(preCompFrom[i]);
  613. }
  614. result.PreComp = preComp;
  615. result.Width = width;
  616. if (m_includeNegated)
  617. {
  618. ECPoint[] preCompNeg = new ECPoint[preComp.Length];
  619. for (int i = 0; i < preCompNeg.Length; ++i)
  620. {
  621. preCompNeg[i] = preComp[i].Negate();
  622. }
  623. result.PreCompNeg = preCompNeg;
  624. }
  625. return result;
  626. }
  627. private bool CheckExisting(WNafPreCompInfo existingWNaf, int width, int reqPreCompLen, bool includeNegated)
  628. {
  629. return null != existingWNaf
  630. && existingWNaf.Width >= width
  631. && CheckTable(existingWNaf.PreComp, reqPreCompLen)
  632. && (!includeNegated || CheckTable(existingWNaf.PreCompNeg, reqPreCompLen));
  633. }
  634. private bool CheckTable(ECPoint[] table, int reqLen)
  635. {
  636. return null != table && table.Length >= reqLen;
  637. }
  638. }
  639. }
  640. }
  641. #pragma warning restore
  642. #endif