summaryrefslogtreecommitdiffstats
path: root/extra/wolfssl/wolfssl/wolfcrypt/src/wc_kyber.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--extra/wolfssl/wolfssl/wolfcrypt/src/wc_kyber.c1247
1 files changed, 1244 insertions, 3 deletions
diff --git a/extra/wolfssl/wolfssl/wolfcrypt/src/wc_kyber.c b/extra/wolfssl/wolfssl/wolfcrypt/src/wc_kyber.c
index 8d516c89..b0b358f0 100644
--- a/extra/wolfssl/wolfssl/wolfcrypt/src/wc_kyber.c
+++ b/extra/wolfssl/wolfssl/wolfcrypt/src/wc_kyber.c
@@ -1,6 +1,6 @@
/* wc_kyber.c
*
- * Copyright (C) 2006-2023 wolfSSL Inc.
+ * Copyright (C) 2006-2024 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
@@ -19,8 +19,1249 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
+/* Implementation based on NIST 3rd Round submission package.
+ * See link at:
+ * https://csrc.nist.gov/Projects/post-quantum-cryptography/post-quantum-cryptography-standardization/round-3-submissions
+ */
+
+#ifdef HAVE_CONFIG_H
+ #include <config.h>
+#endif
+
#include <wolfssl/wolfcrypt/settings.h>
+#include <wolfssl/wolfcrypt/kyber.h>
+#include <wolfssl/wolfcrypt/wc_kyber.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
+#include <wolfssl/wolfcrypt/hash.h>
+#include <wolfssl/wolfcrypt/memory.h>
+
+#ifdef NO_INLINE
+ #include <wolfssl/wolfcrypt/misc.h>
+#else
+ #define WOLFSSL_MISC_INCLUDED
+ #include <wolfcrypt/src/misc.c>
+#endif
+
+#ifdef WOLFSSL_WC_KYBER
+
+/******************************************************************************/
+
+/* Use SHA3-256 to generate 32-bytes of hash. */
+#define KYBER_HASH_H wc_Sha3_256Hash
+/* Use SHA3-512 to generate 64-bytes of hash. */
+#define KYBER_HASH_G wc_Sha3_512Hash
+/* Use SHAKE-256 as a key derivation function (KDF). */
+#ifdef USE_INTEL_SPEEDUP
+#define KYBER_KDF kyber_kdf
+#else
+#define KYBER_KDF wc_Shake256Hash
+#endif
+
+/******************************************************************************/
+
+/**
+ * Initialize the Kyber key.
+ *
+ * @param [in] type Type of key: KYBER512, KYBER768, KYBER1024.
+ * @param [out] key Kyber key object to initialize.
+ * @param [in] heap Dynamic memory hint.
+ * @param [in] devId Device Id.
+ * @return 0 on success.
+ * @return BAD_FUNC_ARG when key is NULL or type is unrecognized.
+ * @return NOT_COMPILED_IN when key type is not supported.
+ */
+int wc_KyberKey_Init(int type, KyberKey* key, void* heap, int devId)
+{
+ int ret = 0;
+
+ /* Validate key. */
+ if (key == NULL) {
+ ret = BAD_FUNC_ARG;
+ }
+ if (ret == 0) {
+ /* Validate type. */
+ switch (type) {
+ case KYBER512:
+ #ifndef WOLFSSL_KYBER512
+ /* Code not compiled in for Kyber-512. */
+ ret = NOT_COMPILED_IN;
+ #endif
+ break;
+ case KYBER768:
+ #ifndef WOLFSSL_KYBER768
+ /* Code not compiled in for Kyber-768. */
+ ret = NOT_COMPILED_IN;
+ #endif
+ break;
+ case KYBER1024:
+ #ifndef WOLFSSL_KYBER1024
+ /* Code not compiled in for Kyber-1024. */
+ ret = NOT_COMPILED_IN;
+ #endif
+ break;
+ default:
+ /* No other values supported. */
+ ret = BAD_FUNC_ARG;
+ break;
+ }
+ }
+ if (ret == 0) {
+ /* Zero out all data. */
+ XMEMSET(key, 0, sizeof(*key));
+
+ /* Keep type for parameters. */
+ key->type = type;
+ /* Cache heap pointer. */
+ key->heap = heap;
+ #ifdef WOLF_CRYPTO_CB
+ /* Cache device id - not used in for this algorithm yet. */
+ key->devId = devId;
+ #endif
+
+ /* Initialize the PRF algorithm object. */
+ ret = kyber_prf_new(&key->prf, heap, devId);
+ }
+ if (ret == 0) {
+ kyber_init();
+ }
+
+ (void)devId;
+
+ return ret;
+}
+
+/**
+ * Free the Kyber key object.
+ *
+ * @param [in, out] key Kyber key object to dispose of.
+ */
+void wc_KyberKey_Free(KyberKey* key)
+{
+ if (key != NULL) {
+ /* Dispose of PRF object. */
+ kyber_prf_free(&key->prf);
+ /* Ensure all private data is zeroed. */
+ ForceZero(key, sizeof(*key));
+ }
+}
+
+/******************************************************************************/
+
+/**
+ * Make a Kyber key object using a random number generator.
+ *
+ * @param [in, out] key Kyber key object.
+ * @param [in] rng Random number generator.
+ * @return 0 on success.
+ * @return BAD_FUNC_ARG when key or rng is NULL.
+ * @return MEMORY_E when dynamic memory allocation failed.
+ */
+int wc_KyberKey_MakeKey(KyberKey* key, WC_RNG* rng)
+{
+ int ret = 0;
+ unsigned char rand[KYBER_MAKEKEY_RAND_SZ];
+
+ /* Validate parameters. */
+ if ((key == NULL) || (rng == NULL)) {
+ ret = BAD_FUNC_ARG;
+ }
+
+ if (ret == 0) {
+ /* Generate random to with PRFs. */
+ ret = wc_RNG_GenerateBlock(rng, rand, KYBER_SYM_SZ);
+ }
+ if (ret == 0) {
+ /* Generate random to with PRFs. */
+ ret = wc_RNG_GenerateBlock(rng, rand + KYBER_SYM_SZ, KYBER_SYM_SZ);
+ }
+ if (ret == 0) {
+ /* Make a key pair from the random. */
+ ret = wc_KyberKey_MakeKeyWithRandom(key, rand, sizeof(rand));
+ }
+
+ /* Ensure seeds are zeroized. */
+ ForceZero((void*)rand, (word32)sizeof(rand));
+
+ return ret;
+}
+
+/**
+ * Make a Kyber key object using random data.
+ *
+ * @param [in, out] key Kyber key ovject.
+ * @param [in] rng Random number generator.
+ * @return 0 on success.
+ * @return BAD_FUNC_ARG when key or rand is NULL.
+ * @return BUFFER_E when length is not KYBER_MAKEKEY_RAND_SZ.
+ * @return NOT_COMPILED_IN when key type is not supported.
+ * @return MEMORY_E when dynamic memory allocation failed.
+ */
+int wc_KyberKey_MakeKeyWithRandom(KyberKey* key, const unsigned char* rand,
+ int len)
+{
+ byte buf[2 * KYBER_SYM_SZ + 1];
+ byte* pubSeed = buf;
+ byte* noiseSeed = buf + KYBER_SYM_SZ;
+ sword16* a = NULL;
+ sword16* e;
+ int ret = 0;
+ int kp = 0;
+
+ /* Validate parameters. */
+ if ((key == NULL) || (rand == NULL)) {
+ ret = BAD_FUNC_ARG;
+ }
+ if ((ret == 0) && (len != KYBER_MAKEKEY_RAND_SZ)) {
+ ret = BUFFER_E;
+ }
+
+ if (ret == 0) {
+ /* Establish parameters based on key type. */
+ switch (key->type) {
+ #ifdef WOLFSSL_KYBER512
+ case KYBER512:
+ kp = KYBER512_K;
+ break;
+ #endif
+ #ifdef WOLFSSL_KYBER768
+ case KYBER768:
+ kp = KYBER768_K;
+ break;
+ #endif
+ #ifdef WOLFSSL_KYBER1024
+ case KYBER1024:
+ kp = KYBER1024_K;
+ break;
+ #endif
+ default:
+ /* No other values supported. */
+ ret = NOT_COMPILED_IN;
+ break;
+ }
+ }
+
+ if (ret == 0) {
+ /* Allocate dynamic memory for matrix and error vector. */
+ a = (sword16*)XMALLOC((kp + 1) * kp * KYBER_N * sizeof(sword16),
+ key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+ if (a == NULL) {
+ ret = MEMORY_E;
+ }
+ }
+ if (ret == 0) {
+ /* Error vector allocated at end of a. */
+ e = a + (kp * kp * KYBER_N);
+
+ /* Expand 16 bytes of random to 32. */
+ ret = KYBER_HASH_G(rand, KYBER_SYM_SZ, buf);
+ }
+ if (ret == 0) {
+ /* Cache the public seed for use in encapsulation and encoding public
+ * key. */
+ XMEMCPY(key->pubSeed, pubSeed, KYBER_SYM_SZ);
+ /* Cache the z value for decapsulation and encoding private key. */
+ XMEMCPY(key->z, rand + KYBER_SYM_SZ, sizeof(key->z));
+
+ /* Generate the matrix A. */
+ ret = kyber_gen_matrix(&key->prf, a, kp, pubSeed, 0);
+ }
+
+ if (ret == 0) {
+ /* Initialize PRF for use in noise generation. */
+ kyber_prf_init(&key->prf);
+ /* Generate noise using PRF. */
+ ret = kyber_get_noise(&key->prf, kp, key->priv, e, NULL, noiseSeed);
+ }
+ if (ret == 0) {
+ /* Generate key pair from random data. */
+ kyber_keygen(key->priv, key->pub, e, a, kp);
+
+ /* Private and public key are set/available. */
+ key->flags |= KYBER_FLAG_PRIV_SET | KYBER_FLAG_PUB_SET;
+ }
+
+ /* Free dynamic memory allocated in function. */
+ XFREE(a, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+
+ return ret;
+}
+
+/******************************************************************************/
+
+/**
+ * Get the size in bytes of cipher text for key.
+ *
+ * @param [in] key Kyber key object.
+ * @param [out] len Length of cipher text in bytes.
+ * @return 0 on success.
+ * @return BAD_FUNC_ARG when key or len is NULL.
+ * @return NOT_COMPILED_IN when key type is not supported.
+ */
+int wc_KyberKey_CipherTextSize(KyberKey* key, word32* len)
+{
+ int ret = 0;
+
+ /* Validate parameters. */
+ if ((key == NULL) || (len == NULL)) {
+ ret = BAD_FUNC_ARG;
+ }
+
+ if (ret == 0) {
+ /* Return in 'len' size of the cipher text for the type of this key. */
+ switch (key->type) {
+ #ifdef WOLFSSL_KYBER512
+ case KYBER512:
+ *len = KYBER512_CIPHER_TEXT_SIZE;
+ break;
+ #endif
+ #ifdef WOLFSSL_KYBER768
+ case KYBER768:
+ *len = KYBER768_CIPHER_TEXT_SIZE;
+ break;
+ #endif
+ #ifdef WOLFSSL_KYBER1024
+ case KYBER1024:
+ *len = KYBER1024_CIPHER_TEXT_SIZE;
+ break;
+ #endif
+ default:
+ /* No other values supported. */
+ ret = NOT_COMPILED_IN;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * Size of a shared secret in bytes. Always KYBER_SS_SZ.
+ *
+ * @param [in] key Kyber key object. Not used.
+ * @param [out] Size of the shared secret created with a Kyber key.
+ * @return 0 on success.
+ * @return 0 to indicate success.
+ */
+int wc_KyberKey_SharedSecretSize(KyberKey* key, word32* len)
+{
+ (void)key;
+
+ *len = KYBER_SS_SZ;
+
+ return 0;
+}
+
+/* Encapsulate data and derive secret.
+ *
+ * @param [in] key Kyber key object.
+ * @param [in] msg Message to encapsulate.
+ * @param [in] coins Coins (seed) to feed to PRF.
+ * @param [in] ct Calculated cipher text.
+ * @return 0 on success.
+ * @return NOT_COMPILED_IN when key type is not supported.
+ */
+static int kyberkey_encapsulate(KyberKey* key, const byte* msg, byte* coins,
+ unsigned char* ct)
+{
+ int ret = 0;
+ sword16* sp;
+ sword16* ep;
+ sword16* k;
+ sword16* epp;
+ unsigned int kp;
+ unsigned int compVecSz;
+#ifndef USE_INTEL_SPEEDUP
+ sword16* at = NULL;
+#else
+ sword16 at[((KYBER_MAX_K + 3) * KYBER_MAX_K + 3) * KYBER_N];
+#endif
+
+ /* Establish parameters based on key type. */
+ switch (key->type) {
+#ifdef WOLFSSL_KYBER512
+ case KYBER512:
+ kp = KYBER512_K;
+ compVecSz = KYBER512_POLY_VEC_COMPRESSED_SZ;
+ break;
+#endif
+#ifdef WOLFSSL_KYBER768
+ case KYBER768:
+ kp = KYBER768_K;
+ compVecSz = KYBER768_POLY_VEC_COMPRESSED_SZ;
+ break;
+#endif
+#ifdef WOLFSSL_KYBER1024
+ case KYBER1024:
+ kp = KYBER1024_K;
+ compVecSz = KYBER1024_POLY_VEC_COMPRESSED_SZ;
+ break;
+#endif
+ default:
+ /* No other values supported. */
+ ret = NOT_COMPILED_IN;
+ break;
+ }
+
+#ifndef USE_INTEL_SPEEDUP
+ if (ret == 0) {
+ /* Allocate dynamic memory for all matrices, vectors and polynomials. */
+ at = (sword16*)XMALLOC(((kp + 3) * kp + 3) * KYBER_N * sizeof(sword16),
+ key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+ if (at == NULL) {
+ ret = MEMORY_E;
+ }
+ }
+#endif
+
+ if (ret == 0) {
+ /* Assign allocated dynamic memory to pointers.
+ * at (m) | k (p) | sp (v) | sp (v) | epp (v) | bp (p) | v (v) */
+ k = at + KYBER_N * kp * kp;
+ sp = k + KYBER_N;
+ ep = sp + KYBER_N * kp;
+ epp = ep + KYBER_N * kp;
+
+ /* Convert msg to a polynomial. */
+ kyber_from_msg(k, msg);
-#ifdef WOLFSSL_HAVE_KYBER
- #error "Contact wolfSSL to get the implementation of this file"
+ /* Generate the transposed matrix. */
+ ret = kyber_gen_matrix(&key->prf, at, kp, key->pubSeed, 1);
+ }
+ if (ret == 0) {
+ /* Initialize the PRF for use in the noise generation. */
+ kyber_prf_init(&key->prf);
+ /* Generate noise using PRF. */
+ ret = kyber_get_noise(&key->prf, kp, sp, ep, epp, coins);
+ }
+ if (ret == 0) {
+ sword16* bp;
+ sword16* v;
+
+ /* Assign remaining allocated dynamic memory to pointers.
+ * at (m) | k (p) | sp (v) | sp (v) | epp (v) | bp (p) | v (v)*/
+ bp = epp + KYBER_N;
+ v = bp + KYBER_N * kp;
+
+ /* Perform encapsulation maths. */
+ kyber_encapsulate(key->pub, bp, v, at, sp, ep, epp, k, kp);
+
+ #ifdef WOLFSSL_KYBER512
+ if (kp == KYBER512_K) {
+ kyber_vec_compress_10(ct, bp, kp);
+ kyber_compress_4(ct + compVecSz, v);
+ }
+ #endif
+ #ifdef WOLFSSL_KYBER768
+ if (kp == KYBER768_K) {
+ kyber_vec_compress_10(ct, bp, kp);
+ kyber_compress_4(ct + compVecSz, v);
+ }
+ #endif
+ #ifdef WOLFSSL_KYBER1024
+ if (kp == KYBER1024_K) {
+ kyber_vec_compress_11(ct, bp);
+ kyber_compress_5(ct + compVecSz, v);
+ }
+ #endif
+ }
+
+#ifndef USE_INTEL_SPEEDUP
+ /* Dispose of dynamic memory allocated in function. */
+ XFREE(at, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
#endif
+
+ return ret;
+}
+
+/**
+ * Encapsulate with random number generator and derive secret.
+ *
+ * @param [in] key Kyber key object.
+ * @param [out] ct Cipher text.
+ * @param [out] ss Shared secret generated.
+ * @param [in] rng Random number generator.
+ * @return 0 on success.
+ * @return BAD_FUNC_ARG when key, ct, ss or RNG is NULL.
+ * @return NOT_COMPILED_IN when key type is not supported.
+ * @return MEMORY_E when dynamic memory allocation failed.
+ */
+int wc_KyberKey_Encapsulate(KyberKey* key, unsigned char* ct, unsigned char* ss,
+ WC_RNG* rng)
+{
+ int ret = 0;
+ unsigned char rand[KYBER_ENC_RAND_SZ];
+
+ /* Validate parameters. */
+ if ((key == NULL) || (ct == NULL) || (ss == NULL) || (rng == NULL)) {
+ ret = BAD_FUNC_ARG;
+ }
+
+ if (ret == 0) {
+ /* Generate seed for use with PRFs. */
+ ret = wc_RNG_GenerateBlock(rng, rand, sizeof(rand));
+ }
+ if (ret == 0) {
+ /* Encapsulate with the random. */
+ ret = wc_KyberKey_EncapsulateWithRandom(key, ct, ss, rand,
+ sizeof(rand));
+ }
+
+ return ret;
+}
+
+/**
+ * Encapsulate with random data and derive secret.
+ *
+ * @param [out] ct Cipher text.
+ * @param [out] ss Shared secret generated.
+ * @param [in] rand Random data.
+ * @param [in] len Random data.
+ * @return 0 on success.
+ * @return BAD_FUNC_ARG when key, ct, ss or RNG is NULL.
+ * @return BUFFER_E when len is not KYBER_ENC_RAND_SZ.
+ * @return NOT_COMPILED_IN when key type is not supported.
+ * @return MEMORY_E when dynamic memory allocation failed.
+ */
+int wc_KyberKey_EncapsulateWithRandom(KyberKey* key, unsigned char* ct,
+ unsigned char* ss, const unsigned char* rand, int len)
+{
+ byte msg[2 * KYBER_SYM_SZ];
+ byte kr[2 * KYBER_SYM_SZ + 1];
+ int ret = 0;
+ unsigned int ctSz;
+
+ /* Validate parameters. */
+ if ((key == NULL) || (ct == NULL) || (ss == NULL) || (rand == NULL)) {
+ ret = BAD_FUNC_ARG;
+ }
+ if ((ret == 0) && (len != KYBER_ENC_RAND_SZ)) {
+ ret = BUFFER_E;
+ }
+
+ if (ret == 0) {
+ /* Establish parameters based on key type. */
+ switch (key->type) {
+ #ifdef WOLFSSL_KYBER512
+ case KYBER512:
+ ctSz = KYBER512_CIPHER_TEXT_SIZE;
+ break;
+ #endif
+ #ifdef WOLFSSL_KYBER768
+ case KYBER768:
+ ctSz = KYBER768_CIPHER_TEXT_SIZE;
+ break;
+ #endif
+ #ifdef WOLFSSL_KYBER1024
+ case KYBER1024:
+ ctSz = KYBER1024_CIPHER_TEXT_SIZE;
+ break;
+ #endif
+ default:
+ /* No other values supported. */
+ ret = NOT_COMPILED_IN;
+ break;
+ }
+ }
+
+ /* If public hash (h) is not stored against key, calculate it. */
+ if ((ret == 0) && ((key->flags & KYBER_FLAG_H_SET) == 0)) {
+ byte* pubKey = NULL;
+ word32 pubKeyLen;
+
+ /* Determine how big an encoded public key will be. */
+ ret = wc_KyberKey_PublicKeySize(key, &pubKeyLen);
+ if (ret == 0) {
+ /* Allocate dynamic memory for encoded public key. */
+ pubKey = (byte*)XMALLOC(pubKeyLen, key->heap,
+ DYNAMIC_TYPE_TMP_BUFFER);
+ if (pubKey == NULL) {
+ ret = MEMORY_E;
+ }
+ }
+ if (ret == 0) {
+ /* Encode public key - h is hash of encoded public key. */
+ ret = wc_KyberKey_EncodePublicKey(key, pubKey, pubKeyLen);
+ }
+ /* Dispose of encoded public key. */
+ XFREE(pubKey, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+ }
+ if ((ret == 0) && ((key->flags & KYBER_FLAG_H_SET) == 0)) {
+ /* Implementation issue if h not cached and flag set. */
+ ret = BAD_STATE_E;
+ }
+
+ if (ret == 0) {
+ /* Hash random to anonymize as seed data. */
+ ret = KYBER_HASH_H(rand, KYBER_SYM_SZ, msg);
+ }
+ if (ret == 0) {
+ /* Copy the hash of the public key into msg. */
+ XMEMCPY(msg + KYBER_SYM_SZ, key->h, KYBER_SYM_SZ);
+
+ /* Hash message into seed buffer. */
+ ret = KYBER_HASH_G(msg, 2 * KYBER_SYM_SZ, kr);
+ }
+
+ if (ret == 0) {
+ /* Encapsulate the message using the key and the seed (coins). */
+ ret = kyberkey_encapsulate(key, msg, kr + KYBER_SYM_SZ, ct);
+ }
+
+ if (ret == 0) {
+ /* Hash the cipher text after the seed. */
+ ret = KYBER_HASH_H(ct, ctSz, kr + KYBER_SYM_SZ);
+ }
+ if (ret == 0) {
+ /* Derive the secret from the seed and hash of cipher text. */
+ ret = KYBER_KDF(kr, 2 * KYBER_SYM_SZ, ss, KYBER_SS_SZ);
+ }
+
+ return ret;
+}
+
+/******************************************************************************/
+
+/* Decapsulate cipher text to the message using key.
+ *
+ * @param [in] Kyber key object.
+ * @param [out] Message than was encapsulated.
+ * @param [in] Cipher text.
+ * @return 0 on success.
+ * @return NOT_COMPILED_IN when key type is not supported.
+ * @return MEMORY_E when dynamic memory allocation failed.
+ */
+static KYBER_NOINLINE int kyberkey_decapsulate(KyberKey* key,
+ unsigned char* msg, const unsigned char* ct)
+{
+ int ret = 0;
+ sword16* v;
+ sword16* mp;
+ unsigned int kp;
+ unsigned int compVecSz;
+#ifndef USE_INTEL_SPEEDUP
+ sword16* bp = NULL;
+#else
+ sword16 bp[(KYBER_MAX_K + 2) * KYBER_N];
+#endif
+
+ /* Establish parameters based on key type. */
+ switch (key->type) {
+#ifdef WOLFSSL_KYBER512
+ case KYBER512:
+ kp = KYBER512_K;
+ compVecSz = KYBER512_POLY_VEC_COMPRESSED_SZ;
+ break;
+#endif
+#ifdef WOLFSSL_KYBER768
+ case KYBER768:
+ kp = KYBER768_K;
+ compVecSz = KYBER768_POLY_VEC_COMPRESSED_SZ;
+ break;
+#endif
+#ifdef WOLFSSL_KYBER1024
+ case KYBER1024:
+ kp = KYBER1024_K;
+ compVecSz = KYBER1024_POLY_VEC_COMPRESSED_SZ;
+ break;
+#endif
+ default:
+ /* No other values supported. */
+ ret = NOT_COMPILED_IN;
+ break;
+ }
+
+#ifndef USE_INTEL_SPEEDUP
+ if (ret == 0) {
+ /* Allocate dynamic memory for a vector and two polynomials. */
+ bp = (sword16*)XMALLOC((kp + 2) * KYBER_N * sizeof(sword16), key->heap,
+ DYNAMIC_TYPE_TMP_BUFFER);
+ if (bp == NULL) {
+ ret = MEMORY_E;
+ }
+ }
+#endif
+ if (ret == 0) {
+ /* Assign allocated dynamic memory to pointers.
+ * bp (v) | v (p) | mp (p) */
+ v = bp + kp * KYBER_N;
+ mp = v + KYBER_N;
+
+ #ifdef WOLFSSL_KYBER512
+ if (kp == KYBER512_K) {
+ kyber_vec_decompress_10(bp, ct, kp);
+ kyber_decompress_4(v, ct + compVecSz);
+ }
+ #endif
+ #ifdef WOLFSSL_KYBER768
+ if (kp == KYBER768_K) {
+ kyber_vec_decompress_10(bp, ct, kp);
+ kyber_decompress_4(v, ct + compVecSz);
+ }
+ #endif
+ #ifdef WOLFSSL_KYBER1024
+ if (kp == KYBER1024_K) {
+ kyber_vec_decompress_11(bp, ct);
+ kyber_decompress_5(v, ct + compVecSz);
+ }
+ #endif
+
+ /* Decapsulate the cipher text into polynomial. */
+ kyber_decapsulate(key->priv, mp, bp, v, kp);
+
+ /* Convert the polynomial into a array of bytes (message). */
+ kyber_to_msg(msg, mp);
+ }
+
+#ifndef USE_INTEL_SPEEDUP
+ /* Dispose of dynamically memory allocated in function. */
+ XFREE(bp, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+ return ret;
+}
+
+/**
+ * Decapsulate the cipher text to calculate the shared secret.
+ *
+ * Validates the cipher text by encapsulating and comparing with data passed in.
+ *
+ * @param [in] key Kyber key object.
+ * @param [out] ss Shared secret.
+ * @param [in] ct Cipher text.
+ * @param [in] len Length of cipher text.
+ * @return 0 on success.
+ * @return BAD_FUNC_ARG when key, ss or cr are NULL.
+ * @return NOT_COMPILED_IN when key type is not supported.
+ * @return BUFFER_E when len is not the length of cipher text for the key type.
+ * @return MEMORY_E when dynamic memory allocation failed.
+ */
+int wc_KyberKey_Decapsulate(KyberKey* key, unsigned char* ss,
+ const unsigned char* ct, word32 len)
+{
+ byte msg[2 * KYBER_SYM_SZ];
+ byte kr[2 * KYBER_SYM_SZ + 1];
+ int ret = 0;
+ unsigned int ctSz;
+ unsigned int i;
+ int fail;
+#ifndef USE_INTEL_SPEEDUP
+ byte* cmp = NULL;
+#else
+ byte cmp[KYBER_MAX_CIPHER_TEXT_SIZE];
+#endif
+
+ /* Validate parameters. */
+ if ((key == NULL) || (ss == NULL) || (ct == NULL)) {
+ ret = BAD_FUNC_ARG;
+ }
+
+ if (ret == 0) {
+ /* Establish cipher text size based on key type. */
+ switch (key->type) {
+ #ifdef WOLFSSL_KYBER512
+ case KYBER512:
+ ctSz = KYBER512_CIPHER_TEXT_SIZE;
+ break;
+ #endif
+ #ifdef WOLFSSL_KYBER768
+ case KYBER768:
+ ctSz = KYBER768_CIPHER_TEXT_SIZE;
+ break;
+ #endif
+ #ifdef WOLFSSL_KYBER1024
+ case KYBER1024:
+ ctSz = KYBER1024_CIPHER_TEXT_SIZE;
+ break;
+ #endif
+ default:
+ /* No other values supported. */
+ ret = NOT_COMPILED_IN;
+ break;
+ }
+ }
+
+ /* Ensure the cipher text passed in is the correct size. */
+ if ((ret == 0) && (len != ctSz)) {
+ ret = BUFFER_E;
+ }
+
+#ifndef USE_INTEL_SPEEDUP
+ if (ret == 0) {
+ /* Allocate memory for cipher text that is generated. */
+ cmp = (byte*)XMALLOC(ctSz, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+ if (cmp == NULL) {
+ ret = MEMORY_E;
+ }
+ }
+#endif
+
+ if (ret == 0) {
+ /* Decapsulate the cipher text. */
+ ret = kyberkey_decapsulate(key, msg, ct);
+ }
+ if (ret == 0) {
+ /* Copy public hash over after the seed. */
+ XMEMCPY(msg + KYBER_SYM_SZ, key->h, KYBER_SYM_SZ);
+ /* Hash message into seed buffer. */
+ ret = KYBER_HASH_G(msg, 2 * KYBER_SYM_SZ, kr);
+ }
+ if (ret == 0) {
+ /* Encapsulate the message. */
+ ret = kyberkey_encapsulate(key, msg, kr + KYBER_SYM_SZ, cmp);
+ }
+ if (ret == 0) {
+ /* Compare generated cipher text with that passed in. */
+ fail = kyber_cmp(ct, cmp, ctSz);
+
+ /* Hash the cipher text after the seed. */
+ ret = KYBER_HASH_H(ct, ctSz, kr + KYBER_SYM_SZ);
+ }
+ if (ret == 0) {
+ /* Change seed to z on comparison failure. */
+ for (i = 0; i < KYBER_SYM_SZ; i++) {
+ kr[i] ^= (kr[i] ^ key->z[i]) & fail;
+ }
+
+ /* Derive the secret from the seed and hash of cipher text. */
+ ret = KYBER_KDF(kr, 2 * KYBER_SYM_SZ, ss, KYBER_SS_SZ);
+ }
+
+#ifndef USE_INTEL_SPEEDUP
+ /* Dispose of dynamic memory allocated in function. */
+ XFREE(cmp, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+ return ret;
+}
+
+/******************************************************************************/
+
+/**
+ * Decode the private key.
+ *
+ * Private Vector | Public Key | Public Hash | Randomizer
+ *
+ * @param [in, out] key Kyber key object.
+ * @param [in] in Buffer holding encoded key.
+ * @param [in] len Length of data in buffer.
+ * @return 0 on success.
+ * @return BAD_FUNC_ARG when key or in is NULL.
+ * @return NOT_COMPILED_IN when key type is not supported.
+ * @return BUFFER_E when len is not the correct size.
+ */
+int wc_KyberKey_DecodePrivateKey(KyberKey* key, unsigned char* in, word32 len)
+{
+ int ret = 0;
+ word32 privLen = 0;
+ word32 pubLen = 0;
+ unsigned int k = 0;
+ unsigned char* p = in;
+
+ /* Validate parameters. */
+ if ((key == NULL) || (in == NULL)) {
+ ret = BAD_FUNC_ARG;
+ }
+
+ if (ret == 0) {
+ /* Establish parameters based on key type. */
+ switch (key->type) {
+ #ifdef WOLFSSL_KYBER512
+ case KYBER512:
+ k = KYBER512_K;
+ privLen = KYBER512_PRIVATE_KEY_SIZE;
+ pubLen = KYBER512_PUBLIC_KEY_SIZE;
+ break;
+ #endif
+ #ifdef WOLFSSL_KYBER768
+ case KYBER768:
+ k = KYBER768_K;
+ privLen = KYBER768_PRIVATE_KEY_SIZE;
+ pubLen = KYBER768_PUBLIC_KEY_SIZE;
+ break;
+ #endif
+ #ifdef WOLFSSL_KYBER1024
+ case KYBER1024:
+ k = KYBER1024_K;
+ privLen = KYBER1024_PRIVATE_KEY_SIZE;
+ pubLen = KYBER1024_PUBLIC_KEY_SIZE;
+ break;
+ #endif
+ default:
+ /* No other values supported. */
+ ret = NOT_COMPILED_IN;
+ break;
+ }
+ }
+ /* Ensure the data is the correct length for the key type. */
+ if ((ret == 0) && (len != privLen)) {
+ ret = BUFFER_E;
+ }
+
+ if (ret == 0) {
+ /* Decode private key that is vector of polynomials. */
+ kyber_from_bytes(key->priv, p, k);
+ p += k * KYBER_POLY_SIZE;
+
+ /* Decode the public key that is after the private key. */
+ ret = wc_KyberKey_DecodePublicKey(key, p, pubLen);
+ }
+ if (ret == 0) {
+ /* Skip over public key. */
+ p += pubLen;
+ /* Copy the hash of the encoded public key that is after public key. */
+ XMEMCPY(key->h, p, sizeof(key->h));
+ p += KYBER_SYM_SZ;
+ /* Copy the z (randomizer) that is after hash. */
+ XMEMCPY(key->z, p, sizeof(key->z));
+ /* Set that private and public keys, and public hash are set. */
+ key->flags |= KYBER_FLAG_H_SET | KYBER_FLAG_BOTH_SET;
+ }
+
+ return ret;
+}
+
+/**
+ * Decode public key.
+ *
+ * Public vector | Public Seed
+ *
+ * @param [in, out] key Kyber key object.
+ * @param [in] in Buffer holding encoded key.
+ * @param [in] len Length of data in buffer.
+ * @return 0 on success.
+ * @return BAD_FUNC_ARG when key or in is NULL.
+ * @return NOT_COMPILED_IN when key type is not supported.
+ * @return BUFFER_E when len is not the correct size.
+ */
+int wc_KyberKey_DecodePublicKey(KyberKey* key, unsigned char* in, word32 len)
+{
+ int ret = 0;
+ word32 pubLen = 0;
+ unsigned int k = 0;
+ unsigned char* p = in;
+
+ if ((key == NULL) || (in == NULL)) {
+ ret = BAD_FUNC_ARG;
+ }
+
+ if (ret == 0) {
+ /* Establish parameters based on key type. */
+ switch (key->type) {
+ #ifdef WOLFSSL_KYBER512
+ case KYBER512:
+ k = KYBER512_K;
+ pubLen = KYBER512_PUBLIC_KEY_SIZE;
+ break;
+ #endif
+ #ifdef WOLFSSL_KYBER768
+ case KYBER768:
+ k = KYBER768_K;
+ pubLen = KYBER768_PUBLIC_KEY_SIZE;
+ break;
+ #endif
+ #ifdef WOLFSSL_KYBER1024
+ case KYBER1024:
+ k = KYBER1024_K;
+ pubLen = KYBER1024_PUBLIC_KEY_SIZE;
+ break;
+ #endif
+ default:
+ /* No other values supported. */
+ ret = NOT_COMPILED_IN;
+ break;
+ }
+ }
+ /* Ensure the data is the correct length for the key type. */
+ if ((ret == 0) && (len != pubLen)) {
+ ret = BUFFER_E;
+ }
+
+ if (ret == 0) {
+ unsigned int i;
+
+ /* Decode public key that is vector of polynomials. */
+ kyber_from_bytes(key->pub, p, k);
+ p += k * KYBER_POLY_SIZE;
+
+ /* Read public key seed. */
+ for (i = 0; i < KYBER_SYM_SZ; i++) {
+ key->pubSeed[i] = p[i];
+ }
+ /* Calculate public hash. */
+ ret = KYBER_HASH_H(in, len, key->h);
+ }
+ if (ret == 0) {
+ /* Record public key and public hash set. */
+ key->flags |= KYBER_FLAG_PUB_SET | KYBER_FLAG_H_SET;
+ }
+
+ return ret;
+}
+
+/**
+ * Get the size in bytes of encoded private key for the key.
+ *
+ * @param [in] key Kyber key object.
+ * @param [out] len Length of encoded private key in bytes.
+ * @return 0 on success.
+ * @return BAD_FUNC_ARG when key or len is NULL.
+ * @return NOT_COMPILED_IN when key type is not supported.
+ */
+int wc_KyberKey_PrivateKeySize(KyberKey* key, word32* len)
+{
+ int ret = 0;
+
+ /* Validate parameters. */
+ if ((key == NULL) || (len == NULL)) {
+ ret = BAD_FUNC_ARG;
+ }
+
+ if (ret == 0) {
+ /* Return in 'len' size of the encoded private key for the type of this
+ * key. */
+ switch (key->type) {
+ #ifdef WOLFSSL_KYBER512
+ case KYBER512:
+ *len = KYBER512_PRIVATE_KEY_SIZE;
+ break;
+ #endif
+ #ifdef WOLFSSL_KYBER768
+ case KYBER768:
+ *len = KYBER768_PRIVATE_KEY_SIZE;
+ break;
+ #endif
+ #ifdef WOLFSSL_KYBER1024
+ case KYBER1024:
+ *len = KYBER1024_PRIVATE_KEY_SIZE;
+ break;
+ #endif
+ default:
+ /* No other values supported. */
+ ret = NOT_COMPILED_IN;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * Get the size in bytes of encoded public key for the key.
+ *
+ * @param [in] key Kyber key object.
+ * @param [out] len Length of encoded public key in bytes.
+ * @return 0 on success.
+ * @return BAD_FUNC_ARG when key or len is NULL.
+ * @return NOT_COMPILED_IN when key type is not supported.
+ */
+int wc_KyberKey_PublicKeySize(KyberKey* key, word32* len)
+{
+ int ret = 0;
+
+ /* Validate parameters. */
+ if ((key == NULL) || (len == NULL)) {
+ ret = BAD_FUNC_ARG;
+ }
+
+ if (ret == 0) {
+ /* Return in 'len' size of the encoded public key for the type of this
+ * key. */
+ switch (key->type) {
+ #ifdef WOLFSSL_KYBER512
+ case KYBER512:
+ *len = KYBER512_PUBLIC_KEY_SIZE;
+ break;
+ #endif
+ #ifdef WOLFSSL_KYBER768
+ case KYBER768:
+ *len = KYBER768_PUBLIC_KEY_SIZE;
+ break;
+ #endif
+ #ifdef WOLFSSL_KYBER1024
+ case KYBER1024:
+ *len = KYBER1024_PUBLIC_KEY_SIZE;
+ break;
+ #endif
+ default:
+ /* No other values supported. */
+ ret = NOT_COMPILED_IN;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * Encode the private key.
+ *
+ * Private Vector | Public Key | Public Hash | Randomizer
+ *
+ * @param [in] key Kyber key object.
+ * @param [out] out Buffer to hold data.
+ * @param [in] len Size of buffer in bytes.
+ * @return 0 on success.
+ * @return BAD_FUNC_ARG when key or out is NULL or private/public key not
+ * available.
+ * @return NOT_COMPILED_IN when key type is not supported.
+ */
+int wc_KyberKey_EncodePrivateKey(KyberKey* key, unsigned char* out, word32 len)
+{
+ int ret = 0;
+ unsigned int k = 0;
+ unsigned int pubLen = 0;
+ unsigned int privLen = 0;
+ unsigned char* p = out;
+
+ if ((key == NULL) || (out == NULL)) {
+ ret = BAD_FUNC_ARG;
+ }
+ if ((ret == 0) &&
+ ((key->flags & KYBER_FLAG_BOTH_SET) != KYBER_FLAG_BOTH_SET)) {
+ ret = BAD_FUNC_ARG;
+ }
+
+ if (ret == 0) {
+ switch (key->type) {
+ #ifdef WOLFSSL_KYBER512
+ case KYBER512:
+ k = KYBER512_K;
+ pubLen = KYBER512_PUBLIC_KEY_SIZE;
+ privLen = KYBER512_PRIVATE_KEY_SIZE;
+ break;
+ #endif
+ #ifdef WOLFSSL_KYBER768
+ case KYBER768:
+ k = KYBER768_K;
+ pubLen = KYBER768_PUBLIC_KEY_SIZE;
+ privLen = KYBER768_PRIVATE_KEY_SIZE;
+ break;
+ #endif
+ #ifdef WOLFSSL_KYBER1024
+ case KYBER1024:
+ k = KYBER1024_K;
+ pubLen = KYBER1024_PUBLIC_KEY_SIZE;
+ privLen = KYBER1024_PRIVATE_KEY_SIZE;
+ break;
+ #endif
+ default:
+ /* No other values supported. */
+ ret = NOT_COMPILED_IN;
+ break;
+ }
+ }
+ /* Check buffer is big enough for encoding. */
+ if ((ret == 0) && (len != privLen)) {
+ ret = BUFFER_E;
+ }
+
+ if (ret == 0) {
+ /* Encode private key that is vector of polynomials. */
+ kyber_to_bytes(p, key->priv, k);
+ p += KYBER_POLY_SIZE * k;
+
+ /* Encode public key. */
+ ret = wc_KyberKey_EncodePublicKey(key, p, pubLen);
+ p += pubLen;
+ }
+ /* Ensure hash of public key is available. */
+ if ((ret == 0) && ((key->flags & KYBER_FLAG_H_SET) == 0)) {
+ ret = KYBER_HASH_H(p - pubLen, pubLen, key->h);
+ }
+ if (ret == 0) {
+ /* Public hash is available. */
+ key->flags |= KYBER_FLAG_H_SET;
+ /* Append public hash. */
+ XMEMCPY(p, key->h, sizeof(key->h));
+ p += KYBER_SYM_SZ;
+ /* Append z (randomizer). */
+ XMEMCPY(p, key->z, sizeof(key->z));
+ }
+
+ return ret;
+}
+
+/**
+ * Encode the public key.
+ *
+ * Public vector | Public Seed
+ *
+ * @param [in] key Kyber key object.
+ * @param [out] out Buffer to hold data.
+ * @param [in] len Size of buffer in bytes.
+ * @return 0 on success.
+ * @return BAD_FUNC_ARG when key or out is NULL or public key not available.
+ * @return NOT_COMPILED_IN when key type is not supported.
+ */
+int wc_KyberKey_EncodePublicKey(KyberKey* key, unsigned char* out, word32 len)
+{
+ int ret = 0;
+ unsigned int k = 0;
+ unsigned int pubLen = 0;
+ unsigned char* p = out;
+
+ if ((key == NULL) || (out == NULL)) {
+ ret = BAD_FUNC_ARG;
+ }
+ if ((ret == 0) &&
+ ((key->flags & KYBER_FLAG_PUB_SET) != KYBER_FLAG_PUB_SET)) {
+ ret = BAD_FUNC_ARG;
+ }
+
+ if (ret == 0) {
+ switch (key->type) {
+ #ifdef WOLFSSL_KYBER512
+ case KYBER512:
+ k = KYBER512_K;
+ pubLen = KYBER512_PUBLIC_KEY_SIZE;
+ break;
+ #endif
+ #ifdef WOLFSSL_KYBER768
+ case KYBER768:
+ k = KYBER768_K;
+ pubLen = KYBER768_PUBLIC_KEY_SIZE;
+ break;
+ #endif
+ #ifdef WOLFSSL_KYBER1024
+ case KYBER1024:
+ k = KYBER1024_K;
+ pubLen = KYBER1024_PUBLIC_KEY_SIZE;
+ break;
+ #endif
+ default:
+ /* No other values supported. */
+ ret = NOT_COMPILED_IN;
+ break;
+ }
+ }
+ /* Check buffer is big enough for encoding. */
+ if ((ret == 0) && (len != pubLen)) {
+ ret = BUFFER_E;
+ }
+
+ if (ret == 0) {
+ int i;
+
+ /* Encode public key polynomial by polynomial. */
+ kyber_to_bytes(p, key->pub, k);
+ p += k * KYBER_POLY_SIZE;
+
+ /* Append public seed. */
+ for (i = 0; i < KYBER_SYM_SZ; i++) {
+ p[i] = key->pubSeed[i];
+ }
+
+ /* Make sure public hash is set. */
+ if ((key->flags & KYBER_FLAG_H_SET) == 0) {
+ ret = KYBER_HASH_H(out, len, key->h);
+ }
+ }
+ if (ret == 0) {
+ /* Public hash is set. */
+ key->flags |= KYBER_FLAG_H_SET;
+ }
+
+ return ret;
+}
+
+#endif /* WOLFSSL_WC_KYBER */