Mod.cs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using System.Diagnostics;
  5. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
  6. using BestHTTP.SecureProtocol.Org.BouncyCastle.Security;
  7. using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  8. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Math.Raw
  9. {
  10. /*
  11. * Modular inversion as implemented in this class is based on the paper "Fast constant-time gcd
  12. * computation and modular inversion" by Daniel J. Bernstein and Bo-Yin Yang.
  13. */
  14. internal static class Mod
  15. {
  16. private const int M30 = 0x3FFFFFFF;
  17. private const ulong M32UL = 0xFFFFFFFFUL;
  18. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
  19. public static void CheckedModOddInverse(ReadOnlySpan<uint> m, ReadOnlySpan<uint> x, Span<uint> z)
  20. #else
  21. public static void CheckedModOddInverse(uint[] m, uint[] x, uint[] z)
  22. #endif
  23. {
  24. if (0 == ModOddInverse(m, x, z))
  25. throw new ArithmeticException("Inverse does not exist.");
  26. }
  27. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
  28. public static void CheckedModOddInverseVar(ReadOnlySpan<uint> m, ReadOnlySpan<uint> x, Span<uint> z)
  29. #else
  30. public static void CheckedModOddInverseVar(uint[] m, uint[] x, uint[] z)
  31. #endif
  32. {
  33. if (!ModOddInverseVar(m, x, z))
  34. throw new ArithmeticException("Inverse does not exist.");
  35. }
  36. public static uint Inverse32(uint d)
  37. {
  38. Debug.Assert((d & 1U) == 1U);
  39. //int x = d + (((d + 1) & 4) << 1); // d.x == 1 mod 2**4
  40. uint x = d; // d.x == 1 mod 2**3
  41. x *= 2 - d * x; // d.x == 1 mod 2**6
  42. x *= 2 - d * x; // d.x == 1 mod 2**12
  43. x *= 2 - d * x; // d.x == 1 mod 2**24
  44. x *= 2 - d * x; // d.x == 1 mod 2**48
  45. Debug.Assert(d * x == 1U);
  46. return x;
  47. }
  48. public static ulong Inverse64(ulong d)
  49. {
  50. Debug.Assert((d & 1UL) == 1UL);
  51. //ulong x = d + (((d + 1) & 4) << 1); // d.x == 1 mod 2**4
  52. ulong x = d; // d.x == 1 mod 2**3
  53. x *= 2 - d * x; // d.x == 1 mod 2**6
  54. x *= 2 - d * x; // d.x == 1 mod 2**12
  55. x *= 2 - d * x; // d.x == 1 mod 2**24
  56. x *= 2 - d * x; // d.x == 1 mod 2**48
  57. x *= 2 - d * x; // d.x == 1 mod 2**96
  58. Debug.Assert(d * x == 1UL);
  59. return x;
  60. }
  61. public static uint ModOddInverse(uint[] m, uint[] x, uint[] z)
  62. {
  63. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
  64. return ModOddInverse(m.AsSpan(), x.AsSpan(), z.AsSpan());
  65. #else
  66. int len32 = m.Length;
  67. Debug.Assert(len32 > 0);
  68. Debug.Assert((m[0] & 1) != 0);
  69. Debug.Assert(m[len32 - 1] != 0);
  70. int bits = (len32 << 5) - Integers.NumberOfLeadingZeros((int)m[len32 - 1]);
  71. int len30 = (bits + 29) / 30;
  72. int[] t = new int[4];
  73. int[] D = new int[len30];
  74. int[] E = new int[len30];
  75. int[] F = new int[len30];
  76. int[] G = new int[len30];
  77. int[] M = new int[len30];
  78. E[0] = 1;
  79. Encode30(bits, x, 0, G, 0);
  80. Encode30(bits, m, 0, M, 0);
  81. Array.Copy(M, 0, F, 0, len30);
  82. int delta = 0;
  83. int m0Inv32 = (int)Inverse32((uint)M[0]);
  84. int maxDivsteps = GetMaximumDivsteps(bits);
  85. for (int divSteps = 0; divSteps < maxDivsteps; divSteps += 30)
  86. {
  87. delta = Divsteps30(delta, F[0], G[0], t);
  88. UpdateDE30(len30, D, E, t, m0Inv32, M);
  89. UpdateFG30(len30, F, G, t);
  90. }
  91. int signF = F[len30 - 1] >> 31;
  92. CNegate30(len30, signF, F);
  93. /*
  94. * D is in the range (-2.M, M). First, conditionally add M if D is negative, to bring it
  95. * into the range (-M, M). Then normalize by conditionally negating (according to signF)
  96. * and/or then adding M, to bring it into the range [0, M).
  97. */
  98. CNormalize30(len30, signF, D, M);
  99. Decode30(bits, D, 0, z, 0);
  100. Debug.Assert(0 != Nat.LessThan(m.Length, z, m));
  101. return (uint)(EqualTo(len30, F, 1) & EqualToZero(len30, G));
  102. #endif
  103. }
  104. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
  105. public static uint ModOddInverse(ReadOnlySpan<uint> m, ReadOnlySpan<uint> x, Span<uint> z)
  106. {
  107. int len32 = m.Length;
  108. Debug.Assert(len32 > 0);
  109. Debug.Assert((m[0] & 1) != 0);
  110. Debug.Assert(m[len32 - 1] != 0);
  111. int bits = (len32 << 5) - Integers.NumberOfLeadingZeros((int)m[len32 - 1]);
  112. int len30 = (bits + 29) / 30;
  113. Span<int> alloc = len30 <= 50
  114. ? stackalloc int[len30 * 5]
  115. : new int[len30 * 5];
  116. Span<int> t = stackalloc int[4];
  117. Span<int> D = alloc[..len30]; alloc = alloc[len30..];
  118. Span<int> E = alloc[..len30]; alloc = alloc[len30..];
  119. Span<int> F = alloc[..len30]; alloc = alloc[len30..];
  120. Span<int> G = alloc[..len30]; alloc = alloc[len30..];
  121. Span<int> M = alloc[..len30];
  122. E[0] = 1;
  123. Encode30(bits, x, G);
  124. Encode30(bits, m, M);
  125. M.CopyTo(F);
  126. int delta = 0;
  127. int m0Inv32 = (int)Inverse32((uint)M[0]);
  128. int maxDivsteps = GetMaximumDivsteps(bits);
  129. for (int divSteps = 0; divSteps < maxDivsteps; divSteps += 30)
  130. {
  131. delta = Divsteps30(delta, F[0], G[0], t);
  132. UpdateDE30(len30, D, E, t, m0Inv32, M);
  133. UpdateFG30(len30, F, G, t);
  134. }
  135. int signF = F[len30 - 1] >> 31;
  136. CNegate30(len30, signF, F);
  137. /*
  138. * D is in the range (-2.M, M). First, conditionally add M if D is negative, to bring it
  139. * into the range (-M, M). Then normalize by conditionally negating (according to signF)
  140. * and/or then adding M, to bring it into the range [0, M).
  141. */
  142. CNormalize30(len30, signF, D, M);
  143. Decode30(bits, D, z);
  144. Debug.Assert(0 != Nat.LessThan(m.Length, z, m));
  145. return (uint)(EqualTo(len30, F, 1) & EqualToZero(len30, G));
  146. }
  147. #endif
  148. public static bool ModOddInverseVar(uint[] m, uint[] x, uint[] z)
  149. {
  150. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
  151. return ModOddInverseVar(m.AsSpan(), x.AsSpan(), z.AsSpan());
  152. #else
  153. int len32 = m.Length;
  154. Debug.Assert(len32 > 0);
  155. Debug.Assert((m[0] & 1) != 0);
  156. Debug.Assert(m[len32 - 1] != 0);
  157. int bits = (len32 << 5) - Integers.NumberOfLeadingZeros((int)m[len32 - 1]);
  158. int len30 = (bits + 29) / 30;
  159. int[] t = new int[4];
  160. int[] D = new int[len30];
  161. int[] E = new int[len30];
  162. int[] F = new int[len30];
  163. int[] G = new int[len30];
  164. int[] M = new int[len30];
  165. E[0] = 1;
  166. Encode30(bits, x, 0, G, 0);
  167. Encode30(bits, m, 0, M, 0);
  168. Array.Copy(M, 0, F, 0, len30);
  169. int clzG = Integers.NumberOfLeadingZeros(G[len30 - 1] | 1) - (len30 * 30 + 2 - bits);
  170. int eta = -1 - clzG;
  171. int lenDE = len30, lenFG = len30;
  172. int m0Inv32 = (int)Inverse32((uint)M[0]);
  173. int maxDivsteps = GetMaximumDivsteps(bits);
  174. int divsteps = 0;
  175. while (!IsZero(lenFG, G))
  176. {
  177. if (divsteps >= maxDivsteps)
  178. return false;
  179. divsteps += 30;
  180. eta = Divsteps30Var(eta, F[0], G[0], t);
  181. UpdateDE30(lenDE, D, E, t, m0Inv32, M);
  182. UpdateFG30(lenFG, F, G, t);
  183. int fn = F[lenFG - 1];
  184. int gn = G[lenFG - 1];
  185. int cond = (lenFG - 2) >> 31;
  186. cond |= fn ^ (fn >> 31);
  187. cond |= gn ^ (gn >> 31);
  188. if (cond == 0)
  189. {
  190. F[lenFG - 2] |= fn << 30;
  191. G[lenFG - 2] |= gn << 30;
  192. --lenFG;
  193. }
  194. }
  195. int signF = F[lenFG - 1] >> 31;
  196. /*
  197. * D is in the range (-2.M, M). First, conditionally add M if D is negative, to bring it
  198. * into the range (-M, M). Then normalize by conditionally negating (according to signF)
  199. * and/or then adding M, to bring it into the range [0, M).
  200. */
  201. int signD = D[lenDE - 1] >> 31;
  202. if (signD < 0)
  203. {
  204. signD = Add30(lenDE, D, M);
  205. }
  206. if (signF < 0)
  207. {
  208. signD = Negate30(lenDE, D);
  209. signF = Negate30(lenFG, F);
  210. }
  211. Debug.Assert(0 == signF);
  212. if (!IsOne(lenFG, F))
  213. return false;
  214. if (signD < 0)
  215. {
  216. signD = Add30(lenDE, D, M);
  217. }
  218. Debug.Assert(0 == signD);
  219. Decode30(bits, D, 0, z, 0);
  220. Debug.Assert(!Nat.Gte(m.Length, z, m));
  221. return true;
  222. #endif
  223. }
  224. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
  225. public static bool ModOddInverseVar(ReadOnlySpan<uint> m, ReadOnlySpan<uint> x, Span<uint> z)
  226. {
  227. int len32 = m.Length;
  228. Debug.Assert(len32 > 0);
  229. Debug.Assert((m[0] & 1) != 0);
  230. Debug.Assert(m[len32 - 1] != 0);
  231. int bits = (len32 << 5) - Integers.NumberOfLeadingZeros((int)m[len32 - 1]);
  232. int len30 = (bits + 29) / 30;
  233. Span<int> alloc = len30 <= 50
  234. ? stackalloc int[len30 * 5]
  235. : new int[len30 * 5];
  236. Span<int> t = stackalloc int[4];
  237. Span<int> D = alloc[..len30]; alloc = alloc[len30..];
  238. Span<int> E = alloc[..len30]; alloc = alloc[len30..];
  239. Span<int> F = alloc[..len30]; alloc = alloc[len30..];
  240. Span<int> G = alloc[..len30]; alloc = alloc[len30..];
  241. Span<int> M = alloc[..len30];
  242. E[0] = 1;
  243. Encode30(bits, x, G);
  244. Encode30(bits, m, M);
  245. M.CopyTo(F);
  246. int clzG = Integers.NumberOfLeadingZeros(G[len30 - 1] | 1) - (len30 * 30 + 2 - bits);
  247. int eta = -1 - clzG;
  248. int lenDE = len30, lenFG = len30;
  249. int m0Inv32 = (int)Inverse32((uint)M[0]);
  250. int maxDivsteps = GetMaximumDivsteps(bits);
  251. int divsteps = 0;
  252. while (!IsZero(lenFG, G))
  253. {
  254. if (divsteps >= maxDivsteps)
  255. return false;
  256. divsteps += 30;
  257. eta = Divsteps30Var(eta, F[0], G[0], t);
  258. UpdateDE30(lenDE, D, E, t, m0Inv32, M);
  259. UpdateFG30(lenFG, F, G, t);
  260. int fn = F[lenFG - 1];
  261. int gn = G[lenFG - 1];
  262. int cond = (lenFG - 2) >> 31;
  263. cond |= fn ^ (fn >> 31);
  264. cond |= gn ^ (gn >> 31);
  265. if (cond == 0)
  266. {
  267. F[lenFG - 2] |= fn << 30;
  268. G[lenFG - 2] |= gn << 30;
  269. --lenFG;
  270. }
  271. }
  272. int signF = F[lenFG - 1] >> 31;
  273. /*
  274. * D is in the range (-2.M, M). First, conditionally add M if D is negative, to bring it
  275. * into the range (-M, M). Then normalize by conditionally negating (according to signF)
  276. * and/or then adding M, to bring it into the range [0, M).
  277. */
  278. int signD = D[lenDE - 1] >> 31;
  279. if (signD < 0)
  280. {
  281. signD = Add30(lenDE, D, M);
  282. }
  283. if (signF < 0)
  284. {
  285. signD = Negate30(lenDE, D);
  286. signF = Negate30(lenFG, F);
  287. }
  288. Debug.Assert(0 == signF);
  289. if (!IsOne(lenFG, F))
  290. return false;
  291. if (signD < 0)
  292. {
  293. signD = Add30(lenDE, D, M);
  294. }
  295. Debug.Assert(0 == signD);
  296. Decode30(bits, D, z);
  297. Debug.Assert(!Nat.Gte(m.Length, z, m));
  298. return true;
  299. }
  300. #endif
  301. public static uint[] Random(SecureRandom random, uint[] p)
  302. {
  303. int len = p.Length;
  304. uint[] s = Nat.Create(len);
  305. uint m = p[len - 1];
  306. m |= m >> 1;
  307. m |= m >> 2;
  308. m |= m >> 4;
  309. m |= m >> 8;
  310. m |= m >> 16;
  311. byte[] bytes = new byte[len << 2];
  312. do
  313. {
  314. random.NextBytes(bytes);
  315. Pack.BE_To_UInt32(bytes, 0, s);
  316. s[len - 1] &= m;
  317. }
  318. while (Nat.Gte(len, s, p));
  319. return s;
  320. }
  321. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
  322. public static void Random(SecureRandom random, ReadOnlySpan<uint> p, Span<uint> z)
  323. {
  324. int len = p.Length;
  325. if (z.Length < len)
  326. throw new ArgumentException("insufficient space", nameof(z));
  327. var s = z[..len];
  328. uint m = p[len - 1];
  329. m |= m >> 1;
  330. m |= m >> 2;
  331. m |= m >> 4;
  332. m |= m >> 8;
  333. m |= m >> 16;
  334. Span<byte> bytes = len <= 256
  335. ? stackalloc byte[len << 2]
  336. : new byte[len << 2];
  337. do
  338. {
  339. random.NextBytes(bytes);
  340. Pack.BE_To_UInt32(bytes, s);
  341. s[len - 1] &= m;
  342. }
  343. while (Nat.Gte(len, s, p));
  344. }
  345. #endif
  346. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
  347. private static int Add30(int len30, Span<int> D, ReadOnlySpan<int> M)
  348. #else
  349. private static int Add30(int len30, int[] D, int[] M)
  350. #endif
  351. {
  352. Debug.Assert(len30 > 0);
  353. Debug.Assert(D.Length >= len30);
  354. Debug.Assert(M.Length >= len30);
  355. int c = 0, last = len30 - 1;
  356. for (int i = 0; i < last; ++i)
  357. {
  358. c += D[i] + M[i];
  359. D[i] = c & M30; c >>= 30;
  360. }
  361. c += D[last] + M[last];
  362. D[last] = c; c >>= 30;
  363. return c;
  364. }
  365. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
  366. private static void CNegate30(int len30, int cond, Span<int> D)
  367. #else
  368. private static void CNegate30(int len30, int cond, int[] D)
  369. #endif
  370. {
  371. Debug.Assert(len30 > 0);
  372. Debug.Assert(D.Length >= len30);
  373. int c = 0, last = len30 - 1;
  374. for (int i = 0; i < last; ++i)
  375. {
  376. c += (D[i] ^ cond) - cond;
  377. D[i] = c & M30; c >>= 30;
  378. }
  379. c += (D[last] ^ cond) - cond;
  380. D[last] = c;
  381. }
  382. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
  383. private static void CNormalize30(int len30, int condNegate, Span<int> D, ReadOnlySpan<int> M)
  384. #else
  385. private static void CNormalize30(int len30, int condNegate, int[] D, int[] M)
  386. #endif
  387. {
  388. Debug.Assert(len30 > 0);
  389. Debug.Assert(D.Length >= len30);
  390. Debug.Assert(M.Length >= len30);
  391. int last = len30 - 1;
  392. {
  393. int c = 0, condAdd = D[last] >> 31;
  394. for (int i = 0; i < last; ++i)
  395. {
  396. int di = D[i] + (M[i] & condAdd);
  397. di = (di ^ condNegate) - condNegate;
  398. c += di; D[i] = c & M30; c >>= 30;
  399. }
  400. {
  401. int di = D[last] + (M[last] & condAdd);
  402. di = (di ^ condNegate) - condNegate;
  403. c += di; D[last] = c;
  404. }
  405. }
  406. {
  407. int c = 0, condAdd = D[last] >> 31;
  408. for (int i = 0; i < last; ++i)
  409. {
  410. int di = D[i] + (M[i] & condAdd);
  411. c += di; D[i] = c & M30; c >>= 30;
  412. }
  413. {
  414. int di = D[last] + (M[last] & condAdd);
  415. c += di; D[last] = c;
  416. }
  417. Debug.Assert(c >> 30 == 0);
  418. }
  419. }
  420. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
  421. private static void Decode30(int bits, ReadOnlySpan<int> x, Span<uint> z)
  422. {
  423. Debug.Assert(bits > 0);
  424. int avail = 0;
  425. ulong data = 0L;
  426. int xOff = 0, zOff = 0;
  427. while (bits > 0)
  428. {
  429. while (avail < System.Math.Min(32, bits))
  430. {
  431. data |= (ulong)x[xOff++] << avail;
  432. avail += 30;
  433. }
  434. z[zOff++] = (uint)data; data >>= 32;
  435. avail -= 32;
  436. bits -= 32;
  437. }
  438. }
  439. #else
  440. private static void Decode30(int bits, int[] x, int xOff, uint[] z, int zOff)
  441. {
  442. Debug.Assert(bits > 0);
  443. int avail = 0;
  444. ulong data = 0L;
  445. while (bits > 0)
  446. {
  447. while (avail < System.Math.Min(32, bits))
  448. {
  449. data |= (ulong)x[xOff++] << avail;
  450. avail += 30;
  451. }
  452. z[zOff++] = (uint)data; data >>= 32;
  453. avail -= 32;
  454. bits -= 32;
  455. }
  456. }
  457. #endif
  458. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
  459. private static int Divsteps30(int delta, int f0, int g0, Span<int> t)
  460. #else
  461. private static int Divsteps30(int delta, int f0, int g0, int[] t)
  462. #endif
  463. {
  464. int u = 1 << 30, v = 0, q = 0, r = 1 << 30;
  465. int f = f0, g = g0;
  466. for (int i = 0; i < 30; ++i)
  467. {
  468. Debug.Assert((f & 1) == 1);
  469. Debug.Assert(((u >> (30 - i)) * f0 + (v >> (30 - i)) * g0) == f << i);
  470. Debug.Assert(((q >> (30 - i)) * f0 + (r >> (30 - i)) * g0) == g << i);
  471. int c1 = delta >> 31;
  472. int c2 = -(g & 1);
  473. int x = f ^ c1;
  474. int y = u ^ c1;
  475. int z = v ^ c1;
  476. g -= x & c2;
  477. q -= y & c2;
  478. r -= z & c2;
  479. c2 &= ~c1;
  480. delta = (delta ^ c2) - (c2 - 1);
  481. f += g & c2;
  482. u += q & c2;
  483. v += r & c2;
  484. g >>= 1;
  485. q >>= 1;
  486. r >>= 1;
  487. }
  488. t[0] = u;
  489. t[1] = v;
  490. t[2] = q;
  491. t[3] = r;
  492. return delta;
  493. }
  494. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
  495. private static int Divsteps30Var(int eta, int f0, int g0, Span<int> t)
  496. #else
  497. private static int Divsteps30Var(int eta, int f0, int g0, int[] t)
  498. #endif
  499. {
  500. int u = 1, v = 0, q = 0, r = 1;
  501. int f = f0, g = g0, m, w, x, y, z;
  502. int i = 30, limit, zeros;
  503. for (; ; )
  504. {
  505. // Use a sentinel bit to count zeros only up to i.
  506. zeros = Integers.NumberOfTrailingZeros(g | (-1 << i));
  507. g >>= zeros;
  508. u <<= zeros;
  509. v <<= zeros;
  510. eta -= zeros;
  511. i -= zeros;
  512. if (i <= 0)
  513. break;
  514. Debug.Assert((f & 1) == 1);
  515. Debug.Assert((g & 1) == 1);
  516. Debug.Assert((u * f0 + v * g0) == f << (30 - i));
  517. Debug.Assert((q * f0 + r * g0) == g << (30 - i));
  518. if (eta < 0)
  519. {
  520. eta = -eta;
  521. x = f; f = g; g = -x;
  522. y = u; u = q; q = -y;
  523. z = v; v = r; r = -z;
  524. // Handle up to 6 divsteps at once, subject to eta and i.
  525. limit = (eta + 1) > i ? i : (eta + 1);
  526. m = (int)((uint.MaxValue >> (32 - limit)) & 63U);
  527. w = (f * g * (f * f - 2)) & m;
  528. }
  529. else
  530. {
  531. // Handle up to 4 divsteps at once, subject to eta and i.
  532. limit = (eta + 1) > i ? i : (eta + 1);
  533. m = (int)((uint.MaxValue >> (32 - limit)) & 15U);
  534. w = f + (((f + 1) & 4) << 1);
  535. w = (-w * g) & m;
  536. }
  537. g += f * w;
  538. q += u * w;
  539. r += v * w;
  540. Debug.Assert((g & m) == 0);
  541. }
  542. t[0] = u;
  543. t[1] = v;
  544. t[2] = q;
  545. t[3] = r;
  546. return eta;
  547. }
  548. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
  549. private static void Encode30(int bits, ReadOnlySpan<uint> x, Span<int> z)
  550. {
  551. Debug.Assert(bits > 0);
  552. int avail = 0;
  553. ulong data = 0UL;
  554. int xOff = 0, zOff = 0;
  555. while (bits > 0)
  556. {
  557. if (avail < System.Math.Min(30, bits))
  558. {
  559. data |= (x[xOff++] & M32UL) << avail;
  560. avail += 32;
  561. }
  562. z[zOff++] = (int)data & M30; data >>= 30;
  563. avail -= 30;
  564. bits -= 30;
  565. }
  566. }
  567. #else
  568. private static void Encode30(int bits, uint[] x, int xOff, int[] z, int zOff)
  569. {
  570. Debug.Assert(bits > 0);
  571. int avail = 0;
  572. ulong data = 0UL;
  573. while (bits > 0)
  574. {
  575. if (avail < System.Math.Min(30, bits))
  576. {
  577. data |= (x[xOff++] & M32UL) << avail;
  578. avail += 32;
  579. }
  580. z[zOff++] = (int)data & M30; data >>= 30;
  581. avail -= 30;
  582. bits -= 30;
  583. }
  584. }
  585. #endif
  586. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
  587. private static int EqualTo(int len, ReadOnlySpan<int> x, int y)
  588. #else
  589. private static int EqualTo(int len, int[] x, int y)
  590. #endif
  591. {
  592. int d = x[0] ^ y;
  593. for (int i = 1; i < len; ++i)
  594. {
  595. d |= x[i];
  596. }
  597. d = (int)((uint)d >> 1) | (d & 1);
  598. return (d - 1) >> 31;
  599. }
  600. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
  601. private static int EqualToZero(int len, ReadOnlySpan<int> x)
  602. #else
  603. private static int EqualToZero(int len, int[] x)
  604. #endif
  605. {
  606. int d = 0;
  607. for (int i = 0; i < len; ++i)
  608. {
  609. d |= x[i];
  610. }
  611. d = (int)((uint)d >> 1) | (d & 1);
  612. return (d - 1) >> 31;
  613. }
  614. private static int GetMaximumDivsteps(int bits)
  615. {
  616. return (49 * bits + (bits < 46 ? 80 : 47)) / 17;
  617. }
  618. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
  619. private static bool IsOne(int len, ReadOnlySpan<int> x)
  620. #else
  621. private static bool IsOne(int len, int[] x)
  622. #endif
  623. {
  624. if (x[0] != 1)
  625. {
  626. return false;
  627. }
  628. for (int i = 1; i < len; ++i)
  629. {
  630. if (x[i] != 0)
  631. {
  632. return false;
  633. }
  634. }
  635. return true;
  636. }
  637. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
  638. private static bool IsZero(int len, ReadOnlySpan<int> x)
  639. #else
  640. private static bool IsZero(int len, int[] x)
  641. #endif
  642. {
  643. if (x[0] != 0)
  644. {
  645. return false;
  646. }
  647. for (int i = 1; i < len; ++i)
  648. {
  649. if (x[i] != 0)
  650. {
  651. return false;
  652. }
  653. }
  654. return true;
  655. }
  656. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
  657. private static int Negate30(int len30, Span<int> D)
  658. #else
  659. private static int Negate30(int len30, int[] D)
  660. #endif
  661. {
  662. Debug.Assert(len30 > 0);
  663. Debug.Assert(D.Length >= len30);
  664. int c = 0, last = len30 - 1;
  665. for (int i = 0; i < last; ++i)
  666. {
  667. c -= D[i];
  668. D[i] = c & M30; c >>= 30;
  669. }
  670. c -= D[last];
  671. D[last] = c; c >>= 30;
  672. return c;
  673. }
  674. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
  675. private static void UpdateDE30(int len30, Span<int> D, Span<int> E, ReadOnlySpan<int> t, int m0Inv32,
  676. ReadOnlySpan<int> M)
  677. #else
  678. private static void UpdateDE30(int len30, int[] D, int[] E, int[] t, int m0Inv32, int[] M)
  679. #endif
  680. {
  681. Debug.Assert(len30 > 0);
  682. Debug.Assert(D.Length >= len30);
  683. Debug.Assert(E.Length >= len30);
  684. Debug.Assert(M.Length >= len30);
  685. Debug.Assert(m0Inv32 * M[0] == 1);
  686. int u = t[0], v = t[1], q = t[2], r = t[3];
  687. int di, ei, i, md, me, mi, sd, se;
  688. long cd, ce;
  689. /*
  690. * We accept D (E) in the range (-2.M, M) and conceptually add the modulus to the input
  691. * value if it is initially negative. Instead of adding it explicitly, we add u and/or v (q
  692. * and/or r) to md (me).
  693. */
  694. sd = D[len30 - 1] >> 31;
  695. se = E[len30 - 1] >> 31;
  696. md = (u & sd) + (v & se);
  697. me = (q & sd) + (r & se);
  698. mi = M[0];
  699. di = D[0];
  700. ei = E[0];
  701. cd = (long)u * di + (long)v * ei;
  702. ce = (long)q * di + (long)r * ei;
  703. /*
  704. * Subtract from md/me an extra term in the range [0, 2^30) such that the low 30 bits of the
  705. * intermediate D/E values will be 0, allowing clean division by 2^30. The final D/E are
  706. * thus in the range (-2.M, M), consistent with the input constraint.
  707. */
  708. md -= (m0Inv32 * (int)cd + md) & M30;
  709. me -= (m0Inv32 * (int)ce + me) & M30;
  710. cd += (long)mi * md;
  711. ce += (long)mi * me;
  712. Debug.Assert(((int)cd & M30) == 0);
  713. Debug.Assert(((int)ce & M30) == 0);
  714. cd >>= 30;
  715. ce >>= 30;
  716. for (i = 1; i < len30; ++i)
  717. {
  718. mi = M[i];
  719. di = D[i];
  720. ei = E[i];
  721. cd += (long)u * di + (long)v * ei + (long)mi * md;
  722. ce += (long)q * di + (long)r * ei + (long)mi * me;
  723. D[i - 1] = (int)cd & M30; cd >>= 30;
  724. E[i - 1] = (int)ce & M30; ce >>= 30;
  725. }
  726. D[len30 - 1] = (int)cd;
  727. E[len30 - 1] = (int)ce;
  728. }
  729. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
  730. private static void UpdateFG30(int len30, Span<int> F, Span<int> G, ReadOnlySpan<int> t)
  731. #else
  732. private static void UpdateFG30(int len30, int[] F, int[] G, int[] t)
  733. #endif
  734. {
  735. Debug.Assert(len30 > 0);
  736. Debug.Assert(F.Length >= len30);
  737. Debug.Assert(G.Length >= len30);
  738. int u = t[0], v = t[1], q = t[2], r = t[3];
  739. int fi, gi, i;
  740. long cf, cg;
  741. fi = F[0];
  742. gi = G[0];
  743. cf = (long)u * fi + (long)v * gi;
  744. cg = (long)q * fi + (long)r * gi;
  745. Debug.Assert(((int)cf & M30) == 0);
  746. Debug.Assert(((int)cg & M30) == 0);
  747. cf >>= 30;
  748. cg >>= 30;
  749. for (i = 1; i < len30; ++i)
  750. {
  751. fi = F[i];
  752. gi = G[i];
  753. cf += (long)u * fi + (long)v * gi;
  754. cg += (long)q * fi + (long)r * gi;
  755. F[i - 1] = (int)cf & M30; cf >>= 30;
  756. G[i - 1] = (int)cg & M30; cg >>= 30;
  757. }
  758. F[len30 - 1] = (int)cf;
  759. G[len30 - 1] = (int)cg;
  760. }
  761. }
  762. }
  763. #pragma warning restore
  764. #endif