/* * Copyright (C) 2024 - 2026, Stephan Mueller * * License: see LICENSE file in root directory * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ /* * This code is derived in parts from the code distribution provided with * https://github.com/PQClean/PQClean/ * * The code is referenced as Public Domain */ #ifndef LC_HQC_192_H #define LC_HQC_192_H #include "ext_headers.h" #include "lc_rng.h" #ifdef __cplusplus extern "C" { #endif /// \cond DO_NOT_DOCUMENT /******************************************************************************* * HQC Parameters ******************************************************************************/ /* #define PARAM_N Define the parameter n of the scheme #define PARAM_N1 Define the parameter n1 of the scheme (length of Reed-Solomon code) #define PARAM_N2 Define the parameter n2 of the scheme (length of Duplicated Reed-Muller code) #define PARAM_N1N2 Define the length in bits of the Concatenated code #define PARAM_OMEGA Define the parameter omega of the scheme #define PARAM_OMEGA_E Define the parameter omega_e of the scheme #define PARAM_OMEGA_R Define the parameter omega_r of the scheme #define SECRET_KEY_BYTES Define the size of the secret key in bytes #define PUBLIC_KEY_BYTES Define the size of the public key in bytes #define SHARED_SECRET_BYTES Define the size of the shared secret in bytes #define CIPHERTEXT_BYTES Define the size of the ciphertext in bytes #define VEC_N_SIZE_BYTES Define the size of the array used to store a PARAM_N sized vector in bytes #define VEC_K_SIZE_BYTES Define the size of the array used to store a PARAM_K sized vector in bytes #define VEC_N1_SIZE_BYTES Define the size of the array used to store a PARAM_N1 sized vector in bytes #define VEC_N1N2_SIZE_BYTES Define the size of the array used to store a PARAM_N1N2 sized vector in bytes #define VEC_N_SIZE_64 Define the size of the array used to store a PARAM_N sized vector in 64 bits #define VEC_K_SIZE_64 Define the size of the array used to store a PARAM_K sized vector in 64 bits #define VEC_N1_SIZE_64 Define the size of the array used to store a PARAM_N1 sized vector in 64 bits #define VEC_N1N2_SIZE_64 Define the size of the array used to store a PARAM_N1N2 sized vector in 64 bits #define PARAM_DELTA Define the parameter delta of the scheme (correcting capacity of the Reed-Solomon code) #define PARAM_M Define a positive integer #define PARAM_GF_POLY Generator polynomial of galois field GF(2^PARAM_M), represented in hexadecimial form #define PARAM_GF_POLY_WT Hamming weight of PARAM_GF_POLY #define PARAM_GF_POLY_M2 Distance between the primitive polynomial first two set bits #define PARAM_GF_MUL_ORDER Define the size of the multiplicative group of GF(2^PARAM_M), i.e 2^PARAM_M -1 #define PARAM_K Define the size of the information bits of the Reed-Solomon code #define PARAM_G Define the size of the generator polynomial of Reed-Solomon code #define PARAM_FFT The additive FFT takes a 2^PARAM_FFT polynomial as input We use the FFT to compute the roots of sigma, whose degree if PARAM_DELTA=24 The smallest power of 2 greater than 24+1 is 32=2^5 #define RS_POLY_COEFS Coefficients of the generator polynomial of the Reed-Solomon code #define RED_MASK A mask for the higher bits of a vector #define SHAKE256_512_BYTES Define the size of SHAKE-256 output in bytes #define SEED_BYTES Define the size of the seed in bytes #define SALT_SIZE_BYTES Define the size of a salt in bytes */ /* Divide a by b and ceil the result */ #define LC_HQC_CEIL_DIVIDE(a, b) (((a) + (b) - 1) / (b)) /* Create a mask */ #define LC_HQC_BITMASK(a, size) ((1UL << (a % size)) - 1) #define LC_HQC_PRNG_DOMAIN 1 #define LC_HQC_SEEDEXPANDER_DOMAIN 2 #define LC_HQC_G_FCT_DOMAIN 3 #define LC_HQC_K_FCT_DOMAIN 4 #define LC_HQC_TYPE 192 #if (LC_HQC_TYPE == 128) #define LC_HQC_CRYPTO_SECRETKEYBYTES 2305 #define LC_HQC_CRYPTO_PUBLICKEYBYTES 2249 #define LC_HQC_CRYPTO_BYTES 64 #define LC_HQC_CRYPTO_CIPHERTEXTBYTES 4433 #define LC_HQC_PARAM_N 17669 #define LC_HQC_PARAM_N1 46 #define LC_HQC_PARAM_N2 384 #define LC_HQC_PARAM_N1N2 17664 #define LC_HQC_PARAM_OMEGA 66 #define LC_HQC_PARAM_OMEGA_E 75 #define LC_HQC_PARAM_OMEGA_R 75 #define LC_HQC_VEC_N_SIZE_BYTES LC_HQC_CEIL_DIVIDE(LC_HQC_PARAM_N, 8) #define LC_HQC_VEC_K_SIZE_BYTES LC_HQC_PARAM_K #define LC_HQC_VEC_N1_SIZE_BYTES LC_HQC_PARAM_N1 #define LC_HQC_VEC_N1N2_SIZE_BYTES LC_HQC_CEIL_DIVIDE(LC_HQC_PARAM_N1N2, 8) #define LC_HQC_VEC_N_SIZE_64 LC_HQC_CEIL_DIVIDE(LC_HQC_PARAM_N, 64) #define LC_HQC_VEC_K_SIZE_64 LC_HQC_CEIL_DIVIDE(LC_HQC_PARAM_K, 8) #define LC_HQC_VEC_N1_SIZE_64 LC_HQC_CEIL_DIVIDE(LC_HQC_PARAM_N1, 8) #define LC_HQC_VEC_N1N2_SIZE_64 LC_HQC_CEIL_DIVIDE(LC_HQC_PARAM_N1N2, 64) /* AVX2 */ #define LC_HQC_PARAM_N_MULT 18048 #define LC_HQC_VEC_N_256_SIZE_64 \ (LC_HQC_CEIL_DIVIDE(LC_HQC_PARAM_N_MULT, 256) << 2) #define LC_HQC_VEC_N1N2_256_SIZE_64 \ (LC_HQC_CEIL_DIVIDE(LC_HQC_PARAM_N1N2, 256) << 2) #define LC_HQC_PARAM_DELTA 15 #define LC_HQC_PARAM_M 8 #define LC_HQC_PARAM_GF_POLY 0x11D #define LC_HQC_PARAM_GF_POLY_WT 5 #define LC_HQC_PARAM_GF_POLY_M2 4 #define LC_HQC_PARAM_GF_MUL_ORDER 255 #define LC_HQC_PARAM_K 16 #define LC_HQC_PARAM_G 31 #define LC_HQC_PARAM_FFT 4 #define LC_HQC_RS_POLY_COEFS \ 89, 69, 153, 116, 176, 117, 111, 75, 73, 233, 242, 233, 65, 210, 21, \ 139, 103, 173, 67, 118, 105, 210, 174, 110, 74, 69, 228, 82, \ 255, 181, 1 #define LC_HQC_SYND_SIZE_256 \ (LC_HQC_CEIL_DIVIDE(2*LC_HQC_PARAM_DELTA, 16)) #define LC_HQC_RED_MASK 0x1f #define LC_HQC_SHAKE256_512_BYTES 64 #define LC_HQC_SEED_BYTES 40 #define LC_HQC_SALT_SIZE_BYTES 16 #elif (LC_HQC_TYPE == 192) #define LC_HQC_CRYPTO_SECRETKEYBYTES 4586 #define LC_HQC_CRYPTO_PUBLICKEYBYTES 4522 #define LC_HQC_CRYPTO_BYTES 64 #define LC_HQC_CRYPTO_CIPHERTEXTBYTES 8978 #define LC_HQC_PARAM_N 35851 #define LC_HQC_PARAM_N1 56 #define LC_HQC_PARAM_N2 640 #define LC_HQC_PARAM_N1N2 35840 #define LC_HQC_PARAM_OMEGA 100 #define LC_HQC_PARAM_OMEGA_E 114 #define LC_HQC_PARAM_OMEGA_R 114 #define LC_HQC_VEC_N_SIZE_BYTES LC_HQC_CEIL_DIVIDE(LC_HQC_PARAM_N, 8) #define LC_HQC_VEC_K_SIZE_BYTES LC_HQC_PARAM_K #define LC_HQC_VEC_N1_SIZE_BYTES LC_HQC_PARAM_N1 #define LC_HQC_VEC_N1N2_SIZE_BYTES LC_HQC_CEIL_DIVIDE(LC_HQC_PARAM_N1N2, 8) #define LC_HQC_VEC_N_SIZE_64 LC_HQC_CEIL_DIVIDE(LC_HQC_PARAM_N, 64) #define LC_HQC_VEC_K_SIZE_64 LC_HQC_LC_HQC_CEIL_DIVIDE(LC_HQC_PARAM_K, 8) #define LC_HQC_VEC_N1_SIZE_64 LC_HQC_CEIL_DIVIDE(LC_HQC_PARAM_N1, 8) #define LC_HQC_VEC_N1N2_SIZE_64 LC_HQC_CEIL_DIVIDE(LC_HQC_PARAM_N1N2, 64) /* AVX2 */ #define LC_HQC_PARAM_N_MULT 36480 #define LC_HQC_VEC_N_256_SIZE_64 \ (LC_HQC_CEIL_DIVIDE(LC_HQC_PARAM_N_MULT, 256) << 2) #define LC_HQC_VEC_N1N2_256_SIZE_64 \ (LC_HQC_CEIL_DIVIDE(LC_HQC_PARAM_N1N2, 256) << 2) #define LC_HQC_PARAM_DELTA 16 #define LC_HQC_PARAM_M 8 #define LC_HQC_PARAM_GF_POLY 0x11D #define LC_HQC_PARAM_GF_POLY_WT 5 #define LC_HQC_PARAM_GF_POLY_M2 4 #define LC_HQC_PARAM_GF_MUL_ORDER 255 #define LC_HQC_PARAM_K 24 #define LC_HQC_PARAM_G 33 #define LC_HQC_PARAM_FFT 5 #define LC_HQC_RS_POLY_COEFS \ 45, 216, 239, 24, 253, 104, 27, 40, 107, 50, 163, 210, 227, 134, 224, \ 158, 119, 13, 158, 1, 238, 164, 82, 43, 15, 232, 246, 142, 50, \ 189, 29, 232, 1 #define LC_HQC_SYND_SIZE_256 \ (LC_HQC_CEIL_DIVIDE(2*LC_HQC_PARAM_DELTA, 16)) #define LC_HQC_RED_MASK 0x7ff #define LC_HQC_SHAKE256_512_BYTES 64 #define LC_HQC_SEED_BYTES 40 #define LC_HQC_SALT_SIZE_BYTES 16 #elif (LC_HQC_TYPE == 256) #define LC_HQC_CRYPTO_SECRETKEYBYTES 7317 #define LC_HQC_CRYPTO_PUBLICKEYBYTES 7245 #define LC_HQC_CRYPTO_BYTES 64 #define LC_HQC_CRYPTO_CIPHERTEXTBYTES 14421 #define LC_HQC_PARAM_N 57637 #define LC_HQC_PARAM_N1 90 #define LC_HQC_PARAM_N2 640 #define LC_HQC_PARAM_N1N2 57600 #define LC_HQC_PARAM_OMEGA 131 #define LC_HQC_PARAM_OMEGA_E 149 #define LC_HQC_PARAM_OMEGA_R 149 #define LC_HQC_VEC_N_SIZE_BYTES LC_HQC_CEIL_DIVIDE(LC_HQC_PARAM_N, 8) #define LC_HQC_VEC_K_SIZE_BYTES LC_HQC_PARAM_K #define LC_HQC_VEC_N1_SIZE_BYTES LC_HQC_PARAM_N1 #define LC_HQC_VEC_N1N2_SIZE_BYTES LC_HQC_CEIL_DIVIDE(LC_HQC_PARAM_N1N2, 8) #define LC_HQC_VEC_N_SIZE_64 LC_HQC_CEIL_DIVIDE(LC_HQC_PARAM_N, 64) #define LC_HQC_VEC_K_SIZE_64 LC_HQC_CEIL_DIVIDE(LC_HQC_PARAM_K, 8) #define LC_HQC_VEC_N1_SIZE_64 LC_HQC_CEIL_DIVIDE(LC_HQC_PARAM_N1, 8) #define LC_HQC_VEC_N1N2_SIZE_64 LC_HQC_CEIL_DIVIDE(LC_HQC_PARAM_N1N2, 64) /* AVX2 */ #define LC_HQC_PARAM_N_MULT 59904 #define LC_HQC_VEC_N_256_SIZE_64 \ (LC_HQC_CEIL_DIVIDE(LC_HQC_PARAM_N_MULT, 256) << 2) #define LC_HQC_VEC_N1N2_256_SIZE_64 \ (LC_HQC_CEIL_DIVIDE(LC_HQC_PARAM_N1N2, 256) << 2) #define LC_HQC_PARAM_DELTA 29 #define LC_HQC_PARAM_M 8 #define LC_HQC_PARAM_GF_POLY 0x11D #define LC_HQC_PARAM_GF_POLY_WT 5 #define LC_HQC_PARAM_GF_POLY_M2 4 #define LC_HQC_PARAM_GF_MUL_ORDER 255 #define LC_HQC_PARAM_K 32 #define LC_HQC_PARAM_G 59 #define LC_HQC_PARAM_FFT 5 #define LC_HQC_RS_POLY_COEFS \ 49, 167, 49, 39, 200, 121, 124, 91, 240, 63, 148, 71, 150, 123, 87, \ 101, 32, 215, 159, 71, 201, 115, 97, 210, 186, 183, 141, 217, \ 123, 12, 31, 243, 180, 219, 152, 239, 99, 141, 4, 246, 191, \ 144, 8, 232, 47, 27, 141, 178, 130, 64, 124, 47, 39, 188, 216, \ 48, 199, 187, 1 #define LC_HQC_SYND_SIZE_256 \ (LC_HQC_CEIL_DIVIDE(2*LC_HQC_PARAM_DELTA, 16)) #define LC_HQC_RED_MASK 0x1fffffffff #define LC_HQC_SHAKE256_512_BYTES 64 #define LC_HQC_SEED_BYTES 40 #define LC_HQC_SALT_SIZE_BYTES 16 #else #error "Unknown HQC type" #endif #define LC_HQC_SECRET_KEY_BYTES LC_HQC_CRYPTO_SECRETKEYBYTES #define LC_HQC_PUBLIC_KEY_BYTES LC_HQC_CRYPTO_PUBLICKEYBYTES #define LC_HQC_SHARED_SECRET_BYTES LC_HQC_CRYPTO_BYTES #define LC_HQC_CIPHERTEXT_BYTES LC_HQC_CRYPTO_CIPHERTEXTBYTES #define LC_HQC_ALIGN_BYTES (sizeof(uint64_t)) /// \endcond /** * @brief Bike public key */ struct lc_hqc_192_pk { uint8_t pk[LC_HQC_PUBLIC_KEY_BYTES]; }; /** * @brief Bike secret key */ struct lc_hqc_192_sk { uint8_t sk[LC_HQC_SECRET_KEY_BYTES]; }; /** * @brief Bike ciphertext */ struct lc_hqc_192_ct { uint8_t ct[LC_HQC_CIPHERTEXT_BYTES]; }; /** * @brief Bike shared secret */ struct lc_hqc_192_ss { uint8_t ss[LC_HQC_SHARED_SECRET_BYTES]; }; /** * @brief Generates public and private key for IND-CCA2-secure HQC key * encapsulation mechanism * * @param [out] pk pointer to already allocated output public key * @param [out] sk pointer to already allocated output private key * @param [in] rng_ctx pointer to seeded random number generator context * * @return 0 (success) or < 0 on error */ int lc_hqc_192_keypair(struct lc_hqc_192_pk *pk, struct lc_hqc_192_sk *sk, struct lc_rng_ctx *rng_ctx); /** * @brief Generates public and private key for IND-CCA2-secure HQC key * encapsulation mechanism from a given seed. * * The idea of the function is the allowance of FIPS 203 to maintain the seed * used to generate a key pair in lieu of maintaining a private key or the * key pair (which used much more memory). The seed must be treated equally * sensitive as a private key. * * The seed is generated by simply obtaining 64 bytes from a properly seeded * DRNG, i.e. the same way as a symmetric key would be generated. * * @param [out] pk pointer to allocated output public key * @param [out] sk pointer to allocated output private key * @param [in] seed buffer with the seed data which must be exactly 64 bytes * in size * @param [in] seedlen length of the seed buffer * * @return 0 (success) or < 0 on error */ int lc_hqc_192_keypair_from_seed(struct lc_hqc_192_pk *pk, struct lc_hqc_192_sk *sk, const uint8_t *seed, size_t seedlen); /** * @brief HQC Key encapsulation * * Generates cipher text and shared secret for given public key. * * @param [out] ct pointer to output cipher text to used for decapsulation * @param [out] ss pointer to output shared secret that will be also produced * during decapsulation * @param [in] pk pointer to input public key * * Returns 0 (success) or < 0 on error */ int lc_hqc_192_enc(struct lc_hqc_192_ct *ct, struct lc_hqc_192_ss *ss, const struct lc_hqc_192_pk *pk); /** * @brief lc_hqc_192_enc_kdf - Key encapsulation with KDF applied to shared * secret * * Generates cipher text and shared secret for given public key. The shared * secret is derived from the HQC SS using the KDF identically to the one used * for Kyber. * * SS <- KMAC256(K = HQC-SS, X = HQC-CT, L = requested SS length, * S = "HQC KEM SS") * * @param [out] ct pointer to output cipher text to used for decapsulation * @param [out] ss pointer to output shared secret that will be also produced * during decapsulation * @param [in] ss_len length of shared secret to be generated * @param [in] pk pointer to input public key * * Returns 0 (success) or < 0 on error */ int lc_hqc_192_enc_kdf(struct lc_hqc_192_ct *ct, uint8_t *ss, size_t ss_len, const struct lc_hqc_192_pk *pk); /** * @brief HQC Key decapsulation * * Generates shared secret for given cipher text and private key * * @param [out] ss pointer to output shared secret that is the same as produced * during encapsulation * @param [in] ct pointer to input cipher text generated during encapsulation * @param [in] sk pointer to input private key * * @return 0 * * On failure, ss will contain a pseudo-random value. */ int lc_hqc_192_dec(struct lc_hqc_192_ss *ss, const struct lc_hqc_192_ct *ct, const struct lc_hqc_192_sk *sk); /** * @brief lc_hqc_dec_kdf - Key decapsulation with KDF applied to shared secret * * Generates cipher text and shared secret for given private key. The shared * secret is derived from the HQC SS using the KDF identically to the one used * for Kyber. * * SS <- KMAC256(K = HQC-SS, X = HQC-CT, L = requested SS length, * S = "HQC KEM SS") * * @param [out] ss pointer to output shared secret that is the same as produced * during encapsulation * @param [in] ss_len length of shared secret to be generated * @param [in] ct pointer to input cipher text generated during encapsulation * @param [in] sk pointer to input private key * * @return 0 * * On failure, ss will contain a pseudo-random value. */ int lc_hqc_192_dec_kdf(uint8_t *ss, size_t ss_len, const struct lc_hqc_192_ct *ct, const struct lc_hqc_192_sk *sk); /* * To allow including the different lc_hqc_*.h files, these macros need to be * undefined. Only during compilation of leancrypto, these macros remain defined * as this header file is not included multiple times. */ #ifndef LC_HQC_INTERNAL #undef LC_HQC_CEIL_DIVIDE #undef LC_HQC_BITMASK #undef LC_HQC_PRNG_DOMAIN #undef LC_HQC_SEEDEXPANDER_DOMAIN #undef LC_HQC_G_FCT_DOMAIN #undef LC_HQC_K_FCT_DOMAIN #undef LC_HQC_TYPE #undef LC_HQC_SECRET_KEY_BYTES #undef LC_HQC_PUBLIC_KEY_BYTES #undef LC_HQC_SHARED_SECRET_BYTES #undef LC_HQC_CIPHERTEXT_BYTES #undef LC_HQC_CRYPTO_SECRETKEYBYTES #undef LC_HQC_CRYPTO_PUBLICKEYBYTES #undef LC_HQC_CRYPTO_BYTES #undef LC_HQC_CRYPTO_CIPHERTEXTBYTES #undef LC_HQC_PARAM_N #undef LC_HQC_PARAM_N1 #undef LC_HQC_PARAM_N2 #undef LC_HQC_PARAM_N1N2 #undef LC_HQC_PARAM_OMEGA #undef LC_HQC_PARAM_OMEGA_E #undef LC_HQC_PARAM_OMEGA_R #undef LC_HQC_VEC_N_SIZE_BYTES #undef LC_HQC_VEC_K_SIZE_BYTES #undef LC_HQC_VEC_N1_SIZE_BYTES #undef LC_HQC_VEC_N1N2_SIZE_BYTES #undef LC_HQC_VEC_N_SIZE_64 #undef LC_HQC_VEC_K_SIZE_64 #undef LC_HQC_VEC_N1_SIZE_64 #undef LC_HQC_VEC_N1N2_SIZE_64 #undef LC_HQC_PARAM_DELTA #undef LC_HQC_PARAM_M #undef LC_HQC_PARAM_GF_POLY #undef LC_HQC_PARAM_GF_POLY #undef LC_HQC_PARAM_GF_POLY #undef LC_HQC_PARAM_GF_MUL_ORDER #undef LC_HQC_PARAM_K #undef LC_HQC_PARAM_G #undef LC_HQC_PARAM_FFT #undef LC_HQC_RS_POLY_COEFS #undef LC_HQC_RED_MASK #undef LC_HQC_SHAKE256_512_BYTES #undef LC_HQC_SEED_BYTES #undef LC_HQC_SALT_SIZE_BYTES #undef LC_HQC_PARAM_N_MULT #undef LC_HQC_VEC_N_256_SIZE_64 #undef LC_HQC_VEC_N1N2_256_SIZE_64 #undef LC_HQC_SYND_SIZE_256 #endif /* LC_HQC_INTERNAL */ #ifdef __cplusplus } #endif #endif /* LC_HQC_192_H */