mirror of
https://github.com/open-quantum-safe/liboqs.git
synced 2025-10-08 00:03:38 -04:00
Clean up and optimize Frodo implementation (#60)
This commit is contained in:
parent
36ae6bf418
commit
c5382941ae
4
Makefile
4
Makefile
@ -47,7 +47,7 @@ endif
|
||||
|
||||
all: links lib tests
|
||||
|
||||
objs/%.o: src/%.c
|
||||
objs/%.o: src/%.c | links
|
||||
@mkdir -p $(@D)
|
||||
$(CC) -c $(CFLAGS) $(INCLUDES) $< -o $@
|
||||
|
||||
@ -95,7 +95,7 @@ $(KEX_RLWE_MSRLN16_OBJS): $(KEX_RLWE_MSRLN16_HEADERS)
|
||||
|
||||
# KEX_LWE_FRODO
|
||||
KEX_LWE_FRODO_OBJS := $(addprefix objs/kex_lwe_frodo/, lwe.o kex_lwe_frodo.o lwe_noise.o)
|
||||
KEX_LWE_FRODO_HEADERS := $(addprefix src/kex_lwe_frodo/, kex_lwe_frodo.h local.h)
|
||||
KEX_LWE_FRODO_HEADERS := $(addprefix src/kex_lwe_frodo/, kex_lwe_frodo.h local.h kex_lwe_frodo_macrify.c lwe_macrify.c)
|
||||
$(KEX_LWE_FRODO_OBJS): $(KEX_LWE_FRODO_HEADERS)
|
||||
|
||||
# KEX_SIDH_CLN16
|
||||
|
@ -18,7 +18,7 @@ OQS_KEX *OQS_KEX_new(OQS_RAND *rand, enum OQS_KEX_alg_name alg_name, const uint8
|
||||
case OQS_KEX_alg_rlwe_newhope:
|
||||
return OQS_KEX_rlwe_newhope_new(rand);
|
||||
case OQS_KEX_alg_lwe_frodo:
|
||||
return OQS_KEX_lwe_frodo_new(rand, seed, seed_len, named_parameters);
|
||||
return OQS_KEX_lwe_frodo_new_recommended(rand, seed, seed_len, named_parameters);
|
||||
case OQS_KEX_alg_sidh_cln16:
|
||||
return OQS_KEX_sidh_cln16_new(rand);
|
||||
default:
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include <oqs/kex.h>
|
||||
#include <oqs/rand.h>
|
||||
#include <oqs/common.h>
|
||||
|
||||
#include "kex_lwe_frodo.h"
|
||||
#include "local.h"
|
||||
@ -21,115 +22,16 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
OQS_KEX *OQS_KEX_lwe_frodo_new(OQS_RAND *rand, const uint8_t *seed, const size_t seed_len, const char *named_parameters) {
|
||||
|
||||
OQS_KEX *k;
|
||||
struct oqs_kex_lwe_frodo_params *params;
|
||||
|
||||
if ((seed_len == 0) || (seed == NULL)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
k = malloc(sizeof(OQS_KEX));
|
||||
if (k == NULL) {
|
||||
goto err;
|
||||
}
|
||||
k->named_parameters = NULL;
|
||||
k->method_name = NULL;
|
||||
|
||||
k->params = malloc(sizeof(struct oqs_kex_lwe_frodo_params));
|
||||
if (NULL == k->params) {
|
||||
goto err;
|
||||
}
|
||||
params = (struct oqs_kex_lwe_frodo_params *) k->params;
|
||||
params->cdf_table = NULL;
|
||||
params->seed = NULL;
|
||||
params->param_name = NULL;
|
||||
|
||||
k->rand = rand;
|
||||
k->ctx = NULL;
|
||||
k->alice_priv_free = &OQS_KEX_lwe_frodo_alice_priv_free;
|
||||
k->free = &OQS_KEX_lwe_frodo_free;
|
||||
|
||||
if (strcmp(named_parameters, "recommended") == 0) {
|
||||
|
||||
k->alice_0 = &OQS_KEX_lwe_frodo_alice_0_recommended;
|
||||
k->bob = &OQS_KEX_lwe_frodo_bob_recommended;
|
||||
k->alice_1 = &OQS_KEX_lwe_frodo_alice_1_recommended;
|
||||
|
||||
k->method_name = strdup("LWE Frodo recommended");
|
||||
if (NULL == k->method_name) {
|
||||
goto err;
|
||||
}
|
||||
k->estimated_classical_security = 144;
|
||||
k->estimated_quantum_security = 130;
|
||||
k->named_parameters = strdup(named_parameters);
|
||||
if (k->named_parameters == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
params->seed = malloc(seed_len);
|
||||
if (NULL == params->seed) {
|
||||
goto err;
|
||||
}
|
||||
memcpy(params->seed, seed, seed_len);
|
||||
params->seed_len = seed_len;
|
||||
params->param_name = strdup("recommended");
|
||||
if (NULL == params->param_name) {
|
||||
goto err;
|
||||
}
|
||||
params->log2_q = 15;
|
||||
params->q = 1 << params->log2_q;
|
||||
params->n = 752;
|
||||
params->extracted_bits = 4;
|
||||
params->nbar = 8;
|
||||
params->key_bits = 256;
|
||||
params->rec_hint_len = LWE_DIV_ROUNDUP(params->nbar * params->nbar, 8);
|
||||
params->pub_len = LWE_DIV_ROUNDUP(params->n * params->nbar * params->log2_q, 8);
|
||||
params->stripe_step = 8;
|
||||
params->sampler_num = 12;
|
||||
params->cdf_table_len = 6;
|
||||
params->cdf_table = malloc(params->cdf_table_len * sizeof(uint16_t));
|
||||
if (NULL == params->cdf_table) {
|
||||
goto err;
|
||||
}
|
||||
uint16_t cdf_table_tmp[6] = {602, 1521, 1927, 2031, 2046, 2047};
|
||||
memcpy(params->cdf_table, cdf_table_tmp, sizeof(cdf_table_tmp));
|
||||
|
||||
} else {
|
||||
|
||||
goto err;
|
||||
|
||||
}
|
||||
|
||||
return k;
|
||||
|
||||
err:
|
||||
if (k) {
|
||||
if (k->params) {
|
||||
free(params->cdf_table);
|
||||
free(params->seed);
|
||||
free(params->param_name);
|
||||
free(k->params);
|
||||
}
|
||||
free(k->named_parameters);
|
||||
free(k->method_name);
|
||||
free(k);
|
||||
}
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
// pre-process code to obtain "recommended" functions
|
||||
#include "recommended.h"
|
||||
#define MACRIFY(NAME) NAME ## _recommended
|
||||
#include "kex_lwe_frodo_macrify.c"
|
||||
// undefine macros to avoid any confusion later
|
||||
#include "recommended.h"
|
||||
#undef MACRIFY
|
||||
|
||||
void OQS_KEX_lwe_frodo_alice_priv_free(UNUSED OQS_KEX *k, void *alice_priv) {
|
||||
if (alice_priv) {
|
||||
free(alice_priv);
|
||||
}
|
||||
free(alice_priv);
|
||||
}
|
||||
|
||||
void OQS_KEX_lwe_frodo_free(OQS_KEX *k) {
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include <oqs/kex.h>
|
||||
#include <oqs/rand.h>
|
||||
|
||||
OQS_KEX *OQS_KEX_lwe_frodo_new(OQS_RAND *rand, const uint8_t *seed, const size_t seed_len, const char *named_parameters);
|
||||
OQS_KEX *OQS_KEX_lwe_frodo_new_recommended(OQS_RAND *rand, const uint8_t *seed, const size_t seed_len, const char *named_parameters);
|
||||
|
||||
int OQS_KEX_lwe_frodo_alice_0_recommended(OQS_KEX *k, void **alice_priv, uint8_t **alice_msg, size_t *alice_msg_len);
|
||||
int OQS_KEX_lwe_frodo_bob_recommended(OQS_KEX *k, const uint8_t *alice_msg, const size_t alice_msg_len, uint8_t **bob_msg, size_t *bob_msg_len, uint8_t **key, size_t *key_len);
|
||||
|
@ -1,65 +1,133 @@
|
||||
OQS_KEX *MACRIFY(OQS_KEX_lwe_frodo_new)(OQS_RAND *rand, const uint8_t *seed, const size_t seed_len, const char *named_parameters) {
|
||||
|
||||
OQS_KEX *k;
|
||||
struct oqs_kex_lwe_frodo_params *params;
|
||||
|
||||
if ((seed_len == 0) || (seed == NULL)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
k = malloc(sizeof(OQS_KEX));
|
||||
if (k == NULL) {
|
||||
goto err;
|
||||
}
|
||||
k->named_parameters = NULL;
|
||||
k->method_name = NULL;
|
||||
|
||||
k->params = malloc(sizeof(struct oqs_kex_lwe_frodo_params));
|
||||
if (NULL == k->params) {
|
||||
goto err;
|
||||
}
|
||||
params = (struct oqs_kex_lwe_frodo_params *) k->params;
|
||||
params->cdf_table = NULL;
|
||||
params->seed = NULL;
|
||||
params->param_name = NULL;
|
||||
|
||||
k->rand = rand;
|
||||
k->ctx = NULL;
|
||||
k->alice_priv_free = &OQS_KEX_lwe_frodo_alice_priv_free;
|
||||
k->free = &OQS_KEX_lwe_frodo_free;
|
||||
|
||||
if (strcmp(named_parameters, "recommended") == 0) {
|
||||
|
||||
k->alice_0 = &OQS_KEX_lwe_frodo_alice_0_recommended;
|
||||
k->bob = &OQS_KEX_lwe_frodo_bob_recommended;
|
||||
k->alice_1 = &OQS_KEX_lwe_frodo_alice_1_recommended;
|
||||
|
||||
k->method_name = strdup("LWE Frodo recommended");
|
||||
if (NULL == k->method_name) {
|
||||
goto err;
|
||||
}
|
||||
k->estimated_classical_security = 144;
|
||||
k->estimated_quantum_security = 130;
|
||||
k->named_parameters = strdup(named_parameters);
|
||||
if (k->named_parameters == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
params->seed = malloc(seed_len);
|
||||
if (NULL == params->seed) {
|
||||
goto err;
|
||||
}
|
||||
memcpy(params->seed, seed, seed_len);
|
||||
params->seed_len = seed_len;
|
||||
params->param_name = strdup("recommended");
|
||||
if (NULL == params->param_name) {
|
||||
goto err;
|
||||
}
|
||||
params->log2_q = PARAMS_LOG2Q;
|
||||
params->q = PARAMS_Q;
|
||||
params->n = PARAMS_N;
|
||||
params->extracted_bits = PARAMS_EXTRACTED_BITS;
|
||||
params->nbar = PARAMS_NBAR;
|
||||
params->key_bits = PARAMS_KEY_BITS;
|
||||
params->rec_hint_len = PARAMS_REC_HINT_LENGTH;
|
||||
params->pub_len = PARAMS_REC_PUB_LENGTH;
|
||||
params->stripe_step = PARAMS_STRIPE_STEP;
|
||||
params->sampler_num = 12;
|
||||
params->cdf_table_len = 6;
|
||||
params->cdf_table = malloc(params->cdf_table_len * sizeof(uint16_t));
|
||||
if (NULL == params->cdf_table) {
|
||||
goto err;
|
||||
}
|
||||
uint16_t cdf_table_tmp[6] = {602, 1521, 1927, 2031, 2046, 2047};
|
||||
memcpy(params->cdf_table, cdf_table_tmp, sizeof(cdf_table_tmp));
|
||||
} else {
|
||||
goto err;
|
||||
}
|
||||
return k;
|
||||
err:
|
||||
OQS_KEX_lwe_frodo_free(k);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int MACRIFY(OQS_KEX_lwe_frodo_alice_0)(OQS_KEX *k, void **alice_priv, uint8_t **alice_msg, size_t *alice_msg_len) {
|
||||
|
||||
int ret;
|
||||
|
||||
struct oqs_kex_lwe_frodo_params *params = (struct oqs_kex_lwe_frodo_params *) k->params;
|
||||
uint16_t *b = NULL, *e = NULL;
|
||||
|
||||
*alice_priv = NULL;
|
||||
*alice_msg = NULL;
|
||||
|
||||
/* allocate private key, error, and outgoing message */
|
||||
*alice_priv = malloc(params->n * params->nbar * sizeof(uint16_t));
|
||||
*alice_priv = malloc(PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
|
||||
if (*alice_priv == NULL) {
|
||||
goto err;
|
||||
}
|
||||
b = (uint16_t *) malloc(params->n * params->nbar * sizeof(uint16_t));
|
||||
if (b == NULL) {
|
||||
goto err;
|
||||
}
|
||||
e = (uint16_t *) malloc(params->n * params->nbar * sizeof(uint16_t));
|
||||
if (e == NULL) {
|
||||
goto err;
|
||||
}
|
||||
*alice_msg = malloc(params->pub_len);
|
||||
uint16_t b[PARAMS_N * PARAMS_NBAR];
|
||||
uint16_t e[PARAMS_N * PARAMS_NBAR];
|
||||
|
||||
*alice_msg = malloc(PARAMS_REC_PUB_LENGTH);
|
||||
*alice_msg_len = PARAMS_REC_PUB_LENGTH;
|
||||
if (*alice_msg == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* generate S and E */
|
||||
ret = oqs_kex_lwe_frodo_sample_n(*alice_priv, params->n * params->nbar, params, k->rand);
|
||||
if (ret != 1) {
|
||||
goto err;
|
||||
}
|
||||
ret = oqs_kex_lwe_frodo_sample_n(e, params->n * params->nbar, params, k->rand);
|
||||
if (ret != 1) {
|
||||
goto err;
|
||||
}
|
||||
oqs_kex_lwe_frodo_sample_n(*alice_priv, PARAMS_N * PARAMS_NBAR, params, k->rand);
|
||||
oqs_kex_lwe_frodo_sample_n(e, PARAMS_N * PARAMS_NBAR, params, k->rand);
|
||||
|
||||
/* compute B = AS + E */
|
||||
ret = MACRIFY(oqs_kex_lwe_frodo_mul_add_as_plus_e_on_the_fly)(b, *alice_priv, e, params);
|
||||
if (ret != 1) {
|
||||
goto err;
|
||||
}
|
||||
oqs_kex_lwe_frodo_pack(*alice_msg, params->pub_len, b, params->n * params->nbar, params->log2_q);
|
||||
MACRIFY(oqs_kex_lwe_frodo_mul_add_as_plus_e_on_the_fly)(b, *alice_priv, e, params);
|
||||
|
||||
oqs_kex_lwe_frodo_pack(*alice_msg, PARAMS_REC_PUB_LENGTH, b, PARAMS_N * PARAMS_NBAR, PARAMS_LOG2Q);
|
||||
|
||||
*alice_msg_len = params->pub_len;
|
||||
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
|
||||
err:
|
||||
ret = 0;
|
||||
OQS_MEM_cleanse(e, sizeof(e));
|
||||
free(*alice_msg);
|
||||
*alice_msg = NULL;
|
||||
free(*alice_priv);
|
||||
*alice_priv = NULL;
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
free(e);
|
||||
free(b);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
int MACRIFY(OQS_KEX_lwe_frodo_bob)(OQS_KEX *k, const uint8_t *alice_msg, const size_t alice_msg_len, uint8_t **bob_msg, size_t *bob_msg_len, uint8_t **key, size_t *key_len) {
|
||||
@ -68,78 +136,46 @@ int MACRIFY(OQS_KEX_lwe_frodo_bob)(OQS_KEX *k, const uint8_t *alice_msg, const s
|
||||
|
||||
struct oqs_kex_lwe_frodo_params *params = (struct oqs_kex_lwe_frodo_params *) k->params;
|
||||
|
||||
uint16_t *bob_priv = NULL;
|
||||
uint8_t *bob_rec = NULL;
|
||||
uint16_t *b = NULL, *bprime = NULL, *eprime = NULL, *eprimeprime = NULL;
|
||||
uint16_t *v = NULL;
|
||||
*bob_msg = NULL;
|
||||
*key = NULL;
|
||||
|
||||
/* check length of other party's public key */
|
||||
if (alice_msg_len != params->pub_len) {
|
||||
if (alice_msg_len != PARAMS_REC_PUB_LENGTH) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* allocate private key, errors, outgoing message, and key */
|
||||
bob_priv = malloc(params->n * params->nbar * sizeof(uint16_t));
|
||||
if (bob_priv == NULL) {
|
||||
goto err;
|
||||
}
|
||||
bprime = (uint16_t *) malloc(params->n * params->nbar * sizeof(uint16_t));
|
||||
if (bprime == NULL) {
|
||||
goto err;
|
||||
}
|
||||
eprime = (uint16_t *) malloc(params->n * params->nbar * sizeof(uint16_t));
|
||||
if (eprime == NULL) {
|
||||
goto err;
|
||||
}
|
||||
eprimeprime = (uint16_t *) malloc(params->nbar * params->nbar * sizeof(uint16_t));
|
||||
if (eprimeprime == NULL) {
|
||||
goto err;
|
||||
}
|
||||
b = (uint16_t *) malloc(params->n * params->nbar * sizeof(uint16_t));
|
||||
if (b == NULL) {
|
||||
goto err;
|
||||
}
|
||||
v = (uint16_t *) malloc(params->nbar * params->nbar * sizeof(uint16_t));
|
||||
if (v == NULL) {
|
||||
goto err;
|
||||
}
|
||||
*bob_msg = malloc(params->pub_len + params->rec_hint_len);
|
||||
uint16_t bob_priv[PARAMS_N * PARAMS_NBAR];
|
||||
uint16_t bprime[PARAMS_N * PARAMS_NBAR];
|
||||
uint16_t eprime[PARAMS_N * PARAMS_NBAR];
|
||||
uint16_t eprimeprime[PARAMS_N * PARAMS_NBAR];
|
||||
uint16_t b[PARAMS_N * PARAMS_NBAR];
|
||||
uint16_t v[PARAMS_N * PARAMS_NBAR];
|
||||
*bob_msg = malloc(PARAMS_REC_PUB_LENGTH + PARAMS_REC_HINT_LENGTH);
|
||||
if (*bob_msg == NULL) {
|
||||
goto err;
|
||||
}
|
||||
bob_rec = *bob_msg + params->pub_len;
|
||||
*key = malloc(params->key_bits >> 3);
|
||||
bob_rec = *bob_msg + PARAMS_REC_PUB_LENGTH;
|
||||
*key = malloc(PARAMS_KEY_BYTES);
|
||||
if (*key == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* generate S' and E' */
|
||||
ret = oqs_kex_lwe_frodo_sample_n(bob_priv, params->n * params->nbar, params, k->rand);
|
||||
if (ret != 1) {
|
||||
goto err;
|
||||
}
|
||||
ret = oqs_kex_lwe_frodo_sample_n(eprime, params->n * params->nbar, params, k->rand);
|
||||
if (ret != 1) {
|
||||
goto err;
|
||||
}
|
||||
oqs_kex_lwe_frodo_sample_n(bob_priv, PARAMS_N * PARAMS_NBAR, params, k->rand);
|
||||
oqs_kex_lwe_frodo_sample_n(eprime, PARAMS_N * PARAMS_NBAR, params, k->rand);
|
||||
|
||||
/* compute B' = S'A + E' */
|
||||
ret = MACRIFY(oqs_kex_lwe_frodo_mul_add_sa_plus_e_on_the_fly)(bprime, bob_priv, eprime, params);
|
||||
if (ret != 1) {
|
||||
goto err;
|
||||
}
|
||||
oqs_kex_lwe_frodo_pack(*bob_msg, params->pub_len, bprime, params->n * params->nbar, params->log2_q);
|
||||
MACRIFY(oqs_kex_lwe_frodo_mul_add_sa_plus_e_on_the_fly)(bprime, bob_priv, eprime, params);
|
||||
|
||||
oqs_kex_lwe_frodo_pack(*bob_msg, PARAMS_REC_PUB_LENGTH, bprime, PARAMS_N * PARAMS_NBAR, PARAMS_LOG2Q);
|
||||
|
||||
/* generate E'' */
|
||||
ret = oqs_kex_lwe_frodo_sample_n(eprimeprime, params->nbar * params->nbar, params, k->rand);
|
||||
if (ret != 1) {
|
||||
goto err;
|
||||
}
|
||||
oqs_kex_lwe_frodo_sample_n(eprimeprime, PARAMS_NBAR * PARAMS_NBAR, params, k->rand);
|
||||
|
||||
/* unpack B */
|
||||
oqs_kex_lwe_frodo_unpack(b, params->n * params->nbar, alice_msg, alice_msg_len, params->log2_q);
|
||||
oqs_kex_lwe_frodo_unpack(b, PARAMS_N * PARAMS_NBAR, alice_msg, alice_msg_len, PARAMS_LOG2Q);
|
||||
|
||||
/* compute V = S'B + E'' */
|
||||
MACRIFY(oqs_kex_lwe_frodo_mul_add_sb_plus_e)(v, b, bob_priv, eprimeprime);
|
||||
@ -150,8 +186,8 @@ int MACRIFY(OQS_KEX_lwe_frodo_bob)(OQS_KEX *k, const uint8_t *alice_msg, const s
|
||||
/* compute K = round(V)_{2^B} */
|
||||
MACRIFY(oqs_kex_lwe_frodo_round2)(*key, v);
|
||||
|
||||
*bob_msg_len = params->pub_len + params->rec_hint_len;
|
||||
*key_len = params->key_bits >> 3;
|
||||
*bob_msg_len = PARAMS_REC_PUB_LENGTH + PARAMS_REC_HINT_LENGTH;
|
||||
*key_len = PARAMS_KEY_BYTES;
|
||||
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
@ -160,85 +196,58 @@ err:
|
||||
ret = 0;
|
||||
free(*bob_msg);
|
||||
*bob_msg = NULL;
|
||||
if (*key != NULL) {
|
||||
memset(*key, 0, params->key_bits >> 3);
|
||||
}
|
||||
free(*key);
|
||||
OQS_MEM_secure_free(*key, PARAMS_KEY_BYTES);
|
||||
*key = NULL;
|
||||
|
||||
cleanup:
|
||||
free(bob_priv);
|
||||
if (eprime != NULL) {
|
||||
memset(eprime, 0, params->n * params->nbar * sizeof(uint16_t));
|
||||
}
|
||||
free(bprime);
|
||||
free(eprime);
|
||||
if (eprimeprime != NULL) {
|
||||
memset(eprimeprime, 0, params->nbar * params->nbar * sizeof(uint16_t));
|
||||
}
|
||||
free(eprimeprime);
|
||||
free(b);
|
||||
if (v != NULL) {
|
||||
memset(v, 0, params->nbar * params->nbar * sizeof(uint16_t));
|
||||
}
|
||||
free(v);
|
||||
OQS_MEM_cleanse(eprime, sizeof(eprime));
|
||||
OQS_MEM_cleanse(eprimeprime, sizeof(eprimeprime));
|
||||
OQS_MEM_cleanse(v, sizeof(v));
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
int MACRIFY(OQS_KEX_lwe_frodo_alice_1)(OQS_KEX *k, const void *alice_priv, const uint8_t *bob_msg, const size_t bob_msg_len, uint8_t **key, size_t *key_len) {
|
||||
int MACRIFY(OQS_KEX_lwe_frodo_alice_1)(UNUSED OQS_KEX *k, const void *alice_priv, const uint8_t *bob_msg, const size_t bob_msg_len, uint8_t **key, size_t *key_len) {
|
||||
|
||||
int ret;
|
||||
|
||||
struct oqs_kex_lwe_frodo_params *params = (struct oqs_kex_lwe_frodo_params *) k->params;
|
||||
|
||||
uint16_t *bprime = NULL, *w = NULL;
|
||||
*key = NULL;
|
||||
|
||||
/* check length of other party's public key */
|
||||
if (bob_msg_len != params->pub_len + params->rec_hint_len) {
|
||||
if (bob_msg_len != PARAMS_REC_PUB_LENGTH + PARAMS_REC_HINT_LENGTH) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* allocate working values and session key */
|
||||
bprime = malloc(params->n * params->nbar * sizeof(uint16_t));
|
||||
if (bprime == NULL) {
|
||||
goto err;
|
||||
}
|
||||
w = malloc(params->nbar * params->nbar * sizeof(uint16_t));
|
||||
if (w == NULL) {
|
||||
goto err;
|
||||
}
|
||||
*key = malloc(params->key_bits >> 3);
|
||||
uint16_t bprime[PARAMS_N * PARAMS_NBAR];
|
||||
uint16_t w[PARAMS_N * PARAMS_NBAR];
|
||||
|
||||
*key = malloc(PARAMS_KEY_BYTES);
|
||||
if (*key == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* unpack B' */
|
||||
oqs_kex_lwe_frodo_unpack(bprime, params->n * params->nbar, bob_msg, params->pub_len, params->log2_q);
|
||||
oqs_kex_lwe_frodo_unpack(bprime, PARAMS_N * PARAMS_NBAR, bob_msg, PARAMS_REC_PUB_LENGTH, PARAMS_LOG2Q);
|
||||
|
||||
/* compute W = B'S */
|
||||
MACRIFY(oqs_kex_lwe_frodo_mul_bs)(w, bprime, (uint16_t *) alice_priv);
|
||||
|
||||
/* compute K = rec(B'S, C) */
|
||||
const uint8_t *bob_rec = bob_msg + params->pub_len;
|
||||
const uint8_t *bob_rec = bob_msg + PARAMS_REC_PUB_LENGTH;
|
||||
MACRIFY(oqs_kex_lwe_frodo_reconcile)(*key, w, bob_rec);
|
||||
|
||||
*key_len = params->key_bits >> 3;
|
||||
*key_len = PARAMS_KEY_BYTES;
|
||||
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
|
||||
err:
|
||||
ret = 0;
|
||||
memset(key, 0, params->key_bits >> 3);
|
||||
free(*key);
|
||||
OQS_MEM_secure_free(*key, PARAMS_KEY_BYTES);
|
||||
*key = NULL;
|
||||
|
||||
cleanup:
|
||||
free(w);
|
||||
free(bprime);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
@ -32,10 +32,10 @@ void oqs_kex_lwe_frodo_key_round_hints(uint16_t *vec, const size_t length, const
|
||||
void oqs_kex_lwe_frodo_pack(unsigned char *out, const size_t outlen, const uint16_t *in, const size_t inlen, const unsigned char lsb);
|
||||
void oqs_kex_lwe_frodo_unpack(uint16_t *out, const size_t outlen, const unsigned char *in, const size_t inlen, const unsigned char lsb);
|
||||
|
||||
int oqs_kex_lwe_frodo_sample_n(uint16_t *s, const size_t n, struct oqs_kex_lwe_frodo_params *params, OQS_RAND *rand);
|
||||
void oqs_kex_lwe_frodo_sample_n(uint16_t *s, const size_t n, struct oqs_kex_lwe_frodo_params *params, OQS_RAND *rand);
|
||||
|
||||
int oqs_kex_lwe_frodo_mul_add_as_plus_e_on_the_fly_recommended(uint16_t *b, const uint16_t *s, const uint16_t *e, struct oqs_kex_lwe_frodo_params *params);
|
||||
int oqs_kex_lwe_frodo_mul_add_sa_plus_e_on_the_fly_recommended(uint16_t *b, const uint16_t *s, const uint16_t *e, struct oqs_kex_lwe_frodo_params *params);
|
||||
void oqs_kex_lwe_frodo_mul_add_as_plus_e_on_the_fly_recommended(uint16_t *b, const uint16_t *s, const uint16_t *e, struct oqs_kex_lwe_frodo_params *params);
|
||||
void oqs_kex_lwe_frodo_mul_add_sa_plus_e_on_the_fly_recommended(uint16_t *b, const uint16_t *s, const uint16_t *e, struct oqs_kex_lwe_frodo_params *params);
|
||||
void oqs_kex_lwe_frodo_mul_add_sb_plus_e_recommended(uint16_t *out, const uint16_t *b, const uint16_t *s, const uint16_t *e);
|
||||
void oqs_kex_lwe_frodo_mul_bs_recommended(uint16_t *out, const uint16_t *b, const uint16_t *s);
|
||||
|
||||
|
@ -71,7 +71,7 @@ void oqs_kex_lwe_frodo_pack(unsigned char *out, const size_t outlen, const uint1
|
||||
int nbits = min(8 - b, bits);
|
||||
uint16_t mask = (1 << nbits) - 1;
|
||||
unsigned char t = (w >> (bits - nbits)) & mask; // the bits to copy from w to out
|
||||
out[i] = out[i] + (t << (8 - b - nbits));
|
||||
out[i] += t << (8 - b - nbits);
|
||||
b += nbits;
|
||||
bits -= nbits;
|
||||
w &= ~(mask << bits); // not strictly necessary; mostly for debugging
|
||||
@ -119,7 +119,7 @@ void oqs_kex_lwe_frodo_unpack(uint16_t *out, const size_t outlen, const unsigned
|
||||
int nbits = min(lsb - b, bits);
|
||||
uint16_t mask = (1 << nbits) - 1;
|
||||
unsigned char t = (w >> (bits - nbits)) & mask; // the bits to copy from w to out
|
||||
out[i] = out[i] + (t << (lsb - b - nbits));
|
||||
out[i] += t << (lsb - b - nbits);
|
||||
b += nbits;
|
||||
bits -= nbits;
|
||||
w &= ~(mask << bits); // not strictly necessary; mostly for debugging
|
||||
@ -140,27 +140,11 @@ void oqs_kex_lwe_frodo_unpack(uint16_t *out, const size_t outlen, const unsigned
|
||||
}
|
||||
}
|
||||
|
||||
#define LWE_DIV_ROUNDUP(x, y) (((x) + (y)-1) / y)
|
||||
|
||||
// define parameters for "recommended" parameter set
|
||||
#define PARAMS_N 752
|
||||
#define PARAMS_NBAR 8
|
||||
#define PARAMS_LOG2Q 15
|
||||
#define PARAMS_Q (1 << PARAMS_LOG2Q)
|
||||
#define PARAMS_EXTRACTED_BITS 4
|
||||
#define PARAMS_KEY_BITS 256
|
||||
#define PARAMS_STRIPE_STEP 8
|
||||
#define PARAMS_REC_HINT_LENGTH LWE_DIV_ROUNDUP(PARAMS_NBAR * PARAMS_NBAR, 8)
|
||||
#include "recommended.h"
|
||||
// pre-process code to obtain "recommended" functions
|
||||
#define MACRIFY(NAME) NAME ## _recommended
|
||||
#include "lwe_macrify.c"
|
||||
// undefine macros to avoid any confusion later
|
||||
#undef PARAMS_N
|
||||
#undef PARAMS_NBAR
|
||||
#undef PARAMS_LOG2Q
|
||||
#undef PARAMS_Q
|
||||
#undef PARAMS_EXTRACTED_BITS
|
||||
#undef PARAMS_KEY_BITS
|
||||
#undef PARAMS_STRIPE_STEP
|
||||
#undef PARAMS_REC_HINT_LENGTH
|
||||
#include "recommended.h"
|
||||
#undef MACRIFY
|
||||
|
@ -1,8 +1,7 @@
|
||||
// [.]_2
|
||||
void MACRIFY(oqs_kex_lwe_frodo_round2)(unsigned char *out, uint16_t *in) {
|
||||
oqs_kex_lwe_frodo_key_round(in, PARAMS_NBAR * PARAMS_NBAR, PARAMS_LOG2Q - PARAMS_EXTRACTED_BITS);
|
||||
int i;
|
||||
for (i = 0; i < PARAMS_NBAR * PARAMS_NBAR; i++) {
|
||||
for (int i = 0; i < PARAMS_NBAR * PARAMS_NBAR; i++) {
|
||||
in[i] >>= PARAMS_LOG2Q - PARAMS_EXTRACTED_BITS; // drop bits that were zeroed out
|
||||
}
|
||||
|
||||
@ -11,7 +10,6 @@ void MACRIFY(oqs_kex_lwe_frodo_round2)(unsigned char *out, uint16_t *in) {
|
||||
}
|
||||
|
||||
void MACRIFY(oqs_kex_lwe_frodo_crossround2)(unsigned char *out, const uint16_t *in) {
|
||||
int i;
|
||||
// out should have enough space for N_BAR * N_BAR bits
|
||||
memset((unsigned char *)out, 0, PARAMS_REC_HINT_LENGTH);
|
||||
|
||||
@ -19,7 +17,7 @@ void MACRIFY(oqs_kex_lwe_frodo_crossround2)(unsigned char *out, const uint16_t *
|
||||
uint16_t half = whole >> 1;
|
||||
uint16_t mask = whole - 1;
|
||||
|
||||
for (i = 0; i < PARAMS_NBAR * PARAMS_NBAR; i++) {
|
||||
for (int i = 0; i < PARAMS_NBAR * PARAMS_NBAR; i++) {
|
||||
uint16_t remainder = in[i] & mask;
|
||||
out[i / 8] += (remainder >= half) << (i % 8);
|
||||
}
|
||||
@ -27,44 +25,24 @@ void MACRIFY(oqs_kex_lwe_frodo_crossround2)(unsigned char *out, const uint16_t *
|
||||
|
||||
void MACRIFY(oqs_kex_lwe_frodo_reconcile)(unsigned char *out, uint16_t *w, const unsigned char *hint) {
|
||||
oqs_kex_lwe_frodo_key_round_hints(w, PARAMS_NBAR * PARAMS_NBAR, PARAMS_LOG2Q - PARAMS_EXTRACTED_BITS, hint);
|
||||
int i;
|
||||
for (i = 0; i < PARAMS_NBAR * PARAMS_NBAR; i++) {
|
||||
for (int i = 0; i < PARAMS_NBAR * PARAMS_NBAR; i++) {
|
||||
w[i] >>= PARAMS_LOG2Q - PARAMS_EXTRACTED_BITS; // drop bits that were zeroed out
|
||||
}
|
||||
oqs_kex_lwe_frodo_pack(out, PARAMS_KEY_BITS / 8, w, PARAMS_NBAR * PARAMS_NBAR, PARAMS_EXTRACTED_BITS);
|
||||
}
|
||||
|
||||
// Generate-and-multiply: generate A row-wise, multiply by s on the right.
|
||||
int MACRIFY(oqs_kex_lwe_frodo_mul_add_as_plus_e_on_the_fly)(uint16_t *out, const uint16_t *s, const uint16_t *e, struct oqs_kex_lwe_frodo_params *params) {
|
||||
void MACRIFY(oqs_kex_lwe_frodo_mul_add_as_plus_e_on_the_fly)(uint16_t *out, const uint16_t *s, const uint16_t *e, struct oqs_kex_lwe_frodo_params *params) {
|
||||
// A (N x N)
|
||||
// s,e (N x N_BAR)
|
||||
// out = A * s + e (N x N_BAR)
|
||||
|
||||
int i, j, k;
|
||||
int ret = 0;
|
||||
uint16_t *a_row = NULL;
|
||||
uint16_t *s_transpose = NULL;
|
||||
|
||||
for (i = 0; i < PARAMS_N; i++) {
|
||||
for (j = 0; j < PARAMS_NBAR; j++) {
|
||||
out[i * PARAMS_NBAR + j] = e[i * PARAMS_NBAR + j];
|
||||
}
|
||||
}
|
||||
|
||||
size_t a_rowlen = PARAMS_N * sizeof(int16_t);
|
||||
a_row = (uint16_t *) malloc(a_rowlen);
|
||||
if (a_row == NULL) {
|
||||
goto err;
|
||||
}
|
||||
memcpy(out, e, PARAMS_NBAR * PARAMS_N * sizeof(uint16_t));
|
||||
|
||||
// transpose s to store it in the column-major order
|
||||
s_transpose = (uint16_t *) malloc(PARAMS_NBAR * PARAMS_N * sizeof(int16_t));
|
||||
if (s_transpose == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (j = 0; j < PARAMS_N; j++) {
|
||||
for (k = 0; k < PARAMS_NBAR; k++) {
|
||||
uint16_t s_transpose[PARAMS_NBAR * PARAMS_N];
|
||||
for (int j = 0; j < PARAMS_N; j++) {
|
||||
for (int k = 0; k < PARAMS_NBAR; k++) {
|
||||
s_transpose[k * PARAMS_N + j] = s[j * PARAMS_NBAR + k];
|
||||
}
|
||||
}
|
||||
@ -73,127 +51,78 @@ int MACRIFY(oqs_kex_lwe_frodo_mul_add_as_plus_e_on_the_fly)(uint16_t *out, const
|
||||
void *aes_key_schedule = NULL;
|
||||
OQS_AES128_load_schedule(params->seed, &aes_key_schedule, 1);
|
||||
|
||||
for (i = 0; i < PARAMS_N; i++) {
|
||||
for (int i = 0; i < PARAMS_N; i++) {
|
||||
uint16_t a_row[PARAMS_N] = {0};
|
||||
// go through A's rows
|
||||
memset(a_row, 0, a_rowlen);
|
||||
for (j = 0; j < PARAMS_N; j += PARAMS_STRIPE_STEP) {
|
||||
for (int j = 0; j < PARAMS_N; j += PARAMS_STRIPE_STEP) {
|
||||
// Loading values in the little-endian order!
|
||||
a_row[j] = i;
|
||||
a_row[j + 1] = j;
|
||||
}
|
||||
|
||||
OQS_AES128_ECB_enc_sch((uint8_t *) a_row, a_rowlen, aes_key_schedule, (uint8_t *) a_row);
|
||||
OQS_AES128_ECB_enc_sch((uint8_t *) a_row, sizeof(a_row), aes_key_schedule, (uint8_t *) a_row);
|
||||
|
||||
for (k = 0; k < PARAMS_NBAR; k++) {
|
||||
for (int k = 0; k < PARAMS_NBAR; k++) {
|
||||
uint16_t sum = 0;
|
||||
for (j = 0; j < PARAMS_N; j++) {
|
||||
for (int j = 0; j < PARAMS_N; j++) {
|
||||
// matrix-vector multiplication happens here
|
||||
sum += a_row[j] * s_transpose[k * PARAMS_N + j];
|
||||
}
|
||||
out[i * PARAMS_NBAR + k] += sum;
|
||||
out[i * PARAMS_NBAR + k] %= PARAMS_Q;
|
||||
//Equivalent to %= PARAMS_Q if PARAMS_Q is a power of 2
|
||||
out[i * PARAMS_NBAR + k] &= PARAMS_Q - 1;
|
||||
}
|
||||
}
|
||||
|
||||
OQS_AES128_free_schedule(aes_key_schedule);
|
||||
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
|
||||
err:
|
||||
memset(out, 0, PARAMS_NBAR * PARAMS_N * sizeof(uint16_t));
|
||||
|
||||
cleanup:
|
||||
if (a_row != NULL) {
|
||||
memset(a_row, 0, a_rowlen);
|
||||
free(a_row);
|
||||
}
|
||||
|
||||
if (s_transpose != NULL) {
|
||||
memset(s_transpose, 0, PARAMS_NBAR * PARAMS_N * sizeof(int16_t));
|
||||
free(s_transpose);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
// Generate-and-multiply: generate A column-wise, multiply by s' on the left.
|
||||
int MACRIFY(oqs_kex_lwe_frodo_mul_add_sa_plus_e_on_the_fly)(uint16_t *out, const uint16_t *s, const uint16_t *e, struct oqs_kex_lwe_frodo_params *params) {
|
||||
void MACRIFY(oqs_kex_lwe_frodo_mul_add_sa_plus_e_on_the_fly)(uint16_t *out, const uint16_t *s, const uint16_t *e, struct oqs_kex_lwe_frodo_params *params) {
|
||||
// a (N x N)
|
||||
// s',e' (N_BAR x N)
|
||||
// out = s'a + e' (N_BAR x N)
|
||||
|
||||
int i, j, k, kk;
|
||||
int ret = 0;
|
||||
uint16_t *a_cols = NULL;
|
||||
uint16_t *a_cols_t = NULL;
|
||||
|
||||
for (i = 0; i < PARAMS_NBAR; i++) {
|
||||
for (j = 0; j < PARAMS_N; j++) {
|
||||
out[i * PARAMS_N + j] = e[i * PARAMS_N + j];
|
||||
}
|
||||
}
|
||||
|
||||
size_t a_colslen = PARAMS_N * PARAMS_STRIPE_STEP * sizeof(int16_t);
|
||||
// a_cols stores 8 columns of A at a time.
|
||||
a_cols = (uint16_t *) malloc(a_colslen);
|
||||
a_cols_t = (uint16_t *) malloc(a_colslen); // a_cols transposed (stored in the column-major order).
|
||||
if ((a_cols == NULL) || (a_cols_t == NULL)) {
|
||||
goto err;
|
||||
}
|
||||
memcpy(out, e, PARAMS_NBAR * PARAMS_N * sizeof(uint16_t));
|
||||
|
||||
assert(params->seed_len == 16);
|
||||
|
||||
void *aes_key_schedule = NULL;
|
||||
OQS_AES128_load_schedule(params->seed, &aes_key_schedule, 1);
|
||||
|
||||
for (kk = 0; kk < PARAMS_N; kk += PARAMS_STRIPE_STEP) {
|
||||
for (int kk = 0; kk < PARAMS_N; kk += PARAMS_STRIPE_STEP) {
|
||||
// Go through A's columns, 8 (== PARAMS_STRIPE_STEP) columns at a time.
|
||||
memset(a_cols, 0, a_colslen);
|
||||
for (i = 0; i < PARAMS_N; i++) {
|
||||
// a_cols stores 8 columns of A at a time.
|
||||
uint16_t a_cols[PARAMS_N * PARAMS_STRIPE_STEP] = {0};
|
||||
for (int i = 0; i < PARAMS_N; i++) {
|
||||
// Loading values in the little-endian order!
|
||||
a_cols[i * PARAMS_STRIPE_STEP] = i;
|
||||
a_cols[i * PARAMS_STRIPE_STEP + 1] = kk;
|
||||
}
|
||||
|
||||
OQS_AES128_ECB_enc_sch((uint8_t *) a_cols, a_colslen, aes_key_schedule, (uint8_t *) a_cols);
|
||||
OQS_AES128_ECB_enc_sch((uint8_t *) a_cols, sizeof(a_cols), aes_key_schedule, (uint8_t *) a_cols);
|
||||
|
||||
// transpose a_cols to have access to it in the column-major order.
|
||||
for (i = 0; i < PARAMS_N; i++)
|
||||
for (k = 0; k < PARAMS_STRIPE_STEP; k++) {
|
||||
uint16_t a_cols_t[PARAMS_N * PARAMS_STRIPE_STEP];
|
||||
for (int i = 0; i < PARAMS_N; i++) {
|
||||
for (int k = 0; k < PARAMS_STRIPE_STEP; k++) {
|
||||
a_cols_t[k * PARAMS_N + i] = a_cols[i * PARAMS_STRIPE_STEP + k];
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < PARAMS_NBAR; i++)
|
||||
for (k = 0; k < PARAMS_STRIPE_STEP; k++) {
|
||||
for (int i = 0; i < PARAMS_NBAR; i++) {
|
||||
for (int k = 0; k < PARAMS_STRIPE_STEP; k++) {
|
||||
uint16_t sum = 0;
|
||||
for (j = 0; j < PARAMS_N; j++) {
|
||||
for (int j = 0; j < PARAMS_N; j++) {
|
||||
sum += s[i * PARAMS_N + j] * a_cols_t[k * PARAMS_N + j];
|
||||
}
|
||||
out[i * PARAMS_N + kk + k] += sum;
|
||||
out[i * PARAMS_N + kk + k] %= PARAMS_Q;
|
||||
out[i * PARAMS_N + kk + k] &= PARAMS_Q - 1; //Works as long as PARAMS_Q is a power of 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OQS_AES128_free_schedule(aes_key_schedule);
|
||||
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
|
||||
err:
|
||||
memset(out, 0, PARAMS_NBAR * PARAMS_N * sizeof(uint16_t));
|
||||
|
||||
cleanup:
|
||||
if (a_cols != NULL) {
|
||||
memset(a_cols, 0, a_colslen);
|
||||
free(a_cols);
|
||||
}
|
||||
|
||||
if (a_cols_t != NULL) {
|
||||
memset(a_cols_t, 0, a_colslen);
|
||||
free(a_cols_t);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// multiply by s on the right
|
||||
@ -201,14 +130,13 @@ void MACRIFY(oqs_kex_lwe_frodo_mul_bs)(uint16_t *out, const uint16_t *b, const u
|
||||
// b (N_BAR x N)
|
||||
// s (N x N_BAR)
|
||||
// out = bs
|
||||
int i, j, k;
|
||||
for (i = 0; i < PARAMS_NBAR; i++) {
|
||||
for (j = 0; j < PARAMS_NBAR; j++) {
|
||||
out[i * PARAMS_NBAR + j] = 0;
|
||||
for (k = 0; k < PARAMS_N; k++) {
|
||||
out[i * PARAMS_NBAR + j] += b[i * PARAMS_N + k] * s[k * PARAMS_NBAR + j];
|
||||
for (int i = 0; i < PARAMS_NBAR; i++) {
|
||||
for (int j = 0; j < PARAMS_NBAR; j++) {
|
||||
uint16_t sum = 0;
|
||||
for (int k = 0; k < PARAMS_N; k++) {
|
||||
sum += b[i * PARAMS_N + k] * s[k * PARAMS_NBAR + j];
|
||||
}
|
||||
out[i * PARAMS_NBAR + j] %= PARAMS_Q; // not really necessary since LWE_Q is a power of 2.
|
||||
out[i * PARAMS_NBAR + j] = sum & (PARAMS_Q - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -219,15 +147,15 @@ void MACRIFY(oqs_kex_lwe_frodo_mul_add_sb_plus_e)(uint16_t *out, const uint16_t
|
||||
// s (N_BAR x N)
|
||||
// e (N_BAR x N_BAR)
|
||||
// out = sb + e
|
||||
int i, j, k;
|
||||
for (k = 0; k < PARAMS_NBAR; k++) {
|
||||
for (i = 0; i < PARAMS_NBAR; i++) {
|
||||
out[k * PARAMS_NBAR + i] = e[k * PARAMS_NBAR + i];
|
||||
for (j = 0; j < PARAMS_N; j++) {
|
||||
out[k * PARAMS_NBAR + i] += s[k * PARAMS_N + j] * b[j * PARAMS_NBAR + i];
|
||||
memcpy(out, e, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t));
|
||||
for (int k = 0; k < PARAMS_NBAR; k++) {
|
||||
for (int i = 0; i < PARAMS_NBAR; i++) {
|
||||
uint16_t sum = 0;
|
||||
for (int j = 0; j < PARAMS_N; j++) {
|
||||
sum += s[k * PARAMS_N + j] * b[j * PARAMS_NBAR + i];
|
||||
}
|
||||
out[k * PARAMS_NBAR + i] %= PARAMS_Q; // not really necessary since LWE_Q is a power of 2.
|
||||
out[k * PARAMS_NBAR + i] += sum;
|
||||
out[k * PARAMS_NBAR + i] &= PARAMS_Q - 1; // not really necessary since LWE_Q is a power of 2.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,33 +5,26 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <oqs/rand.h>
|
||||
#include <oqs/common.h>
|
||||
|
||||
#include "local.h"
|
||||
|
||||
static int lwe_sample_n_inverse_8(uint16_t *s, const size_t n, const uint8_t *cdf_table, const size_t cdf_table_len, OQS_RAND *rand) {
|
||||
|
||||
static void lwe_sample_n_inverse_8(uint16_t *s, const size_t n, const uint8_t *cdf_table, const size_t cdf_table_len, OQS_RAND *rand) {
|
||||
/* Fills vector s with n samples from the noise distribution which requires
|
||||
* 8 bits to sample. The distribution is specified by its CDF. Super-constant
|
||||
* timing: the CDF table is ingested for every sample.
|
||||
*/
|
||||
|
||||
size_t rndlen = n;
|
||||
uint8_t *rndvec = (uint8_t *)malloc(rndlen);
|
||||
if (rndvec == NULL) {
|
||||
fprintf(stderr, "malloc failure\n");
|
||||
return 0;
|
||||
}
|
||||
OQS_RAND_n(rand, rndvec, rndlen);
|
||||
uint8_t rndvec[n];
|
||||
OQS_RAND_n(rand, rndvec, sizeof(rndvec));
|
||||
|
||||
size_t i, j;
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
uint8_t sample = 0;
|
||||
uint8_t rnd = rndvec[i] >> 1; // drop the least significant bit
|
||||
uint8_t sign = rndvec[i] & 0x1; // pick the least significant bit
|
||||
|
||||
// No need to compare with the last value.
|
||||
for (j = 0; j < cdf_table_len - 1; j++) {
|
||||
for (size_t j = 0; j < cdf_table_len - 1; j++) {
|
||||
// Constant time comparison: 1 if cdf_table[j] < rnd, 0 otherwise.
|
||||
// Critically uses the fact that cdf_table[j] and rnd fit in 7 bits.
|
||||
sample += (uint8_t)(cdf_table[j] - rnd) >> 7;
|
||||
@ -39,30 +32,19 @@ static int lwe_sample_n_inverse_8(uint16_t *s, const size_t n, const uint8_t *cd
|
||||
// Assuming that sign is either 0 or 1, flips sample iff sign = 1
|
||||
s[i] = ((-sign) ^ sample) + sign;
|
||||
}
|
||||
|
||||
memset(rndvec, 0, rndlen);
|
||||
free(rndvec);
|
||||
return 1;
|
||||
OQS_MEM_cleanse(rndvec, sizeof(rndvec));
|
||||
}
|
||||
|
||||
static int lwe_sample_n_inverse_12(uint16_t *s, const size_t n, const uint16_t *cdf_table, const size_t cdf_table_len, OQS_RAND *rand) {
|
||||
static void lwe_sample_n_inverse_12(uint16_t *s, const size_t n, const uint16_t *cdf_table, const size_t cdf_table_len, OQS_RAND *rand) {
|
||||
/* Fills vector s with n samples from the noise distribution which requires
|
||||
* 12 bits to sample. The distribution is specified by its CDF. Super-constant
|
||||
* timing: the CDF table is ingested for every sample.
|
||||
*/
|
||||
|
||||
size_t rndlen = 3 * ((n + 1) / 2); // 12 bits of unif randomness per output element
|
||||
uint8_t rnd[3 * ((n + 1) / 2)]; // 12 bits of unif randomness per output element
|
||||
OQS_RAND_n(rand, rnd, sizeof(rnd));
|
||||
|
||||
uint8_t *rnd = (uint8_t *)malloc(rndlen);
|
||||
if (rnd == NULL) {
|
||||
fprintf(stderr, "malloc failure\n");
|
||||
return 0;
|
||||
}
|
||||
OQS_RAND_n(rand, rnd, rndlen);
|
||||
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < n; i += 2) { // two output elements at a time
|
||||
for (size_t i = 0; i < n; i += 2) { // two output elements at a time
|
||||
uint8_t *pRnd = (rnd + 3 * i / 2);
|
||||
|
||||
uint16_t rnd1 = (((pRnd[0] << 8) + pRnd[1]) & 0xFFE0) >> 5; // first 11 bits (0..10)
|
||||
@ -71,9 +53,8 @@ static int lwe_sample_n_inverse_12(uint16_t *s, const size_t n, const uint16_t *
|
||||
uint8_t sample1 = 0;
|
||||
uint8_t sample2 = 0;
|
||||
|
||||
size_t j;
|
||||
// No need to compare with the last value.
|
||||
for (j = 0; j < cdf_table_len - 1; j++) {
|
||||
for (size_t j = 0; j < cdf_table_len - 1; j++) {
|
||||
// Constant time comparison: 1 if LWE_CDF_TABLE[j] < rnd1, 0 otherwise.
|
||||
// Critically uses the fact that LWE_CDF_TABLE[j] and rnd1 fit in 15 bits.
|
||||
sample1 += (uint16_t)(cdf_table[j] - rnd1) >> 15;
|
||||
@ -90,34 +71,25 @@ static int lwe_sample_n_inverse_12(uint16_t *s, const size_t n, const uint16_t *
|
||||
s[i + 1] = ((-sign2) ^ sample2) + sign2;
|
||||
}
|
||||
}
|
||||
|
||||
memset(rnd, 0, rndlen);
|
||||
free(rnd);
|
||||
return 1;
|
||||
OQS_MEM_cleanse(rnd, sizeof(rnd));
|
||||
}
|
||||
|
||||
static int lwe_sample_n_inverse_16(uint16_t *s, const size_t n, const uint16_t *cdf_table, const size_t cdf_table_len, OQS_RAND *rand) {
|
||||
static void lwe_sample_n_inverse_16(uint16_t *s, const size_t n, const uint16_t *cdf_table, const size_t cdf_table_len, OQS_RAND *rand) {
|
||||
/* Fills vector s with n samples from the noise distribution which requires
|
||||
* 16 bits to sample. The distribution is specified by its CDF. Super-constant
|
||||
* timing: the CDF table is ingested for every sample.
|
||||
*/
|
||||
|
||||
size_t rndlen = 2 * n;
|
||||
uint16_t *rndvec = (uint16_t *)malloc(rndlen);
|
||||
if (rndvec == NULL) {
|
||||
return 0;
|
||||
}
|
||||
OQS_RAND_n(rand, (uint8_t *) rndvec, rndlen);
|
||||
uint16_t rndvec[ n ];
|
||||
OQS_RAND_n(rand, (uint8_t *) rndvec, sizeof(rndvec));
|
||||
|
||||
size_t i, j;
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
uint8_t sample = 0;
|
||||
uint16_t rnd = rndvec[i] >> 1; // drop the least significant bit
|
||||
uint8_t sign = rndvec[i] & 0x1; // pick the least significant bit
|
||||
|
||||
// No need to compare with the last value.
|
||||
for (j = 0; j < cdf_table_len - 1; j++) {
|
||||
for (size_t j = 0; j < cdf_table_len - 1; j++) {
|
||||
// Constant time comparison: 1 if LWE_CDF_TABLE[j] < rnd, 0 otherwise.
|
||||
// Critically uses the fact that LWE_CDF_TABLE[j] and rnd fit in 15 bits.
|
||||
sample += (uint16_t)(cdf_table[j] - rnd) >> 15;
|
||||
@ -125,34 +97,30 @@ static int lwe_sample_n_inverse_16(uint16_t *s, const size_t n, const uint16_t *
|
||||
// Assuming that sign is either 0 or 1, flips sample iff sign = 1
|
||||
s[i] = ((-sign) ^ sample) + sign;
|
||||
}
|
||||
|
||||
memset(rndvec, 0, rndlen);
|
||||
free(rndvec);
|
||||
return 1;
|
||||
OQS_MEM_cleanse(rndvec, sizeof(rndvec));
|
||||
}
|
||||
|
||||
int oqs_kex_lwe_frodo_sample_n(uint16_t *s, const size_t n, struct oqs_kex_lwe_frodo_params *params, OQS_RAND *rand) {
|
||||
void oqs_kex_lwe_frodo_sample_n(uint16_t *s, const size_t n, struct oqs_kex_lwe_frodo_params *params, OQS_RAND *rand) {
|
||||
|
||||
switch (params->sampler_num) {
|
||||
case 8: {
|
||||
// have to copy cdf_table from uint16_t to uint8_t
|
||||
uint8_t *cdf_table_8 = malloc(params->cdf_table_len * sizeof(uint8_t));
|
||||
if (NULL == cdf_table_8) {
|
||||
return 0;
|
||||
}
|
||||
uint8_t cdf_table_8[params->cdf_table_len * sizeof(uint8_t)];
|
||||
for (size_t i = 0; i < params->cdf_table_len; i++) {
|
||||
cdf_table_8[i] = (uint8_t) params->cdf_table[i];
|
||||
}
|
||||
int ret = lwe_sample_n_inverse_8(s, n, cdf_table_8, params->cdf_table_len, rand);
|
||||
free(cdf_table_8);
|
||||
return ret;
|
||||
lwe_sample_n_inverse_8(s, n, cdf_table_8, params->cdf_table_len, rand);
|
||||
}
|
||||
break;
|
||||
case 12:
|
||||
return lwe_sample_n_inverse_12(s, n, params->cdf_table, params->cdf_table_len, rand);
|
||||
lwe_sample_n_inverse_12(s, n, params->cdf_table, params->cdf_table_len, rand);
|
||||
break;
|
||||
case 16:
|
||||
return lwe_sample_n_inverse_16(s, n, params->cdf_table, params->cdf_table_len, rand);
|
||||
lwe_sample_n_inverse_16(s, n, params->cdf_table, params->cdf_table_len, rand);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
assert(0); //ERROR
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
29
src/kex_lwe_frodo/recommended.h
Normal file
29
src/kex_lwe_frodo/recommended.h
Normal file
@ -0,0 +1,29 @@
|
||||
//Recommended parameter set. Include twice to undefine
|
||||
|
||||
#ifndef OQS_LWE_FRODO_RECOMMENDED_H
|
||||
#define OQS_LWE_FRODO_RECOMMENDED_H
|
||||
#define PARAMS_N 752
|
||||
#define PARAMS_NBAR 8
|
||||
#define PARAMS_LOG2Q 15
|
||||
#define PARAMS_Q (1 << PARAMS_LOG2Q)
|
||||
#define PARAMS_EXTRACTED_BITS 4
|
||||
#define PARAMS_KEY_BITS 256
|
||||
#define PARAMS_KEY_BYTES (PARAMS_KEY_BITS >> 3)
|
||||
#define PARAMS_STRIPE_STEP 8
|
||||
#define LWE_DIV_ROUNDUP(x, y) (((x) + (y)-1) / y)
|
||||
#define PARAMS_REC_HINT_LENGTH LWE_DIV_ROUNDUP(PARAMS_NBAR * PARAMS_NBAR, 8)
|
||||
#define PARAMS_REC_PUB_LENGTH LWE_DIV_ROUNDUP(PARAMS_N * PARAMS_NBAR * PARAMS_LOG2Q, 8)
|
||||
|
||||
#else
|
||||
|
||||
#undef OQS_LWE_FRODO_RECOMMENDED_H
|
||||
#undef PARAMS_N
|
||||
#undef PARAMS_NBAR
|
||||
#undef PARAMS_LOG2Q
|
||||
#undef PARAMS_Q
|
||||
#undef PARAMS_EXTRACTED_BITS
|
||||
#undef PARAMS_KEY_BITS
|
||||
#undef PARAMS_STRIPE_STEP
|
||||
#undef LWE_DIV_ROUNDUP
|
||||
#undef PARAMS_REC_HINT_LENGTH
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user