mirror of
https://github.com/open-quantum-safe/liboqs.git
synced 2025-12-04 00:03:41 -05:00
Frodo optimizations using macros (#45)
* Use macros to create versions of Frodo functions with hard-coded parameters to enable compiler optimization * Undefine macros to avoid any confusion later.
This commit is contained in:
parent
4753c4b2db
commit
88e5316005
@ -48,14 +48,15 @@ OQS_KEX *OQS_KEX_lwe_frodo_new(OQS_RAND *rand, const uint8_t *seed, const size_t
|
||||
|
||||
k->rand = rand;
|
||||
k->ctx = NULL;
|
||||
k->alice_0 = &OQS_KEX_lwe_frodo_alice_0;
|
||||
k->bob = &OQS_KEX_lwe_frodo_bob;
|
||||
k->alice_1 = &OQS_KEX_lwe_frodo_alice_1;
|
||||
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;
|
||||
@ -119,250 +120,11 @@ err:
|
||||
|
||||
}
|
||||
|
||||
int 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));
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
/* compute B = AS + E */
|
||||
ret = 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);
|
||||
|
||||
*alice_msg_len = params->pub_len;
|
||||
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
|
||||
err:
|
||||
ret = 0;
|
||||
free(*alice_msg);
|
||||
*alice_msg = NULL;
|
||||
free(*alice_priv);
|
||||
*alice_priv = NULL;
|
||||
|
||||
cleanup:
|
||||
free(e);
|
||||
free(b);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
int 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) {
|
||||
|
||||
int ret;
|
||||
|
||||
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) {
|
||||
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);
|
||||
if (*bob_msg == NULL) {
|
||||
goto err;
|
||||
}
|
||||
bob_rec = *bob_msg + params->pub_len;
|
||||
*key = malloc(params->key_bits >> 3);
|
||||
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;
|
||||
}
|
||||
|
||||
/* compute B' = S'A + E' */
|
||||
ret = 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);
|
||||
|
||||
/* generate E'' */
|
||||
ret = oqs_kex_lwe_frodo_sample_n(eprimeprime, params->nbar * params->nbar, params, k->rand);
|
||||
if (ret != 1) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* unpack B */
|
||||
oqs_kex_lwe_frodo_unpack(b, params->n * params->nbar, alice_msg, alice_msg_len, params->log2_q);
|
||||
|
||||
/* compute V = S'B + E'' */
|
||||
oqs_kex_lwe_frodo_mul_add_sb_plus_e(v, b, bob_priv, eprimeprime, params);
|
||||
|
||||
/* compute C = <V>_{2^B} */
|
||||
oqs_kex_lwe_frodo_crossround2(bob_rec, v, params);
|
||||
|
||||
/* compute K = round(V)_{2^B} */
|
||||
oqs_kex_lwe_frodo_round2(*key, v, params);
|
||||
|
||||
*bob_msg_len = params->pub_len + params->rec_hint_len;
|
||||
*key_len = params->key_bits >> 3;
|
||||
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
|
||||
err:
|
||||
ret = 0;
|
||||
free(*bob_msg);
|
||||
*bob_msg = NULL;
|
||||
if (*key != NULL) {
|
||||
memset(*key, 0, params->key_bits >> 3);
|
||||
}
|
||||
free(*key);
|
||||
*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);
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
int 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 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) {
|
||||
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);
|
||||
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);
|
||||
|
||||
/* compute W = B'S */
|
||||
oqs_kex_lwe_frodo_mul_bs(w, bprime, (uint16_t *) alice_priv, params);
|
||||
|
||||
/* compute K = rec(B'S, C) */
|
||||
const uint8_t *bob_rec = bob_msg + params->pub_len;
|
||||
oqs_kex_lwe_frodo_reconcile(*key, w, bob_rec, params);
|
||||
|
||||
*key_len = params->key_bits >> 3;
|
||||
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
|
||||
err:
|
||||
ret = 0;
|
||||
memset(key, 0, params->key_bits >> 3);
|
||||
free(*key);
|
||||
*key = NULL;
|
||||
|
||||
cleanup:
|
||||
free(w);
|
||||
free(bprime);
|
||||
return ret;
|
||||
|
||||
}
|
||||
// pre-process code to obtain "recommended" functions
|
||||
#define MACRIFY(NAME) NAME ## _recommended
|
||||
#include "kex_lwe_frodo_macrify.c"
|
||||
// undefine macros to avoid any confusion later
|
||||
#undef MACRIFY
|
||||
|
||||
void OQS_KEX_lwe_frodo_alice_priv_free(UNUSED OQS_KEX *k, void *alice_priv) {
|
||||
if (alice_priv) {
|
||||
|
||||
@ -14,9 +14,9 @@
|
||||
|
||||
OQS_KEX *OQS_KEX_lwe_frodo_new(OQS_RAND *rand, const uint8_t *seed, const size_t seed_len, const char *named_parameters);
|
||||
|
||||
int OQS_KEX_lwe_frodo_alice_0(OQS_KEX *k, void **alice_priv, uint8_t **alice_msg, size_t *alice_msg_len);
|
||||
int 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);
|
||||
int 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 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);
|
||||
int OQS_KEX_lwe_frodo_alice_1_recommended(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);
|
||||
|
||||
void OQS_KEX_lwe_frodo_alice_priv_free(OQS_KEX *k, void *alice_priv);
|
||||
void OQS_KEX_lwe_frodo_free(OQS_KEX *k);
|
||||
|
||||
244
src/kex_lwe_frodo/kex_lwe_frodo_macrify.c
Normal file
244
src/kex_lwe_frodo/kex_lwe_frodo_macrify.c
Normal file
@ -0,0 +1,244 @@
|
||||
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));
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
*alice_msg_len = params->pub_len;
|
||||
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
|
||||
err:
|
||||
ret = 0;
|
||||
free(*alice_msg);
|
||||
*alice_msg = NULL;
|
||||
free(*alice_priv);
|
||||
*alice_priv = NULL;
|
||||
|
||||
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) {
|
||||
|
||||
int ret;
|
||||
|
||||
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) {
|
||||
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);
|
||||
if (*bob_msg == NULL) {
|
||||
goto err;
|
||||
}
|
||||
bob_rec = *bob_msg + params->pub_len;
|
||||
*key = malloc(params->key_bits >> 3);
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
/* generate E'' */
|
||||
ret = oqs_kex_lwe_frodo_sample_n(eprimeprime, params->nbar * params->nbar, params, k->rand);
|
||||
if (ret != 1) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* unpack B */
|
||||
oqs_kex_lwe_frodo_unpack(b, params->n * params->nbar, alice_msg, alice_msg_len, params->log2_q);
|
||||
|
||||
/* compute V = S'B + E'' */
|
||||
MACRIFY(oqs_kex_lwe_frodo_mul_add_sb_plus_e)(v, b, bob_priv, eprimeprime);
|
||||
|
||||
/* compute C = <V>_{2^B} */
|
||||
MACRIFY(oqs_kex_lwe_frodo_crossround2)(bob_rec, v);
|
||||
|
||||
/* 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;
|
||||
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
|
||||
err:
|
||||
ret = 0;
|
||||
free(*bob_msg);
|
||||
*bob_msg = NULL;
|
||||
if (*key != NULL) {
|
||||
memset(*key, 0, params->key_bits >> 3);
|
||||
}
|
||||
free(*key);
|
||||
*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);
|
||||
|
||||
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 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) {
|
||||
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);
|
||||
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);
|
||||
|
||||
/* 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;
|
||||
MACRIFY(oqs_kex_lwe_frodo_reconcile)(*key, w, bob_rec);
|
||||
|
||||
*key_len = params->key_bits >> 3;
|
||||
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
|
||||
err:
|
||||
ret = 0;
|
||||
memset(key, 0, params->key_bits >> 3);
|
||||
free(*key);
|
||||
*key = NULL;
|
||||
|
||||
cleanup:
|
||||
free(w);
|
||||
free(bprime);
|
||||
return ret;
|
||||
|
||||
}
|
||||
@ -23,9 +23,9 @@ struct oqs_kex_lwe_frodo_params {
|
||||
size_t cdf_table_len;
|
||||
};
|
||||
|
||||
void oqs_kex_lwe_frodo_crossround2(unsigned char *out, const uint16_t *in, struct oqs_kex_lwe_frodo_params *params);
|
||||
void oqs_kex_lwe_frodo_round2(unsigned char *out, uint16_t *in, struct oqs_kex_lwe_frodo_params *params);
|
||||
void oqs_kex_lwe_frodo_reconcile(unsigned char *out, uint16_t *w, const unsigned char *hint, struct oqs_kex_lwe_frodo_params *params);
|
||||
void oqs_kex_lwe_frodo_crossround2_recommended(unsigned char *out, const uint16_t *in);
|
||||
void oqs_kex_lwe_frodo_round2_recommended(unsigned char *out, uint16_t *in);
|
||||
void oqs_kex_lwe_frodo_reconcile_recommended(unsigned char *out, uint16_t *w, const unsigned char *hint);
|
||||
|
||||
void oqs_kex_lwe_frodo_key_round(uint16_t *vec, const size_t length, const int b);
|
||||
void oqs_kex_lwe_frodo_key_round_hints(uint16_t *vec, const size_t length, const int b, const unsigned char *hint);
|
||||
@ -34,9 +34,9 @@ void oqs_kex_lwe_frodo_unpack(uint16_t *out, const size_t outlen, const unsigned
|
||||
|
||||
int 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(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(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(uint16_t *out, const uint16_t *b, const uint16_t *s, const uint16_t *e, struct oqs_kex_lwe_frodo_params *params);
|
||||
void oqs_kex_lwe_frodo_mul_bs(uint16_t *out, const uint16_t *b, const uint16_t *s, struct oqs_kex_lwe_frodo_params *params);
|
||||
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_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);
|
||||
|
||||
#endif /* _OQS_KEX_RLWE_BCNS15_LOCAL_H_ */
|
||||
|
||||
@ -10,239 +10,6 @@
|
||||
|
||||
#define min(x, y) (((x) < (y)) ? (x) : (y))
|
||||
|
||||
// [.]_2
|
||||
void oqs_kex_lwe_frodo_round2(unsigned char *out, uint16_t *in, struct oqs_kex_lwe_frodo_params *params) {
|
||||
oqs_kex_lwe_frodo_key_round(in, params->nbar * params->nbar, params->log2_q - params->extracted_bits);
|
||||
int i;
|
||||
for (i = 0; i < params->nbar * params->nbar; i++) {
|
||||
in[i] >>= params->log2_q - params->extracted_bits; // drop bits that were zeroed out
|
||||
}
|
||||
|
||||
// out should have enough space for the key
|
||||
oqs_kex_lwe_frodo_pack(out, params->key_bits / 8, in, params->nbar * params->nbar, params->extracted_bits);
|
||||
}
|
||||
|
||||
void oqs_kex_lwe_frodo_crossround2(unsigned char *out, const uint16_t *in, struct oqs_kex_lwe_frodo_params *params) {
|
||||
int i;
|
||||
// out should have enough space for N_BAR * N_BAR bits
|
||||
memset((unsigned char *)out, 0, params->rec_hint_len);
|
||||
|
||||
uint16_t whole = 1 << (params->log2_q - params->extracted_bits);
|
||||
uint16_t half = whole >> 1;
|
||||
uint16_t mask = whole - 1;
|
||||
|
||||
for (i = 0; i < params->nbar * params->nbar; i++) {
|
||||
uint16_t remainder = in[i] & mask;
|
||||
out[i / 8] += (remainder >= half) << (i % 8);
|
||||
}
|
||||
}
|
||||
|
||||
void oqs_kex_lwe_frodo_reconcile(unsigned char *out, uint16_t *w, const unsigned char *hint, struct oqs_kex_lwe_frodo_params *params) {
|
||||
oqs_kex_lwe_frodo_key_round_hints(w, params->nbar * params->nbar, params->log2_q - params->extracted_bits, hint);
|
||||
int i;
|
||||
for (i = 0; i < params->nbar * params->nbar; i++) {
|
||||
w[i] >>= params->log2_q - 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 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;
|
||||
}
|
||||
|
||||
// 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++) {
|
||||
s_transpose[k * params->n + j] = s[j * params->nbar + k];
|
||||
}
|
||||
}
|
||||
|
||||
assert(params->seed_len == 16);
|
||||
void *aes_key_schedule = NULL;
|
||||
OQS_AES128_load_schedule(params->seed, &aes_key_schedule, 1);
|
||||
|
||||
for (i = 0; i < params->n; i++) {
|
||||
// go through A's rows
|
||||
memset(a_row, 0, a_rowlen);
|
||||
for (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);
|
||||
|
||||
for (k = 0; k < params->nbar; k++) {
|
||||
uint16_t sum = 0;
|
||||
for (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;
|
||||
}
|
||||
}
|
||||
|
||||
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 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;
|
||||
}
|
||||
|
||||
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) {
|
||||
// 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++) {
|
||||
// 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);
|
||||
|
||||
// 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++) {
|
||||
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++) {
|
||||
uint16_t sum = 0;
|
||||
for (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;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
void oqs_kex_lwe_frodo_mul_bs(uint16_t *out, const uint16_t *b, const uint16_t *s, struct oqs_kex_lwe_frodo_params *params) {
|
||||
// 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];
|
||||
}
|
||||
out[i * params->nbar + j] %= params->q; // not really necessary since LWE_Q is a power of 2.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// multiply by s on the left
|
||||
void oqs_kex_lwe_frodo_mul_add_sb_plus_e(uint16_t *out, const uint16_t *b, const uint16_t *s, const uint16_t *e, struct oqs_kex_lwe_frodo_params *params) {
|
||||
// b (N x N_BAR)
|
||||
// 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];
|
||||
}
|
||||
out[k * params->nbar + i] %= params->q; // not really necessary since LWE_Q is a power of 2.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// round all elements of a vector to the nearest multiple of 2^b
|
||||
void oqs_kex_lwe_frodo_key_round(uint16_t *vec, const size_t length, const int b) {
|
||||
size_t i;
|
||||
@ -374,3 +141,28 @@ 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)
|
||||
// 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
|
||||
#undef MACRIFY
|
||||
|
||||
233
src/kex_lwe_frodo/lwe_macrify.c
Normal file
233
src/kex_lwe_frodo/lwe_macrify.c
Normal file
@ -0,0 +1,233 @@
|
||||
// [.]_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++) {
|
||||
in[i] >>= PARAMS_LOG2Q - PARAMS_EXTRACTED_BITS; // drop bits that were zeroed out
|
||||
}
|
||||
|
||||
// out should have enough space for the key
|
||||
oqs_kex_lwe_frodo_pack(out, PARAMS_KEY_BITS / 8, in, PARAMS_NBAR * PARAMS_NBAR, PARAMS_EXTRACTED_BITS);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
uint16_t whole = 1 << (PARAMS_LOG2Q - PARAMS_EXTRACTED_BITS);
|
||||
uint16_t half = whole >> 1;
|
||||
uint16_t mask = whole - 1;
|
||||
|
||||
for (i = 0; i < PARAMS_NBAR * PARAMS_NBAR; i++) {
|
||||
uint16_t remainder = in[i] & mask;
|
||||
out[i / 8] += (remainder >= half) << (i % 8);
|
||||
}
|
||||
}
|
||||
|
||||
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++) {
|
||||
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) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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++) {
|
||||
s_transpose[k * PARAMS_N + j] = s[j * PARAMS_NBAR + k];
|
||||
}
|
||||
}
|
||||
|
||||
assert(params->seed_len == 16);
|
||||
void *aes_key_schedule = NULL;
|
||||
OQS_AES128_load_schedule(params->seed, &aes_key_schedule, 1);
|
||||
|
||||
for (i = 0; i < PARAMS_N; i++) {
|
||||
// go through A's rows
|
||||
memset(a_row, 0, a_rowlen);
|
||||
for (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);
|
||||
|
||||
for (k = 0; k < PARAMS_NBAR; k++) {
|
||||
uint16_t sum = 0;
|
||||
for (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;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
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) {
|
||||
// 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++) {
|
||||
// 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);
|
||||
|
||||
// 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++) {
|
||||
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++) {
|
||||
uint16_t sum = 0;
|
||||
for (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;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
void MACRIFY(oqs_kex_lwe_frodo_mul_bs)(uint16_t *out, const uint16_t *b, const uint16_t *s) {
|
||||
// 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];
|
||||
}
|
||||
out[i * PARAMS_NBAR + j] %= PARAMS_Q; // not really necessary since LWE_Q is a power of 2.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// multiply by s on the left
|
||||
void MACRIFY(oqs_kex_lwe_frodo_mul_add_sb_plus_e)(uint16_t *out, const uint16_t *b, const uint16_t *s, const uint16_t *e) {
|
||||
// b (N x N_BAR)
|
||||
// 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];
|
||||
}
|
||||
out[k * PARAMS_NBAR + i] %= PARAMS_Q; // not really necessary since LWE_Q is a power of 2.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user