post quantum cryptography
Highly optimized implementation of the NTRUEncrypt algorithm
/home/travis/build/hasufell/pqc/src/ntru_poly.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2014 FH Bielefeld
00003  *
00004  * This file is part of a FH Bielefeld project.
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2.1 of the License, or (at your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this library; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
00019  * MA  02110-1301  USA
00020  */
00021 
00030 #include "ntru_err.h"
00031 #include "ntru_mem.h"
00032 #include "ntru_params.h"
00033 #include "ntru_poly.h"
00034 
00035 #include <stdarg.h>
00036 #include <stdbool.h>
00037 #include <stdint.h>
00038 #include <stdio.h>
00039 #include <stdlib.h>
00040 #include <sys/types.h>
00041 
00042 #include <fmpz_poly.h>
00043 #include <fmpz.h>
00044 
00045 
00054 static
00055 void poly_mod2_to_modq(const fmpz_poly_t a,
00056         fmpz_poly_t Fq,
00057         const ntru_params *params);
00058 
00059 
00060 /*------------------------------------------------------------------------*/
00061 
00062 static void
00063 poly_mod2_to_modq(const fmpz_poly_t a,
00064         fmpz_poly_t Fq,
00065         const ntru_params *params)
00066 {
00067     int v = 2;
00068     fmpz_poly_t poly_tmp, two;
00069 
00070     fmpz_poly_init(poly_tmp);
00071     fmpz_poly_zero(poly_tmp);
00072     fmpz_poly_init(two);
00073     fmpz_poly_set_coeff_ui(two, 0, 2);
00074 
00075     while (v < (int)(params->q)) {
00076         v = v * 2;
00077 
00078         poly_starmultiply(a, Fq, poly_tmp, params, v);
00079         fmpz_poly_sub(poly_tmp, two, poly_tmp);
00080         fmpz_poly_mod_unsigned(poly_tmp, v);
00081         poly_starmultiply(Fq, poly_tmp, Fq, params, v);
00082 
00083     }
00084 
00085     fmpz_poly_clear(poly_tmp);
00086     fmpz_poly_clear(two);
00087 
00088 }
00089 
00090 /*------------------------------------------------------------------------*/
00091 
00092 int
00093 fmpz_cmp_si_n(const fmpz_t f, slong g)
00094 {
00095     fmpz_t f_cmp;
00096 
00097     fmpz_init(f_cmp);
00098 
00099     if (f)
00100         fmpz_set(f_cmp, f);
00101     else
00102         fmpz_set_si(f_cmp, 0);
00103 
00104     return fmpz_cmp_si(f_cmp, g);
00105 }
00106 
00107 /*------------------------------------------------------------------------*/
00108 
00109 void
00110 poly_new(fmpz_poly_t new_poly,
00111         int const * const c,
00112         const size_t len)
00113 {
00114     fmpz_poly_init(new_poly);
00115 
00116     for (uint32_t i = 0; i < len; i++)
00117         fmpz_poly_set_coeff_si(new_poly, i, c[i]);
00118 }
00119 
00120 /*------------------------------------------------------------------------*/
00121 
00122 void
00123 poly_delete(fmpz_poly_t poly)
00124 {
00125     fmpz_poly_clear(poly);
00126 }
00127 
00128 /*------------------------------------------------------------------------*/
00129 
00130 void
00131 poly_delete_array(fmpz_poly_t **poly_array)
00132 {
00133     uint32_t i = 0;
00134 
00135     while(poly_array[i]) {
00136         poly_delete(*(poly_array[i]));
00137         free(poly_array[i]);
00138         i++;
00139     }
00140 
00141     /* avoid double free */
00142     if (i > 1)
00143         free(poly_array);
00144 }
00145 
00146 /*------------------------------------------------------------------------*/
00147 
00148 void
00149 poly_delete_all(fmpz_poly_t poly, ...)
00150 {
00151     fmpz_poly_struct *next_poly;
00152     va_list args;
00153 
00154     next_poly = poly;
00155     va_start(args, poly);
00156     while (next_poly != NULL) {
00157         poly_delete(next_poly);
00158         next_poly = va_arg(args, fmpz_poly_struct*);
00159     }
00160     va_end(args);
00161 }
00162 
00163 /*------------------------------------------------------------------------*/
00164 
00165 void
00166 fmpz_poly_mod_unsigned(fmpz_poly_t a,
00167         const uint32_t mod)
00168 {
00169     nmod_poly_t nmod_tmp;
00170 
00171     nmod_poly_init(nmod_tmp, mod);
00172 
00173     fmpz_poly_get_nmod_poly(nmod_tmp, a);
00174     fmpz_poly_set_nmod_poly_unsigned(a, nmod_tmp);
00175 
00176     nmod_poly_clear(nmod_tmp);
00177 }
00178 
00179 /*------------------------------------------------------------------------*/
00180 
00181 void
00182 fmpz_poly_mod(fmpz_poly_t a,
00183         const uint32_t mod)
00184 {
00185     nmod_poly_t nmod_tmp;
00186 
00187     nmod_poly_init(nmod_tmp, mod);
00188 
00189     fmpz_poly_get_nmod_poly(nmod_tmp, a);
00190     fmpz_poly_set_nmod_poly(a, nmod_tmp);
00191 
00192     nmod_poly_clear(nmod_tmp);
00193 }
00194 
00195 /*------------------------------------------------------------------------*/
00196 
00197 void
00198 fmpz_poly_set_coeff_fmpz_n(fmpz_poly_t poly, slong n,
00199         const fmpz_t x)
00200 {
00201     if (x)
00202         fmpz_poly_set_coeff_fmpz(poly, n, x);
00203     else
00204         fmpz_poly_set_coeff_si(poly, n, 0);
00205 }
00206 
00207 /*------------------------------------------------------------------------*/
00208 
00209 int
00210 fmpz_invmod_ui(fmpz_t f, const fmpz_t g, const uint32_t mod)
00211 {
00212     fmpz_t modulus;
00213 
00214     fmpz_init_set_ui(modulus, mod);
00215 
00216     return fmpz_invmod(f, g, modulus);
00217 }
00218 
00219 /*------------------------------------------------------------------------*/
00220 
00221 void
00222 fmpz_add_n(fmpz_t f, const fmpz_t g, const fmpz_t h)
00223 {
00224     if (!g && !h) {
00225         fmpz_zero(f);
00226     } else {
00227         if (!g && h)
00228             fmpz_add_ui(f, h, 0);
00229         else if (g && !h)
00230             fmpz_add_ui(f, g, 0);
00231         else
00232             fmpz_add(f, g, h);
00233     }
00234 }
00235 
00236 /*------------------------------------------------------------------------*/
00237 
00238 void
00239 poly_starmultiply(const fmpz_poly_t a,
00240         const fmpz_poly_t b,
00241         fmpz_poly_t c,
00242         const ntru_params *params,
00243         uint32_t modulus)
00244 {
00245     fmpz_poly_t a_tmp;
00246     fmpz_t c_coeff_k;
00247 
00248     fmpz_poly_init(a_tmp);
00249     fmpz_init(c_coeff_k);
00250 
00251     /* avoid side effects */
00252     fmpz_poly_set(a_tmp, a);
00253     fmpz_poly_zero(c);
00254 
00255     for (int k = params->N - 1; k >= 0; k--) {
00256         int j;
00257 
00258         j = k + 1;
00259 
00260         fmpz_set_si(c_coeff_k, 0);
00261 
00262         for (int i = params->N - 1; i >= 0; i--) {
00263             fmpz *a_tmp_coeff_i,
00264                  *b_coeff_j;
00265 
00266             if (j == (int)(params->N))
00267                 j = 0;
00268 
00269             a_tmp_coeff_i = fmpz_poly_get_coeff_ptr(a_tmp, i);
00270             b_coeff_j = fmpz_poly_get_coeff_ptr(b, j);
00271 
00272             if (fmpz_cmp_si_n(a_tmp_coeff_i, 0) &&
00273                     fmpz_cmp_si_n(b_coeff_j, 0)) {
00274                 fmpz_t fmpz_tmp;
00275 
00276                 fmpz_init(fmpz_tmp);
00277 
00278                 fmpz_mul(fmpz_tmp, a_tmp_coeff_i, b_coeff_j);
00279                 fmpz_add(fmpz_tmp, fmpz_tmp, c_coeff_k);
00280                 fmpz_mod_ui(c_coeff_k, fmpz_tmp, modulus);
00281 
00282                 fmpz_poly_set_coeff_fmpz(c, k, c_coeff_k);
00283 
00284                 fmpz_clear(fmpz_tmp);
00285             }
00286             j++;
00287         }
00288         fmpz_clear(c_coeff_k);
00289     }
00290 
00291     fmpz_poly_clear(a_tmp);
00292 }
00293 
00294 /*------------------------------------------------------------------------*/
00295 
00296 bool
00297 poly_inverse_poly_q(const fmpz_poly_t a,
00298         fmpz_poly_t Fq,
00299         const ntru_params *params)
00300 {
00301     bool retval = false;
00302     int k = 0,
00303         j = 0;
00304     fmpz *b_last;
00305     fmpz_poly_t a_tmp,
00306                 b,
00307                 c,
00308                 f,
00309                 g;
00310 
00311     /* general initialization of temp variables */
00312     fmpz_poly_init(b);
00313     fmpz_poly_set_coeff_ui(b, 0, 1);
00314     fmpz_poly_init(c);
00315     fmpz_poly_init(f);
00316     fmpz_poly_set(f, a);
00317 
00318     /* set g(x) = x^N − 1 */
00319     fmpz_poly_init(g);
00320     fmpz_poly_set_coeff_si(g, 0, -1);
00321     fmpz_poly_set_coeff_si(g, params->N, 1);
00322 
00323     /* avoid side effects */
00324     fmpz_poly_init(a_tmp);
00325     fmpz_poly_set(a_tmp, a);
00326     fmpz_poly_zero(Fq);
00327 
00328     while (1) {
00329         while (fmpz_is_zero(fmpz_poly_get_coeff_ptr(f, 0))) {
00330             for (uint32_t i = 1; i <= params->N; i++) {
00331                 fmpz *f_coeff = fmpz_poly_get_coeff_ptr(f, i);
00332                 fmpz *c_coeff = fmpz_poly_get_coeff_ptr(c, params->N - i);
00333 
00334                 /* f(x) = f(x) / x */
00335                 fmpz_poly_set_coeff_fmpz_n(f, i - 1,
00336                         f_coeff);
00337 
00338                 /* c(x) = c(x) * x */
00339                 fmpz_poly_set_coeff_fmpz_n(c, params->N + 1 - i,
00340                         c_coeff);
00341             }
00342 
00343             fmpz_poly_set_coeff_si(f, params->N, 0);
00344             fmpz_poly_set_coeff_si(c, 0, 0);
00345 
00346             k++;
00347 
00348             if (fmpz_poly_degree(f) == -1)
00349                 goto _cleanup;
00350         }
00351 
00352         if (fmpz_poly_degree(f) == 0)
00353             break;
00354 
00355         if (fmpz_poly_degree(f) < fmpz_poly_degree(g)) {
00356             fmpz_poly_swap(f, g);
00357             fmpz_poly_swap(b, c);
00358         }
00359 
00360         fmpz_poly_add(f, g, f);
00361         fmpz_poly_mod_unsigned(f, 2);
00362 
00363         fmpz_poly_add(b, c, b);
00364         fmpz_poly_mod_unsigned(b, 2);
00365     }
00366 
00367     k = k % params->N;
00368 
00369     b_last = fmpz_poly_get_coeff_ptr(b, params->N);
00370     if (fmpz_cmp_si_n(b_last, 0))
00371         goto _cleanup;
00372 
00373     /* Fq(x) = x^(N-k) * b(x) */
00374     for (int i = params->N - 1; i >= 0; i--) {
00375         fmpz *b_i;
00376 
00377         j = i - k;
00378 
00379         if (j < 0)
00380             j = j + params->N;
00381 
00382         b_i = fmpz_poly_get_coeff_ptr(b, i);
00383         fmpz_poly_set_coeff_fmpz_n(Fq, j, b_i);
00384     }
00385 
00386     poly_mod2_to_modq(a_tmp, Fq, params);
00387 
00388     /* check if the f * Fq = 1 (mod p) condition holds true */
00389     fmpz_poly_set(a_tmp, a);
00390     poly_starmultiply(a_tmp, Fq, a_tmp, params, params->q);
00391     if (fmpz_poly_is_one(a_tmp))
00392         retval = true;
00393     else
00394         fmpz_poly_zero(Fq);
00395 
00396 _cleanup:
00397     fmpz_poly_clear(a_tmp);
00398     fmpz_poly_clear(b);
00399     fmpz_poly_clear(c);
00400     fmpz_poly_clear(f);
00401     fmpz_poly_clear(g);
00402 
00403     return retval;
00404 }
00405 
00406 /*------------------------------------------------------------------------*/
00407 
00408 bool
00409 poly_inverse_poly_p(const fmpz_poly_t a,
00410         fmpz_poly_t Fp,
00411         const ntru_params *params)
00412 {
00413     bool retval = false;
00414     int k = 0,
00415         j = 0;
00416     fmpz *b_last;
00417     fmpz_poly_t a_tmp,
00418                 b,
00419                 c,
00420                 f,
00421                 g;
00422 
00423     /* general initialization of temp variables */
00424     fmpz_poly_init(b);
00425     fmpz_poly_set_coeff_ui(b, 0, 1);
00426     fmpz_poly_init(c);
00427     fmpz_poly_init(f);
00428     fmpz_poly_set(f, a);
00429 
00430     /* set g(x) = x^N − 1 */
00431     fmpz_poly_init(g);
00432     fmpz_poly_set_coeff_si(g, 0, -1);
00433     fmpz_poly_set_coeff_si(g, params->N, 1);
00434 
00435     /* avoid side effects */
00436     fmpz_poly_init(a_tmp);
00437     fmpz_poly_set(a_tmp, a);
00438     fmpz_poly_zero(Fp);
00439 
00440     while (1) {
00441         while (fmpz_is_zero(fmpz_poly_get_coeff_ptr(f, 0))) {
00442             for (uint32_t i = 1; i <= params->N; i++) {
00443                 fmpz *f_coeff = fmpz_poly_get_coeff_ptr(f, i);
00444                 fmpz *c_coeff = fmpz_poly_get_coeff_ptr(c, params->N - i);
00445 
00446                 /* f(x) = f(x) / x */
00447                 fmpz_poly_set_coeff_fmpz_n(f, i - 1,
00448                         f_coeff);
00449 
00450                 /* c(x) = c(x) * x */
00451                 fmpz_poly_set_coeff_fmpz_n(c, params->N + 1 - i,
00452                         c_coeff);
00453             }
00454 
00455             fmpz_poly_set_coeff_si(f, params->N, 0);
00456             fmpz_poly_set_coeff_si(c, 0, 0);
00457 
00458             k++;
00459 
00460             if (fmpz_poly_degree(f) == -1)
00461                 goto cleanup;
00462         }
00463 
00464         if (fmpz_poly_degree(f) == 0)
00465             break;
00466 
00467         if (fmpz_poly_degree(f) < fmpz_poly_degree(g)) {
00468             /* exchange f and g and exchange b and c */
00469             fmpz_poly_swap(f, g);
00470             fmpz_poly_swap(b, c);
00471         }
00472 
00473         {
00474             fmpz_poly_t c_tmp,
00475                         g_tmp;
00476             fmpz_t u,
00477                    mp_tmp;
00478 
00479             fmpz_init(u);
00480             fmpz_zero(u);
00481 
00482             fmpz_init_set(mp_tmp, fmpz_poly_get_coeff_ptr(f, 0));
00483 
00484             fmpz_poly_init(g_tmp);
00485             fmpz_poly_set(g_tmp, g);
00486 
00487             fmpz_poly_init(c_tmp);
00488             fmpz_poly_set(c_tmp, c);
00489 
00490             /* u = f[0] * g[0]^(-1) mod p */
00491               /* = (f[0] mod p) * (g[0] inverse mod p) mod p */
00492             fmpz_invmod_ui(u,
00493                     fmpz_poly_get_coeff_ptr(g, 0),
00494                     params->p);
00495             fmpz_mod_ui(mp_tmp, mp_tmp, params->p);
00496             fmpz_mul(u, mp_tmp, u);
00497             fmpz_mod_ui(u, u, params->p);
00498 
00499             /* f = f - u * g mod p */
00500             fmpz_poly_scalar_mul_fmpz(g_tmp, g_tmp, u);
00501             fmpz_poly_sub(f, g_tmp, f);
00502             fmpz_poly_mod_unsigned(f, params->p);
00503 
00504             /* b = b - u * c mod p */
00505             fmpz_poly_scalar_mul_fmpz(c_tmp, c_tmp, u);
00506             fmpz_poly_sub(b, c_tmp, b);
00507             fmpz_poly_mod_unsigned(b, params->p);
00508 
00509             fmpz_clear(u);
00510             fmpz_poly_clear(g_tmp);
00511             fmpz_poly_clear(c_tmp);
00512         }
00513     }
00514 
00515     k = k % params->N;
00516 
00517     b_last = fmpz_poly_get_coeff_ptr(b, params->N);
00518     if (fmpz_cmp_si_n(b_last, 0))
00519         goto cleanup;
00520 
00521     /* Fp(x) = x^(N-k) * b(x) */
00522     for (int i = params->N - 1; i >= 0; i--) {
00523         fmpz *b_i;
00524 
00525         /* b(X) = f[0]^(-1) * b(X) (mod p) */
00526         {
00527             fmpz_t mp_tmp;
00528 
00529             fmpz_init(mp_tmp);
00530 
00531             fmpz_invmod_ui(mp_tmp,
00532                     fmpz_poly_get_coeff_ptr(f, 0),
00533                     params->p);
00534 
00535             if (fmpz_poly_get_coeff_ptr(b, i)) {
00536                 fmpz_mul(fmpz_poly_get_coeff_ptr(b, i),
00537                         fmpz_poly_get_coeff_ptr(b, i),
00538                         mp_tmp);
00539                 fmpz_mod_ui(fmpz_poly_get_coeff_ptr(b, i),
00540                         fmpz_poly_get_coeff_ptr(b, i),
00541                         params->p);
00542             }
00543         }
00544 
00545         j = i - k;
00546         if (j < 0)
00547             j = j + params->N;
00548 
00549         b_i = fmpz_poly_get_coeff_ptr(b, i);
00550         fmpz_poly_set_coeff_fmpz_n(Fp, j, b_i);
00551     }
00552 
00553     /* check if the f * Fp = 1 (mod p) condition holds true */
00554     fmpz_poly_set(a_tmp, a);
00555     poly_starmultiply(a_tmp, Fp, a_tmp, params, params->p);
00556     if (fmpz_poly_is_one(a_tmp))
00557         retval = true;
00558     else
00559         fmpz_poly_zero(Fp);
00560 
00561 cleanup:
00562     fmpz_poly_clear(a_tmp);
00563     fmpz_poly_clear(b);
00564     fmpz_poly_clear(c);
00565     fmpz_poly_clear(f);
00566     fmpz_poly_clear(g);
00567 
00568     return retval;
00569 }
00570 
00571 /*------------------------------------------------------------------------*/
00572 
00573 void
00574 poly_draw(const fmpz_poly_t poly)
00575 {
00576     fmpz_poly_print(poly);
00577     flint_printf("\n");
00578 }
00579 
00580 /*------------------------------------------------------------------------*/
00581 
00582 void
00583 poly_draw_pretty(const fmpz_poly_t poly)
00584 {
00585     fmpz_poly_print_pretty(poly, "x");
00586     flint_printf("\n");
00587 }
00588 
00589 /*------------------------------------------------------------------------*/
 All Data Structures Files Functions Variables Typedefs Defines