diff options
Diffstat (limited to '')
-rw-r--r-- | extra/wolfssl/wolfssl/wolfcrypt/src/wc_kyber.c | 1247 |
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 */ |