pp_test.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. /*
  2. *******************************************************************************
  3. \file pp_test.c
  4. \brief Tests for the arithmetic of binary polynomials
  5. \project bee2/test
  6. \created 2023.11.09
  7. \version 2023.11.10
  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/math/pp.h>
  16. #include <bee2/core/u16.h>
  17. #include <bee2/math/ww.h>
  18. /*
  19. *******************************************************************************
  20. Экспоненциальные S-блоки размерности 16
  21. \remark https://eprint.iacr.org/2004/024.
  22. \pre Многочлен x^16 + poly(x) неприводим. Здесь для 16-битового слова p
  23. c битами p_0 (младший), p_1, ..., p_15 (старший) через p(x) обозначается
  24. многочлен
  25. p_15 x^15 + ... + p_1 x + p_0.
  26. \pre Многочлен alpha(x) является примитивным элементом поля
  27. GF(2^16) = GF(2)[x] / (x^16 + poly(x)).
  28. *******************************************************************************
  29. */
  30. static u16 exps16Mul(u16 a, u16 b, u16 poly)
  31. {
  32. size_t i;
  33. u16 c;
  34. for (c = 0, i = 0; i < 16; ++i)
  35. {
  36. c ^= (a & 1) ? b : 0;
  37. a >>= 1;
  38. b = (b << 1) ^ ((b & 0x8000) ? poly : 0);
  39. }
  40. return c;
  41. }
  42. static void exps16Create(u16 s[65536], u16 poly, u16 alpha)
  43. {
  44. size_t pos;
  45. ASSERT(memIsValid(s, 65536 * 2));
  46. s[0] = 0, s[1] = alpha;
  47. for (pos = 2; pos < 65536; ++pos)
  48. s[pos] = exps16Mul(s[pos - 1], alpha, poly);
  49. }
  50. /*
  51. *******************************************************************************
  52. Тест на построение экспоненциальных S-блоков
  53. \remark Многочлен x^16 + x^5 + x^3 + x + 1, который ниже задается словом poly,
  54. является лексикографически минимальным неприводимым пентаномом
  55. (см. https://www.hpl.hp.com/techreports/98/HPL-98-135.pdf).
  56. Неприводимых триномов степени 16 (и, вообще, любой степени кратной 8)
  57. не существует [Swan R.G. Factorization of polynomials over finite fields.
  58. Pacific J. Math., 12, pp. 1099-1106, 1962].
  59. *******************************************************************************
  60. */
  61. static bool_t ppTestExps16()
  62. {
  63. enum {n = W_OF_B(17)};
  64. const u16 poly = 0x002B;
  65. const u16 alpha = 0x0003;
  66. word mod[n];
  67. word a[n];
  68. word t[n];
  69. u16 s1[65536];
  70. u16 s2[65536];
  71. octet stack[1024];
  72. size_t pos;
  73. // подготовить память
  74. if (sizeof(stack) < utilMax(2,
  75. ppIsIrred_deep(n),
  76. ppMulMod_deep(n)))
  77. return FALSE;
  78. // построить модуль (неприводимый многочлен)
  79. u16To(mod, 2, &poly);
  80. wwFrom(mod, mod, 2);
  81. wwSetBit(mod, 16, TRUE);
  82. if (!ppIsIrred(mod, n, stack))
  83. return FALSE;
  84. // построить примитивный элемент
  85. u16To(a, 2, &alpha);
  86. wwFrom(a, a, 2);
  87. wwCopy(t, a, n);
  88. // построить S-блок (с проверкой примитивности)
  89. s1[0] = 0;
  90. for (pos = 1; pos < 65536; ++pos)
  91. {
  92. wwTo(s1 + pos, 2, t);
  93. u16From(s1 + pos, s1 + pos, 2);
  94. ppMulMod(t, t, a, mod, n, stack);
  95. // ord a < 65535?
  96. if (wwEq(t, a, n) && pos < 65535)
  97. return FALSE;
  98. }
  99. // построить S-блок вторым способом
  100. exps16Create(s2, poly, alpha);
  101. if (!memEq(s1, s2, sizeof(s1)))
  102. return FALSE;
  103. // все нормально
  104. return TRUE;
  105. }
  106. /*
  107. *******************************************************************************
  108. Тест редукций
  109. В тестах используются неприводимые триномы и пентаномы, которые задают поля
  110. характеристики 2 в стандартных кривых NIST (SP 800-186). Список кривых
  111. и многочленов:
  112. - K/B-233: x^233 + x^74 + 1;
  113. - K/B-283: x^283 + x^12 + x^7 + x^5 + 1;
  114. - K/B-409: x^409 + x^87 + 1
  115. - K/B-571: x^571 + x^10 + x^5 + x^2 + 1
  116. *******************************************************************************
  117. */
  118. static bool_t ppTestRed()
  119. {
  120. enum { n = W_OF_B(571) };
  121. const pp_trinom_st kb233 = { 233, 74 };
  122. const pp_pentanom_st kb283 = { 283, 12, 7, 5 };
  123. const pp_trinom_st kb409 = { 409, 87 };
  124. const pp_pentanom_st kb571 = { 571, 10, 5, 2 };
  125. size_t reps = 500;
  126. word a[2 * n];
  127. word t[2 * n];
  128. word t1[2 * n];
  129. word mod[n];
  130. octet combo_state[32];
  131. octet stack[2048];
  132. // подготовить память
  133. if (sizeof(combo_state) < prngCOMBO_keep() ||
  134. sizeof(stack) < utilMax(1,
  135. ppRed_deep(n)))
  136. return FALSE;
  137. // инициализировать генератор COMBO
  138. prngCOMBOStart(combo_state, utilNonce32());
  139. // редукция
  140. while (reps--)
  141. {
  142. size_t m;
  143. // генерация
  144. prngCOMBOStepR(a, 2 * O_OF_W(n), combo_state);
  145. // ppRed / ppRedTrinomial[kb233]
  146. ASSERT(W_OF_B(233) == W_OF_B(234));
  147. m = W_OF_B(233);
  148. wwCopy(t, a, 2 * m);
  149. wwCopy(t1, a, 2 * m);
  150. wwSetZero(mod, m);
  151. wwSetBit(mod, kb233.m, TRUE);
  152. wwSetBit(mod, kb233.k, TRUE);
  153. wwSetBit(mod, 0, TRUE);
  154. ppRed(t, mod, m, stack);
  155. ppRedTrinomial(t1, &kb233);
  156. if (!wwEq(t, t1, m))
  157. return FALSE;
  158. // ppRed / ppRedPentanomial[kb283]
  159. ASSERT(W_OF_B(283) == W_OF_B(284));
  160. m = W_OF_B(283);
  161. wwCopy(t, a, 2 * m);
  162. wwCopy(t1, a, 2 * m);
  163. wwSetZero(mod, m);
  164. wwSetBit(mod, kb283.m, TRUE);
  165. wwSetBit(mod, kb283.k, TRUE);
  166. wwSetBit(mod, kb283.l, TRUE);
  167. wwSetBit(mod, kb283.l1, TRUE);
  168. wwSetBit(mod, 0, TRUE);
  169. ppRed(t, mod, m, stack);
  170. ppRedPentanomial(t1, &kb283);
  171. if (!wwEq(t, t1, m))
  172. return FALSE;
  173. // ppRed / ppRedTrinomial[kb409]
  174. ASSERT(W_OF_B(409) == W_OF_B(410));
  175. m = W_OF_B(409);
  176. wwCopy(t, a, 2 * m);
  177. wwCopy(t1, a, 2 * m);
  178. wwSetZero(mod, m);
  179. wwSetBit(mod, kb409.m, TRUE);
  180. wwSetBit(mod, kb409.k, TRUE);
  181. wwSetBit(mod, 0, TRUE);
  182. ppRed(t, mod, m, stack);
  183. ppRedTrinomial(t1, &kb409);
  184. if (!wwEq(t, t1, m))
  185. return FALSE;
  186. // ppRed / ppRedPentanomial[kb571]
  187. ASSERT(W_OF_B(571) == W_OF_B(572));
  188. m = W_OF_B(571);
  189. wwCopy(t, a, 2 * m);
  190. wwCopy(t1, a, 2 * m);
  191. wwSetZero(mod, m);
  192. wwSetBit(mod, kb571.m, TRUE);
  193. wwSetBit(mod, kb571.k, TRUE);
  194. wwSetBit(mod, kb571.l, TRUE);
  195. wwSetBit(mod, kb571.l1, TRUE);
  196. wwSetBit(mod, 0, TRUE);
  197. ppRed(t, mod, m, stack);
  198. ppRedPentanomial(t1, &kb571);
  199. if (!wwEq(t, t1, m))
  200. return FALSE;
  201. }
  202. return TRUE;
  203. }
  204. /*
  205. *******************************************************************************
  206. Интеграция тестов
  207. *******************************************************************************
  208. */
  209. bool_t ppTest()
  210. {
  211. return ppTestExps16() &&
  212. ppTestRed();
  213. }