NTRU_IoT/infidel-code/test/check_internal_poly.c

480 lines
14 KiB
C
Raw Permalink Normal View History

2022-02-01 11:45:47 -05:00
#include <check.h>
#include "ntru_crypto.h"
#include "ntru_crypto_ntru_encrypt_param_sets.h"
#include "ntru_crypto_ntru_mgf1.h"
#include "ntru_crypto_ntru_poly.h"
#include "test_common.h"
#include "check_common.h"
START_TEST(test_gen_poly)
{
uint32_t rc;
uint32_t i;
uint32_t j;
uint8_t md_len;
uint16_t seed_len;
uint16_t mgf_buf_len;
uint16_t num_indices = 0;
NTRU_ENCRYPT_PARAM_SET *params = NULL;
NTRU_ENCRYPT_PARAM_SET_ID param_set_id;
NTRU_CRYPTO_HASH_ALGID hash_algid;
uint8_t *seed_buf_p;
uint8_t *mgf_buf_p;
uint16_t *F_buf_1_p;
uint16_t *F_buf_2_p;
NTRU_CK_MEM seed_buf;
NTRU_CK_MEM mgf_buf;
NTRU_CK_MEM F_buf_1;
NTRU_CK_MEM F_buf_2;
/* Get the parameter set */
param_set_id = PARAM_SET_IDS[_i];
params = ntru_encrypt_get_params_with_id(param_set_id);
ck_assert_ptr_ne(params, NULL);
if (params->hash_algid == NTRU_CRYPTO_HASH_ALGID_SHA1)
{
hash_algid = NTRU_CRYPTO_HASH_ALGID_SHA1;
md_len = SHA_1_MD_LEN;
}
else if (params->hash_algid == NTRU_CRYPTO_HASH_ALGID_SHA256)
{
hash_algid = NTRU_CRYPTO_HASH_ALGID_SHA256;
md_len = SHA_256_MD_LEN;
}
else
{
ck_assert(0);
}
seed_len = 2 * params->sec_strength_len;
mgf_buf_len = 4 + params->N + md_len * (1+params->min_IGF_hash_calls);
if(params->is_product_form)
{
/* Need 2 * (dF1 + dF2 + dF3) indices) */
num_indices = (params->dF_r & 0x000000ff);
num_indices += (params->dF_r & 0x0000ff00) >> 8;
num_indices += (params->dF_r & 0x00ff0000) >> 16;
num_indices *= 2;
}
else
{
num_indices = 2 * params->dF_r;
}
seed_buf_p = ntru_ck_malloc(&seed_buf, seed_len*sizeof(*seed_buf_p));
mgf_buf_p = ntru_ck_malloc(&mgf_buf, mgf_buf_len*sizeof(*mgf_buf_p));
F_buf_1_p = (uint16_t *) ntru_ck_malloc(&F_buf_1,
num_indices*sizeof(F_buf_1_p));
F_buf_2_p = (uint16_t *) ntru_ck_malloc(&F_buf_2,
num_indices*sizeof(F_buf_2_p));
/* Generate a random seed */
rc = ntru_crypto_drbg_generate(drbg, params->sec_strength_len << 3,
seed_len, seed_buf_p);
ck_assert_uint_eq(rc, DRBG_RESULT(DRBG_OK));
/* Generate an "F" type polynomial for this parameter set */
rc = ntru_gen_poly(hash_algid, md_len,
params->min_IGF_hash_calls,
seed_len, seed_buf_p, mgf_buf_p,
params->N, params->c_bits,
params->no_bias_limit,
params->is_product_form,
params->dF_r << 1, F_buf_1_p);
ck_assert_uint_eq(rc, NTRU_RESULT(NTRU_OK));
/* Check that indices are pairwise distinct (per poly for prod-form) */
if(params->is_product_form)
{
uint16_t *Fp;
uint32_t c;
Fp = F_buf_1_p;
c = params->dF_r << 1;
while(c > 0) /* High byte of c is 0x00 */
{
for(i=0; i<(c&0xff)-1; i++)
{
for(j=i+1; j<(c&0xff); j++)
{
ck_assert_uint_ne(Fp[i], Fp[j]);
}
}
Fp += c & 0xff;
c >>= 8;
}
}
else
{
for(i=0; i<2*params->dF_r - 1; i++)
{
for(j=i+1; j<2*params->dF_r; j++)
{
ck_assert_uint_ne(F_buf_1_p[i], F_buf_1_p[j]);
}
}
}
/* Check that we get the same polynomial if we reuse the seed */
rc = ntru_gen_poly(hash_algid, md_len,
params->min_IGF_hash_calls,
seed_len, seed_buf_p, mgf_buf_p,
params->N, params->c_bits,
params->no_bias_limit,
params->is_product_form,
params->dF_r << 1, F_buf_2_p);
ck_assert_uint_eq(rc, NTRU_RESULT(NTRU_OK));
ck_assert_int_eq(
memcmp(F_buf_1_p, F_buf_2_p, num_indices*sizeof(uint16_t)), 0);
/* Check some failure cases */
/* Trigger an mgf failure with an unknown hash_algid */
rc = ntru_gen_poly(-1, md_len,
params->min_IGF_hash_calls,
seed_len, seed_buf_p, mgf_buf_p,
params->N, params->c_bits,
params->no_bias_limit,
params->is_product_form,
params->dF_r << 1, F_buf_2_p);
ck_assert_uint_ne(rc, NTRU_RESULT(NTRU_OK));
ntru_ck_mem_ok(&F_buf_2);
ntru_ck_mem_ok(&F_buf_1);
ntru_ck_mem_ok(&mgf_buf);
ntru_ck_mem_ok(&seed_buf);
ntru_ck_mem_free(&F_buf_2);
ntru_ck_mem_free(&F_buf_1);
ntru_ck_mem_free(&mgf_buf);
ntru_ck_mem_free(&seed_buf);
}
END_TEST
START_TEST(test_min_weight)
{
uint8_t tpoly1[13] = {2, 2, 2, 2, 0, 0, 0, 0, 0, 1, 1, 1, 1};
ck_assert_int_eq(ntru_poly_check_min_weight(13, tpoly1, 4), TRUE);
ck_assert_int_eq(ntru_poly_check_min_weight(13, tpoly1, 5), FALSE);
}
END_TEST
/* test_inv_mod_2
*
* Compares the result of ntru_ring_inv to a fixed value precomputed
* with Pari/GP. Also checks that non-trivial non-invertible elements (factors
* of x^N - 1 mod 2) are recognized as such.
*/
START_TEST(test_inv_mod_2)
{
uint16_t tmp[34];
uint16_t out[17];
uint16_t a[17] = {1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1};
uint16_t test_a[17] = {1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1};
uint16_t b[17] = {1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0};
/* a is invertible with inverse equal to test_a */
ck_assert_int_eq(ntru_ring_inv(a, 17, tmp, out), TRUE);
ck_assert_int_eq(memcmp(out, test_a, sizeof(a)), 0);
/* Test error cases */
/* Changing the parity of a makes it trivially non-invertible */
a[0] = 0;
ck_assert_int_eq(ntru_ring_inv(a, 17, tmp, out), FALSE);
/* b is a nontrivial factor of x^17 - 1 mod 2 */
ck_assert_int_eq(ntru_ring_inv(b, 17, tmp, out), FALSE);
/* Input not provided */
ck_assert_int_eq(ntru_ring_inv(NULL, 17, tmp, out), FALSE);
ck_assert_int_eq(ntru_ring_inv(a, 17, NULL, out), FALSE);
ck_assert_int_eq(ntru_ring_inv(a, 17, tmp, NULL), FALSE);
}
END_TEST
/* test_lift_inv_mod_pow2
*/
START_TEST(test_lift_inv_mod_pow2)
{
uint32_t i;
uint16_t f_inv2[17] = {1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1};
uint16_t f1l = 2;
uint16_t f2l = 2;
uint16_t f3l = 3;
uint16_t fprod[14] = {7, 10, 9, 13, 1, 13, 6, 8, 4, 10, 11, 6, 9, 15};
uint16_t f[17] = {4, 65533, 3, 3, 6, 65533, 0, 0, 3, 65530, 0, 6, 0,
65533, 65533, 65533, 65533};
uint16_t inv_test[17] = {7319, 52697, 32987, 43221, 48819, 42807, 18160,
1250, 48426, 16935, 30796, 41596, 5768, 33264, 16639, 54271, 29334};
uint16_t N = 17;
uint16_t q = 0;
NTRU_CK_MEM scratch;
uint16_t * scratch_p;
NTRU_CK_MEM pol1;
NTRU_CK_MEM pol2;
uint16_t * pol1_p;
uint16_t * pol2_p;
uint16_t scratch_polys;
uint16_t pad_deg;
ntru_ring_mult_coefficients_memreq(N, &scratch_polys, &pad_deg);
ck_assert_uint_ge(scratch_polys, 1);
ck_assert_uint_ge(pad_deg, N);
/* Allocate memory */
scratch_p = (uint16_t*)ntru_ck_malloc(&scratch,
(1+scratch_polys) * pad_deg * sizeof(uint16_t));
pol1_p = (uint16_t*)ntru_ck_malloc(&pol1, pad_deg * sizeof(uint16_t));
pol2_p = (uint16_t*)ntru_ck_malloc(&pol2, pad_deg * sizeof(uint16_t));
/* We should be able to work with dirty scratch space */
randombytes(scratch.ptr, scratch.len);
/* Copy and pad the inputs */
memset(pol1.ptr, 0, pol1.len);
memset(pol2.ptr, 0, pol2.len);
memcpy(pol1_p, f_inv2, N*sizeof(uint16_t));
memcpy(pol2_p, f, N*sizeof(uint16_t));
/* Lift the inverse with f in coefficient form and check */
ntru_ring_lift_inv_pow2_standard(pol1_p, pol2_p, N, q, scratch_p);
for(i=0; i<N; i++)
{
ck_assert_uint_eq(pol1_p[i], inv_test[i]);
}
for(; i<pad_deg; i++)
{
ck_assert_uint_eq(pol1_p[i], 0);
}
randombytes(scratch.ptr, scratch.len);
memset(pol1.ptr, 0, pol1.len);
memcpy(pol1_p, f_inv2, N*sizeof(uint16_t));
/* Lift the inverse with f in product form and check */
ntru_ring_lift_inv_pow2_product(pol1_p, f1l, f2l, f3l, fprod, N, q, scratch_p);
for(i=0; i<N; i++)
{
ck_assert_uint_eq(pol1_p[i], inv_test[i]);
}
for(; i<pad_deg; i++)
{
ck_assert_uint_eq(pol1_p[i], 0);
}
ntru_ck_mem_ok(&scratch);
ntru_ck_mem_ok(&pol1);
ntru_ck_mem_ok(&pol2);
ntru_ck_mem_free(&scratch);
ntru_ck_mem_free(&pol1);
ntru_ck_mem_free(&pol2);
}
END_TEST
/* test_mult_indices
*
* Performs both ntru_ring_mult_indices and ntru_ring_mult_product_indices
* and compares the result with a fixed example generated with Pari/GP.
*/
START_TEST(test_mult_indices)
{
uint32_t i;
uint16_t a[17] = {36486, 20395, 8746, 16637, 26195, 1654, 24222, 13306,
9573, 26946, 29106, 2401, 32146, 2871, 41930, 7902, 3398};
uint16_t b1l = 2;
uint16_t b2l = 2;
uint16_t b3l = 3;
uint16_t bi[14] = {7, 10, 9, 13, 1, 13, 6, 8, 4, 10, 11, 6, 9, 15};
uint16_t test_single[17] = {6644, 48910, 5764, 16270, 2612, 10231, 769,
2577, 58289, 38323, 56334, 29942, 55901, 43714, 17452, 43795, 21225};
uint16_t test_prod[17] = {40787, 24792, 27808, 13989, 56309, 37625, 37436,
32307, 15311, 59789, 32769, 65008, 3711, 54663, 25343, 55984, 6193};
uint16_t N = 17;
uint16_t q = 0;
NTRU_CK_MEM pol1;
NTRU_CK_MEM t;
NTRU_CK_MEM out;
uint16_t *pol1_p;
uint16_t *t_p;
uint16_t *out_p;
uint16_t scratch_polys;
uint16_t pad_deg;
ntru_ring_mult_indices_memreq(N, &scratch_polys, &pad_deg);
ck_assert_uint_ge(scratch_polys, 1);
ck_assert_uint_ge(pad_deg, N);
pol1_p = (uint16_t*)ntru_ck_malloc(&pol1, pad_deg*sizeof(*pol1_p));
t_p = (uint16_t*)ntru_ck_malloc(&t, (scratch_polys+1)*pad_deg*sizeof(*t_p));
out_p = (uint16_t*)ntru_ck_malloc(&out, pad_deg*sizeof(*out_p));
/* Copy and pad the input */
memset(pol1.ptr, 0, pol1.len);
memcpy(pol1_p, a, N*sizeof(uint16_t));
/* We should be able to work with dirty scratch and output memory */
randombytes(t.ptr, t.len);
randombytes(out.ptr, out.len);
/* Test a single mult_indices first */
ntru_ring_mult_indices(pol1_p, b1l, b1l, bi, N, q, t_p, out_p);
/* Check result */
for(i=0; i<N; i++)
{
ck_assert_uint_eq(out_p[i], test_single[i]);
} /* Check padding is zero */
for(; i<pad_deg; i++)
{
ck_assert_uint_eq(out_p[i], 0);
}
/* Check over/under runs */
ntru_ck_mem_ok(&pol1);
ntru_ck_mem_ok(&t);
ntru_ck_mem_ok(&out);
/* Now try a full product form multiplication */
randombytes(t.ptr, t.len);
randombytes(out.ptr, out.len);
/* Multiply */
ntru_ring_mult_product_indices(pol1_p, b1l, b2l, b3l, bi, N, q, t_p, out_p);
/* Check result */
for(i=0; i<N; i++)
{
ck_assert_uint_eq(out_p[i], test_prod[i]);
} /* Check padding is zero */
for(; i<pad_deg; i++)
{
ck_assert_uint_eq(out_p[i], 0);
}
/* Check over/under runs */
ntru_ck_mem_ok(&pol1);
ntru_ck_mem_ok(&t);
ntru_ck_mem_ok(&out);
ntru_ck_mem_free(&pol1);
ntru_ck_mem_free(&t);
ntru_ck_mem_free(&out);
}
END_TEST
START_TEST(test_mult_coefficients)
{
uint32_t i;
uint16_t a[17] = {36486, 20395, 8746, 16637, 26195, 1654, 24222, 13306,
9573, 26946, 29106, 2401, 32146, 2871, 41930, 7902, 3398};
uint16_t b[17] = {5266, 35261, 54826, 45380, 46459, 46509, 56767, 46916,
33670, 11921, 46519, 47628, 20388, 4167, 39405, 2712, 52748};
uint16_t test[17] = {30101, 45125, 62370, 2275, 34473, 7074, 62574, 57665,
5199, 4482, 49487, 17159, 33125, 11061, 19328, 22268, 46230};
uint16_t N = 17;
uint16_t q = 0;
/* Determine proper padding for our mult implementation */
uint16_t num_polys;
uint16_t num_coeffs;
ntru_ring_mult_coefficients_memreq(N, &num_polys, &num_coeffs);
/* Allocate memory */
NTRU_CK_MEM pol1;
NTRU_CK_MEM pol2;
NTRU_CK_MEM tmp;
NTRU_CK_MEM out;
uint16_t *a_p;
uint16_t *b_p;
uint16_t *tmp_p;
uint16_t *out_p;
a_p = (uint16_t*)ntru_ck_malloc(&pol1, num_coeffs*sizeof(uint16_t));
b_p = (uint16_t*)ntru_ck_malloc(&pol2, num_coeffs*sizeof(uint16_t));
tmp_p = (uint16_t*)ntru_ck_malloc(&tmp,
num_polys*num_coeffs*sizeof(uint16_t));
out_p = (uint16_t*)ntru_ck_malloc(&out, num_coeffs*sizeof(uint16_t));
/* Copy and pad the inputs */
memcpy(a_p, a, N*sizeof(uint16_t));
memcpy(b_p, b, N*sizeof(uint16_t));
memset(a_p+N, 0, (num_coeffs-N)*sizeof(uint16_t));
memset(b_p+N, 0, (num_coeffs-N)*sizeof(uint16_t));
/* Should work with dirty scratch and output memory */
randombytes(tmp.ptr+N, (num_coeffs-N)*sizeof(uint16_t));
randombytes(out.ptr, out.len);
/* Multiply */
ntru_ring_mult_coefficients(a_p, b_p, N, q, tmp_p, out_p);
/* Check result */
for(i=0; i<N; i++)
{
ck_assert_uint_eq(out_p[i], test[i]);
} /* Padding should be zero */
for(; i<num_coeffs; i++)
{
ck_assert_uint_eq(out_p[i], 0);
}
/* Check over/under runs */
ntru_ck_mem_ok(&pol1);
ntru_ck_mem_ok(&pol2);
ntru_ck_mem_ok(&tmp);
ntru_ck_mem_ok(&out);
ntru_ck_mem_free(&pol1);
ntru_ck_mem_free(&pol2);
ntru_ck_mem_free(&tmp);
ntru_ck_mem_free(&out);
}
END_TEST
Suite *
ntruencrypt_internal_poly_suite(void)
{
Suite *s;
TCase *tc_poly;
s = suite_create("NTRUEncrypt.Internal.Poly");
tc_poly = tcase_create("Poly");
tcase_add_unchecked_fixture(tc_poly, test_drbg_setup, test_drbg_teardown);
tcase_add_loop_test(tc_poly, test_gen_poly, 0, NUM_PARAM_SETS);
tcase_add_test(tc_poly, test_min_weight);
tcase_add_test(tc_poly, test_inv_mod_2);
tcase_add_test(tc_poly, test_lift_inv_mod_pow2);
tcase_add_test(tc_poly, test_mult_indices);
tcase_add_test(tc_poly, test_mult_coefficients);
suite_add_tcase(s, tc_poly);
return s;
}