post quantum cryptography
Highly optimized implementation of the NTRUEncrypt algorithm
 All Data Structures Files Functions Variables Typedefs Macros Pages
ntru_poly.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2014 FH Bielefeld
3  *
4  * This file is part of a FH Bielefeld project.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  * MA 02110-1301 USA
20  */
21 
30 #include "ntru_err.h"
31 #include "ntru_mem.h"
32 #include "ntru_params.h"
33 #include "ntru_poly.h"
34 
35 #include <stdarg.h>
36 #include <stdbool.h>
37 #include <stdint.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <sys/types.h>
41 
42 #include <fmpz_poly.h>
43 #include <fmpz.h>
44 
45 
54 static
55 void poly_mod2_to_modq(const fmpz_poly_t a,
56  fmpz_poly_t Fq,
57  const ntru_params *params);
58 
59 
60 /*------------------------------------------------------------------------*/
61 
62 static void
63 poly_mod2_to_modq(const fmpz_poly_t a,
64  fmpz_poly_t Fq,
65  const ntru_params *params)
66 {
67  int v = 2;
68  fmpz_poly_t poly_tmp, two;
69 
70  fmpz_poly_init(poly_tmp);
71  fmpz_poly_zero(poly_tmp);
72  fmpz_poly_init(two);
73  fmpz_poly_set_coeff_ui(two, 0, 2);
74 
75  while (v < (int)(params->q)) {
76  v = v * 2;
77 
78  poly_starmultiply(a, Fq, poly_tmp, params, v);
79  fmpz_poly_sub(poly_tmp, two, poly_tmp);
80  fmpz_poly_mod_unsigned(poly_tmp, v);
81  poly_starmultiply(Fq, poly_tmp, Fq, params, v);
82 
83  }
84 
85  fmpz_poly_clear(poly_tmp);
86  fmpz_poly_clear(two);
87 
88 }
89 
90 /*------------------------------------------------------------------------*/
91 
92 int
93 fmpz_cmp_si_n(const fmpz_t f, slong g)
94 {
95  fmpz_t f_cmp;
96 
97  fmpz_init(f_cmp);
98 
99  if (f)
100  fmpz_set(f_cmp, f);
101  else
102  fmpz_set_si(f_cmp, 0);
103 
104  return fmpz_cmp_si(f_cmp, g);
105 }
106 
107 /*------------------------------------------------------------------------*/
108 
109 void
110 poly_new(fmpz_poly_t new_poly,
111  int const * const c,
112  const size_t len)
113 {
114  fmpz_poly_init(new_poly);
115 
116  for (uint32_t i = 0; i < len; i++)
117  fmpz_poly_set_coeff_si(new_poly, i, c[i]);
118 }
119 
120 /*------------------------------------------------------------------------*/
121 
122 void
123 poly_delete(fmpz_poly_t poly)
124 {
125  fmpz_poly_clear(poly);
126 }
127 
128 /*------------------------------------------------------------------------*/
129 
130 void
131 poly_delete_array(fmpz_poly_t **poly_array)
132 {
133  uint32_t i = 0;
134 
135  while(poly_array[i]) {
136  poly_delete(*(poly_array[i]));
137  free(poly_array[i]);
138  i++;
139  }
140 
141  /* avoid double free */
142  if (i > 1)
143  free(poly_array);
144 }
145 
146 /*------------------------------------------------------------------------*/
147 
148 void
149 poly_delete_all(fmpz_poly_t poly, ...)
150 {
151  fmpz_poly_struct *next_poly;
152  va_list args;
153 
154  next_poly = poly;
155  va_start(args, poly);
156  while (next_poly != NULL) {
157  poly_delete(next_poly);
158  next_poly = va_arg(args, fmpz_poly_struct*);
159  }
160  va_end(args);
161 }
162 
163 /*------------------------------------------------------------------------*/
164 
165 void
167  const uint32_t mod)
168 {
169  nmod_poly_t nmod_tmp;
170 
171  nmod_poly_init(nmod_tmp, mod);
172 
173  fmpz_poly_get_nmod_poly(nmod_tmp, a);
174  fmpz_poly_set_nmod_poly_unsigned(a, nmod_tmp);
175 
176  nmod_poly_clear(nmod_tmp);
177 }
178 
179 /*------------------------------------------------------------------------*/
180 
181 void
182 fmpz_poly_mod(fmpz_poly_t a,
183  const uint32_t mod)
184 {
185  nmod_poly_t nmod_tmp;
186 
187  nmod_poly_init(nmod_tmp, mod);
188 
189  fmpz_poly_get_nmod_poly(nmod_tmp, a);
190  fmpz_poly_set_nmod_poly(a, nmod_tmp);
191 
192  nmod_poly_clear(nmod_tmp);
193 }
194 
195 /*------------------------------------------------------------------------*/
196 
197 void
198 fmpz_poly_set_coeff_fmpz_n(fmpz_poly_t poly, slong n,
199  const fmpz_t x)
200 {
201  if (x)
202  fmpz_poly_set_coeff_fmpz(poly, n, x);
203  else
204  fmpz_poly_set_coeff_si(poly, n, 0);
205 }
206 
207 /*------------------------------------------------------------------------*/
208 
209 int
210 fmpz_invmod_ui(fmpz_t f, const fmpz_t g, const uint32_t mod)
211 {
212  fmpz_t modulus;
213 
214  fmpz_init_set_ui(modulus, mod);
215 
216  return fmpz_invmod(f, g, modulus);
217 }
218 
219 /*------------------------------------------------------------------------*/
220 
221 void
222 fmpz_add_n(fmpz_t f, const fmpz_t g, const fmpz_t h)
223 {
224  if (!g && !h) {
225  fmpz_zero(f);
226  } else {
227  if (!g && h)
228  fmpz_add_ui(f, h, 0);
229  else if (g && !h)
230  fmpz_add_ui(f, g, 0);
231  else
232  fmpz_add(f, g, h);
233  }
234 }
235 
236 /*------------------------------------------------------------------------*/
237 
238 void
239 poly_starmultiply(const fmpz_poly_t a,
240  const fmpz_poly_t b,
241  fmpz_poly_t c,
242  const ntru_params *params,
243  uint32_t modulus)
244 {
245  fmpz_poly_t a_tmp;
246  fmpz_t c_coeff_k;
247 
248  fmpz_poly_init(a_tmp);
249  fmpz_init(c_coeff_k);
250 
251  /* avoid side effects */
252  fmpz_poly_set(a_tmp, a);
253  fmpz_poly_zero(c);
254 
255  for (int k = params->N - 1; k >= 0; k--) {
256  int j;
257 
258  j = k + 1;
259 
260  fmpz_set_si(c_coeff_k, 0);
261 
262  for (int i = params->N - 1; i >= 0; i--) {
263  fmpz *a_tmp_coeff_i,
264  *b_coeff_j;
265 
266  if (j == (int)(params->N))
267  j = 0;
268 
269  a_tmp_coeff_i = fmpz_poly_get_coeff_ptr(a_tmp, i);
270  b_coeff_j = fmpz_poly_get_coeff_ptr(b, j);
271 
272  if (fmpz_cmp_si_n(a_tmp_coeff_i, 0) &&
273  fmpz_cmp_si_n(b_coeff_j, 0)) {
274  fmpz_t fmpz_tmp;
275 
276  fmpz_init(fmpz_tmp);
277 
278  fmpz_mul(fmpz_tmp, a_tmp_coeff_i, b_coeff_j);
279  fmpz_add(fmpz_tmp, fmpz_tmp, c_coeff_k);
280  fmpz_mod_ui(c_coeff_k, fmpz_tmp, modulus);
281 
282  fmpz_poly_set_coeff_fmpz(c, k, c_coeff_k);
283 
284  fmpz_clear(fmpz_tmp);
285  }
286  j++;
287  }
288  fmpz_clear(c_coeff_k);
289  }
290 
291  fmpz_poly_clear(a_tmp);
292 }
293 
294 /*------------------------------------------------------------------------*/
295 
296 bool
297 poly_inverse_poly_q(const fmpz_poly_t a,
298  fmpz_poly_t Fq,
299  const ntru_params *params)
300 {
301  bool retval = false;
302  int k = 0,
303  j = 0;
304  fmpz *b_last;
305  fmpz_poly_t a_tmp,
306  b,
307  c,
308  f,
309  g;
310 
311  /* general initialization of temp variables */
312  fmpz_poly_init(b);
313  fmpz_poly_set_coeff_ui(b, 0, 1);
314  fmpz_poly_init(c);
315  fmpz_poly_init(f);
316  fmpz_poly_set(f, a);
317 
318  /* set g(x) = x^N − 1 */
319  fmpz_poly_init(g);
320  fmpz_poly_set_coeff_si(g, 0, -1);
321  fmpz_poly_set_coeff_si(g, params->N, 1);
322 
323  /* avoid side effects */
324  fmpz_poly_init(a_tmp);
325  fmpz_poly_set(a_tmp, a);
326  fmpz_poly_zero(Fq);
327 
328  while (1) {
329  while (fmpz_is_zero(fmpz_poly_get_coeff_ptr(f, 0))) {
330  for (uint32_t i = 1; i <= params->N; i++) {
331  fmpz *f_coeff = fmpz_poly_get_coeff_ptr(f, i);
332  fmpz *c_coeff = fmpz_poly_get_coeff_ptr(c, params->N - i);
333 
334  /* f(x) = f(x) / x */
336  f_coeff);
337 
338  /* c(x) = c(x) * x */
339  fmpz_poly_set_coeff_fmpz_n(c, params->N + 1 - i,
340  c_coeff);
341  }
342 
343  fmpz_poly_set_coeff_si(f, params->N, 0);
344  fmpz_poly_set_coeff_si(c, 0, 0);
345 
346  k++;
347 
348  if (fmpz_poly_degree(f) == -1)
349  goto _cleanup;
350  }
351 
352  if (fmpz_poly_degree(f) == 0)
353  break;
354 
355  if (fmpz_poly_degree(f) < fmpz_poly_degree(g)) {
356  fmpz_poly_swap(f, g);
357  fmpz_poly_swap(b, c);
358  }
359 
360  fmpz_poly_add(f, g, f);
362 
363  fmpz_poly_add(b, c, b);
365  }
366 
367  k = k % params->N;
368 
369  b_last = fmpz_poly_get_coeff_ptr(b, params->N);
370  if (fmpz_cmp_si_n(b_last, 0))
371  goto _cleanup;
372 
373  /* Fq(x) = x^(N-k) * b(x) */
374  for (int i = params->N - 1; i >= 0; i--) {
375  fmpz *b_i;
376 
377  j = i - k;
378 
379  if (j < 0)
380  j = j + params->N;
381 
382  b_i = fmpz_poly_get_coeff_ptr(b, i);
383  fmpz_poly_set_coeff_fmpz_n(Fq, j, b_i);
384  }
385 
386  poly_mod2_to_modq(a_tmp, Fq, params);
387 
388  /* check if the f * Fq = 1 (mod p) condition holds true */
389  fmpz_poly_set(a_tmp, a);
390  poly_starmultiply(a_tmp, Fq, a_tmp, params, params->q);
391  if (fmpz_poly_is_one(a_tmp))
392  retval = true;
393  else
394  fmpz_poly_zero(Fq);
395 
396 _cleanup:
397  fmpz_poly_clear(a_tmp);
398  fmpz_poly_clear(b);
399  fmpz_poly_clear(c);
400  fmpz_poly_clear(f);
401  fmpz_poly_clear(g);
402 
403  return retval;
404 }
405 
406 /*------------------------------------------------------------------------*/
407 
408 bool
409 poly_inverse_poly_p(const fmpz_poly_t a,
410  fmpz_poly_t Fp,
411  const ntru_params *params)
412 {
413  bool retval = false;
414  int k = 0,
415  j = 0;
416  fmpz *b_last;
417  fmpz_poly_t a_tmp,
418  b,
419  c,
420  f,
421  g;
422 
423  /* general initialization of temp variables */
424  fmpz_poly_init(b);
425  fmpz_poly_set_coeff_ui(b, 0, 1);
426  fmpz_poly_init(c);
427  fmpz_poly_init(f);
428  fmpz_poly_set(f, a);
429 
430  /* set g(x) = x^N − 1 */
431  fmpz_poly_init(g);
432  fmpz_poly_set_coeff_si(g, 0, -1);
433  fmpz_poly_set_coeff_si(g, params->N, 1);
434 
435  /* avoid side effects */
436  fmpz_poly_init(a_tmp);
437  fmpz_poly_set(a_tmp, a);
438  fmpz_poly_zero(Fp);
439 
440  while (1) {
441  while (fmpz_is_zero(fmpz_poly_get_coeff_ptr(f, 0))) {
442  for (uint32_t i = 1; i <= params->N; i++) {
443  fmpz *f_coeff = fmpz_poly_get_coeff_ptr(f, i);
444  fmpz *c_coeff = fmpz_poly_get_coeff_ptr(c, params->N - i);
445 
446  /* f(x) = f(x) / x */
448  f_coeff);
449 
450  /* c(x) = c(x) * x */
451  fmpz_poly_set_coeff_fmpz_n(c, params->N + 1 - i,
452  c_coeff);
453  }
454 
455  fmpz_poly_set_coeff_si(f, params->N, 0);
456  fmpz_poly_set_coeff_si(c, 0, 0);
457 
458  k++;
459 
460  if (fmpz_poly_degree(f) == -1)
461  goto cleanup;
462  }
463 
464  if (fmpz_poly_degree(f) == 0)
465  break;
466 
467  if (fmpz_poly_degree(f) < fmpz_poly_degree(g)) {
468  /* exchange f and g and exchange b and c */
469  fmpz_poly_swap(f, g);
470  fmpz_poly_swap(b, c);
471  }
472 
473  {
474  fmpz_poly_t c_tmp,
475  g_tmp;
476  fmpz_t u,
477  mp_tmp;
478 
479  fmpz_init(u);
480  fmpz_zero(u);
481 
482  fmpz_init_set(mp_tmp, fmpz_poly_get_coeff_ptr(f, 0));
483 
484  fmpz_poly_init(g_tmp);
485  fmpz_poly_set(g_tmp, g);
486 
487  fmpz_poly_init(c_tmp);
488  fmpz_poly_set(c_tmp, c);
489 
490  /* u = f[0] * g[0]^(-1) mod p */
491  /* = (f[0] mod p) * (g[0] inverse mod p) mod p */
492  fmpz_invmod_ui(u,
493  fmpz_poly_get_coeff_ptr(g, 0),
494  params->p);
495  fmpz_mod_ui(mp_tmp, mp_tmp, params->p);
496  fmpz_mul(u, mp_tmp, u);
497  fmpz_mod_ui(u, u, params->p);
498 
499  /* f = f - u * g mod p */
500  fmpz_poly_scalar_mul_fmpz(g_tmp, g_tmp, u);
501  fmpz_poly_sub(f, g_tmp, f);
502  fmpz_poly_mod_unsigned(f, params->p);
503 
504  /* b = b - u * c mod p */
505  fmpz_poly_scalar_mul_fmpz(c_tmp, c_tmp, u);
506  fmpz_poly_sub(b, c_tmp, b);
507  fmpz_poly_mod_unsigned(b, params->p);
508 
509  fmpz_clear(u);
510  fmpz_poly_clear(g_tmp);
511  fmpz_poly_clear(c_tmp);
512  }
513  }
514 
515  k = k % params->N;
516 
517  b_last = fmpz_poly_get_coeff_ptr(b, params->N);
518  if (fmpz_cmp_si_n(b_last, 0))
519  goto cleanup;
520 
521  /* Fp(x) = x^(N-k) * b(x) */
522  for (int i = params->N - 1; i >= 0; i--) {
523  fmpz *b_i;
524 
525  /* b(X) = f[0]^(-1) * b(X) (mod p) */
526  {
527  fmpz_t mp_tmp;
528 
529  fmpz_init(mp_tmp);
530 
531  fmpz_invmod_ui(mp_tmp,
532  fmpz_poly_get_coeff_ptr(f, 0),
533  params->p);
534 
535  if (fmpz_poly_get_coeff_ptr(b, i)) {
536  fmpz_mul(fmpz_poly_get_coeff_ptr(b, i),
537  fmpz_poly_get_coeff_ptr(b, i),
538  mp_tmp);
539  fmpz_mod_ui(fmpz_poly_get_coeff_ptr(b, i),
540  fmpz_poly_get_coeff_ptr(b, i),
541  params->p);
542  }
543  }
544 
545  j = i - k;
546  if (j < 0)
547  j = j + params->N;
548 
549  b_i = fmpz_poly_get_coeff_ptr(b, i);
550  fmpz_poly_set_coeff_fmpz_n(Fp, j, b_i);
551  }
552 
553  /* check if the f * Fp = 1 (mod p) condition holds true */
554  fmpz_poly_set(a_tmp, a);
555  poly_starmultiply(a_tmp, Fp, a_tmp, params, params->p);
556  if (fmpz_poly_is_one(a_tmp))
557  retval = true;
558  else
559  fmpz_poly_zero(Fp);
560 
561 cleanup:
562  fmpz_poly_clear(a_tmp);
563  fmpz_poly_clear(b);
564  fmpz_poly_clear(c);
565  fmpz_poly_clear(f);
566  fmpz_poly_clear(g);
567 
568  return retval;
569 }
570 
571 /*------------------------------------------------------------------------*/
572 
573 void
574 poly_draw(const fmpz_poly_t poly)
575 {
576  fmpz_poly_print(poly);
577  flint_printf("\n");
578 }
579 
580 /*------------------------------------------------------------------------*/
581 
582 void
583 poly_draw_pretty(const fmpz_poly_t poly)
584 {
585  fmpz_poly_print_pretty(poly, "x");
586  flint_printf("\n");
587 }
588 
589 /*------------------------------------------------------------------------*/
bool poly_inverse_poly_q(const fmpz_poly_t a, fmpz_poly_t Fq, const ntru_params *params)
Definition: ntru_poly.c:297
uint32_t N
Definition: ntru_params.h:48
void fmpz_poly_mod_unsigned(fmpz_poly_t a, const uint32_t mod)
Definition: ntru_poly.c:166
void fmpz_poly_mod(fmpz_poly_t a, const uint32_t mod)
Definition: ntru_poly.c:182
uint32_t p
Definition: ntru_params.h:56
bool poly_inverse_poly_p(const fmpz_poly_t a, fmpz_poly_t Fp, const ntru_params *params)
Definition: ntru_poly.c:409
header for ntru_mem.c
int fmpz_invmod_ui(fmpz_t f, const fmpz_t g, const uint32_t mod)
Definition: ntru_poly.c:210
void poly_draw(const fmpz_poly_t poly)
Definition: ntru_poly.c:574
NTRU parameters.
void fmpz_poly_set_coeff_fmpz_n(fmpz_poly_t poly, slong n, const fmpz_t x)
Definition: ntru_poly.c:198
void poly_starmultiply(const fmpz_poly_t a, const fmpz_poly_t b, fmpz_poly_t c, const ntru_params *params, uint32_t modulus)
Definition: ntru_poly.c:239
void poly_delete(fmpz_poly_t poly)
Definition: ntru_poly.c:123
void poly_delete_all(fmpz_poly_t poly,...)
Definition: ntru_poly.c:149
error handling
void poly_new(fmpz_poly_t new_poly, int const *const c, const size_t len)
Definition: ntru_poly.c:110
void poly_delete_array(fmpz_poly_t **poly_array)
Definition: ntru_poly.c:131
void fmpz_add_n(fmpz_t f, const fmpz_t g, const fmpz_t h)
Definition: ntru_poly.c:222
uint32_t q
Definition: ntru_params.h:52
int fmpz_cmp_si_n(const fmpz_t f, slong g)
Definition: ntru_poly.c:93
void poly_draw_pretty(const fmpz_poly_t poly)
Definition: ntru_poly.c:583
header for ntru_poly.c
static void poly_mod2_to_modq(const fmpz_poly_t a, fmpz_poly_t Fq, const ntru_params *params)
Definition: ntru_poly.c:63