25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

532 lines
17 KiB

  1. #include "gf2x_arith_mod_xPplusOne.h"
  2. #include "rng.h"
  3. #include "sort.h"
  4. #include <string.h> // memcpy(...), memset(...)
  5. void PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_copy(DIGIT dest[], const DIGIT in[]) {
  6. for (size_t i = 0; i < NUM_DIGITS_GF2X_ELEMENT; i++) {
  7. dest[i] = in[i];
  8. }
  9. }
  10. /* returns the coefficient of the x^exponent term as the LSB of a digit */
  11. DIGIT PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_get_coeff(const DIGIT poly[], size_t exponent) {
  12. size_t straightIdx = (NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_b - 1) - exponent;
  13. size_t digitIdx = straightIdx / DIGIT_SIZE_b;
  14. size_t inDigitIdx = straightIdx % DIGIT_SIZE_b;
  15. return (poly[digitIdx] >> (DIGIT_SIZE_b - 1 - inDigitIdx)) & ((DIGIT) 1) ;
  16. }
  17. /* sets the coefficient of the x^exponent term as the LSB of a digit */
  18. void PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_set_coeff(DIGIT poly[], size_t exponent, DIGIT value) {
  19. size_t straightIdx = (NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_b - 1) - exponent;
  20. size_t digitIdx = straightIdx / DIGIT_SIZE_b;
  21. size_t inDigitIdx = straightIdx % DIGIT_SIZE_b;
  22. /* clear given coefficient */
  23. DIGIT mask = ~(((DIGIT) 1) << (DIGIT_SIZE_b - 1 - inDigitIdx));
  24. poly[digitIdx] = poly[digitIdx] & mask;
  25. poly[digitIdx] = poly[digitIdx] | ((value & ((DIGIT) 1)) << (DIGIT_SIZE_b - 1 - inDigitIdx));
  26. }
  27. /* toggles (flips) the coefficient of the x^exponent term as the LSB of a digit */
  28. void PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_toggle_coeff(DIGIT poly[], size_t exponent) {
  29. size_t straightIdx = (NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_b - 1) - exponent;
  30. size_t digitIdx = straightIdx / DIGIT_SIZE_b;
  31. size_t inDigitIdx = straightIdx % DIGIT_SIZE_b;
  32. /* clear given coefficient */
  33. DIGIT mask = (((DIGIT) 1) << (DIGIT_SIZE_b - 1 - inDigitIdx));
  34. poly[digitIdx] = poly[digitIdx] ^ mask;
  35. }
  36. /* population count for an unsigned 64-bit integer
  37. Source: Hacker's delight, p.66 */
  38. static int popcount_uint64t(uint64_t x) {
  39. x -= (x >> 1) & 0x5555555555555555;
  40. x = (x & 0x3333333333333333) + ((x >> 2) & 0x3333333333333333);
  41. x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0f;
  42. return (int)((x * 0x0101010101010101) >> 56);
  43. }
  44. /* population count for a single polynomial */
  45. int PQCLEAN_LEDAKEMLT12_LEAKTIME_population_count(const DIGIT *poly) {
  46. int ret = 0;
  47. for (int i = NUM_DIGITS_GF2X_ELEMENT - 1; i >= 0; i--) {
  48. ret += popcount_uint64t(poly[i]);
  49. }
  50. return ret;
  51. }
  52. void PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_mod_add(DIGIT Res[], const DIGIT A[], const DIGIT B[]) {
  53. PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_add(Res, A, B, NUM_DIGITS_GF2X_ELEMENT);
  54. }
  55. static void gf2x_mod(DIGIT out[], const DIGIT in[]) {
  56. DIGIT aux[NUM_DIGITS_GF2X_ELEMENT + 1];
  57. memcpy(aux, in, (NUM_DIGITS_GF2X_ELEMENT + 1)*DIGIT_SIZE_B);
  58. PQCLEAN_LEDAKEMLT12_LEAKTIME_right_bit_shift_n(NUM_DIGITS_GF2X_ELEMENT + 1, aux,
  59. MSb_POSITION_IN_MSB_DIGIT_OF_MODULUS);
  60. PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_add(out, aux + 1, in + NUM_DIGITS_GF2X_ELEMENT,
  61. NUM_DIGITS_GF2X_ELEMENT);
  62. out[0] &= ((DIGIT)1 << MSb_POSITION_IN_MSB_DIGIT_OF_MODULUS) - 1;
  63. }
  64. static void right_bit_shift(size_t length, DIGIT in[]) {
  65. size_t j;
  66. for (j = length - 1; j > 0; j--) {
  67. in[j] >>= 1;
  68. in[j] |= (in[j - 1] & (DIGIT)0x01) << (DIGIT_SIZE_b - 1);
  69. }
  70. in[j] >>= 1;
  71. }
  72. /* shifts by whole digits */
  73. static void left_DIGIT_shift_n(size_t length, DIGIT in[], size_t amount) {
  74. size_t j;
  75. for (j = 0; (j + amount) < length; j++) {
  76. in[j] = in[j + amount];
  77. }
  78. for (; j < length; j++) {
  79. in[j] = (DIGIT)0;
  80. }
  81. }
  82. /* may shift by an arbitrary amount*/
  83. static void left_bit_shift_wide_n(size_t length, DIGIT in[], size_t amount) {
  84. left_DIGIT_shift_n(length, in, amount / DIGIT_SIZE_b);
  85. PQCLEAN_LEDAKEMLT12_LEAKTIME_left_bit_shift_n(length, in, amount % DIGIT_SIZE_b);
  86. }
  87. /* Hackers delight, reverses a uint64_t */
  88. static DIGIT reverse_digit(DIGIT x) {
  89. uint64_t t;
  90. x = (x << 31) | (x >> 33);
  91. t = (x ^ (x >> 20)) & 0x00000FFF800007FFLL;
  92. x = (t | (t << 20)) ^ x;
  93. t = (x ^ (x >> 8)) & 0x00F8000F80700807LL;
  94. x = (t | (t << 8)) ^ x;
  95. t = (x ^ (x >> 4)) & 0x0808708080807008LL;
  96. x = (t | (t << 4)) ^ x;
  97. t = (x ^ (x >> 2)) & 0x1111111111111111LL;
  98. x = (t | (t << 2)) ^ x;
  99. return x;
  100. }
  101. void PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_transpose_in_place(DIGIT A[]) {
  102. /* it keeps the lsb in the same position and
  103. * inverts the sequence of the remaining bits */
  104. DIGIT mask = (DIGIT)0x1;
  105. DIGIT rev1, rev2, a00;
  106. int slack_bits_amount = NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_b - P;
  107. a00 = A[NUM_DIGITS_GF2X_ELEMENT - 1] & mask;
  108. right_bit_shift(NUM_DIGITS_GF2X_ELEMENT, A);
  109. for (size_t i = NUM_DIGITS_GF2X_ELEMENT - 1; i >= (NUM_DIGITS_GF2X_ELEMENT + 1) / 2; i--) {
  110. rev1 = reverse_digit(A[i]);
  111. rev2 = reverse_digit(A[NUM_DIGITS_GF2X_ELEMENT - 1 - i]);
  112. A[i] = rev2;
  113. A[NUM_DIGITS_GF2X_ELEMENT - 1 - i] = rev1;
  114. }
  115. A[NUM_DIGITS_GF2X_ELEMENT / 2] = reverse_digit(A[NUM_DIGITS_GF2X_ELEMENT / 2]);
  116. if (slack_bits_amount) {
  117. PQCLEAN_LEDAKEMLT12_LEAKTIME_right_bit_shift_n(NUM_DIGITS_GF2X_ELEMENT, A, slack_bits_amount);
  118. }
  119. A[NUM_DIGITS_GF2X_ELEMENT - 1] = (A[NUM_DIGITS_GF2X_ELEMENT - 1] & (~mask)) | a00;
  120. }
  121. static void rotate_bit_right(DIGIT in[]) { /* x^{-1} * in(x) mod x^P+1 */
  122. DIGIT rotated_bit = in[NUM_DIGITS_GF2X_ELEMENT - 1] & ((DIGIT)0x1);
  123. right_bit_shift(NUM_DIGITS_GF2X_ELEMENT, in);
  124. int msb_offset_in_digit = MSb_POSITION_IN_MSB_DIGIT_OF_MODULUS - 1;
  125. rotated_bit = rotated_bit << msb_offset_in_digit;
  126. in[0] |= rotated_bit;
  127. }
  128. /* cond swap: swaps digits A and B if swap_mask == -1 */
  129. static void gf2x_cswap(DIGIT *a, DIGIT *b, int32_t swap_mask) {
  130. DIGIT t;
  131. for (size_t i = 0; i < NUM_DIGITS_GF2X_ELEMENT; i++) {
  132. t = swap_mask & (a[i] ^ b[i]);
  133. a[i] ^= t;
  134. b[i] ^= t;
  135. }
  136. }
  137. /* returns -1 mask if x != 0, otherwise 0 */
  138. static inline int32_t nonzero(DIGIT x) {
  139. DIGIT t = x;
  140. t = (~t) + 1;
  141. t >>= DIGIT_SIZE_b - 1;
  142. return -((int32_t)t);
  143. }
  144. /* returns -1 mask if x < 0 else 0 */
  145. static inline int32_t negative(int x) {
  146. uint32_t u = x;
  147. u >>= 31;
  148. return -((int32_t)u);
  149. }
  150. /* return f(0) as digit */
  151. static inline DIGIT lsb(const DIGIT *p) {
  152. DIGIT mask = (DIGIT)1;
  153. return p[NUM_DIGITS_GF2X_ELEMENT - 1] & mask;
  154. }
  155. /* multiply poly with scalar and accumulate, expects s all-zero of all-one mask */
  156. static void gf2x_mult_scalar_acc(DIGIT *f, const DIGIT *g, const DIGIT s) {
  157. for (size_t i = 0; i < NUM_DIGITS_GF2X_ELEMENT; i++) {
  158. f[i] = f[i] ^ (s & g[i]);
  159. }
  160. }
  161. /* constant-time inverse, source: gcd.cr.yp.to */
  162. int PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_mod_inverse(DIGIT out[], const DIGIT in[]) {
  163. int32_t swap, delta = 1;
  164. DIGIT g0_mask;
  165. DIGIT f[NUM_DIGITS_GF2X_MODULUS] = {0}; // f = x^P + 1
  166. DIGIT g[NUM_DIGITS_GF2X_ELEMENT]; // g = in
  167. DIGIT *v = out; // v = 0, save space
  168. DIGIT r[NUM_DIGITS_GF2X_ELEMENT] = {0}; // r = 1
  169. f[NUM_DIGITS_GF2X_MODULUS - 1] = 1;
  170. f[0] |= ((DIGIT)1 << MSb_POSITION_IN_MSB_DIGIT_OF_MODULUS);
  171. for (size_t i = 0; i < NUM_DIGITS_GF2X_ELEMENT; i++) {
  172. g[i] = in[i];
  173. }
  174. for (size_t i = 0; i < NUM_DIGITS_GF2X_ELEMENT; i++) {
  175. v[i] = 0;
  176. }
  177. r[NUM_DIGITS_GF2X_ELEMENT - 1] = 1;
  178. for (int loop = 0; loop < 2 * P - 1; ++loop) {
  179. swap = negative(-delta) & nonzero(lsb(g)); // swap = -1 if -delta < 0 AND g(0) != 0
  180. delta ^= swap & (delta ^ -delta); // cond swap delta with -delta if swap
  181. delta++;
  182. gf2x_cswap(f, g, swap);
  183. gf2x_cswap(v, r, swap);
  184. g0_mask = ~lsb(g) + 1;
  185. // g = (g - g0 * f) / x
  186. gf2x_mult_scalar_acc(g, f, g0_mask);
  187. right_bit_shift(NUM_DIGITS_GF2X_ELEMENT, g);
  188. // r = (r - g0 * v) / x
  189. gf2x_mult_scalar_acc(r, v, g0_mask);
  190. rotate_bit_right(r);
  191. }
  192. return nonzero(delta); // -1 if fail, 0 if success
  193. }
  194. void PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_mod_mul(DIGIT Res[], const DIGIT A[], const DIGIT B[]) {
  195. DIGIT aux[2 * NUM_DIGITS_GF2X_ELEMENT];
  196. PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_mul(aux, A, B, NUM_DIGITS_GF2X_ELEMENT);
  197. gf2x_mod(Res, aux);
  198. }
  199. /*PRE: the representation of the sparse coefficients is sorted in increasing
  200. order of the coefficients themselves */
  201. void PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_mod_mul_dense_to_sparse(DIGIT Res[], const DIGIT dense[],
  202. POSITION_T sparse[], size_t nPos) {
  203. DIGIT aux[2 * NUM_DIGITS_GF2X_ELEMENT] = {0x00};
  204. DIGIT resDouble[2 * NUM_DIGITS_GF2X_ELEMENT] = {0x00};
  205. memcpy(aux + NUM_DIGITS_GF2X_ELEMENT, dense, NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B);
  206. memcpy(resDouble + NUM_DIGITS_GF2X_ELEMENT, dense, NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B);
  207. if (sparse[0] != INVALID_POS_VALUE) {
  208. left_bit_shift_wide_n(2 * NUM_DIGITS_GF2X_ELEMENT, resDouble, sparse[0]);
  209. left_bit_shift_wide_n(2 * NUM_DIGITS_GF2X_ELEMENT, aux, sparse[0]);
  210. for (size_t i = 1; i < nPos; i++) {
  211. if (sparse[i] != INVALID_POS_VALUE) {
  212. left_bit_shift_wide_n(2 * NUM_DIGITS_GF2X_ELEMENT, aux, (sparse[i] - sparse[i - 1]) );
  213. PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_add(resDouble, aux, resDouble, 2 * NUM_DIGITS_GF2X_ELEMENT);
  214. }
  215. }
  216. }
  217. gf2x_mod(Res, resDouble);
  218. }
  219. void PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_transpose_in_place_sparse(size_t sizeA, POSITION_T A[]) {
  220. POSITION_T t;
  221. size_t i = 0, j;
  222. if (A[i] == 0) {
  223. i = 1;
  224. }
  225. j = i;
  226. for (; i < sizeA && A[i] != INVALID_POS_VALUE; i++) {
  227. A[i] = P - A[i];
  228. }
  229. for (i -= 1; j < i; j++, i--) {
  230. t = A[j];
  231. A[j] = A[i];
  232. A[i] = t;
  233. }
  234. }
  235. void PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_mod_mul_sparse(size_t sizeR, POSITION_T Res[],
  236. size_t sizeA, const POSITION_T A[],
  237. size_t sizeB, const POSITION_T B[]) {
  238. POSITION_T prod;
  239. POSITION_T lastReadPos;
  240. size_t duplicateCount;
  241. size_t write_idx, read_idx;
  242. /* compute all the coefficients, filling invalid positions with P*/
  243. size_t lastFilledPos = 0;
  244. for (size_t i = 0 ; i < sizeA ; i++) {
  245. for (size_t j = 0 ; j < sizeB ; j++) {
  246. prod = A[i] + B[j];
  247. prod = ( (prod >= P) ? prod - P : prod);
  248. if ((A[i] != INVALID_POS_VALUE) &&
  249. (B[j] != INVALID_POS_VALUE)) {
  250. Res[lastFilledPos] = prod;
  251. } else {
  252. Res[lastFilledPos] = INVALID_POS_VALUE;
  253. }
  254. lastFilledPos++;
  255. }
  256. }
  257. while (lastFilledPos < sizeR) {
  258. Res[lastFilledPos] = INVALID_POS_VALUE;
  259. lastFilledPos++;
  260. }
  261. PQCLEAN_LEDAKEMLT12_LEAKTIME_uint32_sort(Res, sizeR);
  262. /* eliminate duplicates */
  263. write_idx = read_idx = 0;
  264. while (read_idx < sizeR && Res[read_idx] != INVALID_POS_VALUE) {
  265. lastReadPos = Res[read_idx];
  266. read_idx++;
  267. duplicateCount = 1;
  268. while ( (Res[read_idx] == lastReadPos) && (Res[read_idx] != INVALID_POS_VALUE)) {
  269. read_idx++;
  270. duplicateCount++;
  271. }
  272. if (duplicateCount % 2) {
  273. Res[write_idx] = lastReadPos;
  274. write_idx++;
  275. }
  276. }
  277. /* fill remaining cells with INVALID_POS_VALUE */
  278. for (; write_idx < sizeR; write_idx++) {
  279. Res[write_idx] = INVALID_POS_VALUE;
  280. }
  281. }
  282. /* the implementation is safe even in case A or B alias with the result
  283. * PRE: A and B should be sorted, disjunct arrays ending with INVALID_POS_VALUE */
  284. void PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_mod_add_sparse(size_t sizeR, POSITION_T Res[],
  285. size_t sizeA, const POSITION_T A[],
  286. size_t sizeB, const POSITION_T B[]) {
  287. POSITION_T tmpRes[DV * M];
  288. size_t idxA = 0, idxB = 0, idxR = 0;
  289. while ( idxA < sizeA &&
  290. idxB < sizeB &&
  291. A[idxA] != INVALID_POS_VALUE &&
  292. B[idxB] != INVALID_POS_VALUE ) {
  293. if (A[idxA] == B[idxB]) {
  294. idxA++;
  295. idxB++;
  296. } else {
  297. if (A[idxA] < B[idxB]) {
  298. tmpRes[idxR] = A[idxA];
  299. idxA++;
  300. } else {
  301. tmpRes[idxR] = B[idxB];
  302. idxB++;
  303. }
  304. idxR++;
  305. }
  306. }
  307. while (idxA < sizeA && A[idxA] != INVALID_POS_VALUE) {
  308. tmpRes[idxR] = A[idxA];
  309. idxA++;
  310. idxR++;
  311. }
  312. while (idxB < sizeB && B[idxB] != INVALID_POS_VALUE) {
  313. tmpRes[idxR] = B[idxB];
  314. idxB++;
  315. idxR++;
  316. }
  317. while (idxR < sizeR) {
  318. tmpRes[idxR] = INVALID_POS_VALUE;
  319. idxR++;
  320. }
  321. memcpy(Res, tmpRes, sizeof(POSITION_T)*sizeR);
  322. }
  323. /* Return a uniform random value in the range 0..n-1 inclusive,
  324. * applying a rejection sampling strategy and exploiting as a random source
  325. * the NIST seedexpander seeded with the proper key.
  326. * Assumes that the maximum value for the range n is 2^32-1
  327. */
  328. static uint32_t rand_range(const unsigned int n, const int logn, AES_XOF_struct *seed_expander_ctx) {
  329. unsigned long required_rnd_bytes = (logn + 7) / 8;
  330. unsigned char rnd_char_buffer[4];
  331. uint32_t rnd_value;
  332. uint32_t mask = ( (uint32_t)1 << logn) - 1;
  333. do {
  334. PQCLEAN_LEDAKEMLT12_LEAKTIME_seedexpander(seed_expander_ctx, rnd_char_buffer, required_rnd_bytes);
  335. /* obtain an endianness independent representation of the generated random
  336. bytes into an unsigned integer */
  337. rnd_value = ((uint32_t)rnd_char_buffer[3] << 24) +
  338. ((uint32_t)rnd_char_buffer[2] << 16) +
  339. ((uint32_t)rnd_char_buffer[1] << 8) +
  340. ((uint32_t)rnd_char_buffer[0] << 0) ;
  341. rnd_value = mask & rnd_value;
  342. } while (rnd_value >= n);
  343. return rnd_value;
  344. }
  345. /* Obtains fresh randomness and seed-expands it until all the required positions
  346. * for the '1's in the circulant block are obtained */
  347. void PQCLEAN_LEDAKEMLT12_LEAKTIME_rand_circulant_sparse_block(POSITION_T *pos_ones,
  348. size_t countOnes,
  349. AES_XOF_struct *seed_expander_ctx) {
  350. size_t duplicated, placedOnes = 0;
  351. POSITION_T p;
  352. while (placedOnes < countOnes) {
  353. p = rand_range(NUM_BITS_GF2X_ELEMENT,
  354. P_BITS,
  355. seed_expander_ctx);
  356. duplicated = 0;
  357. for (size_t j = 0; j < placedOnes; j++) {
  358. if (pos_ones[j] == p) {
  359. duplicated = 1;
  360. }
  361. }
  362. if (duplicated == 0) {
  363. pos_ones[placedOnes] = p;
  364. placedOnes++;
  365. }
  366. }
  367. }
  368. /* Returns random weight-t circulant block */
  369. void PQCLEAN_LEDAKEMLT12_LEAKTIME_rand_circulant_blocks_sequence(DIGIT sequence[N0 * NUM_DIGITS_GF2X_ELEMENT],
  370. AES_XOF_struct *seed_expander_ctx) {
  371. size_t polyIndex, duplicated, counter = 0;
  372. POSITION_T p, exponent, rndPos[NUM_ERRORS_T];
  373. memset(sequence, 0x00, N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B);
  374. while (counter < NUM_ERRORS_T) {
  375. p = rand_range(N0 * NUM_BITS_GF2X_ELEMENT, P_BITS, seed_expander_ctx);
  376. duplicated = 0;
  377. for (size_t j = 0; j < counter; j++) {
  378. if (rndPos[j] == p) {
  379. duplicated = 1;
  380. }
  381. }
  382. if (duplicated == 0) {
  383. rndPos[counter] = p;
  384. counter++;
  385. }
  386. }
  387. for (size_t j = 0; j < counter; j++) {
  388. polyIndex = rndPos[j] / P;
  389. exponent = rndPos[j] % P;
  390. PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_set_coeff( sequence + NUM_DIGITS_GF2X_ELEMENT * polyIndex, exponent,
  391. ( (DIGIT) 1));
  392. }
  393. }
  394. void PQCLEAN_LEDAKEMLT12_LEAKTIME_rand_error_pos(POSITION_T errorPos[NUM_ERRORS_T],
  395. AES_XOF_struct *seed_expander_ctx) {
  396. int duplicated;
  397. size_t counter = 0;
  398. while (counter < NUM_ERRORS_T) {
  399. POSITION_T p = rand_range(N0 * NUM_BITS_GF2X_ELEMENT, P_BITS, seed_expander_ctx);
  400. duplicated = 0;
  401. for (size_t j = 0; j < counter; j++) {
  402. if (errorPos[j] == p) {
  403. duplicated = 1;
  404. }
  405. }
  406. if (duplicated == 0) {
  407. errorPos[counter] = p;
  408. counter++;
  409. }
  410. }
  411. }
  412. void PQCLEAN_LEDAKEMLT12_LEAKTIME_expand_error(DIGIT sequence[N0 * NUM_DIGITS_GF2X_ELEMENT],
  413. const POSITION_T errorPos[NUM_ERRORS_T]) {
  414. size_t polyIndex;
  415. POSITION_T exponent;
  416. memset(sequence, 0x00, N0 * NUM_DIGITS_GF2X_ELEMENT * DIGIT_SIZE_B);
  417. for (int j = 0; j < NUM_ERRORS_T; j++) {
  418. polyIndex = errorPos[j] / P;
  419. exponent = errorPos[j] % P;
  420. PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_set_coeff( sequence + NUM_DIGITS_GF2X_ELEMENT * polyIndex, exponent,
  421. ( (DIGIT) 1));
  422. }
  423. }
  424. void PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_tobytes(uint8_t *bytes, const DIGIT *poly) {
  425. size_t i, j;
  426. for (i = 0; i < NUM_DIGITS_GF2X_ELEMENT; i++) {
  427. for (j = 0; j < DIGIT_SIZE_B; j++) {
  428. bytes[i * DIGIT_SIZE_B + j] = (uint8_t) (poly[i] >> 8 * j);
  429. }
  430. }
  431. }
  432. void PQCLEAN_LEDAKEMLT12_LEAKTIME_gf2x_frombytes(DIGIT *poly, const uint8_t *poly_bytes) {
  433. size_t i, j;
  434. for (i = 0; i < NUM_DIGITS_GF2X_ELEMENT; i++) {
  435. poly[i] = (DIGIT) 0;
  436. for (j = 0; j < DIGIT_SIZE_B; j++) {
  437. poly[i] |= (DIGIT) poly_bytes[i * DIGIT_SIZE_B + j] << 8 * j;
  438. }
  439. }
  440. }