post quantum cryptography
Highly optimized implementation of the NTRUEncrypt algorithm
|
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 /*------------------------------------------------------------------------*/