Created ntru_poly class for sparse trinary polynomials

This commit is contained in:
Andreas Steffen
2014-02-18 16:17:38 +01:00
parent 65ee857a88
commit 6dd05e0d58
9 changed files with 571 additions and 436 deletions
@@ -15,6 +15,7 @@ libstrongswan_ntru_la_SOURCES = \
ntru_drbg.h ntru_drbg.c \
ntru_ke.h ntru_ke.c \
ntru_mgf1.h ntru_mgf1.c \
ntru_poly.h ntru_poly.c \
ntru_trits.h ntru_trits.c \
ntru_crypto/ntru_crypto.h \
ntru_crypto/ntru_crypto_ntru_convert.h \
@@ -42,6 +42,7 @@
#include "ntru_crypto_ntru_poly.h"
#
#include "ntru_trits.h"
#include "ntru_poly.h"
/* ntru_crypto_ntru_encrypt
*
@@ -99,7 +100,6 @@ ntru_crypto_ntru_encrypt(
int16_t m1 = 0;
uint16_t *scratch_buf = NULL;
uint16_t *ringel_buf = NULL;
uint16_t *r_buf = NULL;
uint8_t *b_buf = NULL;
uint8_t *tmp_buf = NULL;
bool msg_rep_good = FALSE;
@@ -110,6 +110,8 @@ ntru_crypto_ntru_encrypt(
ntru_trits_t *mask;
uint8_t *mask_trits;
chunk_t seed;
ntru_poly_t *r_poly;
uint16_t *r_indices;
/* check for bad parameters */
@@ -186,8 +188,7 @@ ntru_crypto_ntru_encrypt(
return NTRU_OUT_OF_MEMORY;
}
ringel_buf = scratch_buf + ring_mult_tmp_len;
r_buf = ringel_buf + params->N;
b_buf = (uint8_t *)(r_buf + (dr << 1));
b_buf = (uint8_t *)(ringel_buf + params->N);
tmp_buf = (uint8_t *)scratch_buf;
/* set hash algorithm based on security strength */
@@ -225,39 +226,46 @@ ntru_crypto_ntru_encrypt(
memcpy(ptr, pubkey_packed, params->sec_strength_len);
ptr += params->sec_strength_len;
DBG2(DBG_LIB, "generate polynomial r");
/* generate r */
result = ntru_gen_poly(hash_algid,
params->min_IGF_hash_calls,
(uint16_t)(ptr - tmp_buf),
tmp_buf, tmp_buf,
params->N, params->c_bits,
params->no_bias_limit,
params->is_product_form,
params->dF_r << 1, r_buf);
seed = chunk_create(tmp_buf, ptr - tmp_buf);
r_poly = ntru_poly_create(hash_algid, seed,
params->c_bits, params->no_bias_limit,
params->N, 2 * params->dF_r,
params->is_product_form);
if (!r_poly)
{
result = NTRU_MGF1_FAIL;
}
}
if (result == NTRU_OK)
{
uint16_t pubkey_packed_len;
uint16_t pubkey_packed_len;
/* unpack the public key */
assert(pubkey_pack_type == NTRU_ENCRYPT_KEY_PACKED_COEFFICIENTS);
pubkey_packed_len = (params->N * params->q_bits + 7) >> 3;
ntru_octets_2_elements(pubkey_packed_len, pubkey_packed,
params->q_bits, ringel_buf);
/* unpack the public key */
assert(pubkey_pack_type == NTRU_ENCRYPT_KEY_PACKED_COEFFICIENTS);
pubkey_packed_len = (params->N * params->q_bits + 7) >> 3;
ntru_octets_2_elements(pubkey_packed_len, pubkey_packed,
params->q_bits, ringel_buf);
/* form R = h * r */
/* form R = h * r */
r_indices = r_poly->get_indices(r_poly);
if (params->is_product_form)
ntru_ring_mult_product_indices(ringel_buf, (uint16_t)dr1,
(uint16_t)dr2, (uint16_t)dr3,
r_buf, params->N, params->q,
scratch_buf, ringel_buf);
else
ntru_ring_mult_indices(ringel_buf, (uint16_t)dr, (uint16_t)dr,
r_buf, params->N, params->q,
scratch_buf, ringel_buf);
if (params->is_product_form)
{
ntru_ring_mult_product_indices(ringel_buf, (uint16_t)dr1,
(uint16_t)dr2, (uint16_t)dr3,
r_indices, params->N, params->q,
scratch_buf, ringel_buf);
}
else
{
ntru_ring_mult_indices(ringel_buf, (uint16_t)dr, (uint16_t)dr,
r_indices, params->N, params->q,
scratch_buf, ringel_buf);
}
r_poly->destroy(r_poly);
/* form R mod 4 */
ntru_coeffs_mod4_2_octets(params->N, ringel_buf, tmp_buf);
@@ -451,6 +459,8 @@ ntru_crypto_ntru_decrypt(
ntru_trits_t *mask;
uint8_t *mask_trits;
chunk_t seed;
ntru_poly_t *i_poly;
uint16_t *i_indices;
/* check for bad parameters */
if (!privkey_blob || !ct || !pt_len)
@@ -699,69 +709,74 @@ ntru_crypto_ntru_decrypt(
ptr += params->sec_strength_len;
/* generate cr */
DBG2(DBG_LIB, "generate polynomial i");
result = ntru_gen_poly(hash_algid,
params->min_IGF_hash_calls,
(uint16_t)(ptr - tmp_buf),
tmp_buf, tmp_buf,
params->N, params->c_bits,
params->no_bias_limit,
params->is_product_form,
params->dF_r << 1, i_buf);
seed = chunk_create(tmp_buf, ptr - tmp_buf);
i_poly = ntru_poly_create(hash_algid, seed,
params->c_bits, params->no_bias_limit,
params->N, 2 * params->dF_r,
params->is_product_form);
if (!i_poly)
{
result = NTRU_MGF1_FAIL;
}
}
if (result == NTRU_OK)
{
/* unpack the public key */
{
/* unpack the public key */
{
uint16_t pubkey_packed_len;
assert(pubkey_pack_type == NTRU_ENCRYPT_KEY_PACKED_COEFFICIENTS);
pubkey_packed_len = (params->N * params->q_bits + 7) >> 3;
ntru_octets_2_elements(pubkey_packed_len, pubkey_packed,
params->q_bits, ringel_buf1);
}
assert(pubkey_pack_type == NTRU_ENCRYPT_KEY_PACKED_COEFFICIENTS);
pubkey_packed_len = (params->N * params->q_bits + 7) >> 3;
ntru_octets_2_elements(pubkey_packed_len, pubkey_packed,
params->q_bits, ringel_buf1);
}
/* form cR' = h * cr */
/* form cR' = h * cr */
i_indices = i_poly->get_indices(i_poly);
if (params->is_product_form)
{
ntru_ring_mult_product_indices(ringel_buf1, (uint16_t)dF_r1,
(uint16_t)dF_r2, (uint16_t)dF_r3,
i_indices, params->N, params->q,
scratch_buf, ringel_buf1);
}
else
{
ntru_ring_mult_indices(ringel_buf1, (uint16_t)dF_r, (uint16_t)dF_r,
i_indices, params->N, params->q,
scratch_buf, ringel_buf1);
}
i_poly->destroy(i_poly);
if (params->is_product_form)
ntru_ring_mult_product_indices(ringel_buf1, (uint16_t)dF_r1,
(uint16_t)dF_r2, (uint16_t)dF_r3,
i_buf, params->N, params->q,
scratch_buf, ringel_buf1);
else
ntru_ring_mult_indices(ringel_buf1, (uint16_t)dF_r, (uint16_t)dF_r,
i_buf, params->N, params->q,
scratch_buf, ringel_buf1);
/* compare cR' to cR */
for (i = 0; i < params->N; i++) {
if (ringel_buf1[i] != ringel_buf2[i])
/* compare cR' to cR */
for (i = 0; i < params->N; i++)
{
if (ringel_buf1[i] != ringel_buf2[i])
{
decryption_ok = FALSE;
}
}
}
/* output plaintext and plaintext length */
if (decryption_ok)
if (decryption_ok)
{
if (*pt_len < cm_len)
if (*pt_len < cm_len)
{
return NTRU_BUFFER_TOO_SMALL;
}
memcpy(pt, m_buf, cm_len);
*pt_len = cm_len;
memcpy(pt, m_buf, cm_len);
*pt_len = cm_len;
}
}
/* cleanup */
memset(scratch_buf, 0, scratch_buf_len);
free(scratch_buf);
/* cleanup */
memset(scratch_buf, 0, scratch_buf_len);
free(scratch_buf);
if (!decryption_ok)
if (!decryption_ok)
{
return NTRU_FAIL;
}
@@ -836,13 +851,15 @@ ntru_crypto_ntru_encrypt_keygen(
uint16_t *scratch_buf = NULL;
uint16_t *ringel_buf1 = NULL;
uint16_t *ringel_buf2 = NULL;
uint16_t *F_buf = NULL;
uint8_t *tmp_buf = NULL;
uint16_t mod_q_mask;
hash_algorithm_t hash_algid;
uint8_t md_len;
uint16_t seed_len;
chunk_t seed;
uint32_t result = NTRU_OK;
ntru_poly_t *F_poly = NULL;
ntru_poly_t *g_poly = NULL;
uint16_t *F_indices, *g_indices;
/* get a pointer to the parameter-set parameters */
@@ -907,19 +924,16 @@ ntru_crypto_ntru_encrypt_keygen(
}
ringel_buf1 = scratch_buf + (params->N << 1);
ringel_buf2 = ringel_buf1 + params->N;
F_buf = ringel_buf2 + params->N;
tmp_buf = (uint8_t *)scratch_buf;
/* set hash algorithm and seed length based on security strength */
if (params->sec_strength_len <= 20)
{
hash_algid = HASH_SHA1;
md_len = 20;
}
else
{
hash_algid = HASH_SHA256;
md_len = 32;
}
seed_len = params->sec_strength_len + 8;
@@ -943,81 +957,92 @@ ntru_crypto_ntru_encrypt_keygen(
if (result == NTRU_OK)
{
DBG2(DBG_LIB, "generate polynomial F");
/* generate F */
result = ntru_gen_poly(hash_algid,
params->min_IGF_hash_calls,
seed_len, tmp_buf, tmp_buf,
params->N, params->c_bits,
params->no_bias_limit,
params->is_product_form,
params->dF_r << 1, F_buf);
seed = chunk_create(tmp_buf, seed_len);
F_poly = ntru_poly_create(hash_algid, seed,
params->c_bits, params->no_bias_limit,
params->N, 2 * params->dF_r,
params->is_product_form);
if (!F_poly)
{
result = NTRU_MGF1_FAIL;
}
}
if (result == NTRU_OK)
{
uint32_t i;
memset(ringel_buf1, 0, params->N * sizeof(uint16_t));
memset(ringel_buf1, 0, params->N * sizeof(uint16_t));
F_indices = F_poly->get_indices(F_poly);
/* form F as a ring element */
/* form F as a ring element */
if (params->is_product_form)
{
uint32_t dF3_offset = (dF1 + dF2) << 1;
if (params->is_product_form) {
uint32_t dF3_offset = (dF1 + dF2) << 1;
/* form F1 as a ring element */
for (i = 0; i < dF1; i++)
{
ringel_buf1[F_indices[i]] = 1;
}
for (; i < (dF1 << 1); i++)
{
ringel_buf1[F_indices[i]] = mod_q_mask;
}
/* form F1 as a ring element */
/* form F1 * F2 */
ntru_ring_mult_indices(ringel_buf1, (uint16_t)dF2, (uint16_t)dF2,
F_indices + (dF1 << 1), params->N, params->q,
scratch_buf, ringel_buf1);
for (i = 0; i < dF1; i++)
ringel_buf1[F_buf[i]] = 1;
for (; i < (dF1 << 1); i++)
ringel_buf1[F_buf[i]] = mod_q_mask;
/* form (F1 * F2) + F3 */
for (i = 0; i < dF3; i++)
{
uint16_t index = F_indices[dF3_offset + i];
/* form F1 * F2 */
ringel_buf1[index] = (ringel_buf1[index] + 1) & mod_q_mask;
}
for (; i < (dF3 << 1); i++)
{
uint16_t index = F_indices[dF3_offset + i];
ntru_ring_mult_indices(ringel_buf1, (uint16_t)dF2, (uint16_t)dF2,
F_buf + (dF1 << 1), params->N, params->q,
scratch_buf, ringel_buf1);
ringel_buf1[index] = (ringel_buf1[index] - 1) & mod_q_mask;
}
}
else
{
/* form F as a ring element */
for (i = 0; i < dF; i++)
{
ringel_buf1[F_indices[i]] = 1;
}
for (; i < (dF << 1); i++)
{
ringel_buf1[F_indices[i]] = mod_q_mask;
}
}
/* form (F1 * F2) + F3 */
/* form f = 1 + pF */
for (i = 0; i < params->N; i++)
{
ringel_buf1[i] = (ringel_buf1[i] * 3) & mod_q_mask;
}
ringel_buf1[0] = (ringel_buf1[0] + 1) & mod_q_mask;
for (i = 0; i < dF3; i++) {
uint16_t index = F_buf[dF3_offset + i];
ringel_buf1[index] = (ringel_buf1[index] + 1) & mod_q_mask;
}
for (; i < (dF3 << 1); i++) {
uint16_t index = F_buf[dF3_offset + i];
ringel_buf1[index] = (ringel_buf1[index] - 1) & mod_q_mask;
}
} else {
/* form F as a ring element */
for (i = 0; i < dF; i++)
ringel_buf1[F_buf[i]] = 1;
for (; i < (dF << 1); i++)
ringel_buf1[F_buf[i]] = mod_q_mask;
}
/* form f = 1 + pF */
for (i = 0; i < params->N; i++)
ringel_buf1[i] = (ringel_buf1[i] * 3) & mod_q_mask;
ringel_buf1[0] = (ringel_buf1[0] + 1) & mod_q_mask;
/* find f^-1 in (Z/qZ)[X]/(X^N - 1) */
if (!ntru_ring_inv(ringel_buf1, params->N, params->q,
scratch_buf, ringel_buf2))
/* find f^-1 in (Z/qZ)[X]/(X^N - 1) */
if (!ntru_ring_inv(ringel_buf1, params->N, params->q,
scratch_buf, ringel_buf2))
{
result = NTRU_FAIL;
}
}
}
if (result == NTRU_OK)
{
/* get random bytes for seed for generating trinary g
/* get random bytes for seed for generating trinary polynomial g
* as a list of indices
*/
if (!drbg->generate(drbg, params->sec_strength_len * BITS_PER_BYTE,
@@ -1029,53 +1054,52 @@ ntru_crypto_ntru_encrypt_keygen(
if (result == NTRU_OK)
{
uint16_t min_IGF_hash_calls =
((((params->dg << 2) + 2) * params->N_bits) + (md_len << 3) - 1) /
(md_len << 3);
DBG2(DBG_LIB, "generate polynomial g");
/* generate g */
result = ntru_gen_poly(hash_algid,
(uint8_t)min_IGF_hash_calls,
seed_len, tmp_buf, tmp_buf,
params->N, params->c_bits,
params->no_bias_limit, FALSE,
(params->dg << 1) + 1, ringel_buf1);
}
seed = chunk_create(tmp_buf, seed_len);
g_poly = ntru_poly_create(hash_algid, seed,
params->c_bits, params->no_bias_limit,
params->N, 2*params->dg + 1, FALSE);
if (!g_poly)
{
result = NTRU_MGF1_FAIL;
}
}
if (result == NTRU_OK)
{
uint16_t i;
uint16_t i;
/* compute h = p * (f^-1 * g) mod q */
/* compute h = p * (f^-1 * g) mod q */
g_indices = g_poly->get_indices(g_poly);
ntru_ring_mult_indices(ringel_buf2, params->dg + 1, params->dg,
g_indices, params->N, params->q, scratch_buf,
ringel_buf2);
g_poly->destroy(g_poly);
ntru_ring_mult_indices(ringel_buf2, params->dg + 1, params->dg,
ringel_buf1, params->N, params->q, scratch_buf,
ringel_buf2);
for (i = 0; i < params->N; i++)
{
ringel_buf2[i] = (ringel_buf2[i] * 3) & mod_q_mask;
}
for (i = 0; i < params->N; i++)
ringel_buf2[i] = (ringel_buf2[i] * 3) & mod_q_mask;
/* create public key blob */
ntru_crypto_ntru_encrypt_key_create_pubkey_blob(params, ringel_buf2,
pubkey_pack_type,
pubkey_blob);
*pubkey_blob_len = public_key_blob_len;
/* create public key blob */
ntru_crypto_ntru_encrypt_key_create_pubkey_blob(params, ringel_buf2,
pubkey_pack_type,
pubkey_blob);
*pubkey_blob_len = public_key_blob_len;
/* create private key blob */
ntru_crypto_ntru_encrypt_key_create_privkey_blob(params, ringel_buf2,
F_buf,
privkey_pack_type,
tmp_buf, privkey_blob);
*privkey_blob_len = private_key_blob_len;
/* create private key blob */
ntru_crypto_ntru_encrypt_key_create_privkey_blob(params, ringel_buf2,
F_indices,
privkey_pack_type,
tmp_buf, privkey_blob);
*privkey_blob_len = private_key_blob_len;
}
/* cleanup */
memset(scratch_buf, 0, scratch_buf_len);
free(scratch_buf);
return result;
/* cleanup */
DESTROY_IF(F_poly);
memset(scratch_buf, 0, scratch_buf_len);
free(scratch_buf);
return result;
}
@@ -56,7 +56,6 @@ static NTRU_ENCRYPT_PARAM_SET ntruParamSets[] = {
2005, /* 2^c - (2^c mod N) */
11, /* c */
1, /* lLen */
32, /* min. no. of hash calls for IGF-2 */
},
{
@@ -76,7 +75,6 @@ static NTRU_ENCRYPT_PARAM_SET ntruParamSets[] = {
449, /* 2^c - (2^c mod N) */
9, /* c */
1, /* lLen */
31, /* min. no. of hash calls for IGF-2 */
},
{
@@ -96,7 +94,6 @@ static NTRU_ENCRYPT_PARAM_SET ntruParamSets[] = {
2031, /* 2^c - (2^c mod N) */
11, /* c */
1, /* lLen */
27, /* min. no. of hash calls for IGF-2 */
},
{
@@ -116,7 +113,6 @@ static NTRU_ENCRYPT_PARAM_SET ntruParamSets[] = {
7609, /* 2^c - (2^c mod N) */
13, /* c */
1, /* lLen */
25, /* min. no. of hash calls for IGF-2 */
},
{
@@ -136,7 +132,6 @@ static NTRU_ENCRYPT_PARAM_SET ntruParamSets[] = {
3787, /* 2^c - (2^c mod N) */
12, /* c */
1, /* lLen */
15, /* min. no. of hash calls for IGF-2 */
},
{
@@ -156,7 +151,6 @@ static NTRU_ENCRYPT_PARAM_SET ntruParamSets[] = {
1839, /* 2^c - (2^c mod N) */
11, /* c */
1, /* lLen */
16, /* min. no. of hash calls for IGF-2 */
},
{
@@ -176,7 +170,6 @@ static NTRU_ENCRYPT_PARAM_SET ntruParamSets[] = {
887, /* 2^c - (2^c mod N) */
10, /* c */
1, /* lLen */
13, /* min. no. of hash calls for IGF-2 */
},
{
@@ -196,7 +189,6 @@ static NTRU_ENCRYPT_PARAM_SET ntruParamSets[] = {
3513, /* 2^c - (2^c mod N) */
12, /* c */
1, /* lLen */
20, /* min. no. of hash calls for IGF-2 */
},
{
@@ -216,7 +208,6 @@ static NTRU_ENCRYPT_PARAM_SET ntruParamSets[] = {
1977, /* 2^c - (2^c mod N) */
11, /* c */
1, /* lLen */
11, /* min. no. of hash calls for IGF-2 */
},
{
@@ -236,7 +227,6 @@ static NTRU_ENCRYPT_PARAM_SET ntruParamSets[] = {
3805, /* 2^c - (2^c mod N) */
12, /* c */
1, /* lLen */
13, /* min. no. of hash calls for IGF-2 */
},
{
@@ -256,7 +246,6 @@ static NTRU_ENCRYPT_PARAM_SET ntruParamSets[] = {
7609, /* 2^c - (2^c mod N) */
13, /* c */
1, /* lLen */
13, /* min. no. of hash calls for IGF-2 */
},
{
@@ -276,7 +265,6 @@ static NTRU_ENCRYPT_PARAM_SET ntruParamSets[] = {
7495, /* 2^c - (2^c mod N) */
13, /* c */
1, /* lLen */
17, /* min. no. of hash calls for IGF-2 */
},
{
@@ -296,8 +284,7 @@ static NTRU_ENCRYPT_PARAM_SET ntruParamSets[] = {
2005, /* 2^c - (2^c mod N) */
11, /* c */
1, /* lLen */
10, /* min. no. of hash calls for IGF-2 */
},
},
{
NTRU_EES439EP1, /* parameter-set id */
@@ -316,7 +303,6 @@ static NTRU_ENCRYPT_PARAM_SET ntruParamSets[] = {
439, /* 2^c - (2^c mod N) */
9, /* c */
1, /* lLen */
15, /* min. no. of hash calls for IGF-2 */
},
{
@@ -336,7 +322,6 @@ static NTRU_ENCRYPT_PARAM_SET ntruParamSets[] = {
1779, /* 2^c - (2^c mod N) */
11, /* c */
1, /* lLen */
12, /* min. no. of hash calls for IGF-2 */
},
{
@@ -356,7 +341,6 @@ static NTRU_ENCRYPT_PARAM_SET ntruParamSets[] = {
8173, /* 2^c - (2^c mod N) */
13, /* c */
1, /* lLen */
12, /* min. no. of hash calls for IGF-2 */
},
};
@@ -66,8 +66,6 @@ typedef struct _NTRU_ENCRYPT_PARAM_SET {
IGF-2 */
uint8_t m_len_len; /* no. of octets to hold
mLenOctets */
uint8_t min_IGF_hash_calls; /* min. no. of hash calls for
IGF-2 */
} NTRU_ENCRYPT_PARAM_SET;
@@ -22,212 +22,10 @@
*
*****************************************************************************/
/******************************************************************************
*
* File: ntru_crypto_ntru_poly.c
*
* Contents: Routines for generating and operating on polynomials in the
* NTRU algorithm.
*
*****************************************************************************/
#include <stdlib.h>
#include <string.h>
#include "ntru_crypto_ntru_poly.h"
#include "ntru_mgf1.h"
#include <utils/debug.h>
/* ntru_gen_poly
*
* Generates polynomials by creating for each polynomial, a list of the
* indices of the +1 coefficients followed by a list of the indices of
* the -1 coefficients.
*
* If a single polynomial is generated (non-product form), indices_counts
* contains a single value of the total number of indices (for +1 and -1
* comefficients combined).
*
* If multiple polynomials are generated (for product form), their lists of
* indices are sequentially stored in the indices buffer. Each byte of
* indices_counts contains the total number of indices (for +1 and -1
* coefficients combined) for a single polynomial, beginning with the
* low-order byte for the first polynomial. The high-order byte is unused.
*
* Returns NTRU_OK if successful.
* Returns HASH_BAD_ALG if the algorithm is not supported.
*
*/
uint32_t
ntru_gen_poly(
hash_algorithm_t hash_algid, /* in - hash algorithm ID for
IGF-2 */
uint8_t min_calls, /* in - minimum no. of hash
calls */
uint16_t seed_len, /* in - no. of octets in seed */
uint8_t *seed, /* in - pointer to seed */
uint8_t *buf, /* in - pointer to working
buffer */
uint16_t N, /* in - max index + 1 */
uint8_t c_bits, /* in - no. bits for candidate */
uint16_t limit, /* in - conversion to index
limit */
bool is_product_form, /* in - if generating multiple
polys */
uint32_t indices_counts, /* in - nos. of indices needed */
uint16_t *indices) /* out - address for indices */
{
uint8_t md_len;
uint8_t *octets;
uint8_t *used;
uint8_t num_polys;
uint16_t num_indices;
uint16_t octets_available;
uint16_t index_cnt = 0;
uint8_t left = 0;
uint8_t num_left = 0;
ntru_mgf1_t *mgf1;
/* generate minimum MGF1 output */
DBG2(DBG_LIB, "MGF1 is seeded with %u bytes", seed_len);
mgf1 = ntru_mgf1_create(hash_algid, chunk_create(seed, seed_len), TRUE);
if (!mgf1)
{
return NTRU_MGF1_FAIL;
}
md_len = mgf1->get_hash_size(mgf1);
octets = buf;
octets_available = min_calls * md_len;
/* init indices counts for number of polynomials being generated */
if (is_product_form) {
/* number of indices for poly1 is in low byte of indices_counts,
* number of indices for poly2 and poly3 are in next higher bytes
*/
num_polys = 3;
num_indices = (uint16_t)(indices_counts & 0xff);
indices_counts >>= 8;
} else {
/* number of bytes for poly is in low 16 bits of indices_counts */
num_polys = 1;
num_indices = (uint16_t)indices_counts;
}
/* init used-index array */
used = buf + octets_available;
memset(used, 0, N);
/* generate indices (IGF-2) for all polynomials */
DBG2(DBG_LIB, "MGF1 generates %u octets for %u indices",
octets_available, num_indices);
if (!mgf1->get_mask(mgf1, octets_available, octets))
{
mgf1->destroy(mgf1);
return NTRU_MGF1_FAIL;
}
while (num_polys > 0) {
/* generate indices for a single polynomial */
while (index_cnt < num_indices) {
uint16_t index;
uint8_t num_needed;
/* form next index to convert to an index */
do {
/* use any leftover bits first */
if (num_left != 0) {
index = left << (c_bits - num_left);
} else {
index = 0;
}
/* get the rest of the bits needed from new octets */
num_needed = c_bits - num_left;
while (num_needed != 0)
{
/* get another octet */
if (octets_available == 0)
{
octets = buf;
octets_available = md_len;
DBG2(DBG_LIB, "MGF1 generates another %u octets for the "
"remaining %u indices", octets_available,
num_indices - index_cnt);
if (!mgf1->get_mask(mgf1, octets_available, octets))
{
mgf1->destroy(mgf1);
return NTRU_MGF1_FAIL;
}
}
left = *octets++;
--octets_available;
if (num_needed <= 8)
{
/* all bits needed to fill the index are in this octet */
index |= ((uint16_t)(left)) >> (8 - num_needed);
num_left = 8 - num_needed;
num_needed = 0;
left &= 0xff >> (8 - num_left);
} else {
/* another octet will be needed after using this
* whole octet
*/
index |= ((uint16_t)left) << (num_needed - 8);
num_needed -= 8;
}
}
} while (index >= limit);
/* form index and check if unique */
index %= N;
if (!used[index])
{
used[index] = 1;
indices[index_cnt] = index;
++index_cnt;
}
}
--num_polys;
/* init for next polynomial if another polynomial to be generated */
if (num_polys > 0)
{
memset(used, 0, N);
num_indices = num_indices +
(uint16_t)(indices_counts & 0xff);
indices_counts >>= 8;
}
}
mgf1->destroy(mgf1);
return NTRU_OK;
}
/* ntru_poly_check_min_weight
*
* Checks that the number of 0, +1, and -1 trinary ring elements meet or exceed
@@ -43,47 +43,6 @@
/* function declarations */
/* ntru_gen_poly
*
* Generates polynomials by creating for each polynomial, a list of the
* indices of the +1 coefficients followed by a list of the indices of
* the -1 coefficients.
*
* If a single polynomial is generated (non-product form), indices_counts
* contains a single value of the total number of indices (for +1 and -1
* comefficients combined).
*
* If multiple polynomials are generated (for product form), their lists of
* indices are sequentially stored in the indices buffer. Each byte of
* indices_counts contains the total number of indices (for +1 and -1
* coefficients combined) for a single polynomial, beginning with the
* low-order byte for the first polynomial. The high-order byte is unused.
*
* Returns NTRU_OK if successful.
* Returns HASH_BAD_ALG if the algorithm is not supported.
*
*/
extern uint32_t
ntru_gen_poly(
hash_algorithm_t hash_algid, /* in - hash algorithm ID for
IGF-2 */
uint8_t min_calls, /* in - minimum no. of hash
calls */
uint16_t seed_len, /* in - no. of octets in seed */
uint8_t *seed, /* in - pointer to seed */
uint8_t *buf, /* in - pointer to working
buffer */
uint16_t N, /* in - max index + 1 */
uint8_t c_bits, /* in - no. bits for candidate */
uint16_t limit, /* in - conversion to index
limit */
bool is_product_form, /* in - if generating multiple
polys */
uint32_t indices_counts, /* in - nos. of indices needed */
uint16_t *indices); /* out - address for indices */
/* ntru_poly_check_min_weight
*
* Checks that the number of 0, +1, and -1 trinary ring elements meet or exceed
+189
View File
@@ -0,0 +1,189 @@
/*
* Copyright (C) 2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* Copyright (C) 2009-2013 Security Innovation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program 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 General Public License
* for more details.
*/
#include "ntru_poly.h"
#include "ntru_mgf1.h"
#include <utils/debug.h>
#include <utils/test.h>
typedef struct private_ntru_poly_t private_ntru_poly_t;
/**
* Private data of an ntru_poly_t object.
*/
struct private_ntru_poly_t {
/**
* Public ntru_poly_t interface.
*/
ntru_poly_t public;
/**
* Array containing the indices of the non-zero coefficients
*/
uint16_t *indices;
/**
* Number of non-zero coefficients
*/
uint32_t indices_len;
};
METHOD(ntru_poly_t, get_size, size_t,
private_ntru_poly_t *this)
{
return this->indices_len;
}
METHOD(ntru_poly_t, get_indices, uint16_t*,
private_ntru_poly_t *this)
{
return this->indices;
}
METHOD(ntru_poly_t, destroy, void,
private_ntru_poly_t *this)
{
memwipe(this->indices, this->indices_len);
free(this->indices);
free(this);
}
/*
* Described in header.
*/
ntru_poly_t *ntru_poly_create(hash_algorithm_t alg, chunk_t seed,
uint8_t c_bits, uint16_t limit,
uint16_t poly_len, uint32_t indices_count,
bool is_product_form)
{
private_ntru_poly_t *this;
size_t hash_len, octet_count = 0, i, num_polys, num_indices[3], indices_len;
uint8_t octets[HASH_SIZE_SHA512], *used, num_left = 0, num_needed;
uint16_t index, left = 0;
int poly_i = 0, index_i = 0;
ntru_mgf1_t *mgf1;
DBG2(DBG_LIB, "MGF1 is seeded with %u bytes", seed.len);
mgf1 = ntru_mgf1_create(alg, seed, TRUE);
if (!mgf1)
{
return NULL;
}
i = hash_len = mgf1->get_hash_size(mgf1);
if (is_product_form)
{
num_polys = 3;
num_indices[0] = 0xff & indices_count;
num_indices[1] = 0xff & (indices_count >> 8);
num_indices[2] = 0xff & (indices_count >> 16);
indices_len = num_indices[0] + num_indices[1] + num_indices[2];
}
else
{
num_polys = 1;
num_indices[0] = indices_count;
indices_len = indices_count;
}
used = malloc(poly_len);
INIT(this,
.public = {
.get_size = _get_size,
.get_indices = _get_indices,
.destroy = _destroy,
},
.indices_len = indices_len,
.indices = malloc(indices_len * sizeof(uint16_t)),
);
/* generate indices for all polynomials */
while (poly_i < num_polys)
{
memset(used, 0, poly_len);
/* generate indices for a single polynomial */
while (num_indices[poly_i])
{
/* generate a random candidate index with a size of c_bits */
do
{
/* use any leftover bits first */
index = num_left ? left << (c_bits - num_left) : 0;
/* get the rest of the bits needed from new octets */
num_needed = c_bits - num_left;
while (num_needed)
{
if (i == hash_len)
{
/* get another block from MGF1 */
if (!mgf1->get_mask(mgf1, hash_len, octets))
{
mgf1->destroy(mgf1);
destroy(this);
free(used);
return NULL;
}
octet_count += hash_len;
i = 0;
}
left = octets[i++];
if (num_needed <= 8)
{
/* all bits needed to fill the index are in this octet */
index |= left >> (8 - num_needed);
num_left = 8 - num_needed;
num_needed = 0;
left &= 0xff >> (8 - num_left);
}
else
{
/* more than one octet will be needed */
index |= left << (num_needed - 8);
num_needed -= 8;
}
}
}
while (index >= limit);
/* form index and check if unique */
index %= poly_len;
if (!used[index])
{
used[index] = 1;
this->indices[index_i++] = index;
num_indices[poly_i]--;
}
}
poly_i++;
}
DBG2(DBG_LIB, "MGF1 generates %u octets to derive %u indices",
octet_count, this->indices_len);
mgf1->destroy(mgf1);
free(used);
return &this->public;
}
EXPORT_FUNCTION_FOR_TESTS(ntru, ntru_poly_create);
@@ -0,0 +1,68 @@
/*
* Copyright (C) 2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program 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 General Public License
* for more details.
*/
/**
* @defgroup ntru_poly ntru_poly
* @{ @ingroup ntru_p
*/
#ifndef NTRU_POLY_H_
#define NTRU_POLY_H_
typedef struct ntru_poly_t ntru_poly_t;
#include <library.h>
/**
* Implements a trinary polynomial storing the indices of non-zero coefficients
*/
struct ntru_poly_t {
/**
* Get the size of the indices array
*
* @return number of indices
*/
size_t (*get_size)(ntru_poly_t *this);
/**
* @return array containing the indices of the non-zero coefficients
*/
uint16_t* (*get_indices)(ntru_poly_t *this);
/**
* Destroy ntru_poly_t object
*/
void (*destroy)(ntru_poly_t *this);
};
/**
* Create a trits polynomial from a seed using MGF1 with a base hash function
*
* @param alg hash algorithm to be used by MGF1
* @param seed seed used by MGF1 to generate trits from
* @param poly_len size of the trits polynomial
* @param c_bits number of bits for candidate index
* @param limit conversion to index limit
* @param indices_count number of non-zero indices
* @param is_product_form generate multiple polynomials
*/
ntru_poly_t *ntru_poly_create(hash_algorithm_t alg, chunk_t seed,
uint8_t c_bits, uint16_t limit,
uint16_t poly_len, uint32_t indices_count,
bool is_product_form);
#endif /** NTRU_POLY_H_ @}*/