zz_test.c 15 KB

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