static void poly_mod2_to_modq(fmpz_poly_t Fq, const fmpz_poly_t a, const ntru_params *params) { int v = 2; fmpz_poly_t poly_tmp, two; fmpz_poly_init(poly_tmp); fmpz_poly_zero(poly_tmp); fmpz_poly_init(two); fmpz_poly_set_coeff_ui(two, 0, 2); while (v < (int)(params->q)) { v = v * 2; poly_starmultiply(poly_tmp, a, Fq, params, v); fmpz_poly_sub(poly_tmp, two, poly_tmp); fmpz_poly_mod_unsigned(poly_tmp, v); poly_starmultiply(Fq, Fq, poly_tmp, params, v); } fmpz_poly_clear(poly_tmp); fmpz_poly_clear(two); }
int main(void) { int i, result; FLINT_TEST_INIT(state); flint_printf("pseudo_div...."); fflush(stdout); /* Check r = a - q * b has small degree, no aliasing */ for (i = 0; i < 200 * flint_test_multiplier(); i++) { fmpz_poly_t a, b, q, r, prod; fmpz_t p; ulong d; fmpz_init(p); fmpz_poly_init(a); fmpz_poly_init(b); fmpz_poly_init(q); fmpz_poly_init(r); fmpz_poly_init(prod); fmpz_poly_randtest(a, state, n_randint(state, 100), 50); fmpz_poly_randtest_not_zero(b, state, n_randint(state, 100) + 1, 50); fmpz_poly_pseudo_div(q, &d, a, b); fmpz_poly_mul(prod, q, b); fmpz_pow_ui(p, b->coeffs + b->length - 1, d); fmpz_poly_scalar_mul_fmpz(a, a, p); fmpz_poly_sub(r, a, prod); result = (fmpz_poly_length(r) < fmpz_poly_length(b)); if (!result) { flint_printf("FAIL:\n"); fmpz_poly_print(a), flint_printf("\n\n"); fmpz_poly_print(prod), flint_printf("\n\n"); fmpz_poly_print(q), flint_printf("\n\n"); fmpz_poly_print(r), flint_printf("\n\n"); abort(); } fmpz_clear(p); fmpz_poly_clear(a); fmpz_poly_clear(b); fmpz_poly_clear(q); fmpz_poly_clear(r); fmpz_poly_clear(prod); } /* Check q and a alias */ for (i = 0; i < 50 * flint_test_multiplier(); i++) { fmpz_poly_t a, b, q; ulong d; fmpz_poly_init(a); fmpz_poly_init(b); fmpz_poly_init(q); fmpz_poly_randtest(a, state, n_randint(state, 100), 50); fmpz_poly_randtest_not_zero(b, state, n_randint(state, 100) + 1, 50); fmpz_poly_pseudo_div(q, &d, a, b); fmpz_poly_pseudo_div(a, &d, a, b); result = (fmpz_poly_equal(a, q)); if (!result) { flint_printf("FAIL:\n"); fmpz_poly_print(a), flint_printf("\n\n"); fmpz_poly_print(q), flint_printf("\n\n"); abort(); } fmpz_poly_clear(a); fmpz_poly_clear(b); fmpz_poly_clear(q); } /* Check q and b alias */ for (i = 0; i < 50 * flint_test_multiplier(); i++) { fmpz_poly_t a, b, q; ulong d; fmpz_poly_init(a); fmpz_poly_init(b); fmpz_poly_init(q); fmpz_poly_randtest(a, state, n_randint(state, 100), 50); fmpz_poly_randtest_not_zero(b, state, n_randint(state, 100) + 1, 50); fmpz_poly_pseudo_div(q, &d, a, b); fmpz_poly_pseudo_div(b, &d, a, b); result = (fmpz_poly_equal(b, q)); if (!result) { flint_printf("FAIL:\n"); fmpz_poly_print(a), flint_printf("\n\n"); fmpz_poly_print(q), flint_printf("\n\n"); abort(); } fmpz_poly_clear(a); fmpz_poly_clear(b); fmpz_poly_clear(q); } FLINT_TEST_CLEANUP(state); flint_printf("PASS\n"); return 0; }
bool poly_inverse_poly_p(fmpz_poly_t Fp, const fmpz_poly_t a, const ntru_params *params) { bool retval = false; int k = 0, j = 0; fmpz *b_last; fmpz_poly_t a_tmp, b, c, f, g; /* general initialization of temp variables */ 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); /* set g(x) = x^N − 1 */ fmpz_poly_init(g); fmpz_poly_set_coeff_si(g, 0, -1); fmpz_poly_set_coeff_si(g, params->N, 1); /* avoid side effects */ fmpz_poly_init(a_tmp); fmpz_poly_set(a_tmp, a); fmpz_poly_zero(Fp); while (1) { while (fmpz_poly_get_coeff_ptr(f, 0) && fmpz_is_zero(fmpz_poly_get_coeff_ptr(f, 0))) { for (uint32_t i = 1; i <= params->N; i++) { fmpz *f_coeff = fmpz_poly_get_coeff_ptr(f, i); fmpz *c_coeff = fmpz_poly_get_coeff_ptr(c, params->N - i); /* f(x) = f(x) / x */ fmpz_poly_set_coeff_fmpz_n(f, i - 1, f_coeff); /* c(x) = c(x) * x */ fmpz_poly_set_coeff_fmpz_n(c, params->N + 1 - i, c_coeff); } fmpz_poly_set_coeff_si(f, params->N, 0); fmpz_poly_set_coeff_si(c, 0, 0); k++; if (fmpz_poly_degree(f) == -1) goto cleanup; } if (fmpz_poly_is_zero(g) == 1) goto cleanup; if (fmpz_poly_degree(f) == 0) break; if (fmpz_poly_degree(f) < fmpz_poly_degree(g)) { /* exchange f and g and exchange b and c */ fmpz_poly_swap(f, g); fmpz_poly_swap(b, c); } { 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), params->p); fmpz_mod_ui(mp_tmp, mp_tmp, params->p); fmpz_mul(u, mp_tmp, u); fmpz_mod_ui(u, u, params->p); /* f = f - u * g mod p */ fmpz_poly_scalar_mul_fmpz(g_tmp, g_tmp, u); fmpz_poly_sub(f, f, g_tmp); fmpz_poly_mod_unsigned(f, params->p); /* b = b - u * c mod p */ fmpz_poly_scalar_mul_fmpz(c_tmp, c_tmp, u); fmpz_poly_sub(b, b, c_tmp); fmpz_poly_mod_unsigned(b, params->p); fmpz_clear(u); fmpz_poly_clear(g_tmp); fmpz_poly_clear(c_tmp); } } k = k % params->N; b_last = fmpz_poly_get_coeff_ptr(b, params->N); if (fmpz_cmp_si_n(b_last, 0)) goto cleanup; /* Fp(x) = x^(N-k) * b(x) */ for (int i = params->N - 1; i >= 0; i--) { fmpz *b_i; /* b(X) = f[0]^(-1) * b(X) (mod p) */ { fmpz_t mp_tmp; fmpz_init(mp_tmp); fmpz_invmod_ui(mp_tmp, fmpz_poly_get_coeff_ptr(f, 0), params->p); 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), params->p); } } j = i - k; if (j < 0) j = j + params->N; b_i = fmpz_poly_get_coeff_ptr(b, i); fmpz_poly_set_coeff_fmpz_n(Fp, j, b_i); } /* check if the f * Fp = 1 (mod p) condition holds true */ fmpz_poly_set(a_tmp, a); poly_starmultiply(a_tmp, a_tmp, Fp, params, params->p); if (fmpz_poly_is_one(a_tmp)) retval = true; else fmpz_poly_zero(Fp); cleanup: fmpz_poly_clear(a_tmp); fmpz_poly_clear(b); fmpz_poly_clear(c); fmpz_poly_clear(f); fmpz_poly_clear(g); return retval; }