#include #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