zz_test.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  1. /*
  2. *******************************************************************************
  3. \file zz_test.c
  4. \brief Tests for multiple-precision unsigned integers
  5. \project bee2/test
  6. \created 2014.07.15
  7. \version 2025.03.19
  8. \copyright The Bee2 authors
  9. \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt).
  10. *******************************************************************************
  11. */
  12. #include <bee2/core/mem.h>
  13. #include <bee2/core/prng.h>
  14. #include <bee2/core/util.h>
  15. #include <bee2/core/word.h>
  16. #include <bee2/math/zz.h>
  17. #include <bee2/math/ww.h>
  18. /*
  19. *******************************************************************************
  20. Тестирование
  21. *******************************************************************************
  22. */
  23. static bool_t zzTestAdd()
  24. {
  25. enum { n = 8 };
  26. size_t reps = 500;
  27. word a[n];
  28. word b[n];
  29. word c[n];
  30. word c1[n];
  31. octet combo_state[32];
  32. // подготовить память
  33. if (sizeof(combo_state) < prngCOMBO_keep())
  34. return FALSE;
  35. // инициализировать генератор COMBO
  36. prngCOMBOStart(combo_state, utilNonce32());
  37. // сложение / вычитание
  38. while (reps--)
  39. {
  40. word carry;
  41. prngCOMBOStepR(a, O_OF_W(n), combo_state);
  42. prngCOMBOStepR(b, O_OF_W(n), combo_state);
  43. // zzAdd / zzSub / zzIsSumEq
  44. carry = zzAdd(c, a, b, n);
  45. if (zzSub(c1, c, b, n) != carry ||
  46. !wwEq(c1, a, n) ||
  47. SAFE(zzIsSumEq)(c, a, b, n) != wordEq(carry, 0) ||
  48. FAST(zzIsSumEq)(c, a, b, n) != wordEq(carry, 0))
  49. return FALSE;
  50. // zzAdd2 / zzSub2
  51. wwCopy(c1, a, n);
  52. if (zzAdd2(c1, b, n) != carry ||
  53. !wwEq(c1, c, n) ||
  54. zzSub2(c1, b, n) != carry ||
  55. !wwEq(c1, a, n))
  56. return FALSE;
  57. // zzAddW / zzSubW / zzIsSumEqW
  58. carry = zzAddW(c, a, n, b[0]);
  59. if (zzSubW(c1, c, n, b[0]) != carry ||
  60. !wwEq(c1, a, n) ||
  61. SAFE(zzIsSumWEq)(c, a, n, b[0]) != wordEq(carry, 0) ||
  62. FAST(zzIsSumWEq)(c, a, n, b[0]) != wordEq(carry, 0))
  63. return FALSE;
  64. // zzAddW2 / zzSubW2
  65. wwCopy(c1, a, n);
  66. if (zzAddW2(c1, n, b[0]) != carry ||
  67. !wwEq(c1, c, n) ||
  68. zzSubW2(c1, n, b[0]) != carry ||
  69. !wwEq(c1, a, n))
  70. return FALSE;
  71. // zzAddW / zzSubW / zzIsSumEqW [n <- 1]
  72. carry = zzAddW(c, a, 1, b[0]);
  73. if (zzSubW(c1, c, 1, b[0]) != carry ||
  74. !wwEq(c1, a, 1) ||
  75. SAFE(zzIsSumWEq)(c, a, 1, b[0]) != wordEq(carry, 0) ||
  76. FAST(zzIsSumWEq)(c, a, 1, b[0]) != wordEq(carry, 0))
  77. return FALSE;
  78. // zzAdd3 / zzAdd
  79. carry = zzAdd(c, a, b, n);
  80. if (zzAdd3(c1, a, n, b, n) != carry ||
  81. !wwEq(c1, c, n))
  82. return FALSE;
  83. b[n - 1] = 0;
  84. carry = zzAdd(c, a, b, n);
  85. if (zzAdd3(c1, a, n, b, n - 1) != carry ||
  86. !wwEq(c1, c, n) ||
  87. zzAdd3(c1, b, n - 1, a, n) != carry ||
  88. !wwEq(c1, c, n))
  89. return FALSE;
  90. // zzNeg / zzAdd
  91. zzNeg(b, a, n);
  92. if (zzAdd(c, a, b, n) != 1 ||
  93. !wwIsZero(c, n))
  94. return FALSE;
  95. }
  96. // все нормально
  97. return TRUE;
  98. }
  99. static bool_t zzTestMul()
  100. {
  101. enum { n = 8 };
  102. size_t reps = 500;
  103. word a[n];
  104. word b[n];
  105. word r[n];
  106. word c[2 * n];
  107. word c1[2 * n];
  108. word b1[n + 1];
  109. word r1[n];
  110. octet combo_state[32];
  111. octet stack[2048];
  112. // подготовить память
  113. if (sizeof(combo_state) < prngCOMBO_keep() ||
  114. sizeof(stack) < utilMax(4,
  115. zzMul_deep(n, n),
  116. zzSqr_deep(n),
  117. zzDiv_deep(2 * n, n),
  118. zzMod_deep(2 * n, n)))
  119. return FALSE;
  120. // инициализировать генератор COMBO
  121. prngCOMBOStart(combo_state, utilNonce32());
  122. // умножение / деление
  123. while (reps--)
  124. {
  125. size_t na, nb;
  126. word w;
  127. prngCOMBOStepR(a, O_OF_W(n), combo_state);
  128. prngCOMBOStepR(b, O_OF_W(n), combo_state);
  129. // zzSqr / zzMul
  130. for (na = 1; na <= n; ++na)
  131. {
  132. zzSqr(c, a, na, stack);
  133. zzMul(c1, a, na, a, na, stack);
  134. if (!wwEq(c, c1, na + na))
  135. return FALSE;
  136. }
  137. // zzMul / zzDiv / zzMod
  138. for (na = 1; na <= n; ++na)
  139. {
  140. a[na - 1] = a[na - 1] ? a[na - 1] : WORD_1;
  141. zzRandMod(r, a, na, prngCOMBOStepR, combo_state);
  142. for (nb = 1; nb <= n; ++nb)
  143. {
  144. zzMul(c, a, na, b, nb, stack);
  145. zzAddW2(c + na, nb, zzAdd2(c, r, na));
  146. zzMod(r1, c, na + nb, a, na, stack);
  147. if (!wwEq(r, r1, na))
  148. return FALSE;
  149. zzDiv(b1, r1, c, na + nb, a, na, stack);
  150. if (!wwEq(r, r1, na) || !wwEq(b, b1, nb) || b1[nb] != 0)
  151. return FALSE;
  152. }
  153. }
  154. // zzAddMulW / zzSubMulW
  155. for (na = 1; na <= n; ++na)
  156. {
  157. word carry, carry1;
  158. w = r[na - 1];
  159. wwCopy(c, a, na);
  160. carry = zzAddMulW(c, b, na, w);
  161. carry1 = zzSubMulW(c, b, na, w);
  162. if (carry != carry1 || !wwEq(c, a, na))
  163. return FALSE;
  164. }
  165. // zzMulW / zzDivW / zzModW / zzModW2
  166. for (na = 1; na <= n; ++na)
  167. {
  168. w = r[na - 1];
  169. w = w ? w : 1;
  170. c[na] = zzMulW(c, a, na, w);
  171. zzDivW(c1, c, na + 1, w);
  172. if (!wwEq(c1, a, na) || c1[na] != 0)
  173. return FALSE;
  174. r[0] %= w;
  175. c[na + 1] = zzAddW(c, c, na + 1, r[0]);
  176. if (zzModW(c, na + 2, w) != r[0])
  177. return FALSE;
  178. w &= WORD_BIT_HALF - WORD_1;
  179. w = w ? w : WORD_BIT_HALF;
  180. r[1] %= w;
  181. c[na] = zzMulW(c, a, na, w);
  182. c[na + 1] = zzAddW(c, c, na + 1, r[1]);
  183. if (zzModW2(c, na + 2, w) != r[1])
  184. return FALSE;
  185. }
  186. }
  187. // особенные случаи zzDiv()
  188. {
  189. ASSERT(n > 3);
  190. // переполнение частного, уточнение пробного частного
  191. b1[0] = b1[1] = WORD_MAX;
  192. b[0] = WORD_MAX, b[1] = WORD_BIT_HI;
  193. zzMul(a, b, 2, b1, 2, stack);
  194. zzDiv(c1, r, a, 4, b, 2, stack);
  195. if (!wwIsZero(r, 2) || !wwEq(c1, b1, 2) || c1[2] != 0)
  196. return FALSE;
  197. // корректирующее сложение
  198. b1[0] = b1[1] = b1[2] = WORD_MAX;
  199. b[0] = WORD_MAX, b[1] = 0, b[2] = WORD_BIT_HI;
  200. zzMul(a, b, 3, b1, 3, stack);
  201. zzDiv(c1, r, a, 6, b, 3, stack);
  202. if (!wwIsZero(r, 2) || !wwEq(c1, b1, 3) || c1[3] != 0)
  203. return FALSE;
  204. }
  205. // все нормально
  206. return TRUE;
  207. }
  208. static bool_t zzTestMod()
  209. {
  210. enum { n = 8 };
  211. size_t reps = 500;
  212. word a[n];
  213. word b[n];
  214. word t[n];
  215. word t1[n];
  216. word mod[n];
  217. octet combo_state[32];
  218. octet stack[2048];
  219. // подготовить память
  220. if (sizeof(combo_state) < prngCOMBO_keep() ||
  221. sizeof(stack) < utilMax(10,
  222. zzPowerMod_deep(n, 1),
  223. zzMulMod_deep(n),
  224. zzSqrMod_deep(n),
  225. zzMod_deep(n, n),
  226. zzJacobi_deep(n, n),
  227. zzGCD_deep(n, n),
  228. zzIsCoprime_deep(n, n),
  229. zzDivMod_deep(n),
  230. zzInvMod_deep(n),
  231. zzAlmostInvMod_deep(n)))
  232. return FALSE;
  233. // инициализировать генератор COMBO
  234. prngCOMBOStart(combo_state, utilNonce32());
  235. // возведение в степень
  236. wwRepW(mod, n, WORD_MAX);
  237. if (!zzIsOdd(mod, n) || zzIsEven(mod, n))
  238. return FALSE;
  239. if (!zzRandMod(a, mod, n, prngCOMBOStepR, combo_state))
  240. return FALSE;
  241. b[0] = 3;
  242. zzPowerMod(t, a, n, b, 1, mod, stack);
  243. zzSqrMod(t1, a, mod, n, stack);
  244. zzMulMod(t1, t1, a, mod, n, stack);
  245. if (wwCmp(t, t1, n) != 0)
  246. return FALSE;
  247. // сложение / вычитание
  248. while (reps--)
  249. {
  250. size_t k;
  251. // генерация
  252. prngCOMBOStepR(mod, O_OF_W(n), combo_state);
  253. prngCOMBOStepR(a, O_OF_W(n), combo_state);
  254. prngCOMBOStepR(b, O_OF_W(n), combo_state);
  255. if (mod[n - 1] == 0)
  256. mod[n - 1] = WORD_MAX;
  257. zzMod(a, a, n, mod, n, stack);
  258. zzMod(b, b, n, mod, n, stack);
  259. // SAFE(zzAddMod) / SAFE(zzSubMod)
  260. SAFE(zzAddMod)(t, a, b, mod, n);
  261. SAFE(zzSubMod)(t1, t, b, mod, n);
  262. if (!SAFE(wwEq)(t1, a, n))
  263. return FALSE;
  264. SAFE(zzSubMod)(t1, t, a, mod, n);
  265. if (!SAFE(wwEq)(t1, b, n))
  266. return FALSE;
  267. // FAST(zzAddMod) / FAST(zzSubMod)
  268. FAST(zzAddMod)(t, a, b, mod, n);
  269. FAST(zzSubMod)(t1, t, b, mod, n);
  270. if (!FAST(wwEq)(t1, a, n))
  271. return FALSE;
  272. FAST(zzSubMod)(t1, t, a, mod, n);
  273. if (!FAST(wwEq)(t1, b, n))
  274. return FALSE;
  275. // SAFE(zzAddWMod) / SAFE(zzSubWMod)
  276. SAFE(zzAddWMod)(t, a, b[0], mod, n);
  277. SAFE(zzSubWMod)(t1, t, b[0], mod, n);
  278. if (!SAFE(wwEq)(t1, a, n))
  279. return FALSE;
  280. // FAST(zzAddWMod) / FAST(zzSubWMod)
  281. FAST(zzAddWMod)(t, a, b[0], mod, n);
  282. FAST(zzSubWMod)(t1, t, b[0], mod, n);
  283. if (!FAST(wwEq)(t1, a, n))
  284. return FALSE;
  285. // SAFE(zzNegMod)
  286. SAFE(zzNegMod)(t, a, mod, n);
  287. SAFE(zzAddMod)(t1, t, a, mod, n);
  288. if (!SAFE(wwIsZero)(t1, n))
  289. return FALSE;
  290. SAFE(zzNegMod)(t1, t1, mod, n);
  291. if (!SAFE(wwIsZero)(t1, n))
  292. return FALSE;
  293. // FAST(zzNegMod)
  294. FAST(zzNegMod)(t, a, mod, n);
  295. FAST(zzAddMod)(t1, t, a, mod, n);
  296. if (!FAST(wwIsZero)(t1, n))
  297. return FALSE;
  298. FAST(zzNegMod)(t1, t1, mod, n);
  299. if (!FAST(wwIsZero)(t1, n))
  300. return FALSE;
  301. // SAFE(zzDoubleMod) / SAFE(zzHalfMod)
  302. mod[0] |= 1;
  303. SAFE(zzHalfMod)(t, a, mod, n);
  304. SAFE(zzDoubleMod)(t1, t, mod, n);
  305. if (!SAFE(wwEq)(t1, a, n))
  306. return FALSE;
  307. // FAST(zzDoubleMod) / FAST(zzHalfMod)
  308. FAST(zzHalfMod)(t, a, mod, n);
  309. FAST(zzDoubleMod)(t1, t, mod, n);
  310. if (!FAST(wwEq)(t1, a, n))
  311. return FALSE;
  312. // zzMulMod / zzSqrMod
  313. zzMulMod(t, a, a, mod, n, stack);
  314. zzSqrMod(t1, a, mod, n, stack);
  315. if (!wwEq(t, t1, n))
  316. return FALSE;
  317. if (zzJacobi(t1, n, mod, n, stack) == -1)
  318. return FALSE;
  319. // zzMulMod / zzDivMod / zzInvMod
  320. zzGCD(t, a, n, mod, n, stack);
  321. if (wwCmpW(t, n, 1) != 0)
  322. continue;
  323. if (!zzIsCoprime(a, n, mod, n, stack))
  324. return FALSE;
  325. zzInvMod(t, a, mod, n, stack);
  326. zzMulMod(t, t, b, mod, n, stack);
  327. zzDivMod(t1, b, a, mod, n, stack);
  328. if (!wwEq(t, t1, n))
  329. return FALSE;
  330. zzMulMod(t1, t1, a, mod, n, stack);
  331. if (!wwEq(t1, b, n))
  332. return FALSE;
  333. // zzMulWMod / zzMulMod
  334. wwSetZero(b + 1, n - 1);
  335. zzMulWMod(t, a, b[0], mod, n, stack);
  336. zzMulMod(t1, a, b, mod, n, stack);
  337. if (!wwEq(t, t1, n))
  338. return FALSE;
  339. // zzAlmostInvMod
  340. k = zzAlmostInvMod(t, a, mod, n, stack);
  341. while (k--)
  342. zzHalfMod(t, t, mod, n);
  343. zzInvMod(t1, a, mod, n, stack);
  344. if (!wwEq(t, t1, n))
  345. return FALSE;
  346. }
  347. // все нормально
  348. return TRUE;
  349. }
  350. static bool_t zzTestGCD()
  351. {
  352. enum { n = 8 };
  353. size_t reps = 100;
  354. word a[n];
  355. word b[n];
  356. word t[n];
  357. word t1[2 * n];
  358. word p[2 * n];
  359. word p1[3 * n];
  360. octet combo_state[32];
  361. octet stack[2048];
  362. // подготовить память
  363. if (sizeof(combo_state) < prngCOMBO_keep() ||
  364. sizeof(stack) < utilMax(4,
  365. zzMul_deep(n, n),
  366. zzGCD_deep(n, n),
  367. zzLCM_deep(n, n),
  368. zzExGCD_deep(n, n)))
  369. return FALSE;
  370. // инициализировать генератор COMBO
  371. prngCOMBOStart(combo_state, utilNonce32());
  372. // эксперименты
  373. while (reps--)
  374. {
  375. size_t na, nb;
  376. // генерация
  377. prngCOMBOStepR(a, O_OF_W(n), combo_state);
  378. prngCOMBOStepR(b, O_OF_W(n), combo_state);
  379. a[0] = a[0] ? a[0] : 1;
  380. b[0] = b[0] ? b[0] : 2;
  381. // цикл по длинами
  382. for (na = 1; na < n; ++na)
  383. for (nb = 1; nb < n; ++nb)
  384. {
  385. // zzGCD / zzLCM / zzMul
  386. zzGCD(t, a, na, b, nb, stack);
  387. zzLCM(t1, a, na, b, nb, stack);
  388. zzMul(p, a, na, b, nb, stack);
  389. zzMul(p1, t, MIN2(na, nb), t1, na + nb, stack);
  390. if (wwCmp2(p, na + nb, p1, na + nb + MIN2(na, nb)) != 0)
  391. return FALSE;
  392. // zzExGCD / zzMul
  393. zzExGCD(t, t1, t1 + n, a, na, b, nb, stack);
  394. zzMul(p, t1, nb, a, na, stack);
  395. zzMul(p1, t1 + n, na, b, nb, stack);
  396. zzSub2(p, p1, na + nb);
  397. if (wwCmp2(p, na + nb, t, MIN2(na, nb)) != 0)
  398. return FALSE;
  399. }
  400. }
  401. return TRUE;
  402. }
  403. static bool_t zzTestRed()
  404. {
  405. enum { n = 8 };
  406. size_t reps = 500;
  407. word a[2 * n];
  408. word t[2 * n];
  409. word t1[2 * n];
  410. word barr_param[n + 2];
  411. word mod[n];
  412. octet combo_state[32];
  413. octet stack[2048];
  414. // подготовить память
  415. if (sizeof(combo_state) < prngCOMBO_keep() ||
  416. sizeof(stack) < utilMax(6,
  417. zzRed_deep(n),
  418. zzRedCrand_deep(n),
  419. zzRedBarrStart_deep(n),
  420. zzRedBarr_deep(n),
  421. zzRedMont_deep(n),
  422. zzRedCrandMont_deep(n)))
  423. return FALSE;
  424. // инициализировать генератор COMBO
  425. prngCOMBOStart(combo_state, utilNonce32());
  426. // редукция
  427. while (reps--)
  428. {
  429. // генерация
  430. prngCOMBOStepR(mod, O_OF_W(n), combo_state);
  431. prngCOMBOStepR(a, O_OF_W(2 * n), combo_state);
  432. mod[n - 1] = mod[n - 1] ? mod[n - 1] : 1;
  433. // zzRed / zzRedBarr
  434. wwCopy(t, a, 2 * n);
  435. zzRed(t, mod, n, stack);
  436. zzRedBarrStart(barr_param, mod, n, stack);
  437. wwCopy(t1, a, 2 * n);
  438. zzRedBarr(t1, mod, n, barr_param, stack);
  439. if (!wwEq(t1, t, n))
  440. return FALSE;
  441. // zzRed / FAST(zzRedBarr)
  442. wwCopy(t1, a, 2 * n);
  443. FAST(zzRedBarr)(t1, mod, n, barr_param, stack);
  444. if (!wwEq(t1, t, n))
  445. return FALSE;
  446. // zzRed / SAFE(zzRedMont)
  447. mod[0] |= 1;
  448. wwCopy(t, a, 2 * n);
  449. zzRed(t, mod, n, stack);
  450. wwCopy(t1, a, 2 * n);
  451. SAFE(zzRedMont)(t1, mod, n, wordNegInv(mod[0]), stack);
  452. wwCopy(t1 + n, t1, n);
  453. wwSetZero(t1, n);
  454. zzRed(t1, mod, n, stack);
  455. if (!wwEq(t1, t, n))
  456. return FALSE;
  457. // zzRed / FAST(zzRedMont)
  458. wwCopy(t1, a, 2 * n);
  459. FAST(zzRedMont)(t1, mod, n, wordNegInv(mod[0]), stack);
  460. wwCopy(t1 + n, t1, n);
  461. wwSetZero(t1, n);
  462. zzRed(t1, mod, n, stack);
  463. if (!wwEq(t1, t, n))
  464. return FALSE;
  465. // zzRed / SAFE(zzRedCrand)
  466. wwRepW(mod + 1, n - 1, WORD_MAX);
  467. wwCopy(t, a, 2 * n);
  468. zzRed(t, mod, n, stack);
  469. wwCopy(t1, a, 2 * n);
  470. SAFE(zzRedCrand)(t1, mod, n, stack);
  471. if (!wwEq(t1, t, n))
  472. return FALSE;
  473. // zzRed / FAST(zzRedCrand)
  474. wwCopy(t1, a, 2 * n);
  475. FAST(zzRedCrand)(t1, mod, n, stack);
  476. if (!wwEq(t1, t, n))
  477. return FALSE;
  478. // SAFE(zzRedMont) / SAFE(zzRedCrandMont)
  479. wwCopy(t, a, 2 * n);
  480. wwCopy(t1, a, 2 * n);
  481. SAFE(zzRedMont)(t, mod, n, wordNegInv(mod[0]), stack);
  482. SAFE(zzRedCrandMont)(t1, mod, n, wordNegInv(mod[0]), stack);
  483. if (!SAFE(wwEq)(t1, t, n))
  484. return FALSE;
  485. // FAST(zzRedMont) / FAST(zzRedCrandMont)
  486. wwCopy(t, a, 2 * n);
  487. wwCopy(t1, a, 2 * n);
  488. FAST(zzRedMont)(t, mod, n, wordNegInv(mod[0]), stack);
  489. FAST(zzRedCrandMont)(t1, mod, n, wordNegInv(mod[0]), stack);
  490. if (!FAST(wwEq)(t1, t, n))
  491. return FALSE;
  492. }
  493. return TRUE;
  494. }
  495. static bool_t zzTestEtc()
  496. {
  497. enum { n = 8 };
  498. size_t reps1 = 500;
  499. size_t reps2 = 500;
  500. word a[n];
  501. word b[2 * n];
  502. word t[(2 * n + 1) / 2];
  503. octet combo_state[32];
  504. octet stack[2048];
  505. // подготовить память
  506. if (sizeof(combo_state) < prngCOMBO_keep() ||
  507. sizeof(stack) < utilMax(3,
  508. zzSqr_deep(n),
  509. zzSqrt_deep(n),
  510. zzJacobi_deep(2 * n, n)))
  511. return FALSE;
  512. // инициализировать генератор COMBO
  513. prngCOMBOStart(combo_state, utilNonce32());
  514. // символ Якоби
  515. while (reps1--)
  516. {
  517. prngCOMBOStepR(a, O_OF_W(n), combo_state);
  518. zzSqr(b, a, n, stack);
  519. prngCOMBOStepR(t, O_OF_W(n), combo_state);
  520. t[0] |= 1;
  521. // (a^2 / t) != -1?
  522. if (zzJacobi(b, 2 * n, t, n, stack) == -1)
  523. return FALSE;
  524. }
  525. // квадратные корни
  526. while (reps2--)
  527. {
  528. prngCOMBOStepR(a, O_OF_W(n), combo_state);
  529. // sqrt(a^2) == a?
  530. zzSqr(b, a, n, stack);
  531. zzSqrt(t, b, 2 * n, stack);
  532. if (!wwEq(a, t, n))
  533. return FALSE;
  534. // sqrt(a^2 + 1) == a?
  535. zzAddW2(b, 2 * n, 1);
  536. zzSqrt(t, b, 2 * n, stack);
  537. if (!wwEq(a, t, n))
  538. return FALSE;
  539. // sqrt(a^2 - 1) + 1 == a?
  540. if (wwIsZero(a, n))
  541. continue;
  542. zzSubW2(b, 2 * n, 2);
  543. zzSqrt(t, b, 2 * n, stack);
  544. if (wwEq(a, t, n))
  545. return FALSE;
  546. if (!zzIsSumWEq(a, t, n, 1))
  547. return FALSE;
  548. }
  549. return TRUE;
  550. }
  551. bool_t zzTest()
  552. {
  553. return zzTestAdd() &&
  554. zzTestMul() &&
  555. zzTestMod() &&
  556. zzTestGCD() &&
  557. zzTestRed() &&
  558. zzTestEtc();
  559. }