X25519Field.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763
  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.Math.Raw;
  6. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Math.EC.Rfc7748
  7. {
  8. public abstract 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. protected X25519Field() {}
  19. public static void Add(int[] x, int[] y, int[] z)
  20. {
  21. for (int i = 0; i < Size; ++i)
  22. {
  23. z[i] = x[i] + y[i];
  24. }
  25. }
  26. public static void AddOne(int[] z)
  27. {
  28. z[0] += 1;
  29. }
  30. public static void AddOne(int[] z, int zOff)
  31. {
  32. z[zOff] += 1;
  33. }
  34. public static void Apm(int[] x, int[] y, int[] zp, int[] zm)
  35. {
  36. for (int i = 0; i < Size; ++i)
  37. {
  38. int xi = x[i], yi = y[i];
  39. zp[i] = xi + yi;
  40. zm[i] = xi - yi;
  41. }
  42. }
  43. public static int AreEqual(int[] x, int[] y)
  44. {
  45. int d = 0;
  46. for (int i = 0; i < Size; ++i)
  47. {
  48. d |= x[i] ^ y[i];
  49. }
  50. d |= d >> 16;
  51. d &= 0xFFFF;
  52. return (d - 1) >> 31;
  53. }
  54. public static bool AreEqualVar(int[] x, int[] y)
  55. {
  56. return 0 != AreEqual(x, y);
  57. }
  58. public static void Carry(int[] z)
  59. {
  60. int z0 = z[0], z1 = z[1], z2 = z[2], z3 = z[3], z4 = z[4];
  61. int z5 = z[5], z6 = z[6], z7 = z[7], z8 = z[8], z9 = z[9];
  62. z2 += (z1 >> 26); z1 &= M26;
  63. z4 += (z3 >> 26); z3 &= M26;
  64. z7 += (z6 >> 26); z6 &= M26;
  65. z9 += (z8 >> 26); z8 &= M26;
  66. z3 += (z2 >> 25); z2 &= M25;
  67. z5 += (z4 >> 25); z4 &= M25;
  68. z8 += (z7 >> 25); z7 &= M25;
  69. //z0 += (z9 >> 24) * 19; z9 &= M24;
  70. z0 += (z9 >> 25) * 38; z9 &= M25;
  71. z1 += (z0 >> 26); z0 &= M26;
  72. z6 += (z5 >> 26); z5 &= M26;
  73. z2 += (z1 >> 26); z1 &= M26;
  74. z4 += (z3 >> 26); z3 &= M26;
  75. z7 += (z6 >> 26); z6 &= M26;
  76. z9 += (z8 >> 26); z8 &= M26;
  77. z[0] = z0; z[1] = z1; z[2] = z2; z[3] = z3; z[4] = z4;
  78. z[5] = z5; z[6] = z6; z[7] = z7; z[8] = z8; z[9] = z9;
  79. }
  80. public static void CMov(int cond, int[] x, int xOff, int[] z, int zOff)
  81. {
  82. Debug.Assert(0 == cond || -1 == cond);
  83. for (int i = 0; i < Size; ++i)
  84. {
  85. int z_i = z[zOff + i], diff = z_i ^ x[xOff + i];
  86. z_i ^= (diff & cond);
  87. z[zOff + i] = z_i;
  88. }
  89. }
  90. public static void CNegate(int negate, int[] z)
  91. {
  92. Debug.Assert(negate >> 1 == 0);
  93. int mask = 0 - negate;
  94. for (int i = 0; i < Size; ++i)
  95. {
  96. z[i] = (z[i] ^ mask) - mask;
  97. }
  98. }
  99. public static void Copy(int[] x, int xOff, int[] z, int zOff)
  100. {
  101. for (int i = 0; i < Size; ++i)
  102. {
  103. z[zOff + i] = x[xOff + i];
  104. }
  105. }
  106. public static int[] Create()
  107. {
  108. return new int[Size];
  109. }
  110. public static int[] CreateTable(int n)
  111. {
  112. return new int[Size * n];
  113. }
  114. public static void CSwap(int swap, int[] a, int[] b)
  115. {
  116. Debug.Assert(swap >> 1 == 0);
  117. Debug.Assert(a != b);
  118. int mask = 0 - swap;
  119. for (int i = 0; i < Size; ++i)
  120. {
  121. int ai = a[i], bi = b[i];
  122. int dummy = mask & (ai ^ bi);
  123. a[i] = ai ^ dummy;
  124. b[i] = bi ^ dummy;
  125. }
  126. }
  127. [CLSCompliantAttribute(false)]
  128. public static void Decode(uint[] x, int xOff, int[] z)
  129. {
  130. Decode128(x, xOff, z, 0);
  131. Decode128(x, xOff + 4, z, 5);
  132. z[9] &= M24;
  133. }
  134. public static void Decode(byte[] x, int xOff, int[] z)
  135. {
  136. Decode128(x, xOff, z, 0);
  137. Decode128(x, xOff + 16, z, 5);
  138. z[9] &= M24;
  139. }
  140. private static void Decode128(uint[] x, int xOff, int[] z, int zOff)
  141. {
  142. uint t0 = x[xOff + 0], t1 = x[xOff + 1], t2 = x[xOff + 2], t3 = x[xOff + 3];
  143. z[zOff + 0] = (int)t0 & M26;
  144. z[zOff + 1] = (int)((t1 << 6) | (t0 >> 26)) & M26;
  145. z[zOff + 2] = (int)((t2 << 12) | (t1 >> 20)) & M25;
  146. z[zOff + 3] = (int)((t3 << 19) | (t2 >> 13)) & M26;
  147. z[zOff + 4] = (int)(t3 >> 7);
  148. }
  149. private static void Decode128(byte[] bs, int off, int[] z, int zOff)
  150. {
  151. uint t0 = Decode32(bs, off + 0);
  152. uint t1 = Decode32(bs, off + 4);
  153. uint t2 = Decode32(bs, off + 8);
  154. uint t3 = Decode32(bs, off + 12);
  155. z[zOff + 0] = (int)t0 & M26;
  156. z[zOff + 1] = (int)((t1 << 6) | (t0 >> 26)) & M26;
  157. z[zOff + 2] = (int)((t2 << 12) | (t1 >> 20)) & M25;
  158. z[zOff + 3] = (int)((t3 << 19) | (t2 >> 13)) & M26;
  159. z[zOff + 4] = (int)(t3 >> 7);
  160. }
  161. private static uint Decode32(byte[] bs, int off)
  162. {
  163. uint n = bs[off];
  164. n |= (uint)bs[++off] << 8;
  165. n |= (uint)bs[++off] << 16;
  166. n |= (uint)bs[++off] << 24;
  167. return n;
  168. }
  169. [CLSCompliantAttribute(false)]
  170. public static void Encode(int[] x, uint[] z, int zOff)
  171. {
  172. Encode128(x, 0, z, zOff);
  173. Encode128(x, 5, z, zOff + 4);
  174. }
  175. public static void Encode(int[] x, byte[] z, int zOff)
  176. {
  177. Encode128(x, 0, z, zOff);
  178. Encode128(x, 5, z, zOff + 16);
  179. }
  180. private static void Encode128(int[] x, int xOff, uint[] z, int zOff)
  181. {
  182. uint x0 = (uint)x[xOff + 0], x1 = (uint)x[xOff + 1], x2 = (uint)x[xOff + 2], x3 = (uint)x[xOff + 3],
  183. x4 = (uint)x[xOff + 4];
  184. z[zOff + 0] = x0 | (x1 << 26);
  185. z[zOff + 1] = (x1 >> 6) | (x2 << 20);
  186. z[zOff + 2] = (x2 >> 12) | (x3 << 13);
  187. z[zOff + 3] = (x3 >> 19) | (x4 << 7);
  188. }
  189. private static void Encode128(int[] x, int xOff, byte[] bs, int off)
  190. {
  191. uint x0 = (uint)x[xOff + 0], x1 = (uint)x[xOff + 1], x2 = (uint)x[xOff + 2];
  192. uint x3 = (uint)x[xOff + 3], x4 = (uint)x[xOff + 4];
  193. uint t0 = x0 | (x1 << 26); Encode32(t0, bs, off + 0);
  194. uint t1 = (x1 >> 6) | (x2 << 20); Encode32(t1, bs, off + 4);
  195. uint t2 = (x2 >> 12) | (x3 << 13); Encode32(t2, bs, off + 8);
  196. uint t3 = (x3 >> 19) | (x4 << 7); Encode32(t3, bs, off + 12);
  197. }
  198. private static void Encode32(uint n, byte[] bs, int off)
  199. {
  200. bs[ off] = (byte)(n );
  201. bs[++off] = (byte)(n >> 8);
  202. bs[++off] = (byte)(n >> 16);
  203. bs[++off] = (byte)(n >> 24);
  204. }
  205. public static void Inv(int[] x, int[] z)
  206. {
  207. //int[] x2 = Create();
  208. //int[] t = Create();
  209. //PowPm5d8(x, x2, t);
  210. //Sqr(t, 3, t);
  211. //Mul(t, x2, z);
  212. int[] t = Create();
  213. uint[] u = new uint[8];
  214. Copy(x, 0, t, 0);
  215. Normalize(t);
  216. Encode(t, u, 0);
  217. Mod.ModOddInverse(P32, u, u);
  218. Decode(u, 0, z);
  219. }
  220. public static void InvVar(int[] x, int[] z)
  221. {
  222. int[] t = Create();
  223. uint[] u = new uint[8];
  224. Copy(x, 0, t, 0);
  225. Normalize(t);
  226. Encode(t, u, 0);
  227. Mod.ModOddInverseVar(P32, u, u);
  228. Decode(u, 0, z);
  229. }
  230. public static int IsOne(int[] x)
  231. {
  232. int d = x[0] ^ 1;
  233. for (int i = 1; i < Size; ++i)
  234. {
  235. d |= x[i];
  236. }
  237. d |= d >> 16;
  238. d &= 0xFFFF;
  239. return (d - 1) >> 31;
  240. }
  241. public static bool IsOneVar(int[] x)
  242. {
  243. return 0 != IsOne(x);
  244. }
  245. public static int IsZero(int[] x)
  246. {
  247. int d = 0;
  248. for (int i = 0; i < Size; ++i)
  249. {
  250. d |= x[i];
  251. }
  252. d |= d >> 16;
  253. d &= 0xFFFF;
  254. return (d - 1) >> 31;
  255. }
  256. public static bool IsZeroVar(int[] x)
  257. {
  258. return 0 != IsZero(x);
  259. }
  260. public static void Mul(int[] x, int y, int[] z)
  261. {
  262. int x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3], x4 = x[4];
  263. int x5 = x[5], x6 = x[6], x7 = x[7], x8 = x[8], x9 = x[9];
  264. long c0, c1, c2, c3;
  265. c0 = (long)x2 * y; x2 = (int)c0 & M25; c0 >>= 25;
  266. c1 = (long)x4 * y; x4 = (int)c1 & M25; c1 >>= 25;
  267. c2 = (long)x7 * y; x7 = (int)c2 & M25; c2 >>= 25;
  268. //c3 = (long)x9 * y; x9 = (int)c3 & M24; c3 >>= 24;
  269. //c3 *= 19;
  270. c3 = (long)x9 * y; x9 = (int)c3 & M25; c3 >>= 25;
  271. c3 *= 38;
  272. c3 += (long)x0 * y; z[0] = (int)c3 & M26; c3 >>= 26;
  273. c1 += (long)x5 * y; z[5] = (int)c1 & M26; c1 >>= 26;
  274. c3 += (long)x1 * y; z[1] = (int)c3 & M26; c3 >>= 26;
  275. c0 += (long)x3 * y; z[3] = (int)c0 & M26; c0 >>= 26;
  276. c1 += (long)x6 * y; z[6] = (int)c1 & M26; c1 >>= 26;
  277. c2 += (long)x8 * y; z[8] = (int)c2 & M26; c2 >>= 26;
  278. z[2] = x2 + (int)c3;
  279. z[4] = x4 + (int)c0;
  280. z[7] = x7 + (int)c1;
  281. z[9] = x9 + (int)c2;
  282. }
  283. public static void Mul(int[] x, int[] y, int[] z)
  284. {
  285. int x0 = x[0], y0 = y[0];
  286. int x1 = x[1], y1 = y[1];
  287. int x2 = x[2], y2 = y[2];
  288. int x3 = x[3], y3 = y[3];
  289. int x4 = x[4], y4 = y[4];
  290. int u0 = x[5], v0 = y[5];
  291. int u1 = x[6], v1 = y[6];
  292. int u2 = x[7], v2 = y[7];
  293. int u3 = x[8], v3 = y[8];
  294. int u4 = x[9], v4 = y[9];
  295. long a0 = (long)x0 * y0;
  296. long a1 = (long)x0 * y1
  297. + (long)x1 * y0;
  298. long a2 = (long)x0 * y2
  299. + (long)x1 * y1
  300. + (long)x2 * y0;
  301. long a3 = (long)x1 * y2
  302. + (long)x2 * y1;
  303. a3 <<= 1;
  304. a3 += (long)x0 * y3
  305. + (long)x3 * y0;
  306. long a4 = (long)x2 * y2;
  307. a4 <<= 1;
  308. a4 += (long)x0 * y4
  309. + (long)x1 * y3
  310. + (long)x3 * y1
  311. + (long)x4 * y0;
  312. long a5 = (long)x1 * y4
  313. + (long)x2 * y3
  314. + (long)x3 * y2
  315. + (long)x4 * y1;
  316. a5 <<= 1;
  317. long a6 = (long)x2 * y4
  318. + (long)x4 * y2;
  319. a6 <<= 1;
  320. a6 += (long)x3 * y3;
  321. long a7 = (long)x3 * y4
  322. + (long)x4 * y3;
  323. long a8 = (long)x4 * y4;
  324. a8 <<= 1;
  325. long b0 = (long)u0 * v0;
  326. long b1 = (long)u0 * v1
  327. + (long)u1 * v0;
  328. long b2 = (long)u0 * v2
  329. + (long)u1 * v1
  330. + (long)u2 * v0;
  331. long b3 = (long)u1 * v2
  332. + (long)u2 * v1;
  333. b3 <<= 1;
  334. b3 += (long)u0 * v3
  335. + (long)u3 * v0;
  336. long b4 = (long)u2 * v2;
  337. b4 <<= 1;
  338. b4 += (long)u0 * v4
  339. + (long)u1 * v3
  340. + (long)u3 * v1
  341. + (long)u4 * v0;
  342. long b5 = (long)u1 * v4
  343. + (long)u2 * v3
  344. + (long)u3 * v2
  345. + (long)u4 * v1;
  346. //b5 <<= 1;
  347. long b6 = (long)u2 * v4
  348. + (long)u4 * v2;
  349. b6 <<= 1;
  350. b6 += (long)u3 * v3;
  351. long b7 = (long)u3 * v4
  352. + (long)u4 * v3;
  353. long b8 = (long)u4 * v4;
  354. //b8 <<= 1;
  355. a0 -= b5 * 76;
  356. a1 -= b6 * 38;
  357. a2 -= b7 * 38;
  358. a3 -= b8 * 76;
  359. a5 -= b0;
  360. a6 -= b1;
  361. a7 -= b2;
  362. a8 -= b3;
  363. //long a9 = -b4;
  364. x0 += u0; y0 += v0;
  365. x1 += u1; y1 += v1;
  366. x2 += u2; y2 += v2;
  367. x3 += u3; y3 += v3;
  368. x4 += u4; y4 += v4;
  369. long c0 = (long)x0 * y0;
  370. long c1 = (long)x0 * y1
  371. + (long)x1 * y0;
  372. long c2 = (long)x0 * y2
  373. + (long)x1 * y1
  374. + (long)x2 * y0;
  375. long c3 = (long)x1 * y2
  376. + (long)x2 * y1;
  377. c3 <<= 1;
  378. c3 += (long)x0 * y3
  379. + (long)x3 * y0;
  380. long c4 = (long)x2 * y2;
  381. c4 <<= 1;
  382. c4 += (long)x0 * y4
  383. + (long)x1 * y3
  384. + (long)x3 * y1
  385. + (long)x4 * y0;
  386. long c5 = (long)x1 * y4
  387. + (long)x2 * y3
  388. + (long)x3 * y2
  389. + (long)x4 * y1;
  390. c5 <<= 1;
  391. long c6 = (long)x2 * y4
  392. + (long)x4 * y2;
  393. c6 <<= 1;
  394. c6 += (long)x3 * y3;
  395. long c7 = (long)x3 * y4
  396. + (long)x4 * y3;
  397. long c8 = (long)x4 * y4;
  398. c8 <<= 1;
  399. int z8, z9;
  400. long t;
  401. t = a8 + (c3 - a3);
  402. z8 = (int)t & M26; t >>= 26;
  403. //t += a9 + (c4 - a4);
  404. t += (c4 - a4) - b4;
  405. //z9 = (int)t & M24; t >>= 24;
  406. //t = a0 + (t + ((c5 - a5) << 1)) * 19;
  407. z9 = (int)t & M25; t >>= 25;
  408. t = a0 + (t + c5 - a5) * 38;
  409. z[0] = (int)t & M26; t >>= 26;
  410. t += a1 + (c6 - a6) * 38;
  411. z[1] = (int)t & M26; t >>= 26;
  412. t += a2 + (c7 - a7) * 38;
  413. z[2] = (int)t & M25; t >>= 25;
  414. t += a3 + (c8 - a8) * 38;
  415. z[3] = (int)t & M26; t >>= 26;
  416. //t += a4 - a9 * 38;
  417. t += a4 + b4 * 38;
  418. z[4] = (int)t & M25; t >>= 25;
  419. t += a5 + (c0 - a0);
  420. z[5] = (int)t & M26; t >>= 26;
  421. t += a6 + (c1 - a1);
  422. z[6] = (int)t & M26; t >>= 26;
  423. t += a7 + (c2 - a2);
  424. z[7] = (int)t & M25; t >>= 25;
  425. t += z8;
  426. z[8] = (int)t & M26; t >>= 26;
  427. z[9] = z9 + (int)t;
  428. }
  429. public static void Negate(int[] x, int[] z)
  430. {
  431. for (int i = 0; i < Size; ++i)
  432. {
  433. z[i] = -x[i];
  434. }
  435. }
  436. public static void Normalize(int[] z)
  437. {
  438. int x = (z[9] >> 23) & 1;
  439. Reduce(z, x);
  440. Reduce(z, -x);
  441. Debug.Assert(z[9] >> 24 == 0);
  442. }
  443. public static void One(int[] z)
  444. {
  445. z[0] = 1;
  446. for (int i = 1; i < Size; ++i)
  447. {
  448. z[i] = 0;
  449. }
  450. }
  451. private static void PowPm5d8(int[] x, int[] rx2, int[] rz)
  452. {
  453. // z = x^((p-5)/8) = x^FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD
  454. // (250 1s) (1 0s) (1 1s)
  455. // Addition chain: [1] 2 3 5 10 15 25 50 75 125 [250]
  456. int[] x2 = rx2; Sqr(x, x2); Mul(x, x2, x2);
  457. int[] x3 = Create(); Sqr(x2, x3); Mul(x, x3, x3);
  458. int[] x5 = x3; Sqr(x3, 2, x5); Mul(x2, x5, x5);
  459. int[] x10 = Create(); Sqr(x5, 5, x10); Mul(x5, x10, x10);
  460. int[] x15 = Create(); Sqr(x10, 5, x15); Mul(x5, x15, x15);
  461. int[] x25 = x5; Sqr(x15, 10, x25); Mul(x10, x25, x25);
  462. int[] x50 = x10; Sqr(x25, 25, x50); Mul(x25, x50, x50);
  463. int[] x75 = x15; Sqr(x50, 25, x75); Mul(x25, x75, x75);
  464. int[] x125 = x25; Sqr(x75, 50, x125); Mul(x50, x125, x125);
  465. int[] x250 = x50; Sqr(x125, 125, x250); Mul(x125, x250, x250);
  466. int[] t = x125;
  467. Sqr(x250, 2, t);
  468. Mul(t, x, rz);
  469. }
  470. private static void Reduce(int[] z, int x)
  471. {
  472. int t = z[9], z9 = t & M24;
  473. t = (t >> 24) + x;
  474. long cc = t * 19;
  475. cc += z[0]; z[0] = (int)cc & M26; cc >>= 26;
  476. cc += z[1]; z[1] = (int)cc & M26; cc >>= 26;
  477. cc += z[2]; z[2] = (int)cc & M25; cc >>= 25;
  478. cc += z[3]; z[3] = (int)cc & M26; cc >>= 26;
  479. cc += z[4]; z[4] = (int)cc & M25; cc >>= 25;
  480. cc += z[5]; z[5] = (int)cc & M26; cc >>= 26;
  481. cc += z[6]; z[6] = (int)cc & M26; cc >>= 26;
  482. cc += z[7]; z[7] = (int)cc & M25; cc >>= 25;
  483. cc += z[8]; z[8] = (int)cc & M26; cc >>= 26;
  484. z[9] = z9 + (int)cc;
  485. }
  486. public static void Sqr(int[] x, int[] z)
  487. {
  488. int x0 = x[0];
  489. int x1 = x[1];
  490. int x2 = x[2];
  491. int x3 = x[3];
  492. int x4 = x[4];
  493. int u0 = x[5];
  494. int u1 = x[6];
  495. int u2 = x[7];
  496. int u3 = x[8];
  497. int u4 = x[9];
  498. int x1_2 = x1 * 2;
  499. int x2_2 = x2 * 2;
  500. int x3_2 = x3 * 2;
  501. int x4_2 = x4 * 2;
  502. long a0 = (long)x0 * x0;
  503. long a1 = (long)x0 * x1_2;
  504. long a2 = (long)x0 * x2_2
  505. + (long)x1 * x1;
  506. long a3 = (long)x1_2 * x2_2
  507. + (long)x0 * x3_2;
  508. long a4 = (long)x2 * x2_2
  509. + (long)x0 * x4_2
  510. + (long)x1 * x3_2;
  511. long a5 = (long)x1_2 * x4_2
  512. + (long)x2_2 * x3_2;
  513. long a6 = (long)x2_2 * x4_2
  514. + (long)x3 * x3;
  515. long a7 = (long)x3 * x4_2;
  516. long a8 = (long)x4 * x4_2;
  517. int u1_2 = u1 * 2;
  518. int u2_2 = u2 * 2;
  519. int u3_2 = u3 * 2;
  520. int u4_2 = u4 * 2;
  521. long b0 = (long)u0 * u0;
  522. long b1 = (long)u0 * u1_2;
  523. long b2 = (long)u0 * u2_2
  524. + (long)u1 * u1;
  525. long b3 = (long)u1_2 * u2_2
  526. + (long)u0 * u3_2;
  527. long b4 = (long)u2 * u2_2
  528. + (long)u0 * u4_2
  529. + (long)u1 * u3_2;
  530. long b5 = (long)u1_2 * u4_2
  531. + (long)u2_2 * u3_2;
  532. long b6 = (long)u2_2 * u4_2
  533. + (long)u3 * u3;
  534. long b7 = (long)u3 * u4_2;
  535. long b8 = (long)u4 * u4_2;
  536. a0 -= b5 * 38;
  537. a1 -= b6 * 38;
  538. a2 -= b7 * 38;
  539. a3 -= b8 * 38;
  540. a5 -= b0;
  541. a6 -= b1;
  542. a7 -= b2;
  543. a8 -= b3;
  544. //long a9 = -b4;
  545. x0 += u0;
  546. x1 += u1;
  547. x2 += u2;
  548. x3 += u3;
  549. x4 += u4;
  550. x1_2 = x1 * 2;
  551. x2_2 = x2 * 2;
  552. x3_2 = x3 * 2;
  553. x4_2 = x4 * 2;
  554. long c0 = (long)x0 * x0;
  555. long c1 = (long)x0 * x1_2;
  556. long c2 = (long)x0 * x2_2
  557. + (long)x1 * x1;
  558. long c3 = (long)x1_2 * x2_2
  559. + (long)x0 * x3_2;
  560. long c4 = (long)x2 * x2_2
  561. + (long)x0 * x4_2
  562. + (long)x1 * x3_2;
  563. long c5 = (long)x1_2 * x4_2
  564. + (long)x2_2 * x3_2;
  565. long c6 = (long)x2_2 * x4_2
  566. + (long)x3 * x3;
  567. long c7 = (long)x3 * x4_2;
  568. long c8 = (long)x4 * x4_2;
  569. int z8, z9;
  570. long t;
  571. t = a8 + (c3 - a3);
  572. z8 = (int)t & M26; t >>= 26;
  573. //t += a9 + (c4 - a4);
  574. t += (c4 - a4) - b4;
  575. //z9 = (int)t & M24; t >>= 24;
  576. //t = a0 + (t + ((c5 - a5) << 1)) * 19;
  577. z9 = (int)t & M25; t >>= 25;
  578. t = a0 + (t + c5 - a5) * 38;
  579. z[0] = (int)t & M26; t >>= 26;
  580. t += a1 + (c6 - a6) * 38;
  581. z[1] = (int)t & M26; t >>= 26;
  582. t += a2 + (c7 - a7) * 38;
  583. z[2] = (int)t & M25; t >>= 25;
  584. t += a3 + (c8 - a8) * 38;
  585. z[3] = (int)t & M26; t >>= 26;
  586. //t += a4 - a9 * 38;
  587. t += a4 + b4 * 38;
  588. z[4] = (int)t & M25; t >>= 25;
  589. t += a5 + (c0 - a0);
  590. z[5] = (int)t & M26; t >>= 26;
  591. t += a6 + (c1 - a1);
  592. z[6] = (int)t & M26; t >>= 26;
  593. t += a7 + (c2 - a2);
  594. z[7] = (int)t & M25; t >>= 25;
  595. t += z8;
  596. z[8] = (int)t & M26; t >>= 26;
  597. z[9] = z9 + (int)t;
  598. }
  599. public static void Sqr(int[] x, int n, int[] z)
  600. {
  601. Debug.Assert(n > 0);
  602. Sqr(x, z);
  603. while (--n > 0)
  604. {
  605. Sqr(z, z);
  606. }
  607. }
  608. public static bool SqrtRatioVar(int[] u, int[] v, int[] z)
  609. {
  610. int[] uv3 = Create();
  611. int[] uv7 = Create();
  612. Mul(u, v, uv3);
  613. Sqr(v, uv7);
  614. Mul(uv3, uv7, uv3);
  615. Sqr(uv7, uv7);
  616. Mul(uv7, uv3, uv7);
  617. int[] t = Create();
  618. int[] x = Create();
  619. PowPm5d8(uv7, t, x);
  620. Mul(x, uv3, x);
  621. int[] vx2 = Create();
  622. Sqr(x, vx2);
  623. Mul(vx2, v, vx2);
  624. Sub(vx2, u, t);
  625. Normalize(t);
  626. if (IsZeroVar(t))
  627. {
  628. Copy(x, 0, z, 0);
  629. return true;
  630. }
  631. Add(vx2, u, t);
  632. Normalize(t);
  633. if (IsZeroVar(t))
  634. {
  635. Mul(x, RootNegOne, z);
  636. return true;
  637. }
  638. return false;
  639. }
  640. public static void Sub(int[] x, int[] y, int[] z)
  641. {
  642. for (int i = 0; i < Size; ++i)
  643. {
  644. z[i] = x[i] - y[i];
  645. }
  646. }
  647. public static void SubOne(int[] z)
  648. {
  649. z[0] -= 1;
  650. }
  651. public static void Zero(int[] z)
  652. {
  653. for (int i = 0; i < Size; ++i)
  654. {
  655. z[i] = 0;
  656. }
  657. }
  658. }
  659. }
  660. #pragma warning restore
  661. #endif