X25519Field.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using System.Diagnostics;
  5. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Math.Raw;
  6. namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Math.EC.Rfc7748
  7. {
  8. public static class X25519Field
  9. {
  10. public const int Size = 10;
  11. private const int M24 = 0x00FFFFFF;
  12. private const int M25 = 0x01FFFFFF;
  13. private const int M26 = 0x03FFFFFF;
  14. private static readonly uint[] P32 = new uint[]{ 0xFFFFFFEDU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
  15. 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0x7FFFFFFFU };
  16. private static readonly int[] RootNegOne = { 0x020EA0B0, 0x0386C9D2, 0x00478C4E, 0x0035697F, 0x005E8630,
  17. 0x01FBD7A7, 0x0340264F, 0x01F0B2B4, 0x00027E0E, 0x00570649 };
  18. public static void Add(int[] x, int[] y, int[] z)
  19. {
  20. for (int i = 0; i < Size; ++i)
  21. {
  22. z[i] = x[i] + y[i];
  23. }
  24. }
  25. public static void AddOne(int[] z)
  26. {
  27. z[0] += 1;
  28. }
  29. public static void AddOne(int[] z, int zOff)
  30. {
  31. z[zOff] += 1;
  32. }
  33. public static void Apm(int[] x, int[] y, int[] zp, int[] zm)
  34. {
  35. for (int i = 0; i < Size; ++i)
  36. {
  37. int xi = x[i], yi = y[i];
  38. zp[i] = xi + yi;
  39. zm[i] = xi - yi;
  40. }
  41. }
  42. public static int AreEqual(int[] x, int[] y)
  43. {
  44. int d = 0;
  45. for (int i = 0; i < Size; ++i)
  46. {
  47. d |= x[i] ^ y[i];
  48. }
  49. d |= d >> 16;
  50. d &= 0xFFFF;
  51. return (d - 1) >> 31;
  52. }
  53. public static bool AreEqualVar(int[] x, int[] y)
  54. {
  55. return 0 != AreEqual(x, y);
  56. }
  57. public static void Carry(int[] z)
  58. {
  59. int z0 = z[0], z1 = z[1], z2 = z[2], z3 = z[3], z4 = z[4];
  60. int z5 = z[5], z6 = z[6], z7 = z[7], z8 = z[8], z9 = z[9];
  61. z2 += (z1 >> 26); z1 &= M26;
  62. z4 += (z3 >> 26); z3 &= M26;
  63. z7 += (z6 >> 26); z6 &= M26;
  64. z9 += (z8 >> 26); z8 &= M26;
  65. z3 += (z2 >> 25); z2 &= M25;
  66. z5 += (z4 >> 25); z4 &= M25;
  67. z8 += (z7 >> 25); z7 &= M25;
  68. //z0 += (z9 >> 24) * 19; z9 &= M24;
  69. z0 += (z9 >> 25) * 38; z9 &= M25;
  70. z1 += (z0 >> 26); z0 &= M26;
  71. z6 += (z5 >> 26); z5 &= M26;
  72. z2 += (z1 >> 26); z1 &= M26;
  73. z4 += (z3 >> 26); z3 &= M26;
  74. z7 += (z6 >> 26); z6 &= M26;
  75. z9 += (z8 >> 26); z8 &= M26;
  76. z[0] = z0; z[1] = z1; z[2] = z2; z[3] = z3; z[4] = z4;
  77. z[5] = z5; z[6] = z6; z[7] = z7; z[8] = z8; z[9] = z9;
  78. }
  79. public static void CMov(int cond, int[] x, int xOff, int[] z, int zOff)
  80. {
  81. Debug.Assert(0 == cond || -1 == cond);
  82. for (int i = 0; i < Size; ++i)
  83. {
  84. int z_i = z[zOff + i], diff = z_i ^ x[xOff + i];
  85. z_i ^= (diff & cond);
  86. z[zOff + i] = z_i;
  87. }
  88. }
  89. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  90. public static void CMov(int cond, ReadOnlySpan<int> x, Span<int> z)
  91. {
  92. Debug.Assert(0 == cond || -1 == cond);
  93. for (int i = 0; i < Size; ++i)
  94. {
  95. int z_i = z[i], diff = z_i ^ x[i];
  96. z_i ^= (diff & cond);
  97. z[i] = z_i;
  98. }
  99. }
  100. #endif
  101. public static void CNegate(int negate, int[] z)
  102. {
  103. Debug.Assert(negate >> 1 == 0);
  104. int mask = 0 - negate;
  105. for (int i = 0; i < Size; ++i)
  106. {
  107. z[i] = (z[i] ^ mask) - mask;
  108. }
  109. }
  110. public static void Copy(int[] x, int xOff, int[] z, int zOff)
  111. {
  112. for (int i = 0; i < Size; ++i)
  113. {
  114. z[zOff + i] = x[xOff + i];
  115. }
  116. }
  117. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  118. public static void Copy(ReadOnlySpan<int> x, Span<int> z)
  119. {
  120. x[..Size].CopyTo(z);
  121. }
  122. #endif
  123. public static int[] Create()
  124. {
  125. return new int[Size];
  126. }
  127. public static int[] CreateTable(int n)
  128. {
  129. return new int[Size * n];
  130. }
  131. public static void CSwap(int swap, int[] a, int[] b)
  132. {
  133. Debug.Assert(swap >> 1 == 0);
  134. Debug.Assert(a != b);
  135. int mask = 0 - swap;
  136. for (int i = 0; i < Size; ++i)
  137. {
  138. int ai = a[i], bi = b[i];
  139. int dummy = mask & (ai ^ bi);
  140. a[i] = ai ^ dummy;
  141. b[i] = bi ^ dummy;
  142. }
  143. }
  144. [CLSCompliant(false)]
  145. public static void Decode(uint[] x, int xOff, int[] z)
  146. {
  147. Decode128(x, xOff, z, 0);
  148. Decode128(x, xOff + 4, z, 5);
  149. z[9] &= M24;
  150. }
  151. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  152. [CLSCompliant(false)]
  153. public static void Decode(ReadOnlySpan<uint> x, Span<int> z)
  154. {
  155. Decode128(x, z);
  156. Decode128(x[4..], z[5..]);
  157. z[9] &= M24;
  158. }
  159. #endif
  160. public static void Decode(byte[] x, int xOff, int[] z)
  161. {
  162. Decode128(x, xOff, z, 0);
  163. Decode128(x, xOff + 16, z, 5);
  164. z[9] &= M24;
  165. }
  166. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  167. public static void Decode(ReadOnlySpan<byte> x, Span<int> z)
  168. {
  169. Decode128(x, z);
  170. Decode128(x[16..], z[5..]);
  171. z[9] &= M24;
  172. }
  173. #endif
  174. private static void Decode128(uint[] x, int xOff, int[] z, int zOff)
  175. {
  176. uint t0 = x[xOff + 0], t1 = x[xOff + 1], t2 = x[xOff + 2], t3 = x[xOff + 3];
  177. z[zOff + 0] = (int)t0 & M26;
  178. z[zOff + 1] = (int)((t1 << 6) | (t0 >> 26)) & M26;
  179. z[zOff + 2] = (int)((t2 << 12) | (t1 >> 20)) & M25;
  180. z[zOff + 3] = (int)((t3 << 19) | (t2 >> 13)) & M26;
  181. z[zOff + 4] = (int)(t3 >> 7);
  182. }
  183. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  184. private static void Decode128(ReadOnlySpan<uint> x, Span<int> z)
  185. {
  186. uint t0 = x[0], t1 = x[1], t2 = x[2], t3 = x[3];
  187. z[0] = (int)t0 & M26;
  188. z[1] = (int)((t1 << 6) | (t0 >> 26)) & M26;
  189. z[2] = (int)((t2 << 12) | (t1 >> 20)) & M25;
  190. z[3] = (int)((t3 << 19) | (t2 >> 13)) & M26;
  191. z[4] = (int)(t3 >> 7);
  192. }
  193. #endif
  194. private static void Decode128(byte[] bs, int off, int[] z, int zOff)
  195. {
  196. uint t0 = Decode32(bs, off + 0);
  197. uint t1 = Decode32(bs, off + 4);
  198. uint t2 = Decode32(bs, off + 8);
  199. uint t3 = Decode32(bs, off + 12);
  200. z[zOff + 0] = (int)t0 & M26;
  201. z[zOff + 1] = (int)((t1 << 6) | (t0 >> 26)) & M26;
  202. z[zOff + 2] = (int)((t2 << 12) | (t1 >> 20)) & M25;
  203. z[zOff + 3] = (int)((t3 << 19) | (t2 >> 13)) & M26;
  204. z[zOff + 4] = (int)(t3 >> 7);
  205. }
  206. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  207. private static void Decode128(ReadOnlySpan<byte> bs, Span<int> z)
  208. {
  209. uint t0 = Decode32(bs);
  210. uint t1 = Decode32(bs[4..]);
  211. uint t2 = Decode32(bs[8..]);
  212. uint t3 = Decode32(bs[12..]);
  213. z[0] = (int)t0 & M26;
  214. z[1] = (int)((t1 << 6) | (t0 >> 26)) & M26;
  215. z[2] = (int)((t2 << 12) | (t1 >> 20)) & M25;
  216. z[3] = (int)((t3 << 19) | (t2 >> 13)) & M26;
  217. z[4] = (int)(t3 >> 7);
  218. }
  219. #endif
  220. private static uint Decode32(byte[] bs, int off)
  221. {
  222. uint n = bs[off];
  223. n |= (uint)bs[++off] << 8;
  224. n |= (uint)bs[++off] << 16;
  225. n |= (uint)bs[++off] << 24;
  226. return n;
  227. }
  228. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  229. private static uint Decode32(ReadOnlySpan<byte> bs)
  230. {
  231. uint n = bs[0];
  232. n |= (uint)bs[1] << 8;
  233. n |= (uint)bs[2] << 16;
  234. n |= (uint)bs[3] << 24;
  235. return n;
  236. }
  237. #endif
  238. [CLSCompliant(false)]
  239. public static void Encode(int[] x, uint[] z, int zOff)
  240. {
  241. Encode128(x, 0, z, zOff);
  242. Encode128(x, 5, z, zOff + 4);
  243. }
  244. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  245. [CLSCompliant(false)]
  246. public static void Encode(ReadOnlySpan<int> x, Span<uint> z)
  247. {
  248. Encode128(x, z);
  249. Encode128(x[5..], z[4..]);
  250. }
  251. #endif
  252. public static void Encode(int[] x, byte[] z, int zOff)
  253. {
  254. Encode128(x, 0, z, zOff);
  255. Encode128(x, 5, z, zOff + 16);
  256. }
  257. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  258. public static void Encode(ReadOnlySpan<int> x, Span<byte> z)
  259. {
  260. Encode128(x, z);
  261. Encode128(x[5..], z[16..]);
  262. }
  263. #endif
  264. private static void Encode128(int[] x, int xOff, uint[] z, int zOff)
  265. {
  266. uint x0 = (uint)x[xOff + 0], x1 = (uint)x[xOff + 1], x2 = (uint)x[xOff + 2], x3 = (uint)x[xOff + 3],
  267. x4 = (uint)x[xOff + 4];
  268. z[zOff + 0] = x0 | (x1 << 26);
  269. z[zOff + 1] = (x1 >> 6) | (x2 << 20);
  270. z[zOff + 2] = (x2 >> 12) | (x3 << 13);
  271. z[zOff + 3] = (x3 >> 19) | (x4 << 7);
  272. }
  273. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  274. private static void Encode128(ReadOnlySpan<int> x, Span<uint> z)
  275. {
  276. uint x0 = (uint)x[0], x1 = (uint)x[1], x2 = (uint)x[2], x3 = (uint)x[3], x4 = (uint)x[4];
  277. z[0] = x0 | (x1 << 26);
  278. z[1] = (x1 >> 6) | (x2 << 20);
  279. z[2] = (x2 >> 12) | (x3 << 13);
  280. z[3] = (x3 >> 19) | (x4 << 7);
  281. }
  282. #endif
  283. private static void Encode128(int[] x, int xOff, byte[] bs, int off)
  284. {
  285. uint x0 = (uint)x[xOff + 0], x1 = (uint)x[xOff + 1], x2 = (uint)x[xOff + 2];
  286. uint x3 = (uint)x[xOff + 3], x4 = (uint)x[xOff + 4];
  287. uint t0 = x0 | (x1 << 26); Encode32(t0, bs, off + 0);
  288. uint t1 = (x1 >> 6) | (x2 << 20); Encode32(t1, bs, off + 4);
  289. uint t2 = (x2 >> 12) | (x3 << 13); Encode32(t2, bs, off + 8);
  290. uint t3 = (x3 >> 19) | (x4 << 7); Encode32(t3, bs, off + 12);
  291. }
  292. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  293. private static void Encode128(ReadOnlySpan<int> x, Span<byte> bs)
  294. {
  295. uint x0 = (uint)x[0], x1 = (uint)x[1], x2 = (uint)x[2];
  296. uint x3 = (uint)x[3], x4 = (uint)x[4];
  297. uint t0 = x0 | (x1 << 26); Encode32(t0, bs);
  298. uint t1 = (x1 >> 6) | (x2 << 20); Encode32(t1, bs[4..]);
  299. uint t2 = (x2 >> 12) | (x3 << 13); Encode32(t2, bs[8..]);
  300. uint t3 = (x3 >> 19) | (x4 << 7); Encode32(t3, bs[12..]);
  301. }
  302. #endif
  303. private static void Encode32(uint n, byte[] bs, int off)
  304. {
  305. bs[ off] = (byte)(n );
  306. bs[++off] = (byte)(n >> 8);
  307. bs[++off] = (byte)(n >> 16);
  308. bs[++off] = (byte)(n >> 24);
  309. }
  310. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  311. private static void Encode32(uint n, Span<byte> bs)
  312. {
  313. bs[0] = (byte)(n );
  314. bs[1] = (byte)(n >> 8);
  315. bs[2] = (byte)(n >> 16);
  316. bs[3] = (byte)(n >> 24);
  317. }
  318. #endif
  319. public static void Inv(int[] x, int[] z)
  320. {
  321. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  322. Inv(x.AsSpan(), z.AsSpan());
  323. #else
  324. //int[] x2 = Create();
  325. //int[] t = Create();
  326. //PowPm5d8(x, x2, t);
  327. //Sqr(t, 3, t);
  328. //Mul(t, x2, z);
  329. int[] t = Create();
  330. uint[] u = new uint[8];
  331. Copy(x, 0, t, 0);
  332. Normalize(t);
  333. Encode(t, u, 0);
  334. Mod.ModOddInverse(P32, u, u);
  335. Decode(u, 0, z);
  336. #endif
  337. }
  338. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  339. public static void Inv(ReadOnlySpan<int> x, Span<int> z)
  340. {
  341. Span<int> t = stackalloc int[Size];
  342. Span<uint> u = stackalloc uint[8];
  343. Copy(x, t);
  344. Normalize(t);
  345. Encode(t, u);
  346. Mod.ModOddInverse(P32, u, u);
  347. Decode(u, z);
  348. }
  349. #endif
  350. public static void InvVar(int[] x, int[] z)
  351. {
  352. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  353. InvVar(x.AsSpan(), z.AsSpan());
  354. #else
  355. int[] t = Create();
  356. uint[] u = new uint[8];
  357. Copy(x, 0, t, 0);
  358. Normalize(t);
  359. Encode(t, u, 0);
  360. Mod.ModOddInverseVar(P32, u, u);
  361. Decode(u, 0, z);
  362. #endif
  363. }
  364. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  365. public static void InvVar(ReadOnlySpan<int> x, Span<int> z)
  366. {
  367. Span<int> t = stackalloc int[Size];
  368. Span<uint> u = stackalloc uint[8];
  369. Copy(x, t);
  370. Normalize(t);
  371. Encode(t, u);
  372. Mod.ModOddInverseVar(P32, u, u);
  373. Decode(u, z);
  374. }
  375. #endif
  376. public static int IsOne(int[] x)
  377. {
  378. int d = x[0] ^ 1;
  379. for (int i = 1; i < Size; ++i)
  380. {
  381. d |= x[i];
  382. }
  383. d |= d >> 16;
  384. d &= 0xFFFF;
  385. return (d - 1) >> 31;
  386. }
  387. public static bool IsOneVar(int[] x)
  388. {
  389. return 0 != IsOne(x);
  390. }
  391. public static int IsZero(int[] x)
  392. {
  393. int d = 0;
  394. for (int i = 0; i < Size; ++i)
  395. {
  396. d |= x[i];
  397. }
  398. d |= d >> 16;
  399. d &= 0xFFFF;
  400. return (d - 1) >> 31;
  401. }
  402. public static bool IsZeroVar(int[] x)
  403. {
  404. return 0 != IsZero(x);
  405. }
  406. public static void Mul(int[] x, int y, int[] z)
  407. {
  408. int x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3], x4 = x[4];
  409. int x5 = x[5], x6 = x[6], x7 = x[7], x8 = x[8], x9 = x[9];
  410. long c0, c1, c2, c3;
  411. c0 = (long)x2 * y; x2 = (int)c0 & M25; c0 >>= 25;
  412. c1 = (long)x4 * y; x4 = (int)c1 & M25; c1 >>= 25;
  413. c2 = (long)x7 * y; x7 = (int)c2 & M25; c2 >>= 25;
  414. //c3 = (long)x9 * y; x9 = (int)c3 & M24; c3 >>= 24;
  415. //c3 *= 19;
  416. c3 = (long)x9 * y; x9 = (int)c3 & M25; c3 >>= 25;
  417. c3 *= 38;
  418. c3 += (long)x0 * y; z[0] = (int)c3 & M26; c3 >>= 26;
  419. c1 += (long)x5 * y; z[5] = (int)c1 & M26; c1 >>= 26;
  420. c3 += (long)x1 * y; z[1] = (int)c3 & M26; c3 >>= 26;
  421. c0 += (long)x3 * y; z[3] = (int)c0 & M26; c0 >>= 26;
  422. c1 += (long)x6 * y; z[6] = (int)c1 & M26; c1 >>= 26;
  423. c2 += (long)x8 * y; z[8] = (int)c2 & M26; c2 >>= 26;
  424. z[2] = x2 + (int)c3;
  425. z[4] = x4 + (int)c0;
  426. z[7] = x7 + (int)c1;
  427. z[9] = x9 + (int)c2;
  428. }
  429. public static void Mul(int[] x, int[] y, int[] z)
  430. {
  431. int x0 = x[0], y0 = y[0];
  432. int x1 = x[1], y1 = y[1];
  433. int x2 = x[2], y2 = y[2];
  434. int x3 = x[3], y3 = y[3];
  435. int x4 = x[4], y4 = y[4];
  436. int u0 = x[5], v0 = y[5];
  437. int u1 = x[6], v1 = y[6];
  438. int u2 = x[7], v2 = y[7];
  439. int u3 = x[8], v3 = y[8];
  440. int u4 = x[9], v4 = y[9];
  441. long a0 = (long)x0 * y0;
  442. long a1 = (long)x0 * y1
  443. + (long)x1 * y0;
  444. long a2 = (long)x0 * y2
  445. + (long)x1 * y1
  446. + (long)x2 * y0;
  447. long a3 = (long)x1 * y2
  448. + (long)x2 * y1;
  449. a3 <<= 1;
  450. a3 += (long)x0 * y3
  451. + (long)x3 * y0;
  452. long a4 = (long)x2 * y2;
  453. a4 <<= 1;
  454. a4 += (long)x0 * y4
  455. + (long)x1 * y3
  456. + (long)x3 * y1
  457. + (long)x4 * y0;
  458. long a5 = (long)x1 * y4
  459. + (long)x2 * y3
  460. + (long)x3 * y2
  461. + (long)x4 * y1;
  462. a5 <<= 1;
  463. long a6 = (long)x2 * y4
  464. + (long)x4 * y2;
  465. a6 <<= 1;
  466. a6 += (long)x3 * y3;
  467. long a7 = (long)x3 * y4
  468. + (long)x4 * y3;
  469. long a8 = (long)x4 * y4;
  470. a8 <<= 1;
  471. long b0 = (long)u0 * v0;
  472. long b1 = (long)u0 * v1
  473. + (long)u1 * v0;
  474. long b2 = (long)u0 * v2
  475. + (long)u1 * v1
  476. + (long)u2 * v0;
  477. long b3 = (long)u1 * v2
  478. + (long)u2 * v1;
  479. b3 <<= 1;
  480. b3 += (long)u0 * v3
  481. + (long)u3 * v0;
  482. long b4 = (long)u2 * v2;
  483. b4 <<= 1;
  484. b4 += (long)u0 * v4
  485. + (long)u1 * v3
  486. + (long)u3 * v1
  487. + (long)u4 * v0;
  488. long b5 = (long)u1 * v4
  489. + (long)u2 * v3
  490. + (long)u3 * v2
  491. + (long)u4 * v1;
  492. //b5 <<= 1;
  493. long b6 = (long)u2 * v4
  494. + (long)u4 * v2;
  495. b6 <<= 1;
  496. b6 += (long)u3 * v3;
  497. long b7 = (long)u3 * v4
  498. + (long)u4 * v3;
  499. long b8 = (long)u4 * v4;
  500. //b8 <<= 1;
  501. a0 -= b5 * 76;
  502. a1 -= b6 * 38;
  503. a2 -= b7 * 38;
  504. a3 -= b8 * 76;
  505. a5 -= b0;
  506. a6 -= b1;
  507. a7 -= b2;
  508. a8 -= b3;
  509. //long a9 = -b4;
  510. x0 += u0; y0 += v0;
  511. x1 += u1; y1 += v1;
  512. x2 += u2; y2 += v2;
  513. x3 += u3; y3 += v3;
  514. x4 += u4; y4 += v4;
  515. long c0 = (long)x0 * y0;
  516. long c1 = (long)x0 * y1
  517. + (long)x1 * y0;
  518. long c2 = (long)x0 * y2
  519. + (long)x1 * y1
  520. + (long)x2 * y0;
  521. long c3 = (long)x1 * y2
  522. + (long)x2 * y1;
  523. c3 <<= 1;
  524. c3 += (long)x0 * y3
  525. + (long)x3 * y0;
  526. long c4 = (long)x2 * y2;
  527. c4 <<= 1;
  528. c4 += (long)x0 * y4
  529. + (long)x1 * y3
  530. + (long)x3 * y1
  531. + (long)x4 * y0;
  532. long c5 = (long)x1 * y4
  533. + (long)x2 * y3
  534. + (long)x3 * y2
  535. + (long)x4 * y1;
  536. c5 <<= 1;
  537. long c6 = (long)x2 * y4
  538. + (long)x4 * y2;
  539. c6 <<= 1;
  540. c6 += (long)x3 * y3;
  541. long c7 = (long)x3 * y4
  542. + (long)x4 * y3;
  543. long c8 = (long)x4 * y4;
  544. c8 <<= 1;
  545. int z8, z9;
  546. long t;
  547. t = a8 + (c3 - a3);
  548. z8 = (int)t & M26; t >>= 26;
  549. //t += a9 + (c4 - a4);
  550. t += (c4 - a4) - b4;
  551. //z9 = (int)t & M24; t >>= 24;
  552. //t = a0 + (t + ((c5 - a5) << 1)) * 19;
  553. z9 = (int)t & M25; t >>= 25;
  554. t = a0 + (t + c5 - a5) * 38;
  555. z[0] = (int)t & M26; t >>= 26;
  556. t += a1 + (c6 - a6) * 38;
  557. z[1] = (int)t & M26; t >>= 26;
  558. t += a2 + (c7 - a7) * 38;
  559. z[2] = (int)t & M25; t >>= 25;
  560. t += a3 + (c8 - a8) * 38;
  561. z[3] = (int)t & M26; t >>= 26;
  562. //t += a4 - a9 * 38;
  563. t += a4 + b4 * 38;
  564. z[4] = (int)t & M25; t >>= 25;
  565. t += a5 + (c0 - a0);
  566. z[5] = (int)t & M26; t >>= 26;
  567. t += a6 + (c1 - a1);
  568. z[6] = (int)t & M26; t >>= 26;
  569. t += a7 + (c2 - a2);
  570. z[7] = (int)t & M25; t >>= 25;
  571. t += z8;
  572. z[8] = (int)t & M26; t >>= 26;
  573. z[9] = z9 + (int)t;
  574. }
  575. public static void Negate(int[] x, int[] z)
  576. {
  577. for (int i = 0; i < Size; ++i)
  578. {
  579. z[i] = -x[i];
  580. }
  581. }
  582. public static void Normalize(int[] z)
  583. {
  584. int x = (z[9] >> 23) & 1;
  585. Reduce(z, x);
  586. Reduce(z, -x);
  587. Debug.Assert(z[9] >> 24 == 0);
  588. }
  589. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  590. public static void Normalize(Span<int> z)
  591. {
  592. int x = (z[9] >> 23) & 1;
  593. Reduce(z, x);
  594. Reduce(z, -x);
  595. Debug.Assert(z[9] >> 24 == 0);
  596. }
  597. #endif
  598. public static void One(int[] z)
  599. {
  600. z[0] = 1;
  601. for (int i = 1; i < Size; ++i)
  602. {
  603. z[i] = 0;
  604. }
  605. }
  606. private static void PowPm5d8(int[] x, int[] rx2, int[] rz)
  607. {
  608. // z = x^((p-5)/8) = x^FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD
  609. // (250 1s) (1 0s) (1 1s)
  610. // Addition chain: [1] 2 3 5 10 15 25 50 75 125 [250]
  611. int[] x2 = rx2; Sqr(x, x2); Mul(x, x2, x2);
  612. int[] x3 = Create(); Sqr(x2, x3); Mul(x, x3, x3);
  613. int[] x5 = x3; Sqr(x3, 2, x5); Mul(x2, x5, x5);
  614. int[] x10 = Create(); Sqr(x5, 5, x10); Mul(x5, x10, x10);
  615. int[] x15 = Create(); Sqr(x10, 5, x15); Mul(x5, x15, x15);
  616. int[] x25 = x5; Sqr(x15, 10, x25); Mul(x10, x25, x25);
  617. int[] x50 = x10; Sqr(x25, 25, x50); Mul(x25, x50, x50);
  618. int[] x75 = x15; Sqr(x50, 25, x75); Mul(x25, x75, x75);
  619. int[] x125 = x25; Sqr(x75, 50, x125); Mul(x50, x125, x125);
  620. int[] x250 = x50; Sqr(x125, 125, x250); Mul(x125, x250, x250);
  621. int[] t = x125;
  622. Sqr(x250, 2, t);
  623. Mul(t, x, rz);
  624. }
  625. private static void Reduce(int[] z, int x)
  626. {
  627. int t = z[9], z9 = t & M24;
  628. t = (t >> 24) + x;
  629. long cc = t * 19;
  630. cc += z[0]; z[0] = (int)cc & M26; cc >>= 26;
  631. cc += z[1]; z[1] = (int)cc & M26; cc >>= 26;
  632. cc += z[2]; z[2] = (int)cc & M25; cc >>= 25;
  633. cc += z[3]; z[3] = (int)cc & M26; cc >>= 26;
  634. cc += z[4]; z[4] = (int)cc & M25; cc >>= 25;
  635. cc += z[5]; z[5] = (int)cc & M26; cc >>= 26;
  636. cc += z[6]; z[6] = (int)cc & M26; cc >>= 26;
  637. cc += z[7]; z[7] = (int)cc & M25; cc >>= 25;
  638. cc += z[8]; z[8] = (int)cc & M26; cc >>= 26;
  639. z[9] = z9 + (int)cc;
  640. }
  641. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  642. private static void Reduce(Span<int> z, int x)
  643. {
  644. int t = z[9], z9 = t & M24;
  645. t = (t >> 24) + x;
  646. long cc = t * 19;
  647. cc += z[0]; z[0] = (int)cc & M26; cc >>= 26;
  648. cc += z[1]; z[1] = (int)cc & M26; cc >>= 26;
  649. cc += z[2]; z[2] = (int)cc & M25; cc >>= 25;
  650. cc += z[3]; z[3] = (int)cc & M26; cc >>= 26;
  651. cc += z[4]; z[4] = (int)cc & M25; cc >>= 25;
  652. cc += z[5]; z[5] = (int)cc & M26; cc >>= 26;
  653. cc += z[6]; z[6] = (int)cc & M26; cc >>= 26;
  654. cc += z[7]; z[7] = (int)cc & M25; cc >>= 25;
  655. cc += z[8]; z[8] = (int)cc & M26; cc >>= 26;
  656. z[9] = z9 + (int)cc;
  657. }
  658. #endif
  659. public static void Sqr(int[] x, int[] z)
  660. {
  661. int x0 = x[0];
  662. int x1 = x[1];
  663. int x2 = x[2];
  664. int x3 = x[3];
  665. int x4 = x[4];
  666. int u0 = x[5];
  667. int u1 = x[6];
  668. int u2 = x[7];
  669. int u3 = x[8];
  670. int u4 = x[9];
  671. int x1_2 = x1 * 2;
  672. int x2_2 = x2 * 2;
  673. int x3_2 = x3 * 2;
  674. int x4_2 = x4 * 2;
  675. long a0 = (long)x0 * x0;
  676. long a1 = (long)x0 * x1_2;
  677. long a2 = (long)x0 * x2_2
  678. + (long)x1 * x1;
  679. long a3 = (long)x1_2 * x2_2
  680. + (long)x0 * x3_2;
  681. long a4 = (long)x2 * x2_2
  682. + (long)x0 * x4_2
  683. + (long)x1 * x3_2;
  684. long a5 = (long)x1_2 * x4_2
  685. + (long)x2_2 * x3_2;
  686. long a6 = (long)x2_2 * x4_2
  687. + (long)x3 * x3;
  688. long a7 = (long)x3 * x4_2;
  689. long a8 = (long)x4 * x4_2;
  690. int u1_2 = u1 * 2;
  691. int u2_2 = u2 * 2;
  692. int u3_2 = u3 * 2;
  693. int u4_2 = u4 * 2;
  694. long b0 = (long)u0 * u0;
  695. long b1 = (long)u0 * u1_2;
  696. long b2 = (long)u0 * u2_2
  697. + (long)u1 * u1;
  698. long b3 = (long)u1_2 * u2_2
  699. + (long)u0 * u3_2;
  700. long b4 = (long)u2 * u2_2
  701. + (long)u0 * u4_2
  702. + (long)u1 * u3_2;
  703. long b5 = (long)u1_2 * u4_2
  704. + (long)u2_2 * u3_2;
  705. long b6 = (long)u2_2 * u4_2
  706. + (long)u3 * u3;
  707. long b7 = (long)u3 * u4_2;
  708. long b8 = (long)u4 * u4_2;
  709. a0 -= b5 * 38;
  710. a1 -= b6 * 38;
  711. a2 -= b7 * 38;
  712. a3 -= b8 * 38;
  713. a5 -= b0;
  714. a6 -= b1;
  715. a7 -= b2;
  716. a8 -= b3;
  717. //long a9 = -b4;
  718. x0 += u0;
  719. x1 += u1;
  720. x2 += u2;
  721. x3 += u3;
  722. x4 += u4;
  723. x1_2 = x1 * 2;
  724. x2_2 = x2 * 2;
  725. x3_2 = x3 * 2;
  726. x4_2 = x4 * 2;
  727. long c0 = (long)x0 * x0;
  728. long c1 = (long)x0 * x1_2;
  729. long c2 = (long)x0 * x2_2
  730. + (long)x1 * x1;
  731. long c3 = (long)x1_2 * x2_2
  732. + (long)x0 * x3_2;
  733. long c4 = (long)x2 * x2_2
  734. + (long)x0 * x4_2
  735. + (long)x1 * x3_2;
  736. long c5 = (long)x1_2 * x4_2
  737. + (long)x2_2 * x3_2;
  738. long c6 = (long)x2_2 * x4_2
  739. + (long)x3 * x3;
  740. long c7 = (long)x3 * x4_2;
  741. long c8 = (long)x4 * x4_2;
  742. int z8, z9;
  743. long t;
  744. t = a8 + (c3 - a3);
  745. z8 = (int)t & M26; t >>= 26;
  746. //t += a9 + (c4 - a4);
  747. t += (c4 - a4) - b4;
  748. //z9 = (int)t & M24; t >>= 24;
  749. //t = a0 + (t + ((c5 - a5) << 1)) * 19;
  750. z9 = (int)t & M25; t >>= 25;
  751. t = a0 + (t + c5 - a5) * 38;
  752. z[0] = (int)t & M26; t >>= 26;
  753. t += a1 + (c6 - a6) * 38;
  754. z[1] = (int)t & M26; t >>= 26;
  755. t += a2 + (c7 - a7) * 38;
  756. z[2] = (int)t & M25; t >>= 25;
  757. t += a3 + (c8 - a8) * 38;
  758. z[3] = (int)t & M26; t >>= 26;
  759. //t += a4 - a9 * 38;
  760. t += a4 + b4 * 38;
  761. z[4] = (int)t & M25; t >>= 25;
  762. t += a5 + (c0 - a0);
  763. z[5] = (int)t & M26; t >>= 26;
  764. t += a6 + (c1 - a1);
  765. z[6] = (int)t & M26; t >>= 26;
  766. t += a7 + (c2 - a2);
  767. z[7] = (int)t & M25; t >>= 25;
  768. t += z8;
  769. z[8] = (int)t & M26; t >>= 26;
  770. z[9] = z9 + (int)t;
  771. }
  772. public static void Sqr(int[] x, int n, int[] z)
  773. {
  774. Debug.Assert(n > 0);
  775. Sqr(x, z);
  776. while (--n > 0)
  777. {
  778. Sqr(z, z);
  779. }
  780. }
  781. public static bool SqrtRatioVar(int[] u, int[] v, int[] z)
  782. {
  783. int[] uv3 = Create();
  784. int[] uv7 = Create();
  785. Mul(u, v, uv3);
  786. Sqr(v, uv7);
  787. Mul(uv3, uv7, uv3);
  788. Sqr(uv7, uv7);
  789. Mul(uv7, uv3, uv7);
  790. int[] t = Create();
  791. int[] x = Create();
  792. PowPm5d8(uv7, t, x);
  793. Mul(x, uv3, x);
  794. int[] vx2 = Create();
  795. Sqr(x, vx2);
  796. Mul(vx2, v, vx2);
  797. Sub(vx2, u, t);
  798. Normalize(t);
  799. if (IsZeroVar(t))
  800. {
  801. Copy(x, 0, z, 0);
  802. return true;
  803. }
  804. Add(vx2, u, t);
  805. Normalize(t);
  806. if (IsZeroVar(t))
  807. {
  808. Mul(x, RootNegOne, z);
  809. return true;
  810. }
  811. return false;
  812. }
  813. public static void Sub(int[] x, int[] y, int[] z)
  814. {
  815. for (int i = 0; i < Size; ++i)
  816. {
  817. z[i] = x[i] - y[i];
  818. }
  819. }
  820. public static void SubOne(int[] z)
  821. {
  822. z[0] -= 1;
  823. }
  824. public static void Zero(int[] z)
  825. {
  826. for (int i = 0; i < Size; ++i)
  827. {
  828. z[i] = 0;
  829. }
  830. }
  831. }
  832. }
  833. #pragma warning restore
  834. #endif