2014-04-14 20:28:35 +00:00
|
|
|
|
/*
|
2014-04-15 11:35:04 +00:00
|
|
|
|
* Copyright (C) 2014 FH Bielefeld
|
2014-04-14 20:28:35 +00:00
|
|
|
|
*
|
2014-04-15 11:35:04 +00:00
|
|
|
|
* This file is part of a FH Bielefeld project.
|
2014-04-14 20:28:35 +00:00
|
|
|
|
*
|
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
|
|
|
* MA 02110-1301 USA
|
|
|
|
|
*/
|
|
|
|
|
|
2014-05-25 00:15:24 +00:00
|
|
|
|
/**
|
|
|
|
|
* @file poly.c
|
|
|
|
|
* This files purpose is to handle polynomials
|
|
|
|
|
* in general, allowing modification, arithmetic
|
|
|
|
|
* and common algorithms like inverting them.
|
|
|
|
|
* @brief operations on polynomials
|
|
|
|
|
*/
|
|
|
|
|
|
2014-04-15 16:49:17 +00:00
|
|
|
|
#include "context.h"
|
2014-04-14 20:28:35 +00:00
|
|
|
|
#include "err.h"
|
2014-04-20 17:50:49 +00:00
|
|
|
|
#include "mem.h"
|
2014-04-16 21:23:41 +00:00
|
|
|
|
#include "poly.h"
|
2014-04-14 20:28:35 +00:00
|
|
|
|
|
2014-04-20 17:55:30 +00:00
|
|
|
|
#include <stdarg.h>
|
2014-04-15 16:49:17 +00:00
|
|
|
|
#include <stdbool.h>
|
2014-04-14 20:28:35 +00:00
|
|
|
|
#include <stdio.h>
|
2014-04-16 21:23:41 +00:00
|
|
|
|
#include <stdbool.h>
|
2014-04-14 20:28:35 +00:00
|
|
|
|
|
2014-05-24 21:11:02 +00:00
|
|
|
|
#include <fmpz_poly.h>
|
|
|
|
|
#include <fmpz.h>
|
|
|
|
|
|
2014-04-17 21:43:29 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* static declarations
|
|
|
|
|
*/
|
2014-05-24 21:11:02 +00:00
|
|
|
|
static void poly_mod2_to_modq(fmpz_poly_t a,
|
|
|
|
|
fmpz_poly_t Fq,
|
2014-04-20 17:57:45 +00:00
|
|
|
|
ntru_context *ctx);
|
2014-04-17 21:43:29 +00:00
|
|
|
|
|
|
|
|
|
|
2014-04-14 20:28:35 +00:00
|
|
|
|
/**
|
2014-05-24 21:11:02 +00:00
|
|
|
|
* Find the inverse polynomial modulo a power of 2,
|
|
|
|
|
* which is q.
|
2014-04-14 20:28:35 +00:00
|
|
|
|
*
|
2014-05-24 21:11:02 +00:00
|
|
|
|
* @param a polynomial to invert
|
|
|
|
|
* @param Fq polynomial [out]
|
|
|
|
|
* @param ctx NTRU context
|
2014-04-14 20:28:35 +00:00
|
|
|
|
*/
|
2014-05-24 21:11:02 +00:00
|
|
|
|
static void poly_mod2_to_modq(fmpz_poly_t a,
|
|
|
|
|
fmpz_poly_t Fq,
|
|
|
|
|
ntru_context *ctx)
|
2014-04-14 20:28:35 +00:00
|
|
|
|
{
|
2014-05-24 21:11:02 +00:00
|
|
|
|
int v = 2;
|
|
|
|
|
fmpz_poly_t poly_tmp, two;
|
2014-04-14 20:28:35 +00:00
|
|
|
|
|
2014-05-24 21:11:02 +00:00
|
|
|
|
fmpz_poly_init(poly_tmp);
|
|
|
|
|
fmpz_poly_zero(poly_tmp);
|
|
|
|
|
fmpz_poly_init(two);
|
|
|
|
|
fmpz_poly_set_coeff_ui(two, 0, 2);
|
2014-04-30 15:18:08 +00:00
|
|
|
|
|
2014-05-24 21:11:02 +00:00
|
|
|
|
while (v < (int)(ctx->q)) {
|
|
|
|
|
v = v * 2;
|
2014-04-30 15:18:08 +00:00
|
|
|
|
|
2014-05-24 21:11:02 +00:00
|
|
|
|
poly_starmultiply(a, Fq, poly_tmp, ctx, v);
|
|
|
|
|
fmpz_poly_sub(poly_tmp, two, poly_tmp);
|
|
|
|
|
fmpz_poly_mod_unsigned(poly_tmp, v);
|
|
|
|
|
poly_starmultiply(Fq, poly_tmp, Fq, ctx, v);
|
2014-04-14 20:28:35 +00:00
|
|
|
|
|
|
|
|
|
}
|
2014-05-24 21:11:02 +00:00
|
|
|
|
|
|
|
|
|
fmpz_poly_clear(poly_tmp);
|
|
|
|
|
fmpz_poly_clear(two);
|
|
|
|
|
|
2014-04-14 20:28:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-04-15 16:49:17 +00:00
|
|
|
|
/**
|
|
|
|
|
* Initializes and builds a polynomial with the
|
|
|
|
|
* coefficient values of c[] of size len within NTRU
|
2014-05-24 23:48:55 +00:00
|
|
|
|
* context ctx and returns a newly allocated polynomial.
|
|
|
|
|
* For an empty polynom, both parameters can be NULL/0.
|
2014-04-15 16:49:17 +00:00
|
|
|
|
*
|
|
|
|
|
* @param c array of polynomial coefficients, can be NULL
|
|
|
|
|
* @param len size of the coefficient array, can be 0
|
|
|
|
|
* @return newly allocated polynomial pointer, must be freed
|
2014-05-24 21:11:02 +00:00
|
|
|
|
* with fmpz_poly_clear()
|
2014-04-15 16:49:17 +00:00
|
|
|
|
*/
|
2014-05-24 21:11:02 +00:00
|
|
|
|
fmpz_poly_t *poly_new(int const * const c,
|
2014-04-30 15:22:25 +00:00
|
|
|
|
const size_t len)
|
2014-04-15 16:49:17 +00:00
|
|
|
|
{
|
2014-05-24 21:11:02 +00:00
|
|
|
|
fmpz_poly_t *new_poly = ntru_malloc(sizeof(*new_poly));
|
2014-04-15 16:49:17 +00:00
|
|
|
|
|
2014-05-24 21:11:02 +00:00
|
|
|
|
fmpz_poly_init(*new_poly);
|
2014-04-15 20:50:11 +00:00
|
|
|
|
|
2014-05-24 21:11:02 +00:00
|
|
|
|
for (unsigned int i = 0; i < len; i++)
|
|
|
|
|
fmpz_poly_set_coeff_si(*new_poly, i, c[i]);
|
2014-04-15 16:49:17 +00:00
|
|
|
|
|
2014-05-24 21:11:02 +00:00
|
|
|
|
return new_poly;
|
2014-04-17 15:34:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-04-15 12:22:46 +00:00
|
|
|
|
/**
|
|
|
|
|
* This deletes the internal structure of a polynomial,
|
|
|
|
|
* and frees the pointer. Don't call this on stack variables,
|
|
|
|
|
* this is intended for use after ntru_ functions, that
|
|
|
|
|
* return a polynomial pointer.
|
|
|
|
|
*
|
|
|
|
|
* @param poly the polynomial to delete
|
|
|
|
|
*/
|
2014-05-24 21:11:02 +00:00
|
|
|
|
void poly_delete(fmpz_poly_t *poly)
|
2014-04-15 12:22:46 +00:00
|
|
|
|
{
|
2014-05-24 21:11:02 +00:00
|
|
|
|
fmpz_poly_clear(*poly);
|
2014-04-15 12:22:46 +00:00
|
|
|
|
free(poly);
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-20 17:55:30 +00:00
|
|
|
|
/**
|
|
|
|
|
* This deletes the internal structure of all polynomials,
|
|
|
|
|
* and frees the pointers. Don't call this on stack variables,
|
|
|
|
|
* this is intended for use after ntru_ functions, that
|
|
|
|
|
* return a polynomial pointer.
|
|
|
|
|
* You must call this with NULL as last argument!
|
|
|
|
|
*
|
|
|
|
|
* @param poly the polynomial to delete
|
|
|
|
|
* @param ... follow up polynomials
|
|
|
|
|
*/
|
2014-05-24 21:11:02 +00:00
|
|
|
|
void poly_delete_all(fmpz_poly_t *poly, ...)
|
2014-04-20 17:55:30 +00:00
|
|
|
|
{
|
2014-05-24 21:11:02 +00:00
|
|
|
|
fmpz_poly_t *next_poly;
|
2014-04-20 17:55:30 +00:00
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
|
|
next_poly = poly;
|
|
|
|
|
va_start(args, poly);
|
|
|
|
|
while (next_poly != NULL) {
|
2014-05-24 21:11:02 +00:00
|
|
|
|
poly_delete(next_poly);
|
|
|
|
|
next_poly = va_arg(args, fmpz_poly_t*);
|
2014-04-20 17:55:30 +00:00
|
|
|
|
}
|
|
|
|
|
va_end(args);
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-15 20:50:42 +00:00
|
|
|
|
/**
|
2014-05-24 21:11:02 +00:00
|
|
|
|
* Calls fmpz_poly_get_nmod_poly() and
|
|
|
|
|
* fmpz_poly_set_nmod_poly_unsigned() in a row,
|
|
|
|
|
* so we don't have to deal with the intermediate
|
|
|
|
|
* nmod_poly_t type if we don't need it.
|
2014-04-15 20:50:42 +00:00
|
|
|
|
*
|
2014-05-24 21:11:02 +00:00
|
|
|
|
* @param a the polynom to apply the modulus to
|
|
|
|
|
* @param mod the modulus
|
2014-04-15 20:50:42 +00:00
|
|
|
|
*/
|
2014-05-24 21:11:02 +00:00
|
|
|
|
void fmpz_poly_mod_unsigned(fmpz_poly_t a,
|
|
|
|
|
unsigned int mod)
|
2014-04-15 20:50:42 +00:00
|
|
|
|
{
|
2014-05-24 21:11:02 +00:00
|
|
|
|
nmod_poly_t nmod_tmp;
|
2014-04-15 20:50:42 +00:00
|
|
|
|
|
2014-05-24 21:11:02 +00:00
|
|
|
|
nmod_poly_init(nmod_tmp, mod);
|
2014-04-15 20:50:42 +00:00
|
|
|
|
|
2014-05-24 21:11:02 +00:00
|
|
|
|
fmpz_poly_get_nmod_poly(nmod_tmp, a);
|
|
|
|
|
fmpz_poly_set_nmod_poly_unsigned(a, nmod_tmp);
|
2014-04-15 20:50:42 +00:00
|
|
|
|
|
2014-05-24 21:11:02 +00:00
|
|
|
|
nmod_poly_clear(nmod_tmp);
|
2014-04-15 20:50:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-04-30 15:19:58 +00:00
|
|
|
|
/**
|
2014-05-24 21:11:02 +00:00
|
|
|
|
* Calls fmpz_poly_get_nmod_poly() and
|
|
|
|
|
* fmpz_poly_set_nmod_poly() in a row,
|
|
|
|
|
* so we don't have to deal with the intermediate
|
|
|
|
|
* nmod_poly_t type if we don't need it.
|
2014-04-30 15:19:58 +00:00
|
|
|
|
*
|
2014-05-24 21:11:02 +00:00
|
|
|
|
* @param a the polynom to apply the modulus to
|
|
|
|
|
* @param mod the modulus
|
2014-04-30 15:19:58 +00:00
|
|
|
|
*/
|
2014-05-24 21:11:02 +00:00
|
|
|
|
void fmpz_poly_mod(fmpz_poly_t a,
|
|
|
|
|
unsigned int mod)
|
2014-04-30 15:19:58 +00:00
|
|
|
|
{
|
2014-05-24 21:11:02 +00:00
|
|
|
|
nmod_poly_t nmod_tmp;
|
2014-04-30 15:19:58 +00:00
|
|
|
|
|
2014-05-24 21:11:02 +00:00
|
|
|
|
nmod_poly_init(nmod_tmp, mod);
|
2014-04-30 15:19:58 +00:00
|
|
|
|
|
2014-05-24 21:11:02 +00:00
|
|
|
|
fmpz_poly_get_nmod_poly(nmod_tmp, a);
|
|
|
|
|
fmpz_poly_set_nmod_poly(a, nmod_tmp);
|
2014-04-30 15:19:58 +00:00
|
|
|
|
|
2014-05-24 21:11:02 +00:00
|
|
|
|
nmod_poly_clear(nmod_tmp);
|
2014-04-30 15:19:58 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-04-14 20:28:35 +00:00
|
|
|
|
/**
|
2014-05-24 21:11:02 +00:00
|
|
|
|
* The same as fmpz_poly_set_coeff_fmpz() except that it
|
|
|
|
|
* will take care of null-pointer coefficients and use
|
|
|
|
|
* fmpz_poly_set_coeff_si() in that case.
|
2014-04-16 21:23:41 +00:00
|
|
|
|
*
|
2014-05-24 21:11:02 +00:00
|
|
|
|
* @param poly the polynom we want to change a coefficient of
|
|
|
|
|
* @param n the coefficient we want to set
|
|
|
|
|
* @param x the value to assign to the coefficient
|
2014-04-16 21:23:41 +00:00
|
|
|
|
*/
|
2014-05-24 21:11:02 +00:00
|
|
|
|
void fmpz_poly_set_coeff_fmpz_n(fmpz_poly_t poly, slong n,
|
|
|
|
|
const fmpz_t x)
|
2014-04-16 21:23:41 +00:00
|
|
|
|
{
|
2014-05-24 21:11:02 +00:00
|
|
|
|
if (x)
|
|
|
|
|
fmpz_poly_set_coeff_fmpz(poly, n, x);
|
|
|
|
|
else
|
|
|
|
|
fmpz_poly_set_coeff_si(poly, n, 0);
|
2014-04-16 21:23:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-04-17 21:43:29 +00:00
|
|
|
|
/**
|
2014-05-24 21:11:02 +00:00
|
|
|
|
* Wrapper around fmpz_invmod() where we convert
|
|
|
|
|
* mod to an fmpz_t implicitly.
|
2014-04-17 21:43:29 +00:00
|
|
|
|
*
|
2014-05-24 21:11:02 +00:00
|
|
|
|
* @param f result [out]
|
|
|
|
|
* @param g the inverse
|
|
|
|
|
* @param mod the modulo
|
2014-04-17 21:43:29 +00:00
|
|
|
|
*/
|
2014-05-24 21:11:02 +00:00
|
|
|
|
int fmpz_invmod_ui(fmpz_t f, const fmpz_t g, unsigned int mod)
|
2014-04-17 21:43:29 +00:00
|
|
|
|
{
|
2014-05-24 21:11:02 +00:00
|
|
|
|
fmpz_t modulus;
|
2014-04-17 21:43:29 +00:00
|
|
|
|
|
2014-05-24 21:11:02 +00:00
|
|
|
|
fmpz_init_set_ui(modulus, mod);
|
2014-04-17 21:43:29 +00:00
|
|
|
|
|
2014-05-24 21:11:02 +00:00
|
|
|
|
return fmpz_invmod(f, g, modulus);
|
2014-04-17 21:43:29 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-04-20 17:57:45 +00:00
|
|
|
|
/**
|
2014-05-24 21:11:02 +00:00
|
|
|
|
* The same as fmpz_add() except that it handles NULL
|
|
|
|
|
* pointer for g and h.
|
|
|
|
|
*/
|
|
|
|
|
void fmpz_add_n(fmpz_t f, const fmpz_t g, const fmpz_t h)
|
|
|
|
|
{
|
|
|
|
|
if (!g && !h) {
|
|
|
|
|
fmpz_zero(f);
|
|
|
|
|
} else {
|
|
|
|
|
if (!g && h)
|
|
|
|
|
fmpz_add_ui(f, h, 0);
|
|
|
|
|
else if (g && !h)
|
|
|
|
|
fmpz_add_ui(f, g, 0);
|
|
|
|
|
else
|
|
|
|
|
fmpz_add(f, g, h);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Starmultiplication, as follows:
|
|
|
|
|
* c = a * b mod (x^N − 1)
|
2014-04-20 17:57:45 +00:00
|
|
|
|
*
|
2014-05-24 21:11:02 +00:00
|
|
|
|
* @param a polynom to multiply (can be the same as c)
|
|
|
|
|
* @param b polynom to multiply
|
|
|
|
|
* @param c polynom [out]
|
2014-04-20 17:57:45 +00:00
|
|
|
|
* @param ctx NTRU context
|
2014-05-24 21:11:02 +00:00
|
|
|
|
* @param modulus whether we use p or q
|
2014-04-20 17:57:45 +00:00
|
|
|
|
*/
|
2014-05-24 21:11:02 +00:00
|
|
|
|
void poly_starmultiply(fmpz_poly_t a,
|
|
|
|
|
fmpz_poly_t b,
|
|
|
|
|
fmpz_poly_t c,
|
|
|
|
|
ntru_context *ctx,
|
|
|
|
|
unsigned int modulus)
|
2014-04-20 17:57:45 +00:00
|
|
|
|
{
|
2014-05-24 21:11:02 +00:00
|
|
|
|
fmpz_poly_t a_tmp;
|
|
|
|
|
fmpz_t c_coeff_k;
|
2014-04-20 17:57:45 +00:00
|
|
|
|
|
2014-05-24 21:11:02 +00:00
|
|
|
|
fmpz_poly_init(a_tmp);
|
|
|
|
|
fmpz_init(c_coeff_k);
|
|
|
|
|
|
|
|
|
|
/* avoid side effects */
|
|
|
|
|
fmpz_poly_set(a_tmp, a);
|
|
|
|
|
fmpz_poly_zero(c);
|
|
|
|
|
|
|
|
|
|
for (int k = ctx->N - 1; k >= 0; k--) {
|
|
|
|
|
int j;
|
|
|
|
|
|
|
|
|
|
j = k + 1;
|
|
|
|
|
|
|
|
|
|
fmpz_set_si(c_coeff_k, 0);
|
|
|
|
|
|
|
|
|
|
for (int i = ctx->N - 1; i >= 0; i--) {
|
|
|
|
|
fmpz *a_tmp_coeff_i,
|
|
|
|
|
*b_coeff_j;
|
|
|
|
|
|
|
|
|
|
if (j == (int)(ctx->N))
|
|
|
|
|
j = 0;
|
|
|
|
|
|
|
|
|
|
a_tmp_coeff_i = fmpz_poly_get_coeff_ptr(a_tmp, i);
|
|
|
|
|
b_coeff_j = fmpz_poly_get_coeff_ptr(b, j);
|
|
|
|
|
|
|
|
|
|
if (a_tmp_coeff_i && fmpz_cmp_si(a_tmp_coeff_i, 0) &&
|
|
|
|
|
b_coeff_j && fmpz_cmp_si(b_coeff_j, 0)) {
|
|
|
|
|
fmpz_t fmpz_tmp;
|
|
|
|
|
|
|
|
|
|
fmpz_init(fmpz_tmp);
|
|
|
|
|
|
|
|
|
|
fmpz_mul(fmpz_tmp, a_tmp_coeff_i, b_coeff_j);
|
|
|
|
|
fmpz_add(fmpz_tmp, fmpz_tmp, c_coeff_k);
|
|
|
|
|
fmpz_mod_ui(c_coeff_k, fmpz_tmp, modulus);
|
|
|
|
|
|
|
|
|
|
fmpz_poly_set_coeff_fmpz(c, k, c_coeff_k);
|
|
|
|
|
|
|
|
|
|
fmpz_clear(fmpz_tmp);
|
|
|
|
|
}
|
|
|
|
|
j++;
|
|
|
|
|
}
|
|
|
|
|
fmpz_clear(c_coeff_k);
|
2014-04-20 17:57:45 +00:00
|
|
|
|
}
|
2014-05-24 21:11:02 +00:00
|
|
|
|
|
|
|
|
|
fmpz_poly_clear(a_tmp);
|
2014-04-20 17:57:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-04-16 21:23:41 +00:00
|
|
|
|
/**
|
2014-05-24 21:11:02 +00:00
|
|
|
|
* Compute the inverse of a polynomial in modulo a power of 2,
|
|
|
|
|
* which is q. This is based off the pseudo-code for "Inversion
|
|
|
|
|
* in (Z/2Z)[X](X^N - 1)" and "Inversion in (Z/p^r Z)[X](X^N - 1)".
|
|
|
|
|
* See NTRU Cryptosystems Tech Report #014 "Almost Inverses
|
|
|
|
|
* and Fast NTRU Key Creation."
|
2014-04-16 21:23:41 +00:00
|
|
|
|
*
|
|
|
|
|
* @param a polynomial to invert (is allowed to be the same as param Fq)
|
|
|
|
|
* @param Fq polynomial [out]
|
|
|
|
|
* @param ctx NTRU context
|
2014-05-12 22:20:46 +00:00
|
|
|
|
* @return true if invertible, false if not
|
2014-04-16 21:23:41 +00:00
|
|
|
|
*/
|
2014-05-24 21:11:02 +00:00
|
|
|
|
bool poly_inverse_poly_q(fmpz_poly_t a,
|
|
|
|
|
fmpz_poly_t Fq,
|
2014-04-16 21:23:41 +00:00
|
|
|
|
ntru_context *ctx)
|
|
|
|
|
{
|
2014-05-24 21:11:02 +00:00
|
|
|
|
bool retval = true;
|
2014-04-16 21:23:41 +00:00
|
|
|
|
int k = 0,
|
2014-04-20 17:57:45 +00:00
|
|
|
|
j = 0;
|
2014-05-24 21:11:02 +00:00
|
|
|
|
fmpz *b_last;
|
|
|
|
|
fmpz_poly_t a_tmp,
|
|
|
|
|
b,
|
|
|
|
|
c,
|
|
|
|
|
f,
|
|
|
|
|
g;
|
2014-04-16 21:23:41 +00:00
|
|
|
|
|
2014-04-29 12:27:15 +00:00
|
|
|
|
/* general initialization of temp variables */
|
2014-05-24 21:11:02 +00:00
|
|
|
|
fmpz_poly_init(b);
|
|
|
|
|
fmpz_poly_set_coeff_ui(b, 0, 1);
|
|
|
|
|
fmpz_poly_init(c);
|
|
|
|
|
fmpz_poly_init(f);
|
|
|
|
|
fmpz_poly_set(f, a);
|
2014-04-29 12:27:15 +00:00
|
|
|
|
|
|
|
|
|
/* set g(x) = x^N − 1 */
|
2014-05-24 21:11:02 +00:00
|
|
|
|
fmpz_poly_init(g);
|
|
|
|
|
fmpz_poly_set_coeff_si(g, 0, -1);
|
|
|
|
|
fmpz_poly_set_coeff_si(g, ctx->N, 1);
|
2014-04-29 12:27:15 +00:00
|
|
|
|
|
2014-04-17 15:37:30 +00:00
|
|
|
|
/* avoid side effects */
|
2014-05-24 21:11:02 +00:00
|
|
|
|
fmpz_poly_init(a_tmp);
|
|
|
|
|
fmpz_poly_set(a_tmp, a);
|
|
|
|
|
fmpz_poly_zero(Fq);
|
2014-04-17 15:37:30 +00:00
|
|
|
|
|
2014-04-16 21:23:41 +00:00
|
|
|
|
while (1) {
|
2014-05-24 21:11:02 +00:00
|
|
|
|
while (fmpz_is_zero(fmpz_poly_get_coeff_ptr(f, 0))) {
|
2014-04-16 21:23:41 +00:00
|
|
|
|
for (unsigned int i = 1; i <= ctx->N; i++) {
|
2014-05-24 21:11:02 +00:00
|
|
|
|
fmpz *f_coeff = fmpz_poly_get_coeff_ptr(f, i);
|
|
|
|
|
fmpz *c_coeff = fmpz_poly_get_coeff_ptr(c, ctx->N - i);
|
|
|
|
|
|
2014-04-29 12:27:15 +00:00
|
|
|
|
/* f(x) = f(x) / x */
|
2014-05-24 21:11:02 +00:00
|
|
|
|
fmpz_poly_set_coeff_fmpz_n(f, i - 1,
|
|
|
|
|
f_coeff);
|
|
|
|
|
|
2014-04-29 12:27:15 +00:00
|
|
|
|
/* c(x) = c(x) * x */
|
2014-05-24 21:11:02 +00:00
|
|
|
|
fmpz_poly_set_coeff_fmpz_n(c, ctx->N + 1 - i,
|
|
|
|
|
c_coeff);
|
2014-04-16 21:23:41 +00:00
|
|
|
|
}
|
2014-05-24 21:11:02 +00:00
|
|
|
|
|
|
|
|
|
fmpz_poly_set_coeff_si(f, ctx->N, 0);
|
|
|
|
|
fmpz_poly_set_coeff_si(c, 0, 0);
|
|
|
|
|
|
2014-04-16 21:23:41 +00:00
|
|
|
|
k++;
|
2014-05-24 21:11:02 +00:00
|
|
|
|
|
|
|
|
|
if (fmpz_poly_degree(f) == -1) {
|
|
|
|
|
retval = false;
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
2014-04-16 21:23:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-05-24 21:11:02 +00:00
|
|
|
|
if (fmpz_poly_degree(f) == 0)
|
2014-04-30 15:22:57 +00:00
|
|
|
|
break;
|
2014-04-16 21:23:41 +00:00
|
|
|
|
|
2014-05-24 21:11:02 +00:00
|
|
|
|
if (fmpz_poly_degree(f) < fmpz_poly_degree(g)) {
|
|
|
|
|
fmpz_poly_swap(f, g);
|
|
|
|
|
fmpz_poly_swap(b, c);
|
2014-04-16 21:23:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-05-24 21:11:02 +00:00
|
|
|
|
fmpz_poly_add(f, g, f);
|
|
|
|
|
fmpz_poly_mod_unsigned(f, 2);
|
|
|
|
|
|
|
|
|
|
fmpz_poly_add(b, c, b);
|
|
|
|
|
fmpz_poly_mod_unsigned(b, 2);
|
2014-04-16 21:23:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
k = k % ctx->N;
|
|
|
|
|
|
2014-05-24 21:11:02 +00:00
|
|
|
|
b_last = fmpz_poly_get_coeff_ptr(b, ctx->N);
|
|
|
|
|
if (b_last && fmpz_cmp_si(b_last, 0)) {
|
|
|
|
|
retval = false;
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
2014-05-12 22:20:46 +00:00
|
|
|
|
|
2014-04-29 12:27:15 +00:00
|
|
|
|
/* Fq(x) = x^(N-k) * b(x) */
|
2014-04-16 21:23:41 +00:00
|
|
|
|
for (int i = ctx->N - 1; i >= 0; i--) {
|
2014-05-24 21:11:02 +00:00
|
|
|
|
fmpz *b_i;
|
|
|
|
|
|
2014-04-16 21:23:41 +00:00
|
|
|
|
j = i - k;
|
2014-05-24 21:11:02 +00:00
|
|
|
|
|
2014-04-16 21:23:41 +00:00
|
|
|
|
if (j < 0)
|
|
|
|
|
j = j + ctx->N;
|
2014-05-24 21:11:02 +00:00
|
|
|
|
|
|
|
|
|
b_i = fmpz_poly_get_coeff_ptr(b, i);
|
|
|
|
|
fmpz_poly_set_coeff_fmpz_n(Fq, j, b_i);
|
2014-04-16 21:23:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-05-24 21:11:02 +00:00
|
|
|
|
poly_mod2_to_modq(a_tmp, Fq, ctx);
|
2014-04-16 21:23:41 +00:00
|
|
|
|
|
2014-05-24 21:11:02 +00:00
|
|
|
|
/* check if the f * Fq = 1 (mod p) condition holds true */
|
|
|
|
|
fmpz_poly_set(a_tmp, a);
|
|
|
|
|
poly_starmultiply(a_tmp, Fq, a_tmp, ctx, ctx->q);
|
|
|
|
|
if (!fmpz_poly_is_one(a_tmp))
|
|
|
|
|
retval = false;
|
2014-04-16 21:23:41 +00:00
|
|
|
|
|
2014-05-24 21:11:02 +00:00
|
|
|
|
cleanup:
|
|
|
|
|
fmpz_poly_clear(a_tmp);
|
|
|
|
|
fmpz_poly_clear(b);
|
|
|
|
|
fmpz_poly_clear(c);
|
|
|
|
|
fmpz_poly_clear(f);
|
|
|
|
|
fmpz_poly_clear(g);
|
2014-04-16 21:23:41 +00:00
|
|
|
|
|
2014-05-24 21:11:02 +00:00
|
|
|
|
if (!retval)
|
|
|
|
|
fmpz_poly_zero(Fq);
|
2014-04-16 21:23:41 +00:00
|
|
|
|
|
2014-05-24 21:11:02 +00:00
|
|
|
|
return retval;
|
2014-04-16 21:23:41 +00:00
|
|
|
|
}
|
2014-04-29 12:27:52 +00:00
|
|
|
|
|
|
|
|
|
/**
|
2014-05-24 21:11:02 +00:00
|
|
|
|
* Compute the inverse of a polynomial in (Z/pZ)[X]/(X^N - 1).
|
|
|
|
|
* See NTRU Cryptosystems Tech Report #014 "Almost Inverses
|
|
|
|
|
* and Fast NTRU Key Creation."
|
2014-04-29 12:27:52 +00:00
|
|
|
|
*
|
|
|
|
|
* @param a polynomial to invert
|
2014-05-24 23:13:34 +00:00
|
|
|
|
* @param Fp polynomial [out]
|
2014-04-29 12:27:52 +00:00
|
|
|
|
* @param ctx NTRU context
|
|
|
|
|
*/
|
2014-05-24 21:11:02 +00:00
|
|
|
|
bool poly_inverse_poly_p(fmpz_poly_t a,
|
|
|
|
|
fmpz_poly_t Fp,
|
2014-04-29 12:27:52 +00:00
|
|
|
|
ntru_context *ctx)
|
|
|
|
|
{
|
2014-05-24 21:11:02 +00:00
|
|
|
|
bool retval = true;
|
2014-04-29 12:27:52 +00:00
|
|
|
|
int k = 0,
|
|
|
|
|
j = 0;
|
2014-05-24 21:11:02 +00:00
|
|
|
|
fmpz *b_last;
|
|
|
|
|
fmpz_poly_t a_tmp,
|
|
|
|
|
b,
|
|
|
|
|
c,
|
|
|
|
|
f,
|
|
|
|
|
g;
|
2014-04-29 12:27:52 +00:00
|
|
|
|
|
|
|
|
|
/* general initialization of temp variables */
|
2014-05-24 21:11:02 +00:00
|
|
|
|
fmpz_poly_init(b);
|
|
|
|
|
fmpz_poly_set_coeff_ui(b, 0, 1);
|
|
|
|
|
fmpz_poly_init(c);
|
|
|
|
|
fmpz_poly_init(f);
|
|
|
|
|
fmpz_poly_set(f, a);
|
2014-04-29 12:27:52 +00:00
|
|
|
|
|
|
|
|
|
/* set g(x) = x^N − 1 */
|
2014-05-24 21:11:02 +00:00
|
|
|
|
fmpz_poly_init(g);
|
|
|
|
|
fmpz_poly_set_coeff_si(g, 0, -1);
|
|
|
|
|
fmpz_poly_set_coeff_si(g, ctx->N, 1);
|
2014-04-29 12:27:52 +00:00
|
|
|
|
|
|
|
|
|
/* avoid side effects */
|
2014-05-24 21:11:02 +00:00
|
|
|
|
fmpz_poly_init(a_tmp);
|
|
|
|
|
fmpz_poly_set(a_tmp, a);
|
|
|
|
|
fmpz_poly_zero(Fp);
|
2014-04-29 12:27:52 +00:00
|
|
|
|
|
|
|
|
|
while (1) {
|
2014-05-24 21:11:02 +00:00
|
|
|
|
while (fmpz_is_zero(fmpz_poly_get_coeff_ptr(f, 0))) {
|
2014-04-29 12:27:52 +00:00
|
|
|
|
for (unsigned int i = 1; i <= ctx->N; i++) {
|
2014-05-24 21:11:02 +00:00
|
|
|
|
fmpz *f_coeff_tmp = fmpz_poly_get_coeff_ptr(f, i);
|
|
|
|
|
fmpz *c_coeff_tmp = fmpz_poly_get_coeff_ptr(c, ctx->N - i);
|
|
|
|
|
|
2014-04-29 12:27:52 +00:00
|
|
|
|
/* f(x) = f(x) / x */
|
2014-05-24 21:11:02 +00:00
|
|
|
|
fmpz_poly_set_coeff_fmpz_n(f, i - 1,
|
|
|
|
|
f_coeff_tmp);
|
|
|
|
|
|
2014-04-29 12:27:52 +00:00
|
|
|
|
/* c(x) = c(x) * x */
|
2014-05-24 21:11:02 +00:00
|
|
|
|
fmpz_poly_set_coeff_fmpz_n(c, ctx->N + 1 - i,
|
|
|
|
|
c_coeff_tmp);
|
2014-04-29 12:27:52 +00:00
|
|
|
|
}
|
2014-05-24 21:11:02 +00:00
|
|
|
|
|
|
|
|
|
fmpz_poly_set_coeff_si(f, ctx->N, 0);
|
|
|
|
|
fmpz_poly_set_coeff_si(c, 0, 0);
|
|
|
|
|
|
2014-04-29 12:27:52 +00:00
|
|
|
|
k++;
|
2014-05-24 21:11:02 +00:00
|
|
|
|
|
|
|
|
|
if (fmpz_poly_degree(f) == -1) {
|
|
|
|
|
retval = false;
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
2014-04-29 12:27:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-05-24 21:11:02 +00:00
|
|
|
|
if (fmpz_poly_degree(f) == 0)
|
2014-04-30 15:22:57 +00:00
|
|
|
|
break;
|
2014-04-29 12:27:52 +00:00
|
|
|
|
|
2014-05-24 21:11:02 +00:00
|
|
|
|
if (fmpz_poly_degree(f) < fmpz_poly_degree(g)) {
|
2014-04-29 17:59:59 +00:00
|
|
|
|
/* exchange f and g and exchange b and c */
|
2014-05-24 21:11:02 +00:00
|
|
|
|
fmpz_poly_swap(f, g);
|
|
|
|
|
fmpz_poly_swap(b, c);
|
2014-04-29 12:27:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
2014-05-24 21:11:02 +00:00
|
|
|
|
fmpz_poly_t c_tmp,
|
|
|
|
|
g_tmp;
|
|
|
|
|
fmpz_t u,
|
|
|
|
|
mp_tmp;
|
|
|
|
|
|
|
|
|
|
fmpz_init(u);
|
|
|
|
|
fmpz_zero(u);
|
|
|
|
|
|
|
|
|
|
fmpz_init_set(mp_tmp, fmpz_poly_get_coeff_ptr(f, 0));
|
|
|
|
|
|
|
|
|
|
fmpz_poly_init(g_tmp);
|
|
|
|
|
fmpz_poly_set(g_tmp, g);
|
|
|
|
|
|
|
|
|
|
fmpz_poly_init(c_tmp);
|
|
|
|
|
fmpz_poly_set(c_tmp, c);
|
|
|
|
|
|
|
|
|
|
/* u = f[0] * g[0]^(-1) mod p */
|
|
|
|
|
/* = (f[0] mod p) * (g[0] inverse mod p) mod p */
|
|
|
|
|
fmpz_invmod_ui(u,
|
|
|
|
|
fmpz_poly_get_coeff_ptr(g, 0),
|
|
|
|
|
ctx->p);
|
|
|
|
|
fmpz_mod_ui(mp_tmp, mp_tmp, ctx->p);
|
|
|
|
|
fmpz_mul(u, mp_tmp, u);
|
|
|
|
|
fmpz_mod_ui(u, u, ctx->p);
|
2014-04-29 12:27:52 +00:00
|
|
|
|
|
|
|
|
|
/* f = f - u * g mod p */
|
2014-05-24 21:11:02 +00:00
|
|
|
|
fmpz_poly_scalar_mul_fmpz(g_tmp, g_tmp, u);
|
|
|
|
|
fmpz_poly_sub(f, g_tmp, f);
|
|
|
|
|
fmpz_poly_mod_unsigned(f, ctx->p);
|
2014-04-29 12:27:52 +00:00
|
|
|
|
|
|
|
|
|
/* b = b - u * c mod p */
|
2014-05-24 21:11:02 +00:00
|
|
|
|
fmpz_poly_scalar_mul_fmpz(c_tmp, c_tmp, u);
|
|
|
|
|
fmpz_poly_sub(b, c_tmp, b);
|
|
|
|
|
fmpz_poly_mod_unsigned(b, ctx->p);
|
2014-04-29 12:27:52 +00:00
|
|
|
|
|
2014-05-24 21:11:02 +00:00
|
|
|
|
fmpz_clear(u);
|
|
|
|
|
fmpz_poly_clear(g_tmp);
|
|
|
|
|
fmpz_poly_clear(c_tmp);
|
2014-04-29 12:27:52 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
k = k % ctx->N;
|
|
|
|
|
|
2014-05-24 21:11:02 +00:00
|
|
|
|
b_last = fmpz_poly_get_coeff_ptr(b, ctx->N);
|
|
|
|
|
if (b_last && fmpz_cmp_si(b_last, 0)) {
|
|
|
|
|
retval = false;
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-29 12:27:52 +00:00
|
|
|
|
/* Fp(x) = x^(N-k) * b(x) */
|
|
|
|
|
for (int i = ctx->N - 1; i >= 0; i--) {
|
2014-05-24 21:11:02 +00:00
|
|
|
|
fmpz *b_i;
|
2014-04-29 12:27:52 +00:00
|
|
|
|
|
|
|
|
|
/* b(X) = f[0]^(-1) * b(X) (mod p) */
|
|
|
|
|
{
|
2014-05-24 21:11:02 +00:00
|
|
|
|
fmpz_t mp_tmp;
|
2014-04-29 12:27:52 +00:00
|
|
|
|
|
2014-05-24 21:11:02 +00:00
|
|
|
|
fmpz_init(mp_tmp);
|
2014-04-29 12:27:52 +00:00
|
|
|
|
|
2014-05-24 21:11:02 +00:00
|
|
|
|
fmpz_invmod_ui(mp_tmp,
|
|
|
|
|
fmpz_poly_get_coeff_ptr(f, 0),
|
|
|
|
|
ctx->p);
|
2014-04-29 12:27:52 +00:00
|
|
|
|
|
2014-05-24 21:11:02 +00:00
|
|
|
|
if (fmpz_poly_get_coeff_ptr(b, i)) {
|
|
|
|
|
fmpz_mul(fmpz_poly_get_coeff_ptr(b, i),
|
|
|
|
|
fmpz_poly_get_coeff_ptr(b, i),
|
|
|
|
|
mp_tmp);
|
|
|
|
|
fmpz_mod_ui(fmpz_poly_get_coeff_ptr(b, i),
|
|
|
|
|
fmpz_poly_get_coeff_ptr(b, i),
|
|
|
|
|
ctx->p);
|
|
|
|
|
}
|
2014-04-16 21:23:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-04-29 12:27:52 +00:00
|
|
|
|
j = i - k;
|
|
|
|
|
if (j < 0)
|
|
|
|
|
j = j + ctx->N;
|
|
|
|
|
|
2014-05-24 21:11:02 +00:00
|
|
|
|
b_i = fmpz_poly_get_coeff_ptr(b, i);
|
|
|
|
|
fmpz_poly_set_coeff_fmpz_n(Fp, j, b_i);
|
2014-04-29 12:27:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-05-24 21:11:02 +00:00
|
|
|
|
/* check if the f * Fq = 1 (mod p) condition holds true */
|
|
|
|
|
fmpz_poly_set(a_tmp, a);
|
|
|
|
|
poly_starmultiply(a_tmp, Fp, a_tmp, ctx, ctx->p);
|
|
|
|
|
if (!fmpz_poly_is_one(a_tmp))
|
|
|
|
|
retval = false;
|
2014-04-16 21:23:41 +00:00
|
|
|
|
|
2014-05-24 21:11:02 +00:00
|
|
|
|
cleanup:
|
|
|
|
|
fmpz_poly_clear(a_tmp);
|
|
|
|
|
fmpz_poly_clear(b);
|
|
|
|
|
fmpz_poly_clear(c);
|
|
|
|
|
fmpz_poly_clear(f);
|
|
|
|
|
fmpz_poly_clear(g);
|
2014-04-20 14:45:05 +00:00
|
|
|
|
|
2014-05-24 21:11:02 +00:00
|
|
|
|
if (!retval)
|
|
|
|
|
fmpz_poly_zero(Fp);
|
2014-05-12 11:46:59 +00:00
|
|
|
|
|
2014-05-24 21:11:02 +00:00
|
|
|
|
return retval;
|
2014-05-12 11:46:59 +00:00
|
|
|
|
}
|
2014-05-24 23:40:07 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Draws a polynomial to stdout.
|
|
|
|
|
*
|
|
|
|
|
* @param poly draw this
|
|
|
|
|
*/
|
|
|
|
|
void poly_draw(fmpz_poly_t poly)
|
|
|
|
|
{
|
|
|
|
|
fmpz_poly_print(poly);
|
|
|
|
|
flint_printf("\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Draws a polynomial to stdout,
|
|
|
|
|
* in pretty format.
|
|
|
|
|
*
|
|
|
|
|
* @param poly draw this
|
|
|
|
|
*/
|
|
|
|
|
void poly_draw_pretty(fmpz_poly_t poly)
|
|
|
|
|
{
|
|
|
|
|
fmpz_poly_print_pretty(poly, "x");
|
|
|
|
|
flint_printf("\n");
|
|
|
|
|
}
|