frodo: FrodoKEM KE method

This commit is contained in:
Andreas Steffen 2019-11-06 23:08:43 +01:00 committed by Tobias Brunner
parent 283323227f
commit 03589a6cd7
11 changed files with 1742 additions and 0 deletions

View File

@ -154,6 +154,7 @@ ARG_ENABL_SET([mgf1], [enable the MGF1 software implementation plugin.
ARG_ENABL_SET([newhope], [enable New Hope crypto plugin.])
ARG_DISBL_SET([nonce], [disable nonce generation plugin.])
ARG_ENABL_SET([ntru], [enables the NTRU crypto plugin.])
ARG_ENABL_SET([frodo], [enable FrodoKEM Post Quantum Safe plugin.])
ARG_ENABL_SET([oqs], [enable Open Quantum Safe (liboqs) plugin.])
ARG_ENABL_SET([openssl], [enables the OpenSSL crypto plugin.])
ARG_ENABL_SET([wolfssl], [enables the wolfSSL crypto plugin.])
@ -1503,6 +1504,7 @@ ADD_PLUGIN([ctr], [s charon scripts nm cmd])
ADD_PLUGIN([ccm], [s charon scripts nm cmd])
ADD_PLUGIN([gcm], [s charon scripts nm cmd])
ADD_PLUGIN([ntru], [s charon scripts nm cmd])
ADD_PLUGIN([frodo], [s charon scripts nm cmd])
ADD_PLUGIN([oqs], [s charon scripts nm cmd])
ADD_PLUGIN([drbg], [s charon pki scripts nm cmd])
ADD_PLUGIN([newhope], [s charon scripts nm cmd])
@ -1676,6 +1678,7 @@ AM_CONDITIONAL(USE_NEWHOPE, test x$newhope = xtrue)
AM_CONDITIONAL(USE_BLISS, test x$bliss = xtrue)
AM_CONDITIONAL(USE_DRBG, test x$drbg = xtrue)
AM_CONDITIONAL(USE_OQS, test x$oqs = xtrue)
AM_CONDITIONAL(USE_FRODO, test x$frodo = xtrue)
# charon plugins
# ----------------
@ -1959,6 +1962,7 @@ AC_CONFIG_FILES([
src/libstrongswan/plugins/bliss/tests/Makefile
src/libstrongswan/plugins/newhope/Makefile
src/libstrongswan/plugins/newhope/tests/Makefile
src/libstrongswan/plugins/frodo/Makefile
src/libstrongswan/plugins/oqs/Makefile
src/libstrongswan/plugins/oqs/tests/Makefile
src/libstrongswan/plugins/test_vectors/Makefile

View File

@ -681,6 +681,13 @@ if MONOLITHIC
endif
endif
if USE_FRODO
SUBDIRS += plugins/frodo
if MONOLITHIC
libstrongswan_la_LIBADD += plugins/frodo/libstrongswan-frodo.la
endif
endif
if USE_TEST_VECTORS
SUBDIRS += plugins/test_vectors
if MONOLITHIC

View File

@ -0,0 +1,26 @@
AM_CPPFLAGS = \
-I$(top_srcdir)/src/libstrongswan
AM_CFLAGS = \
$(PLUGIN_CFLAGS)
# these files are also used by the tests, we can't directly refer to them
# because of the subdirectory, which would cause distclean to fail
noinst_LTLIBRARIES = libfrodo.la
libfrodo_la_SOURCES = \
frodo.h frodo.c \
frodo_params.h frodo_params.c \
frodo_utils.h frodo_utils.c
if MONOLITHIC
noinst_LTLIBRARIES += libstrongswan-frodo.la
else
plugin_LTLIBRARIES = libstrongswan-frodo.la
endif
libstrongswan_frodo_la_SOURCES = \
frodo_plugin.h frodo_plugin.c
libstrongswan_frodo_la_LDFLAGS = -module -avoid-version
libstrongswan_frodo_la_LIBADD = libfrodo.la

View File

@ -0,0 +1,596 @@
/*
* MIT License
*
* Copyright (C) Microsoft Corporation
*
* Copyright (C) 2019 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "frodo.h"
#include "frodo_params.h"
#include "frodo_utils.h"
#include <utils/debug.h>
typedef struct private_frodo_t private_frodo_t;
/**
* Private data of an frodo_t object.
*/
struct private_frodo_t {
/**
* Public frodo_t interface.
*/
frodo_t public;
/**
* key exchange method
*/
key_exchange_method_t method;
/**
* If TRUE use AES128 for generating matrix A, otherwise use SHAKE128
*/
bool use_aes;
/**
* Frodo parameters
*/
const frodo_params_t *params;
/**
* Public Key
*/
uint8_t *public_key;
/**
* Secret Key
*/
uint8_t *secret_key;
/**
* Ciphertext
*/
uint8_t *ciphertext;
/**
* Shared secret
*/
uint8_t *shared_secret;
/**
* NIST CTR DRBG
*/
drbg_t *drbg;
/**
* SHAKE-128 or SHAKE-256 eXtended Output Function
*/
xof_t *xof;
};
/**
*
*/
static bool need_drbg(private_frodo_t *this)
{
uint32_t strength = 256;
rng_t *entropy;
if (this->drbg)
{
return TRUE;
}
/* entropy will be owned by drbg */
entropy = lib->crypto->create_rng(lib->crypto, RNG_TRUE);
if (!entropy)
{
DBG1(DBG_LIB, "could not attach entropy source for DRBG");
return FALSE;
}
this->drbg = lib->crypto->create_drbg(lib->crypto, DRBG_CTR_AES256,
strength, entropy, chunk_empty);
if (!this->drbg)
{
DBG1(DBG_LIB, "could not instantiate DRBG at %u bit security", strength);
entropy->destroy(entropy);
return FALSE;
}
return TRUE;
}
/**
* Generator function shared between encaps and decaps shared secret
*/
static bool generate(private_frodo_t *this, chunk_t G2in, uint8_t *k,
uint16_t *Bp, uint16_t *C)
{
const uint32_t n_x_nb = this->params->n * this->params->nb;
const uint32_t nb_x_nb = this->params->nb * this->params->nb;
const uint32_t log_q = this->params->log_q;
const uint32_t seed_A_len = this->params->seed_A_len;
const uint32_t ss_len = this->params->ss_len;
const uint32_t pk_len = this->params->pk_len;
uint8_t *mu = G2in.ptr + ss_len;
uint8_t *pk_seedA = this->public_key;
uint8_t *pk_b = this->public_key + seed_A_len;
uint16_t B[n_x_nb], Sp[n_x_nb], Ep[n_x_nb], Epp[nb_x_nb], V[nb_x_nb];
chunk_t seedSE = chunk_alloc(1 + ss_len);
if (!this->xof->set_seed(this->xof, G2in) ||
!this->xof->get_bytes(this->xof, ss_len, seedSE.ptr + 1) ||
!this->xof->get_bytes(this->xof, ss_len, k))
{
return FALSE;
}
*seedSE.ptr = 0x96;
/* Generate Sp and Ep, and compute Bp = Sp*A + Ep. Generate A on-the-fly */
if (!this->xof->set_seed(this->xof, seedSE) ||
!this->xof->get_bytes(this->xof,
n_x_nb * sizeof(uint16_t), (uint8_t*)Sp) ||
!this->xof->get_bytes(this->xof,
n_x_nb * sizeof(uint16_t), (uint8_t*)Ep) ||
!this->xof->get_bytes(this->xof,
nb_x_nb * sizeof(uint16_t), (uint8_t*)Epp))
{
return FALSE;
}
frodo_sample_n(this->params, Sp, n_x_nb);
frodo_sample_n(this->params, Ep, n_x_nb);
frodo_mul_add_sa_plus_e(this->params, Bp, Sp, Ep, pk_seedA, this->use_aes);
/* Generate Epp, and compute V = Sp*B + Epp */
frodo_sample_n(this->params, Epp, nb_x_nb);
frodo_unpack(B, n_x_nb, pk_b, pk_len - seed_A_len, log_q);
frodo_mul_add_sb_plus_e(this->params, V, B, Sp, Epp);
/* Encode mu, and compute C = V + enc(mu) (mod q) */
frodo_key_encode(this->params, C, (uint16_t*)mu);
frodo_add(this->params, C, V, C);
/* Cleanup */
memwipe((uint8_t *)Sp, n_x_nb * sizeof(uint16_t));
memwipe((uint8_t *)Ep, n_x_nb * sizeof(uint16_t));
memwipe((uint8_t *)Epp, nb_x_nb * sizeof(uint16_t));
memwipe((uint8_t *)V, nb_x_nb * sizeof(uint16_t));
chunk_clear(&seedSE);
return TRUE;
}
/**
* Generate the shared secret and encrypt it with the configured public key
*/
static bool encaps_shared_secret(private_frodo_t *this)
{
const uint32_t n_x_nb = this->params->n * this->params->nb;
const uint32_t nb_x_nb = this->params->nb * this->params->nb;
const uint32_t log_q = this->params->log_q;
const uint32_t extr_bits = this->params->extr_bits;
const uint32_t ct_c1_len = (n_x_nb * log_q)/8;
const uint32_t ct_c2_len = (nb_x_nb * log_q)/8;
const uint32_t mu_len = (nb_x_nb * extr_bits)/8;
const uint32_t ss_len = this->params->ss_len;
const uint32_t ct_len = this->params->ct_len;
const uint32_t pk_len = this->params->pk_len;
chunk_t pk = chunk_create(this->public_key, pk_len);
chunk_t G2in = chunk_alloca(ss_len + mu_len);
uint8_t *pkh = G2in.ptr;
uint8_t *mu = G2in.ptr + ss_len;
uint8_t *ct_c1, *ct_c2;
uint8_t Fin[ct_len + ss_len];
uint8_t *Fin_ct = &Fin[0];
uint8_t *Fin_k = &Fin[ct_len];
uint8_t k[ss_len];
uint16_t Bp[n_x_nb], C[nb_x_nb];
if (!this->ciphertext)
{
this->ciphertext = malloc(ct_len);
}
ct_c1 = this->ciphertext;
ct_c2 = this->ciphertext + ct_c1_len;
/* pkh <- G_1(pk) */
if (!this->xof->set_seed(this->xof, pk) ||
!this->xof->get_bytes(this->xof, ss_len, pkh))
{
return FALSE;
}
/* Generate random mu */
if (!this->drbg->generate(this->drbg, mu_len, mu))
{
DBG1(DBG_LIB, "could not generate mu");
return FALSE;
}
if (!generate(this, G2in, k, Bp, C))
{
return FALSE;
}
frodo_pack(ct_c1, ct_c1_len, Bp, n_x_nb, log_q);
frodo_pack(ct_c2, ct_c2_len, C, nb_x_nb, log_q);
/* Compute ss = F(ct||KK) */
memcpy(Fin_ct, this->ciphertext, ct_len);
memcpy(Fin_k, k, ss_len);
if (!this->xof->set_seed(this->xof, chunk_create(Fin, ct_len + ss_len)) ||
!this->xof->get_bytes(this->xof, ss_len, this->shared_secret))
{
return FALSE;
}
/* Cleanup */
memwipe(mu, mu_len);
memwipe(k, ss_len);
memwipe(Fin_k, ss_len);
return TRUE;
}
/**
* Decapsulate the shared secret using the secret key
*/
static bool decaps_shared_secret(private_frodo_t *this)
{
const uint32_t n_x_nb = this->params->n * this->params->nb;
const uint32_t nb_x_nb = this->params->nb * this->params->nb;
const uint32_t log_q = this->params->log_q;
const uint32_t extr_bits = this->params->extr_bits;
const uint32_t ct_c1_len = (n_x_nb * log_q)/8;
const uint32_t ct_c2_len = (nb_x_nb * log_q)/8;
const uint32_t mu_len = (nb_x_nb * extr_bits)/8;
const uint32_t ss_len = this->params->ss_len;
const uint32_t ct_len = this->params->ct_len;
const uint32_t pk_len = this->params->pk_len;
chunk_t G2in = chunk_alloca(ss_len + mu_len);
uint8_t *pkh = G2in.ptr;
uint8_t *muprime = G2in.ptr + ss_len;
uint8_t *ct_c1 = this->ciphertext;
uint8_t *ct_c2 = this->ciphertext + ct_c1_len;
uint8_t *sk_s = this->secret_key;
uint16_t *sk_S = (uint16_t *)(this->secret_key + ss_len + pk_len);
uint8_t *sk_pkh = this->secret_key + ss_len + pk_len + 2*n_x_nb;
uint8_t Fin[ct_len + ss_len];
uint8_t *Fin_ct = &Fin[0];
uint8_t *Fin_k = &Fin[ct_len];
uint8_t kprime[ss_len];
uint16_t Bp[n_x_nb], BBp[n_x_nb];
uint16_t W[nb_x_nb], C[nb_x_nb], CC[nb_x_nb];
/* Compute W = C - Bp*S (mod q), and decode the randomness mu */
frodo_unpack(Bp, n_x_nb, ct_c1, ct_c1_len, log_q);
frodo_unpack(C, nb_x_nb, ct_c2, ct_c2_len, log_q);
frodo_mul_bs(this->params, W, Bp, sk_S);
frodo_sub(this->params, W, C, W);
frodo_key_decode(this->params, (uint16_t*)muprime, W);
memcpy(pkh, sk_pkh, ss_len);
if (!generate(this, G2in, kprime, BBp, CC))
{
return FALSE;
}
/* Prepare input to F */
memcpy(Fin_ct, this->ciphertext, ct_len);
/* Reducing BBp modulo q */
for (int i = 0; i < n_x_nb; i++)
{
BBp[i] = BBp[i] & ((1 << log_q) - 1);
}
/* Is (Bp == BBp & C == CC) = true */
if (memcmp(Bp, BBp, n_x_nb * sizeof(uint16_t)) == 0 &&
memcmp(C, CC, nb_x_nb * sizeof(uint16_t)) == 0)
{
/* Load k' to do ss = F(ct || k') */
memcpy(Fin_k, kprime, ss_len);
}
else
{
/* Load s to do ss = F(ct || s) */
memcpy(Fin_k, sk_s, ss_len);
}
if (!this->xof->set_seed(this->xof, chunk_create(Fin, ct_len + ss_len)) ||
!this->xof->get_bytes(this->xof, ss_len, this->shared_secret))
{
return FALSE;
}
/* Cleanup: */
memwipe((uint8_t *)W, nb_x_nb * sizeof(uint16_t));
memwipe(muprime, mu_len);
memwipe(kprime, ss_len);
memwipe(Fin_k, ss_len);
return TRUE;
}
/**
*
*/
static bool set_ciphertext(private_frodo_t *this, chunk_t value)
{
if (value.len != this->params->ct_len)
{
DBG1(DBG_LIB, "wrong %N ciphertext size of %u bytes, %u bytes expected",
key_exchange_method_names, this->method, value.len,
this->params->ct_len);
return FALSE;
}
this->ciphertext = malloc(value.len);
memcpy(this->ciphertext, value.ptr, value.len);
return decaps_shared_secret(this);
}
METHOD(key_exchange_t, get_public_key, bool,
private_frodo_t *this, chunk_t *value)
{
/* responder action */
if (this->ciphertext)
{
*value = chunk_clone(
chunk_create(this->ciphertext, this->params->ct_len));
return TRUE;
}
/* initiator action */
if (!this->secret_key)
{
const uint32_t n_x_nb = this->params->n * this->params->nb;
const uint32_t log_q = this->params->log_q;
const uint32_t seed_A_len = this->params->seed_A_len;
const uint32_t ss_len = this->params->ss_len;
const uint32_t pk_len = this->params->pk_len;
uint8_t *pk_seedA, *pk_b, *sk_pos;
uint16_t B[n_x_nb], S[n_x_nb], E[n_x_nb];
uint8_t randomness[ss_len + ss_len + seed_A_len];
uint8_t *randomness_s = &randomness[0];
uint8_t *randomness_seedSE = &randomness[ss_len];
uint8_t *randomness_z = &randomness[ss_len + ss_len];
uint8_t seedSE[1 + ss_len];
this->secret_key = malloc(this->params->sk_len);
pk_seedA = this->public_key;
pk_b = this->public_key + seed_A_len;
/* Do we need an entropy source? */
/* TODO */
/* Generate the secret value s and the seeds for S, E and seed_A */
if (!need_drbg(this) ||
!this->drbg->generate(this->drbg, 2*ss_len + seed_A_len, randomness))
{
DBG1(DBG_LIB, "could not generate randomness");
return FALSE;
}
/* Generate seed_A as part of the public key */
if (!this->xof->set_seed(this->xof,
chunk_create(randomness_z, seed_A_len)) ||
!this->xof->get_bytes(this->xof, seed_A_len, pk_seedA))
{
return FALSE;
}
/* Generate S and E, and compute B = A*S + E. Generate A on-the-fly */
seedSE[0] = 0x5F;
memcpy(&seedSE[1], randomness_seedSE, ss_len);
if (!this->xof->set_seed(this->xof, chunk_create(seedSE, 1 + ss_len)) ||
!this->xof->get_bytes(this->xof,
n_x_nb * sizeof(uint16_t), (uint8_t*)S) ||
!this->xof->get_bytes(this->xof,
n_x_nb * sizeof(uint16_t), (uint8_t*)E))
{
return FALSE;
}
frodo_sample_n(this->params, S, n_x_nb);
frodo_sample_n(this->params, E, n_x_nb);
if (!frodo_mul_add_as_plus_e(this->params, B, S, E, this->public_key,
this->use_aes))
{
return FALSE;
}
/* Encode the second part of the public key */
frodo_pack(pk_b, pk_len - seed_A_len, B, n_x_nb, log_q);
/* Add s, pk and S to the secret key */
sk_pos = this->secret_key;
memcpy(sk_pos, randomness_s, ss_len);
sk_pos += ss_len;
memcpy(sk_pos, this->public_key, pk_len);
sk_pos += pk_len;
memcpy(sk_pos, S, n_x_nb * sizeof(uint16_t));
sk_pos += n_x_nb * sizeof(uint16_t);
/* Add H(pk) to the secret key */
if (!this->xof->set_seed(this->xof,
chunk_create(this->public_key, pk_len)) ||
!this->xof->get_bytes(this->xof, ss_len, sk_pos))
{
return FALSE;
}
/* Cleanup */
memwipe((uint8_t *)S, n_x_nb * sizeof(uint16_t));
memwipe((uint8_t *)E, n_x_nb * sizeof(uint16_t));
memwipe(randomness, ss_len + ss_len + seed_A_len);
memwipe(seedSE, 1 + ss_len);
}
*value = chunk_clone(chunk_create(this->public_key, this->params->pk_len));
return TRUE;
}
METHOD(key_exchange_t, get_shared_secret, bool,
private_frodo_t *this, chunk_t *secret)
{
*secret = chunk_clone(
chunk_create(this->shared_secret, this->params->ss_len));
return TRUE;
}
METHOD(key_exchange_t, set_public_key, bool,
private_frodo_t *this, chunk_t value)
{
/* initiator action */
if (this->secret_key)
{
return set_ciphertext(this, value);
}
/* responder action */
if (value.len != this->params->pk_len)
{
DBG1(DBG_LIB, "wrong %N public key size of %u bytes, %u bytes expected",
key_exchange_method_names, this->method, value.len,
this->params->pk_len);
return FALSE;
}
memcpy(this->public_key, value.ptr, value.len);
return need_drbg(this) && encaps_shared_secret(this);
}
METHOD(key_exchange_t, get_method, key_exchange_method_t,
private_frodo_t *this)
{
return this->method;
}
METHOD(key_exchange_t, set_seed, bool,
private_frodo_t *this, chunk_t value, drbg_t *drbg)
{
DESTROY_IF(this->drbg);
this->drbg = drbg->get_ref(drbg);
return TRUE;
}
METHOD(key_exchange_t, destroy, void,
private_frodo_t *this)
{
DESTROY_IF(this->drbg);
this->xof->destroy(this->xof);
memwipe(this->secret_key, this->params->sk_len);
free(this->secret_key);
memwipe(this->shared_secret, this->params->ss_len);
free(this->shared_secret);
free(this->public_key);
free(this->ciphertext);
free(this);
}
/*
* Described in header.
*/
frodo_t *frodo_create(key_exchange_method_t method)
{
private_frodo_t *this;
const frodo_params_t *params;
frodo_kem_type_t id;
bool use_aes;
xof_t *xof;
switch (method)
{
case KE_FRODO_SHAKE_L1:
id = FRODO_KEM_L1;
use_aes = FALSE;
break;
case KE_FRODO_SHAKE_L3:
id = FRODO_KEM_L3;
use_aes = FALSE;
break;
case KE_FRODO_SHAKE_L5:
id = FRODO_KEM_L5;
use_aes = FALSE;
break;
case KE_FRODO_AES_L1:
id = FRODO_KEM_L1;
use_aes = TRUE;
break;
case KE_FRODO_AES_L3:
id = FRODO_KEM_L3;
use_aes = TRUE;
break;
case KE_FRODO_AES_L5:
id = FRODO_KEM_L5;
use_aes = TRUE;
break;
default:
return NULL;
}
params = frodo_params_get_by_id(id);
xof = lib->crypto->create_xof(lib->crypto, params->xof_type);
if (!xof)
{
DBG1(DBG_LIB, "could not instantiate %N", ext_out_function_names,
params->xof_type);
return NULL;
}
INIT(this,
.public = {
.ke = {
.get_method = _get_method,
.get_public_key = _get_public_key,
.set_public_key = _set_public_key,
.get_shared_secret = _get_shared_secret,
.set_seed = _set_seed,
.destroy = _destroy,
},
},
.method = method,
.use_aes = use_aes,
.params = params,
.xof = xof,
.public_key = malloc(params->pk_len),
.shared_secret = malloc(params->ss_len),
);
return &this->public;
}

View File

@ -0,0 +1,47 @@
/*
* Copyright (C) 2019 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 frodo frodo
* @{ @ingroup frodo_p
*/
#ifndef FRODO_H_
#define FRODO_H_
typedef struct frodo_t frodo_t;
#include <library.h>
/**
* Quantum-safe key encapsulation implementation using FrodoKEM
*/
struct frodo_t {
/**
* Implements key_exchange_t interface.
*/
key_exchange_t ke;
};
/**
* Creates a new frodo_t object.
*
* @param method key exchange method
* @return frodo_t object, NULL if not supported
*/
frodo_t *frodo_create(key_exchange_method_t method);
#endif /** FRODO_H_ @}*/

View File

@ -0,0 +1,111 @@
/*
* MIT License
*
* Copyright (C) Microsoft Corporation
*
* Copyright (C) 2019 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "frodo_params.h"
const uint16_t cdf_table_1[] = { 4643, 13363, 20579, 25843, 29227,
31145, 32103, 32525, 32689, 32745,
32762, 32766, 32767
};
const uint16_t cdf_table_3[] = { 5638, 15915, 23689, 28571, 31116,
32217, 32613, 32731, 32760, 32766,
32767
};
const uint16_t cdf_table_5[] = { 9142, 23462, 30338, 32361, 32725,
32765, 32767
};
/**
* FrodoKEM parameter definitions
*/
static const frodo_params_t frodo_params[] = {
{
FRODO_KEM_L1, /* Frodo KEM ID */
640, /* Lattice dimension n */
8, /* Dimension n_bar */
15, /* Logarithm of modulus q */
2, /* Extracted bits extr_bits */
16, /* Size of seed_A seed_A_len */
16, /* Size of shared secret ss_len */
9720, /* Size of ciphertext ct_len */
9616, /* Size of public key pk_len */
19888, /* Size of secret key sk_len */
13, /* Size of CDF table cdf_table_len */
cdf_table_1, /* CDF table */
XOF_SHAKE_128, /* SHAKE XOF */
},
{
FRODO_KEM_L3, /* Frodo KEM ID */
976, /* Lattice dimension n */
8, /* Dimension n_bar */
16, /* Logarithm of modulus q */
3, /* Extracted bits extr_bits */
16, /* Size of seed_A seed_A_len */
24, /* Size of shared secret ss_len */
15744, /* Size of ciphertext ct_len */
15632, /* Size of public key pk_len */
31296, /* Size of secret key sk_len */
11, /* Size of CDF table cdf_table_len */
cdf_table_3, /* CDF table */
XOF_SHAKE_256, /* SHAKE XOF */
},
{
FRODO_KEM_L5, /* Frodo KEM ID */
1344, /* Lattice dimension n */
8, /* Dimension n_bar */
16, /* Logarithm of modulus q */
4, /* Extracted bits extr_bits */
16, /* Size of seed_A seed_A_len */
32, /* Size of shared secret ss_len */
21632, /* Size of ciphertext ct_len */
21520, /* Size of public key pk_len */
43088, /* Size of secret key sk_len */
7, /* Size of CDF table cdf_table_len */
cdf_table_5, /* CDF table */
XOF_SHAKE_256, /* SHAKE XOF */
},
};
/**
* See header.
*/
const frodo_params_t* frodo_params_get_by_id(frodo_kem_type_t id)
{
int i;
for (i = 0; i < countof(frodo_params); i++)
{
if (frodo_params[i].id == id)
{
return &frodo_params[i];
}
}
return NULL;
}

View File

@ -0,0 +1,129 @@
/*
* MIT License
*
* Copyright (C) Microsoft Corporation
*
* Copyright (C) 2019 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* @defgroup frodo_params frodo_params
* @{ @ingroup frodo_p
*/
#ifndef FRODO_PARAMS_H_
#define FRODO_PARAMS_H_
#include <library.h>
typedef struct frodo_params_t frodo_params_t;
typedef enum frodo_kem_type_t frodo_kem_type_t;
/**
* FrodoKEM types with various security strengths
*/
enum frodo_kem_type_t {
FRODO_KEM_L1,
FRODO_KEM_L3,
FRODO_KEM_L5,
};
/**
* FrodoKEM parameter definitions
*/
struct frodo_params_t {
/**
* Frodo key exchange ID
*/
const frodo_kem_type_t id;
/**
* Lattice dimension
*/
const uint32_t n;
/**
* Dimension n_bar
*/
const uint32_t nb;
/**
* Logarithm of modulus q
*/
const uint32_t log_q;
/**
* Extracted bits
*/
const uint32_t extr_bits;
/**
* Size of seed_A
*/
const uint32_t seed_A_len;
/**
* Size of shared secret
*/
const uint32_t ss_len;
/**
* Size of ciphertext
*/
const uint32_t ct_len;
/**
* Size of public key
*/
const uint32_t pk_len;
/**
* Size of secret key
*/
const uint32_t sk_len;
/**
* Size of CDF table
*/
const uint32_t cdf_table_len;
/**
* CDF table
*/
const uint16_t *cdf_table;
/**
* SHAKE extended output function
*/
ext_out_function_t xof_type;
};
/**
* Get Frodo parameters by Frodo key exchange ID
*
* @param id Frodo KEM ID
* @return Frodo parameters
*/
const frodo_params_t* frodo_params_get_by_id(frodo_kem_type_t id);
#endif /** FRODO_PARAMS_H_ @}*/

View File

@ -0,0 +1,104 @@
/*
* Copyright (C) 2019 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.
*/
#include "frodo_plugin.h"
#include "frodo.h"
#include <library.h>
typedef struct private_frodo_plugin_t private_frodo_plugin_t;
/**
* private data of frodo_plugin
*/
struct private_frodo_plugin_t {
/**
* public functions
*/
frodo_plugin_t public;
};
METHOD(plugin_t, get_name, char*,
private_frodo_plugin_t *this)
{
return "frodo";
}
METHOD(plugin_t, get_features, int,
private_frodo_plugin_t *this, plugin_feature_t *features[])
{
static plugin_feature_t f[] = {
PLUGIN_REGISTER(KE, frodo_create),
PLUGIN_PROVIDE(KE, KE_FRODO_SHAKE_L1),
PLUGIN_DEPENDS(XOF, XOF_SHAKE_128),
PLUGIN_DEPENDS(DRBG, DRBG_CTR_AES256),
PLUGIN_DEPENDS(RNG, RNG_TRUE),
PLUGIN_PROVIDE(KE, KE_FRODO_SHAKE_L3),
PLUGIN_DEPENDS(XOF, XOF_SHAKE_256),
PLUGIN_DEPENDS(XOF, XOF_SHAKE_128),
PLUGIN_DEPENDS(DRBG, DRBG_CTR_AES256),
PLUGIN_DEPENDS(RNG, RNG_TRUE),
PLUGIN_PROVIDE(KE, KE_FRODO_SHAKE_L5),
PLUGIN_DEPENDS(XOF, XOF_SHAKE_256),
PLUGIN_DEPENDS(XOF, XOF_SHAKE_128),
PLUGIN_DEPENDS(DRBG, DRBG_CTR_AES256),
PLUGIN_DEPENDS(RNG, RNG_TRUE),
PLUGIN_PROVIDE(KE, KE_FRODO_AES_L1),
PLUGIN_DEPENDS(XOF, XOF_SHAKE_128),
PLUGIN_DEPENDS(CRYPTER, ENCR_AES_ECB, 16),
PLUGIN_DEPENDS(DRBG, DRBG_CTR_AES256),
PLUGIN_DEPENDS(RNG, RNG_TRUE),
PLUGIN_PROVIDE(KE, KE_FRODO_AES_L3),
PLUGIN_DEPENDS(XOF, XOF_SHAKE_256),
PLUGIN_DEPENDS(CRYPTER, ENCR_AES_ECB, 16),
PLUGIN_DEPENDS(DRBG, DRBG_CTR_AES256),
PLUGIN_DEPENDS(RNG, RNG_TRUE),
PLUGIN_PROVIDE(KE, KE_FRODO_AES_L5),
PLUGIN_DEPENDS(XOF, XOF_SHAKE_256),
PLUGIN_DEPENDS(CRYPTER, ENCR_AES_ECB, 16),
PLUGIN_DEPENDS(DRBG, DRBG_CTR_AES256),
PLUGIN_DEPENDS(RNG, RNG_TRUE),
};
*features = f;
return countof(f);
}
METHOD(plugin_t, destroy, void,
private_frodo_plugin_t *this)
{
free(this);
}
/*
* see header file
*/
plugin_t *frodo_plugin_create()
{
private_frodo_plugin_t *this;
INIT(this,
.public = {
.plugin = {
.get_name = _get_name,
.get_features = _get_features,
.destroy = _destroy,
},
},
);
return &this->public.plugin;
}

View File

@ -0,0 +1,42 @@
/*
* Copyright (C) 2019 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 frodo_p frodo
* @ingroup plugins
*
* @defgroup frodo_plugin frodo_plugin
* @{ @ingroup frodo_p
*/
#ifndef FRODO_PLUGIN_H_
#define FRODO_PLUGIN_H_
#include <plugins/plugin.h>
typedef struct frodo_plugin_t frodo_plugin_t;
/**
* Plugin implementing Frodo-based key exchange
*/
struct frodo_plugin_t {
/**
* implements plugin interface
*/
plugin_t plugin;
};
#endif /** FRODO_PLUGIN_H_ @}*/

View File

@ -0,0 +1,507 @@
/*
* MIT License
*
* Copyright (C) Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "frodo_utils.h"
/**
* See header
*/
void frodo_pack(u_char *out, size_t outlen, uint16_t *in, size_t inlen,
u_char lsb)
{
size_t i = 0; /* whole bytes already filled in */
size_t j = 0; /* whole uint16_t already copied */
uint16_t w = 0; /* the leftover, not yet copied */
u_char bits = 0; /* the number of lsb in w */
memset(out, 0x00, outlen);
while (i < outlen && (j < inlen || ((j == inlen) && (bits > 0))))
{
u_char b = 0; /* bits in out[i] already filled in */
/**
* in: | | |********|********|
* ^
* j
* w : | ****|
* ^
* bits
* out:|**|**|**|**|**|**|**|**|* |
* ^^
* ib
*/
while (b < 8)
{
int nbits = min(8 - b, bits);
uint16_t mask = (1 << nbits) - 1;
u_char t = (w >> (bits - nbits)) & mask; /* the bits to copy from w to out */
out[i] = out[i] + (t << (8 - b - nbits));
b += nbits;
bits -= nbits;
/* not strictly necessary; mostly for debugging */
w &= ~(mask << bits);
if (bits == 0)
{
if (j < inlen)
{
w = in[j];
bits = lsb;
j++;
}
else
{
break; /* the input vector is exhausted */
}
}
}
if (b == 8)
{
i++; /* out[i] is filled in */
}
}
}
/**
* See header
*/
void frodo_unpack(uint16_t *out, size_t outlen, u_char *in, size_t inlen,
u_char lsb)
{
size_t i = 0; /* whole uint16_t already filled in */
size_t j = 0; /* whole bytes already copied */
u_char w = 0; /* the leftover, not yet copied */
u_char bits = 0; /* the number of lsb bits of w */
memset(out, 0, outlen * sizeof(uint16_t));
while (i < outlen && (j < inlen || ((j == inlen) && (bits > 0))))
{
u_char b = 0; /* bits in out[i] already filled in */
/**
* in: | | | | | | |**|**|...
* ^
* j
* w : | *|
* ^
* bits
* out:| *****| *****| *** | |...
* ^ ^
* i b
*/
while (b < lsb)
{
int nbits = min(lsb - b, bits);
uint16_t mask = (1 << nbits) - 1;
u_char t = (w >> (bits - nbits)) & mask; /* the bits to copy from w to out */
out[i] = out[i] + (t << (lsb - b - nbits));
b += nbits;
bits -= nbits;
/* not strictly necessary; mostly for debugging */
w &= ~(mask << bits);
if (bits == 0)
{
if (j < inlen)
{
w = in[j];
bits = 8;
j++;
}
else
{
break; /* the input vector is exhausted */
}
}
}
if (b == lsb)
{
i++; /* out[i] is filled in */
}
}
}
/**
* See header
*/
void frodo_sample_n(const frodo_params_t *params, uint16_t *s, size_t n)
{
int i, j;
for (i = 0; i < n; i++)
{
uint8_t sample = 0;
uint16_t prnd = s[i] >> 1; /* Drop the least significant bit */
uint8_t sign = s[i] & 0x1; /* Pick the least significant bit */
/* No need to compare with the last value */
for (j = 0; j < params->cdf_table_len - 1; j++)
{
/**
* Constant time comparison: 1 if CDF_TABLE[j] < s, 0 otherwise.
* Uses the fact that CDF_TABLE[j] and s fit in 15 bits
*/
sample += (uint16_t)(params->cdf_table[j] - prnd) >> 15;
}
/* Assuming that sign is either 0 or 1, flips sample iff sign = 1 */
s[i] = ((-sign) ^ sample) + sign;
}
}
/**
* Generate square matrix A by using SHAKE128
*/
static bool generate_matrix_by_shake(const frodo_params_t *params, uint16_t *A,
uint8_t *seed_A)
{
const uint32_t seed_A_len = params->seed_A_len;
const uint32_t n = params->n;
uint8_t seed_A_separated[2 + seed_A_len];
uint16_t *seed_A_origin = (uint16_t*)&seed_A_separated;
uint16_t i;
bool success = FALSE;
xof_t *xof;
memcpy(&seed_A_separated[2], seed_A, seed_A_len);
/* Instantiate a SHAKE-128 eXtended Output Function */
xof = lib->crypto->create_xof(lib->crypto, XOF_SHAKE_128);
if (!xof)
{
DBG1(DBG_LIB, "could not instantiate %N", ext_out_function_names,
XOF_SHAKE_128);
return FALSE;
}
for (i = 0; i < n; i++)
{
seed_A_origin[0] = i;
if (!xof->set_seed(xof, chunk_create(seed_A_separated, 2 + seed_A_len)))
{
goto err;
}
if (!xof->get_bytes(xof, 2*n, (uint8_t*)(A + i*n)))
{
goto err;
}
}
success = TRUE;
err:
xof->destroy(xof);
return success;
}
/**
* Generate square matrix A by using AES128
*/
static bool generate_matrix_by_aes(const frodo_params_t *params, uint16_t *A,
uint8_t *seed_A)
{
const uint32_t n = params->n;
const uint32_t A_len = n * n * sizeof(uint16_t);
crypter_t *crypter;
chunk_t A_chunk;
bool success = FALSE;
uint32_t block_len, step, k;
uint16_t i, j;
memset((uint8_t*)A, 0x00, A_len);
crypter = lib->crypto->create_crypter(lib->crypto, ENCR_AES_ECB, 16);
if (!crypter)
{
DBG1(DBG_LIB, "could not instantiate AES_ECB-128");
return FALSE;
}
block_len = crypter->get_block_size(crypter);
step = block_len / sizeof(uint16_t);
if (!crypter->set_key(crypter, chunk_create(seed_A, params->seed_A_len)))
{
goto err;
}
/* ECB encryption */
for (i = 0; i < n; i++)
{
for (j = 0; j < n; j += step)
{
k = i*n + j;
A[k] = i;
A[k + 1] = j;
}
}
A_chunk = chunk_create((uint8_t*)A, A_len);
if (!crypter->encrypt(crypter, A_chunk, chunk_empty, NULL))
{
goto err;
}
success = TRUE;
err:
crypter->destroy(crypter);
return success;
}
/**
* See header
*/
bool frodo_mul_add_as_plus_e(const frodo_params_t *params, uint16_t *out,
uint16_t *s, uint16_t *e, uint8_t *seed_A,
bool use_aes)
{
const uint32_t n = params->n;
const uint32_t nb = params->nb;
const uint32_t n_x_n = n * n;
int16_t A[n_x_n];
int i, j, k;
if (use_aes ? !generate_matrix_by_aes (params, A, seed_A) :
!generate_matrix_by_shake(params, A, seed_A))
{
return FALSE;
}
memcpy(out, e, nb * n * sizeof(uint16_t));
for (i = 0; i < n; i++)
{
/* Matrix multiplication-addition A*s + e */
for (k = 0; k < nb; k++)
{
uint16_t sum = 0;
for (j = 0; j < n; j++)
{
sum += A[i*n + j] * s[k*n + j];
}
/* Adding e. No need to reduce modulo 2^15,
* extra bits are taken care of during packing later on.
*/
out[i*nb + k] += sum;}
}
return TRUE;
}
/**
* See header
*/
bool frodo_mul_add_sa_plus_e(const frodo_params_t *params, uint16_t *out,
uint16_t *s, uint16_t *e, uint8_t *seed_A,
bool use_aes)
{
const uint32_t n = params->n;
const uint32_t nb = params->nb;
const uint32_t n_x_n = n * n;
int16_t A[n_x_n];
int i, j, k;
if (use_aes ? !generate_matrix_by_aes (params, A, seed_A) :
!generate_matrix_by_shake(params, A, seed_A))
{
return FALSE;
}
memcpy(out, e, nb * n * sizeof(uint16_t));
/* Matrix multiplication-addition A*s + e*/
for (i = 0; i < n; i++)
{
for (k = 0; k < nb; k++)
{
uint16_t sum = 0;
for (j = 0; j < n; j++)
{
sum += A[j*n + i] * s[k*n + j];
}
/* Adding e. No need to reduce modulo 2^15,
* extra bits are taken care of during packing later on.
*/
out[k*n + i] += sum;
}
}
return TRUE;
}
/**
* See header
*/
void frodo_mul_add_sb_plus_e(const frodo_params_t *params, uint16_t *out,
uint16_t *b, uint16_t *s, uint16_t *e)
{
const uint32_t n = params->n;
const uint32_t nb = params->nb;
const uint32_t log_q = params->log_q;
int i, j, k;
for (k = 0; k < nb; k++)
{
for (i = 0; i < nb; i++)
{
out[k*nb + i] = e[k*nb + i];
for (j = 0; j < n; j++)
{
out[k*nb + i] += s[k*n + j] * b[j*nb + i];
}
out[k*nb + i] = (uint32_t)(out[k*nb + i]) & ((1 << log_q) - 1);
}
}
}
/**
* See header
*/
void frodo_mul_bs(const frodo_params_t *params, uint16_t *out,
uint16_t *b, uint16_t *s)
{
const uint32_t n = params->n;
const uint32_t nb = params->nb;
const uint32_t log_q = params->log_q;
int i, j, k;
for (i = 0; i < nb; i++)
{
for (j = 0; j < nb; j++)
{
out[i*nb + j] = 0;
for (k = 0; k < n; k++)
{
out[i*nb + j] += b[i*n + k] * s[j*n + k];
}
out[i*nb + j] = (uint32_t)(out[i*nb + j]) & ((1 << log_q) - 1);
}
}
}
/**
* See header
*/
void frodo_add(const frodo_params_t *params, uint16_t *out,
uint16_t *a, uint16_t *b)
{
const uint32_t nb = params->nb;
const uint32_t log_q = params->log_q;
u_int i;
for (i = 0; i < (nb * nb); i++)
{
out[i] = (a[i] + b[i]) & ((1 << log_q) - 1);
}
}
void frodo_sub(const frodo_params_t *params, uint16_t *out,
uint16_t *a, uint16_t *b)
{
const uint32_t nb = params->nb;
const uint32_t log_q = params->log_q;
u_int i;
for (i = 0; i < (nb * nb); i++)
{
out[i] = (a[i] - b[i]) & ((1 << log_q) - 1);
}
}
/**
* See header
*/
void frodo_key_encode(const frodo_params_t *params, uint16_t *out, uint16_t *in)
{
const uint32_t nb = params->nb;
const uint32_t log_q = params->log_q;
const uint32_t extr_bits = params->extr_bits;
u_int i, j, npieces_word = 8;
u_int nwords = (nb * nb)/8;
uint64_t temp, mask = ((uint64_t)1 << extr_bits) - 1;
uint16_t* pos = out;
for (i = 0; i < nwords; i++)
{
temp = 0;
for(j = 0; j < extr_bits; j++)
{
temp |= ((uint64_t)((uint8_t*)in)[i*extr_bits + j]) << (8*j);
}
for (j = 0; j < npieces_word; j++)
{
*pos = (uint16_t)((temp & mask) << (log_q - extr_bits));
temp >>= extr_bits;
pos++;
}
}
}
/**
* See header
*/
void frodo_key_decode(const frodo_params_t *params, uint16_t *out, uint16_t *in)
{
const uint32_t nb = params->nb;
const uint32_t log_q = params->log_q;
const uint32_t extr_bits = params->extr_bits;
u_int i, j, index = 0, npieces_word = 8;
u_int nwords = (nb * nb) / 8;
uint16_t temp;
u_int maskex = ((uint16_t)1 << extr_bits) - 1;
u_int maskq = ((uint16_t)1 << log_q) - 1;
uint8_t *pos = (uint8_t*)out;
uint64_t templong;
for (i = 0; i < nwords; i++)
{
templong = 0;
for (j = 0; j < npieces_word; j++)
{
/* temp = floor(in*2^{-11}+0.5) */
temp = ((in[index] & maskq) +
(1 << (log_q - extr_bits - 1))) >> (log_q - extr_bits);
templong |= ((uint64_t)(temp & maskex)) << (extr_bits * j);
index++;
}
for(j = 0; j < extr_bits; j++)
{
pos[i*extr_bits + j] = (templong >> (8*j)) & 0xFF;
}
}
}

View File

@ -0,0 +1,169 @@
/*
* MIT License
*
* Copyright (C) Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* @defgroup frodo_utils frodo_utls
* @{ @ingroup frodo_p
*/
#ifndef FRODO_UTILS_H_
#define FRODO_UTILS_H_
#include "frodo_params.h"
#include <library.h>
/**
* Pack the input uint16 vector into a char output vector,
* copying lsb bits from each input element.
* If inlen * lsb / 8 > outlen, only outlen * 8 bits are copied.
*
* @param out
* @param outlen
* @param in
* @param inlen
* @param lsb
*/
void frodo_pack(u_char *out, size_t outlen, uint16_t *in, size_t inlen,
u_char lsb);
/**
* Unpack the input char vector into a uint16_t output vector,
* copying lsb bits for each output element from input.
* outlen must be at least ceil(inlen * 8 / lsb).
*
* @param out
* @param outlen
* @param in
* @param inlen
* @param lsb
*/
void frodo_unpack(uint16_t *out, size_t outlen, u_char *in, size_t inlen,
u_char lsb);
/**
* Fills vector s with n samples from the noise distribution which requires
* 16 bits to sample. The distribution is specified by its CDF.
*
* @param params parameter set
* @param s pseudo-random values (are overwritten by output)
* @param n size of s
*/
void frodo_sample_n(const frodo_params_t *params, uint16_t *s, size_t n);
/**
* Generate-and-multiply: generate matrix A (N x N) row-wise,
* multiply by s on the right.
*
* @param params parameter set
* @param out out = A*s + e (N x N_BAR)
* @param s array (N x N_BAR)
* @param e array (N x N_BAR)
* @param seed_A seed for matrix A
* @param use_aes if TRUE use AES128 for matrix A, otherwise use SHAKE128
* @return TRUE if successful
*/
bool frodo_mul_add_as_plus_e(const frodo_params_t *params, uint16_t *out,
uint16_t *s, uint16_t *e, uint8_t *seed_A,
bool use_aes);
/**
* Generate-and-multiply: generate matrix A (N x N) column-wise,
*
* @param params parameter set
* @param out out = s'*A + e' (N_BAR x N)
* @param s array (N_BAR x N)
* @param e array (N_BAR x N)
* @param seed_A seed for matrix A
* @param use_aes if TRUE use AES128 for matrix A, otherwise use SHAKE128
* @return TRUE if successful
*/
bool frodo_mul_add_sa_plus_e(const frodo_params_t *params, uint16_t *out,
uint16_t *s, uint16_t *e, uint8_t *seed_A,
bool use_aes);
/**
* Multiply by s on the left
*
* @param params parameter set
* @param b array (N x N_BAR)
* @param s array (N_BAR x N)
* @param e array (N_BAR x N_BAR)
* @param out out = s*b + e (N_BAR x N_BAR)
*/
void frodo_mul_add_sb_plus_e(const frodo_params_t *params, uint16_t *out,
uint16_t *b, uint16_t *s, uint16_t *e);
/**
* Multiply by s on the right
*
* @param params parameter set
* @param out out = b*s (N_BAR x N_BAR)
* @param b array (N_BAR x N),
* @param s array (N x N_BAR)
*/
void frodo_mul_bs(const frodo_params_t *params, uint16_t *out,
uint16_t *b, uint16_t *s);
/**
* Add a and b
*
* @param params parameter set
* @param out c = a + b (N_BAR x N_AR)
* @param a array (N_BAR x N_BAR)
* @param b array (N_BAR x N_BAR)
*/
void frodo_add(const frodo_params_t *params, uint16_t *out,
uint16_t *a, uint16_t *b);
/**
* Subtract a and b
*
* @param params parameter set
* @param out c = a - b (N_BAR x N_AR)
* @param a array (N_BAR x N_BAR)
* @param b array (N_BAR x N_BAR)
*/
void frodo_sub(const frodo_params_t *params, uint16_t *out,
uint16_t *a, uint16_t *b);
/**
* Encode
*
* @param params parameter set
* @param out encoded key
* @param in key to be encoded
*/
void frodo_key_encode(const frodo_params_t *params, uint16_t *out, uint16_t *in);
/**
* Decode
*
* @param params parameter set
* @param out decoded key
* @param in key to be decoded
*/
void frodo_key_decode(const frodo_params_t *params, uint16_t *out, uint16_t *in);
#endif /** FRODO_UTILS_H_ @}*/