void ntru_decrypt_poly(NtruIntPoly *e, NtruEncPrivKey *priv, uint16_t q, NtruIntPoly *d) { ntru_mult_priv(&priv->t, e, d, q-1); ntru_mult_fac(d, 3); ntru_add(d, e); ntru_mod_center(d, q); ntru_mod3(d); }
uint8_t ntru_gen_key_pair_single(const NtruEncParams *params, NtruEncPrivKey *priv, NtruEncPubKey *pub, NtruIntPoly *fq, NtruRandContext *rand_ctx) { uint16_t N = params->N; uint16_t q = params->q; uint16_t df1 = params->df1; #ifndef NTRU_AVOID_HAMMING_WT_PATENT uint16_t df2 = params->df2; uint16_t df3 = params->df3; #endif /* NTRU_AVOID_HAMMING_WT_PATENT */ if (q & (q-1)) /* check that modulus is a power of 2 */ return NTRU_ERR_INVALID_PARAM; /* choose a random f that is invertible mod q */ #ifndef NTRU_AVOID_HAMMING_WT_PATENT if (params->prod_flag) { NtruPrivPoly *t = &priv->t; t->prod_flag = 1; t->poly.prod.N = N; priv->q = q; for (;;) { /* choose random t, find the inverse of 3t+1 */ if (!ntru_rand_prod(N, df1, df2, df3, df3, &t->poly.prod, rand_ctx)) return NTRU_ERR_PRNG; if (ntru_invert(t, q-1, fq)) break; } } else #endif /* NTRU_AVOID_HAMMING_WT_PATENT */ { NtruPrivPoly *t = &priv->t; t->prod_flag = 0; priv->q = q; for (;;) { /* choose random t, find the inverse of 3t+1 */ if (!ntru_rand_tern(N, df1, df1, &t->poly.tern, rand_ctx)) return NTRU_ERR_PRNG; if (ntru_invert(t, q-1, fq)) break; } } /* choose a random g */ NtruPrivPoly g; uint8_t result = ntru_gen_g(params, &g, rand_ctx); if (result != NTRU_SUCCESS) return result; NtruIntPoly *h = &pub->h; if (!ntru_mult_priv(&g, fq, h, q-1)) return NTRU_ERR_INVALID_PARAM; ntru_mult_fac(h, 3); ntru_mod_mask(h, q-1); ntru_clear_priv(&g); pub->q = q; return NTRU_SUCCESS; }
uint8_t ntru_encrypt(uint8_t *msg, uint16_t msg_len, NtruEncPubKey *pub, const NtruEncParams *params, NtruRandContext *rand_ctx, uint8_t *enc) { uint16_t N = params->N; uint16_t q = params->q; uint16_t db = params->db; uint16_t max_len_bytes = ntru_max_msg_len(params); uint16_t dm0 = params->dm0; if (max_len_bytes > 255) return NTRU_ERR_INVALID_MAX_LEN; if (msg_len > max_len_bytes) return NTRU_ERR_MSG_TOO_LONG; for (;;) { /* M = b|octL|msg|p0 */ uint8_t b[db/8]; if (ntru_rand_generate(b, db/8, rand_ctx) != NTRU_SUCCESS) return NTRU_ERR_PRNG; uint16_t M_len = db/8 + 1 + max_len_bytes + 1; uint8_t M[M_len]; memcpy(&M, &b, db/8); uint8_t *M_head = (uint8_t*)&M + db/8; *M_head = msg_len; M_head++; memcpy(M_head, msg, msg_len); M_head += msg_len; memset(M_head, 0, max_len_bytes+1-msg_len); NtruIntPoly mtrin; ntru_from_sves((uint8_t*)&M, M_len, N, &mtrin); uint16_t blen = params->db / 8; uint16_t sdata_len = sizeof(params->oid) + msg_len + blen + blen; uint8_t sdata[sdata_len]; ntru_get_seed(msg, msg_len, &pub->h, (uint8_t*)&b, params, (uint8_t*)&sdata); NtruIntPoly R; NtruPrivPoly r; ntru_gen_blind_poly((uint8_t*)&sdata, sdata_len, params, &r); ntru_mult_priv(&r, &pub->h, &R, q); uint16_t oR4_len = (N*2+7) / 8; uint8_t oR4[oR4_len]; ntru_to_arr4(&R, (uint8_t*)&oR4); NtruIntPoly mask; ntru_MGF((uint8_t*)&oR4, oR4_len, params, &mask); ntru_add_int(&mtrin, &mask); ntru_mod3(&mtrin); if (!ntru_check_rep_weight(&mtrin, dm0)) continue; ntru_add_int(&R, &mtrin); ntru_to_arr(&R, q, enc); return NTRU_SUCCESS; } }
uint8_t ntru_gen_pub(const NtruEncParams *params, NtruEncPrivKey *priv, NtruEncPubKey *pub, NtruRandContext *rand_ctx) { ntru_set_optimized_impl(); uint16_t q = params->q; NtruIntPoly fq; if (!ntru_invert(&priv->t, q-1, &fq)) return NTRU_ERR_INVALID_KEY; NtruIntPoly *h = &pub->h; NtruPrivPoly g; uint8_t result = ntru_gen_g(params, &g, rand_ctx); if (result != NTRU_SUCCESS) return result; if (!ntru_mult_priv(&g, &fq, h, q-1)) return NTRU_ERR_INVALID_PARAM; ntru_clear_int(&fq); ntru_mult_fac(h, 3); ntru_mod_mask(h, q-1); pub->q = q; return NTRU_SUCCESS; }
uint8_t ntru_gen_key_pair_multi(const NtruEncParams *params, NtruEncPrivKey *priv, NtruEncPubKey *pub, NtruRandContext *rand_ctx, uint32_t num_pub) { ntru_set_optimized_impl(); uint16_t q = params->q; NtruIntPoly fq; uint8_t result = ntru_gen_key_pair_single(params, priv, pub, &fq, rand_ctx); if (result != NTRU_SUCCESS) return result; uint32_t i; for (i=1; i<num_pub; i++) { NtruIntPoly *h = &pub[i].h; NtruPrivPoly g; result = ntru_gen_g(params, &g, rand_ctx); if (result != NTRU_SUCCESS) return result; if (!ntru_mult_priv(&g, &fq, h, q-1)) return NTRU_ERR_INVALID_PARAM; ntru_mult_fac(h, 3); ntru_mod_mask(h, q-1); pub[i].q = q; } ntru_clear_int(&fq); return result; }
uint8_t ntru_decrypt(uint8_t *enc, NtruEncKeyPair *kp, const NtruEncParams *params, uint8_t *dec, uint16_t *dec_len) { ntru_set_optimized_impl(); uint16_t N = params->N; uint16_t q = params->q; uint16_t db = params->db; uint16_t max_len_bytes = ntru_max_msg_len(params); uint16_t dm0 = params->dm0; if (q & (q-1)) /* check that modulus is a power of 2 */ return NTRU_ERR_INVALID_PARAM; if (max_len_bytes > 255) return NTRU_ERR_INVALID_MAX_LEN; uint16_t blen = db / 8; uint8_t retcode = NTRU_SUCCESS; NtruIntPoly e; ntru_from_arr(enc, N, q, &e); NtruIntPoly ci; ntru_decrypt_poly(&e, &kp->priv, q, &ci); if (!ntru_check_rep_weight(&ci, dm0) && retcode==NTRU_SUCCESS) retcode = NTRU_ERR_DM0_VIOLATION; NtruIntPoly cR = e; ntru_sub(&cR, &ci); ntru_mod_mask(&cR, q-1); uint16_t coR4_len = (N*2+7) / 8; uint8_t coR4[coR4_len]; ntru_to_arr4(&cR, (uint8_t*)&coR4); NtruIntPoly mask; ntru_MGF((uint8_t*)&coR4, coR4_len, params, &mask); NtruIntPoly cmtrin = ci; ntru_sub(&cmtrin, &mask); ntru_mod3(&cmtrin); uint16_t cM_len_bits = (N*3+1) / 2; uint16_t cM_len_bytes = (cM_len_bits+7) / 8; uint8_t cM[cM_len_bytes+3]; /* 3 extra bytes for ntru_to_sves() */ if (!ntru_to_sves(&cmtrin, (uint8_t*)&cM) && retcode==NTRU_SUCCESS) retcode = NTRU_ERR_INVALID_ENCODING; uint8_t cb[blen]; uint8_t *cM_head = cM; memcpy(cb, cM_head, blen); cM_head += blen; uint8_t cl = *cM_head; /* llen=1, so read one byte */ cM_head++; if (cl > max_len_bytes) { if (retcode == NTRU_SUCCESS) retcode = NTRU_ERR_MSG_TOO_LONG; cl = max_len_bytes; /* prevent buffer overrun in memcpy below */ } memcpy(dec, cM_head, cl); cM_head += cl; uint8_t *i; for (i=cM_head; i<cM+cM_len_bytes; i++) if (*i && retcode==NTRU_SUCCESS) retcode = NTRU_ERR_NO_ZERO_PAD; uint16_t sdata_len = sizeof(params->oid) + cl + blen + db/8; uint8_t sdata[sdata_len]; ntru_get_seed(dec, cl, &kp->pub.h, (uint8_t*)&cb, params, (uint8_t*)&sdata); NtruPrivPoly cr; ntru_gen_blind_poly((uint8_t*)&sdata, sdata_len, params, &cr); NtruIntPoly cR_prime; ntru_mult_priv(&cr, &kp->pub.h, &cR_prime, q-1); if (!ntru_equals_int(&cR_prime, &cR) && retcode==NTRU_SUCCESS) retcode = NTRU_ERR_INVALID_ENCODING; *dec_len = cl; return retcode; }
uint8_t ntru_gen_key_pair(const NtruEncParams *params, NtruEncKeyPair *kp, NtruRandContext *rand_ctx) { uint16_t N = params->N; uint16_t q = params->q; uint16_t df1 = params->df1; #ifndef NTRU_AVOID_HAMMING_WT_PATENT uint16_t df2 = params->df2; uint16_t df3 = params->df3; #endif /* NTRU_AVOID_HAMMING_WT_PATENT */ NtruIntPoly fq; /* choose a random f that is invertible mod q */ #ifndef NTRU_AVOID_HAMMING_WT_PATENT if (params->prod_flag) { NtruPrivPoly *t = &kp->priv.t; t->prod_flag = 1; t->poly.prod.N = N; kp->priv.q = q; for (;;) { /* choose random t, find the inverse of 3t+1 */ if (!ntru_rand_prod(N, df1, df2, df3, df3, &t->poly.prod, rand_ctx)) return NTRU_ERR_PRNG; if (ntru_invert(t, q, &fq)) break; } } else #endif /* NTRU_AVOID_HAMMING_WT_PATENT */ { NtruPrivPoly *t = &kp->priv.t; t->prod_flag = 0; kp->priv.q = q; for (;;) { /* choose random t, find the inverse of 3t+1 */ if (!ntru_rand_tern(N, df1, df1, &t->poly.tern, rand_ctx)) return NTRU_ERR_PRNG; if (ntru_invert(t, q, &fq)) break; } } /* choose a random g that is invertible mod q */ NtruPrivPoly g; uint16_t dg = N / 3; for (;;) { #ifndef NTRU_AVOID_HAMMING_WT_PATENT if (params->prod_flag && !ntru_rand_prod(N, df1, df2, df3, df3, &g.poly.prod, rand_ctx)) return NTRU_ERR_PRNG; if (!params->prod_flag && !ntru_rand_tern(N, dg, dg, &g.poly.tern, rand_ctx)) return NTRU_ERR_PRNG; g.prod_flag = params->prod_flag; #else if (!ntru_rand_tern(N, dg, dg, &g.poly.tern, rand_ctx)) return NTRU_ERR_PRNG; g.prod_flag = 0; #endif /* NTRU_AVOID_HAMMING_WT_PATENT */ if (!NTRU_CHECK_INVERTIBILITY_G) break; NtruIntPoly gq; if (ntru_invert(&g, q, &gq)) break; } NtruIntPoly *h = &kp->pub.h; if (!ntru_mult_priv(&g, &fq, h, q)) return NTRU_ERR_PRNG; ntru_mult_fac(h, 3); ntru_mod(h, q); ntru_clear_priv(&g); ntru_clear_int(&fq); kp->pub.q = q; return NTRU_SUCCESS; }