diff --git a/src/kem/hqc/CMakeLists.txt b/src/kem/hqc/CMakeLists.txt index 29877b22e4..81adfd38ca 100644 --- a/src/kem/hqc/CMakeLists.txt +++ b/src/kem/hqc/CMakeLists.txt @@ -1,41 +1,87 @@ # SPDX-License-Identifier: MIT -# This file was generated by -# scripts/copy_from_upstream/copy_from_upstream.py - set(_HQC_OBJS "") +# ------------------------------- +# Include directories +# ------------------------------- +set(HQC_INCLUDE_DIRS + oqs_adapter + hqc_ref/src + hqc_ref/src/common + hqc_ref/src/common/hqc-1 + hqc_ref/src/common/hqc-3 + hqc_ref/src/common/hqc-5 + hqc_ref/src/ref + hqc_ref/src/ref/hqc-1 + hqc_ref/src/ref/hqc-3 + hqc_ref/src/ref/hqc-5 + hqc_ref/lib/fips202 # FIPS202 headers +) + +# ------------------------------- +# HQC ref. FIPS202 library +# ------------------------------- +add_library(hqc_ref_fips202_obj OBJECT hqc_ref/lib/fips202/fips202.c) +target_include_directories(hqc_ref_fips202_obj PRIVATE hqc_ref/lib/fips202) + +# ------------------------------- +# Common sources (exclude kem.c) +# ------------------------------- +file(GLOB COMMON_SOURCES kem_hqc_128.c kem_hqc_192.c kem_hqc_256.c + hqc_ref/src/common/*.c) +list(REMOVE_ITEM COMMON_SOURCES hqc_ref/src/common/kem.c) + +# ------------------------------- +# Common object library +# ------------------------------- +add_library(hqc_ref_common_obj OBJECT ${COMMON_SOURCES}) +target_include_directories(hqc_ref_common_obj PRIVATE ${HQC_INCLUDE_DIRS}) +target_link_libraries(hqc_ref_common_obj PRIVATE hqc_ref_fips202_obj) + +# ------------------------------- +# Function to build kem.c per HQC level +# ------------------------------- +function(add_kem_level level) + add_library(hqc_ref_kem_${level} OBJECT hqc_ref/src/common/kem.c) + target_include_directories( + hqc_ref_kem_${level} PRIVATE hqc_ref/src/common/hqc-${level} + ${HQC_INCLUDE_DIRS}) + target_compile_definitions(hqc_ref_kem_${level} + PRIVATE KEM_PREFIX=REF_HQC_${level}) + target_link_libraries(hqc_ref_kem_${level} PRIVATE hqc_ref_common_obj + hqc_ref_fips202_obj) + target_compile_options(hqc_ref_kem_${level} PRIVATE -O0) +endfunction() + +# ------------------------------- +# Ref object library +# ------------------------------- +file(GLOB REF_SOURCES hqc_ref/src/ref/*.c) + +add_library(hqc_ref_ref_obj OBJECT ${REF_SOURCES}) +target_include_directories(hqc_ref_ref_obj PRIVATE ${HQC_INCLUDE_DIRS}) +target_link_libraries(hqc_ref_ref_obj PRIVATE hqc_ref_common_obj + hqc_ref_fips202_obj) + +list(APPEND _HQC_OBJS $ + $ $) + if(OQS_ENABLE_KEM_hqc_128) - add_library(hqc_128_clean OBJECT kem_hqc_128.c pqclean_hqc-128_clean/code.c pqclean_hqc-128_clean/fft.c pqclean_hqc-128_clean/gf.c pqclean_hqc-128_clean/gf2x.c pqclean_hqc-128_clean/hqc.c pqclean_hqc-128_clean/kem.c pqclean_hqc-128_clean/parsing.c pqclean_hqc-128_clean/reed_muller.c pqclean_hqc-128_clean/reed_solomon.c pqclean_hqc-128_clean/shake_ds.c pqclean_hqc-128_clean/shake_prng.c pqclean_hqc-128_clean/vector.c) - target_include_directories(hqc_128_clean PRIVATE ${CMAKE_CURRENT_LIST_DIR}/pqclean_hqc-128_clean) - target_include_directories(hqc_128_clean PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims) - target_compile_options(hqc_128_clean PRIVATE -O0) - if (CMAKE_SYSTEM_NAME STREQUAL "Darwin") - target_compile_definitions(hqc_128_clean PRIVATE old_gas_syntax) - endif() - set(_HQC_OBJS ${_HQC_OBJS} $) + add_kem_level("1") + list(APPEND _HQC_OBJS $) endif() if(OQS_ENABLE_KEM_hqc_192) - add_library(hqc_192_clean OBJECT kem_hqc_192.c pqclean_hqc-192_clean/code.c pqclean_hqc-192_clean/fft.c pqclean_hqc-192_clean/gf.c pqclean_hqc-192_clean/gf2x.c pqclean_hqc-192_clean/hqc.c pqclean_hqc-192_clean/kem.c pqclean_hqc-192_clean/parsing.c pqclean_hqc-192_clean/reed_muller.c pqclean_hqc-192_clean/reed_solomon.c pqclean_hqc-192_clean/shake_ds.c pqclean_hqc-192_clean/shake_prng.c pqclean_hqc-192_clean/vector.c) - target_include_directories(hqc_192_clean PRIVATE ${CMAKE_CURRENT_LIST_DIR}/pqclean_hqc-192_clean) - target_include_directories(hqc_192_clean PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims) - target_compile_options(hqc_192_clean PRIVATE -O0) - if (CMAKE_SYSTEM_NAME STREQUAL "Darwin") - target_compile_definitions(hqc_192_clean PRIVATE old_gas_syntax) - endif() - set(_HQC_OBJS ${_HQC_OBJS} $) + add_kem_level("3") + list(APPEND _HQC_OBJS $) endif() if(OQS_ENABLE_KEM_hqc_256) - add_library(hqc_256_clean OBJECT kem_hqc_256.c pqclean_hqc-256_clean/code.c pqclean_hqc-256_clean/fft.c pqclean_hqc-256_clean/gf.c pqclean_hqc-256_clean/gf2x.c pqclean_hqc-256_clean/hqc.c pqclean_hqc-256_clean/kem.c pqclean_hqc-256_clean/parsing.c pqclean_hqc-256_clean/reed_muller.c pqclean_hqc-256_clean/reed_solomon.c pqclean_hqc-256_clean/shake_ds.c pqclean_hqc-256_clean/shake_prng.c pqclean_hqc-256_clean/vector.c) - target_include_directories(hqc_256_clean PRIVATE ${CMAKE_CURRENT_LIST_DIR}/pqclean_hqc-256_clean) - target_include_directories(hqc_256_clean PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims) - target_compile_options(hqc_256_clean PRIVATE -O0) - if (CMAKE_SYSTEM_NAME STREQUAL "Darwin") - target_compile_definitions(hqc_256_clean PRIVATE old_gas_syntax) - endif() - set(_HQC_OBJS ${_HQC_OBJS} $) + add_kem_level("5") + list(APPEND _HQC_OBJS $) endif() -set(HQC_OBJS ${_HQC_OBJS} PARENT_SCOPE) +set(HQC_OBJS + ${_HQC_OBJS} + PARENT_SCOPE) diff --git a/src/kem/hqc/hqc_ref/lib/CMakeLists.txt b/src/kem/hqc/hqc_ref/lib/CMakeLists.txt new file mode 100644 index 0000000000..1ebebbf46e --- /dev/null +++ b/src/kem/hqc/hqc_ref/lib/CMakeLists.txt @@ -0,0 +1,12 @@ +# lib/CMakeLists.txt +# Build all third-party libraries in lib/ + +# FIPS202 implementation +file(GLOB FIPS202_SRCS + "${CMAKE_CURRENT_SOURCE_DIR}/fips202/fips202.c" +) +add_library(fips202 STATIC ${FIPS202_SRCS}) + +target_include_directories(fips202 PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/fips202 +) diff --git a/src/kem/hqc/hqc_ref/lib/fips202/fips202.c b/src/kem/hqc/hqc_ref/lib/fips202/fips202.c new file mode 100644 index 0000000000..be16d98721 --- /dev/null +++ b/src/kem/hqc/hqc_ref/lib/fips202/fips202.c @@ -0,0 +1,792 @@ +// Implementation from PQClean project + +/* Based on the public domain implementation in + * crypto_hash/keccakc512/simple/ from http://bench.cr.yp.to/supercop.html + * by Ronny Van Keer + * and the public domain "TweetFips202" implementation + * from https://twitter.com/tweetfips202 + * by Gilles Van Assche, Daniel J. Bernstein, and Peter Schwabe */ + +#include +#include + +#include "fips202.h" + +#define NROUNDS 24 +#define ROL(a, offset) (((a) << (offset)) ^ ((a) >> (64 - (offset)))) + +/************************************************* + * Name: load64 + * + * Description: Load 8 bytes into uint64_t in little-endian order + * + * Arguments: - const uint8_t *x: pointer to input byte array + * + * Returns the loaded 64-bit unsigned integer + **************************************************/ +static uint64_t load64(const uint8_t *x) { + uint64_t r = 0; + for (size_t i = 0; i < 8; ++i) { + r |= (uint64_t)x[i] << 8 * i; + } + + return r; +} + +/************************************************* + * Name: store64 + * + * Description: Store a 64-bit integer to a byte array in little-endian order + * + * Arguments: - uint8_t *x: pointer to the output byte array + * - uint64_t u: input 64-bit unsigned integer + **************************************************/ +static void store64(uint8_t *x, uint64_t u) { + for (size_t i = 0; i < 8; ++i) { + x[i] = (uint8_t)(u >> 8 * i); + } +} + +/* Keccak round constants */ +static const uint64_t KeccakF_RoundConstants[NROUNDS] = { + 0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL, 0x8000000080008000ULL, 0x000000000000808bULL, + 0x0000000080000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008aULL, 0x0000000000000088ULL, + 0x0000000080008009ULL, 0x000000008000000aULL, 0x000000008000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, + 0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL, 0x000000000000800aULL, 0x800000008000000aULL, + 0x8000000080008081ULL, 0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL}; + +/************************************************* + * Name: KeccakF1600_StatePermute + * + * Description: The Keccak F1600 Permutation + * + * Arguments: - uint64_t *state: pointer to input/output Keccak state + **************************************************/ +static void KeccakF1600_StatePermute(uint64_t *state) { + int round; + + uint64_t Aba, Abe, Abi, Abo, Abu; + uint64_t Aga, Age, Agi, Ago, Agu; + uint64_t Aka, Ake, Aki, Ako, Aku; + uint64_t Ama, Ame, Ami, Amo, Amu; + uint64_t Asa, Ase, Asi, Aso, Asu; + uint64_t BCa, BCe, BCi, BCo, BCu; + uint64_t Da, De, Di, Do, Du; + uint64_t Eba, Ebe, Ebi, Ebo, Ebu; + uint64_t Ega, Ege, Egi, Ego, Egu; + uint64_t Eka, Eke, Eki, Eko, Eku; + uint64_t Ema, Eme, Emi, Emo, Emu; + uint64_t Esa, Ese, Esi, Eso, Esu; + + // copyFromState(A, state) + Aba = state[0]; + Abe = state[1]; + Abi = state[2]; + Abo = state[3]; + Abu = state[4]; + Aga = state[5]; + Age = state[6]; + Agi = state[7]; + Ago = state[8]; + Agu = state[9]; + Aka = state[10]; + Ake = state[11]; + Aki = state[12]; + Ako = state[13]; + Aku = state[14]; + Ama = state[15]; + Ame = state[16]; + Ami = state[17]; + Amo = state[18]; + Amu = state[19]; + Asa = state[20]; + Ase = state[21]; + Asi = state[22]; + Aso = state[23]; + Asu = state[24]; + + for (round = 0; round < NROUNDS; round += 2) { + // prepareTheta + BCa = Aba ^ Aga ^ Aka ^ Ama ^ Asa; + BCe = Abe ^ Age ^ Ake ^ Ame ^ Ase; + BCi = Abi ^ Agi ^ Aki ^ Ami ^ Asi; + BCo = Abo ^ Ago ^ Ako ^ Amo ^ Aso; + BCu = Abu ^ Agu ^ Aku ^ Amu ^ Asu; + + // thetaRhoPiChiIotaPrepareTheta(round , A, E) + Da = BCu ^ ROL(BCe, 1); + De = BCa ^ ROL(BCi, 1); + Di = BCe ^ ROL(BCo, 1); + Do = BCi ^ ROL(BCu, 1); + Du = BCo ^ ROL(BCa, 1); + + Aba ^= Da; + BCa = Aba; + Age ^= De; + BCe = ROL(Age, 44); + Aki ^= Di; + BCi = ROL(Aki, 43); + Amo ^= Do; + BCo = ROL(Amo, 21); + Asu ^= Du; + BCu = ROL(Asu, 14); + Eba = BCa ^ ((~BCe) & BCi); + Eba ^= KeccakF_RoundConstants[round]; + Ebe = BCe ^ ((~BCi) & BCo); + Ebi = BCi ^ ((~BCo) & BCu); + Ebo = BCo ^ ((~BCu) & BCa); + Ebu = BCu ^ ((~BCa) & BCe); + + Abo ^= Do; + BCa = ROL(Abo, 28); + Agu ^= Du; + BCe = ROL(Agu, 20); + Aka ^= Da; + BCi = ROL(Aka, 3); + Ame ^= De; + BCo = ROL(Ame, 45); + Asi ^= Di; + BCu = ROL(Asi, 61); + Ega = BCa ^ ((~BCe) & BCi); + Ege = BCe ^ ((~BCi) & BCo); + Egi = BCi ^ ((~BCo) & BCu); + Ego = BCo ^ ((~BCu) & BCa); + Egu = BCu ^ ((~BCa) & BCe); + + Abe ^= De; + BCa = ROL(Abe, 1); + Agi ^= Di; + BCe = ROL(Agi, 6); + Ako ^= Do; + BCi = ROL(Ako, 25); + Amu ^= Du; + BCo = ROL(Amu, 8); + Asa ^= Da; + BCu = ROL(Asa, 18); + Eka = BCa ^ ((~BCe) & BCi); + Eke = BCe ^ ((~BCi) & BCo); + Eki = BCi ^ ((~BCo) & BCu); + Eko = BCo ^ ((~BCu) & BCa); + Eku = BCu ^ ((~BCa) & BCe); + + Abu ^= Du; + BCa = ROL(Abu, 27); + Aga ^= Da; + BCe = ROL(Aga, 36); + Ake ^= De; + BCi = ROL(Ake, 10); + Ami ^= Di; + BCo = ROL(Ami, 15); + Aso ^= Do; + BCu = ROL(Aso, 56); + Ema = BCa ^ ((~BCe) & BCi); + Eme = BCe ^ ((~BCi) & BCo); + Emi = BCi ^ ((~BCo) & BCu); + Emo = BCo ^ ((~BCu) & BCa); + Emu = BCu ^ ((~BCa) & BCe); + + Abi ^= Di; + BCa = ROL(Abi, 62); + Ago ^= Do; + BCe = ROL(Ago, 55); + Aku ^= Du; + BCi = ROL(Aku, 39); + Ama ^= Da; + BCo = ROL(Ama, 41); + Ase ^= De; + BCu = ROL(Ase, 2); + Esa = BCa ^ ((~BCe) & BCi); + Ese = BCe ^ ((~BCi) & BCo); + Esi = BCi ^ ((~BCo) & BCu); + Eso = BCo ^ ((~BCu) & BCa); + Esu = BCu ^ ((~BCa) & BCe); + + // prepareTheta + BCa = Eba ^ Ega ^ Eka ^ Ema ^ Esa; + BCe = Ebe ^ Ege ^ Eke ^ Eme ^ Ese; + BCi = Ebi ^ Egi ^ Eki ^ Emi ^ Esi; + BCo = Ebo ^ Ego ^ Eko ^ Emo ^ Eso; + BCu = Ebu ^ Egu ^ Eku ^ Emu ^ Esu; + + // thetaRhoPiChiIotaPrepareTheta(round+1, E, A) + Da = BCu ^ ROL(BCe, 1); + De = BCa ^ ROL(BCi, 1); + Di = BCe ^ ROL(BCo, 1); + Do = BCi ^ ROL(BCu, 1); + Du = BCo ^ ROL(BCa, 1); + + Eba ^= Da; + BCa = Eba; + Ege ^= De; + BCe = ROL(Ege, 44); + Eki ^= Di; + BCi = ROL(Eki, 43); + Emo ^= Do; + BCo = ROL(Emo, 21); + Esu ^= Du; + BCu = ROL(Esu, 14); + Aba = BCa ^ ((~BCe) & BCi); + Aba ^= KeccakF_RoundConstants[round + 1]; + Abe = BCe ^ ((~BCi) & BCo); + Abi = BCi ^ ((~BCo) & BCu); + Abo = BCo ^ ((~BCu) & BCa); + Abu = BCu ^ ((~BCa) & BCe); + + Ebo ^= Do; + BCa = ROL(Ebo, 28); + Egu ^= Du; + BCe = ROL(Egu, 20); + Eka ^= Da; + BCi = ROL(Eka, 3); + Eme ^= De; + BCo = ROL(Eme, 45); + Esi ^= Di; + BCu = ROL(Esi, 61); + Aga = BCa ^ ((~BCe) & BCi); + Age = BCe ^ ((~BCi) & BCo); + Agi = BCi ^ ((~BCo) & BCu); + Ago = BCo ^ ((~BCu) & BCa); + Agu = BCu ^ ((~BCa) & BCe); + + Ebe ^= De; + BCa = ROL(Ebe, 1); + Egi ^= Di; + BCe = ROL(Egi, 6); + Eko ^= Do; + BCi = ROL(Eko, 25); + Emu ^= Du; + BCo = ROL(Emu, 8); + Esa ^= Da; + BCu = ROL(Esa, 18); + Aka = BCa ^ ((~BCe) & BCi); + Ake = BCe ^ ((~BCi) & BCo); + Aki = BCi ^ ((~BCo) & BCu); + Ako = BCo ^ ((~BCu) & BCa); + Aku = BCu ^ ((~BCa) & BCe); + + Ebu ^= Du; + BCa = ROL(Ebu, 27); + Ega ^= Da; + BCe = ROL(Ega, 36); + Eke ^= De; + BCi = ROL(Eke, 10); + Emi ^= Di; + BCo = ROL(Emi, 15); + Eso ^= Do; + BCu = ROL(Eso, 56); + Ama = BCa ^ ((~BCe) & BCi); + Ame = BCe ^ ((~BCi) & BCo); + Ami = BCi ^ ((~BCo) & BCu); + Amo = BCo ^ ((~BCu) & BCa); + Amu = BCu ^ ((~BCa) & BCe); + + Ebi ^= Di; + BCa = ROL(Ebi, 62); + Ego ^= Do; + BCe = ROL(Ego, 55); + Eku ^= Du; + BCi = ROL(Eku, 39); + Ema ^= Da; + BCo = ROL(Ema, 41); + Ese ^= De; + BCu = ROL(Ese, 2); + Asa = BCa ^ ((~BCe) & BCi); + Ase = BCe ^ ((~BCi) & BCo); + Asi = BCi ^ ((~BCo) & BCu); + Aso = BCo ^ ((~BCu) & BCa); + Asu = BCu ^ ((~BCa) & BCe); + } + + // copyToState(state, A) + state[0] = Aba; + state[1] = Abe; + state[2] = Abi; + state[3] = Abo; + state[4] = Abu; + state[5] = Aga; + state[6] = Age; + state[7] = Agi; + state[8] = Ago; + state[9] = Agu; + state[10] = Aka; + state[11] = Ake; + state[12] = Aki; + state[13] = Ako; + state[14] = Aku; + state[15] = Ama; + state[16] = Ame; + state[17] = Ami; + state[18] = Amo; + state[19] = Amu; + state[20] = Asa; + state[21] = Ase; + state[22] = Asi; + state[23] = Aso; + state[24] = Asu; +} + +/************************************************* + * Name: keccak_absorb + * + * Description: Absorb step of Keccak; + * non-incremental, starts by zeroeing the state. + * + * Arguments: - uint64_t *s: pointer to (uninitialized) output Keccak state + * - uint32_t r: rate in bytes (e.g., 168 for SHAKE128) + * - const uint8_t *m: pointer to input to be absorbed into s + * - size_t mlen: length of input in bytes + * - uint8_t p: domain-separation byte for different + * Keccak-derived functions + **************************************************/ +static void keccak_absorb(uint64_t *s, uint32_t r, const uint8_t *m, size_t mlen, uint8_t p) { + size_t i; + uint8_t t[200]; + + /* Zero state */ + for (i = 0; i < 25; ++i) { + s[i] = 0; + } + + while (mlen >= r) { + for (i = 0; i < r / 8; ++i) { + s[i] ^= load64(m + 8 * i); + } + + KeccakF1600_StatePermute(s); + mlen -= r; + m += r; + } + + for (i = 0; i < r; ++i) { + t[i] = 0; + } + for (i = 0; i < mlen; ++i) { + t[i] = m[i]; + } + t[i] = p; + t[r - 1] |= 128; + for (i = 0; i < r / 8; ++i) { + s[i] ^= load64(t + 8 * i); + } +} + +/************************************************* + * Name: keccak_squeezeblocks + * + * Description: Squeeze step of Keccak. Squeezes full blocks of r bytes each. + * Modifies the state. Can be called multiple times to keep + * squeezing, i.e., is incremental. + * + * Arguments: - uint8_t *h: pointer to output blocks + * - size_t nblocks: number of blocks to be + * squeezed (written to h) + * - uint64_t *s: pointer to input/output Keccak state + * - uint32_t r: rate in bytes (e.g., 168 for SHAKE128) + **************************************************/ +static void keccak_squeezeblocks(uint8_t *h, size_t nblocks, uint64_t *s, uint32_t r) { + while (nblocks > 0) { + KeccakF1600_StatePermute(s); + for (size_t i = 0; i < (r >> 3); i++) { + store64(h + 8 * i, s[i]); + } + h += r; + nblocks--; + } +} + +/************************************************* + * Name: keccak_inc_init + * + * Description: Initializes the incremental Keccak state to zero. + * + * Arguments: - uint64_t *s_inc: pointer to input/output incremental state + * First 25 values represent Keccak state. + * 26th value represents either the number of absorbed bytes + * that have not been permuted, or not-yet-squeezed bytes. + **************************************************/ +static void keccak_inc_init(uint64_t *s_inc) { + size_t i; + + for (i = 0; i < 25; ++i) { + s_inc[i] = 0; + } + s_inc[25] = 0; +} + +/************************************************* + * Name: keccak_inc_absorb + * + * Description: Incremental keccak absorb + * Preceded by keccak_inc_init, succeeded by keccak_inc_finalize + * + * Arguments: - uint64_t *s_inc: pointer to input/output incremental state + * First 25 values represent Keccak state. + * 26th value represents either the number of absorbed bytes + * that have not been permuted, or not-yet-squeezed bytes. + * - uint32_t r: rate in bytes (e.g., 168 for SHAKE128) + * - const uint8_t *m: pointer to input to be absorbed into s + * - size_t mlen: length of input in bytes + **************************************************/ +static void keccak_inc_absorb(uint64_t *s_inc, uint32_t r, const uint8_t *m, size_t mlen) { + size_t i; + + /* Recall that s_inc[25] is the non-absorbed bytes xored into the state */ + while (mlen + s_inc[25] >= r) { + for (i = 0; i < r - (uint32_t)s_inc[25]; i++) { + /* Take the i'th byte from message + xor with the s_inc[25] + i'th byte of the state; little-endian */ + s_inc[(s_inc[25] + i) >> 3] ^= (uint64_t)m[i] << (8 * ((s_inc[25] + i) & 0x07)); + } + mlen -= (size_t)(r - s_inc[25]); + m += r - s_inc[25]; + s_inc[25] = 0; + + KeccakF1600_StatePermute(s_inc); + } + + for (i = 0; i < mlen; i++) { + s_inc[(s_inc[25] + i) >> 3] ^= (uint64_t)m[i] << (8 * ((s_inc[25] + i) & 0x07)); + } + s_inc[25] += mlen; +} + +/************************************************* + * Name: keccak_inc_finalize + * + * Description: Finalizes Keccak absorb phase, prepares for squeezing + * + * Arguments: - uint64_t *s_inc: pointer to input/output incremental state + * First 25 values represent Keccak state. + * 26th value represents either the number of absorbed bytes + * that have not been permuted, or not-yet-squeezed bytes. + * - uint32_t r: rate in bytes (e.g., 168 for SHAKE128) + * - uint8_t p: domain-separation byte for different + * Keccak-derived functions + **************************************************/ +static void keccak_inc_finalize(uint64_t *s_inc, uint32_t r, uint8_t p) { + /* After keccak_inc_absorb, we are guaranteed that s_inc[25] < r, + so we can always use one more byte for p in the current state. */ + s_inc[s_inc[25] >> 3] ^= (uint64_t)p << (8 * (s_inc[25] & 0x07)); + s_inc[(r - 1) >> 3] ^= (uint64_t)128 << (8 * ((r - 1) & 0x07)); + s_inc[25] = 0; +} + +/************************************************* + * Name: keccak_inc_squeeze + * + * Description: Incremental Keccak squeeze; can be called on byte-level + * + * Arguments: - uint8_t *h: pointer to output bytes + * - size_t outlen: number of bytes to be squeezed + * - uint64_t *s_inc: pointer to input/output incremental state + * First 25 values represent Keccak state. + * 26th value represents either the number of absorbed bytes + * that have not been permuted, or not-yet-squeezed bytes. + * - uint32_t r: rate in bytes (e.g., 168 for SHAKE128) + **************************************************/ +static void keccak_inc_squeeze(uint8_t *h, size_t outlen, uint64_t *s_inc, uint32_t r) { + size_t i; + + /* First consume any bytes we still have sitting around */ + for (i = 0; i < outlen && i < s_inc[25]; i++) { + /* There are s_inc[25] bytes left, so r - s_inc[25] is the first + available byte. We consume from there, i.e., up to r. */ + h[i] = (uint8_t)(s_inc[(r - s_inc[25] + i) >> 3] >> (8 * ((r - s_inc[25] + i) & 0x07))); + } + h += i; + outlen -= i; + s_inc[25] -= i; + + /* Then squeeze the remaining necessary blocks */ + while (outlen > 0) { + KeccakF1600_StatePermute(s_inc); + + for (i = 0; i < outlen && i < r; i++) { + h[i] = (uint8_t)(s_inc[i >> 3] >> (8 * (i & 0x07))); + } + h += i; + outlen -= i; + s_inc[25] = r - i; + } +} + +void shake128_inc_init(shake128incctx *state) { + keccak_inc_init(state->ctx); +} + +void shake128_inc_absorb(shake128incctx *state, const uint8_t *input, size_t inlen) { + keccak_inc_absorb(state->ctx, SHAKE128_RATE, input, inlen); +} + +void shake128_inc_finalize(shake128incctx *state) { + keccak_inc_finalize(state->ctx, SHAKE128_RATE, 0x1F); +} + +void shake128_inc_squeeze(uint8_t *output, size_t outlen, shake128incctx *state) { + keccak_inc_squeeze(output, outlen, state->ctx, SHAKE128_RATE); +} + +void shake256_inc_init(shake256incctx *state) { + keccak_inc_init(state->ctx); +} + +void shake256_inc_absorb(shake256incctx *state, const uint8_t *input, size_t inlen) { + keccak_inc_absorb(state->ctx, SHAKE256_RATE, input, inlen); +} + +void shake256_inc_finalize(shake256incctx *state) { + keccak_inc_finalize(state->ctx, SHAKE256_RATE, 0x1F); +} + +void shake256_inc_squeeze(uint8_t *output, size_t outlen, shake256incctx *state) { + keccak_inc_squeeze(output, outlen, state->ctx, SHAKE256_RATE); +} + +/************************************************* + * Name: shake128_absorb + * + * Description: Absorb step of the SHAKE128 XOF. + * non-incremental, starts by zeroeing the state. + * + * Arguments: - uint64_t *s: pointer to (uninitialized) output Keccak state + * - const uint8_t *input: pointer to input to be absorbed + * into s + * - size_t inlen: length of input in bytes + **************************************************/ +void shake128_absorb(shake128ctx *state, const uint8_t *input, size_t inlen) { + keccak_absorb(state->ctx, SHAKE128_RATE, input, inlen, 0x1F); +} + +/************************************************* + * Name: shake128_squeezeblocks + * + * Description: Squeeze step of SHAKE128 XOF. Squeezes full blocks of + * SHAKE128_RATE bytes each. Modifies the state. Can be called + * multiple times to keep squeezing, i.e., is incremental. + * + * Arguments: - uint8_t *output: pointer to output blocks + * - size_t nblocks: number of blocks to be squeezed + * (written to output) + * - shake128ctx *state: pointer to input/output Keccak state + **************************************************/ +void shake128_squeezeblocks(uint8_t *output, size_t nblocks, shake128ctx *state) { + keccak_squeezeblocks(output, nblocks, state->ctx, SHAKE128_RATE); +} + +/************************************************* + * Name: shake256_absorb + * + * Description: Absorb step of the SHAKE256 XOF. + * non-incremental, starts by zeroeing the state. + * + * Arguments: - shake256ctx *state: pointer to (uninitialized) output Keccak state + * - const uint8_t *input: pointer to input to be absorbed + * into s + * - size_t inlen: length of input in bytes + **************************************************/ +void shake256_absorb(shake256ctx *state, const uint8_t *input, size_t inlen) { + keccak_absorb(state->ctx, SHAKE256_RATE, input, inlen, 0x1F); +} + +/************************************************* + * Name: shake256_squeezeblocks + * + * Description: Squeeze step of SHAKE256 XOF. Squeezes full blocks of + * SHAKE256_RATE bytes each. Modifies the state. Can be called + * multiple times to keep squeezing, i.e., is incremental. + * + * Arguments: - uint8_t *output: pointer to output blocks + * - size_t nblocks: number of blocks to be squeezed + * (written to output) + * - shake256ctx *state: pointer to input/output Keccak state + **************************************************/ +void shake256_squeezeblocks(uint8_t *output, size_t nblocks, shake256ctx *state) { + keccak_squeezeblocks(output, nblocks, state->ctx, SHAKE256_RATE); +} + +/************************************************* + * Name: shake128 + * + * Description: SHAKE128 XOF with non-incremental API + * + * Arguments: - uint8_t *output: pointer to output + * - size_t outlen: requested output length in bytes + * - const uint8_t *input: pointer to input + * - size_t inlen: length of input in bytes + **************************************************/ +void shake128(uint8_t *output, size_t outlen, const uint8_t *input, size_t inlen) { + size_t nblocks = outlen / SHAKE128_RATE; + uint8_t t[SHAKE128_RATE]; + shake128ctx s; + + shake128_absorb(&s, input, inlen); + shake128_squeezeblocks(output, nblocks, &s); + + output += nblocks * SHAKE128_RATE; + outlen -= nblocks * SHAKE128_RATE; + + if (outlen) { + shake128_squeezeblocks(t, 1, &s); + for (size_t i = 0; i < outlen; ++i) { + output[i] = t[i]; + } + } +} + +/************************************************* + * Name: shake256 + * + * Description: SHAKE256 XOF with non-incremental API + * + * Arguments: - uint8_t *output: pointer to output + * - size_t outlen: requested output length in bytes + * - const uint8_t *input: pointer to input + * - size_t inlen: length of input in bytes + **************************************************/ +void shake256(uint8_t *output, size_t outlen, const uint8_t *input, size_t inlen) { + size_t nblocks = outlen / SHAKE256_RATE; + uint8_t t[SHAKE256_RATE]; + shake256ctx s; + + shake256_absorb(&s, input, inlen); + shake256_squeezeblocks(output, nblocks, &s); + + output += nblocks * SHAKE256_RATE; + outlen -= nblocks * SHAKE256_RATE; + + if (outlen) { + shake256_squeezeblocks(t, 1, &s); + for (size_t i = 0; i < outlen; ++i) { + output[i] = t[i]; + } + } +} + +void sha3_256_inc_init(sha3_256incctx *state) { + keccak_inc_init(state->ctx); +} + +void sha3_256_inc_absorb(sha3_256incctx *state, const uint8_t *input, size_t inlen) { + keccak_inc_absorb(state->ctx, SHA3_256_RATE, input, inlen); +} + +void sha3_256_inc_finalize(uint8_t *output, sha3_256incctx *state) { + uint8_t t[SHA3_256_RATE]; + keccak_inc_finalize(state->ctx, SHA3_256_RATE, 0x06); + + keccak_squeezeblocks(t, 1, state->ctx, SHA3_256_RATE); + + for (size_t i = 0; i < 32; i++) { + output[i] = t[i]; + } +} + +/************************************************* + * Name: sha3_256 + * + * Description: SHA3-256 with non-incremental API + * + * Arguments: - uint8_t *output: pointer to output + * - const uint8_t *input: pointer to input + * - size_t inlen: length of input in bytes + **************************************************/ +void sha3_256(uint8_t *output, const uint8_t *input, size_t inlen) { + uint64_t s[25]; + uint8_t t[SHA3_256_RATE]; + + /* Absorb input */ + keccak_absorb(s, SHA3_256_RATE, input, inlen, 0x06); + + /* Squeeze output */ + keccak_squeezeblocks(t, 1, s, SHA3_256_RATE); + + for (size_t i = 0; i < 32; i++) { + output[i] = t[i]; + } +} + +void sha3_384_inc_init(sha3_384incctx *state) { + keccak_inc_init(state->ctx); +} + +void sha3_384_inc_absorb(sha3_384incctx *state, const uint8_t *input, size_t inlen) { + keccak_inc_absorb(state->ctx, SHA3_384_RATE, input, inlen); +} + +void sha3_384_inc_finalize(uint8_t *output, sha3_384incctx *state) { + uint8_t t[SHA3_384_RATE]; + keccak_inc_finalize(state->ctx, SHA3_384_RATE, 0x06); + + keccak_squeezeblocks(t, 1, state->ctx, SHA3_384_RATE); + + for (size_t i = 0; i < 48; i++) { + output[i] = t[i]; + } +} + +/************************************************* + * Name: sha3_384 + * + * Description: SHA3-256 with non-incremental API + * + * Arguments: - uint8_t *output: pointer to output + * - const uint8_t *input: pointer to input + * - size_t inlen: length of input in bytes + **************************************************/ +void sha3_384(uint8_t *output, const uint8_t *input, size_t inlen) { + uint64_t s[25]; + uint8_t t[SHA3_384_RATE]; + + /* Absorb input */ + keccak_absorb(s, SHA3_384_RATE, input, inlen, 0x06); + + /* Squeeze output */ + keccak_squeezeblocks(t, 1, s, SHA3_384_RATE); + + for (size_t i = 0; i < 48; i++) { + output[i] = t[i]; + } +} + +void sha3_512_inc_init(sha3_512incctx *state) { + keccak_inc_init(state->ctx); +} + +void sha3_512_inc_absorb(sha3_512incctx *state, const uint8_t *input, size_t inlen) { + keccak_inc_absorb(state->ctx, SHA3_512_RATE, input, inlen); +} + +void sha3_512_inc_finalize(uint8_t *output, sha3_512incctx *state) { + uint8_t t[SHA3_512_RATE]; + keccak_inc_finalize(state->ctx, SHA3_512_RATE, 0x06); + + keccak_squeezeblocks(t, 1, state->ctx, SHA3_512_RATE); + + for (size_t i = 0; i < 64; i++) { + output[i] = t[i]; + } +} + +/************************************************* + * Name: sha3_512 + * + * Description: SHA3-512 with non-incremental API + * + * Arguments: - uint8_t *output: pointer to output + * - const uint8_t *input: pointer to input + * - size_t inlen: length of input in bytes + **************************************************/ +void sha3_512(uint8_t *output, const uint8_t *input, size_t inlen) { + uint64_t s[25]; + uint8_t t[SHA3_512_RATE]; + + /* Absorb input */ + keccak_absorb(s, SHA3_512_RATE, input, inlen, 0x06); + + /* Squeeze output */ + keccak_squeezeblocks(t, 1, s, SHA3_512_RATE); + + for (size_t i = 0; i < 64; i++) { + output[i] = t[i]; + } +} diff --git a/src/kem/hqc/hqc_ref/lib/fips202/fips202.h b/src/kem/hqc/hqc_ref/lib/fips202/fips202.h new file mode 100644 index 0000000000..60d7ecabc7 --- /dev/null +++ b/src/kem/hqc/hqc_ref/lib/fips202/fips202.h @@ -0,0 +1,87 @@ +#ifndef FIPS202_H +#define FIPS202_H + +#include +#include + +#define SHAKE128_RATE 168 +#define SHAKE256_RATE 136 +#define SHA3_256_RATE 136 +#define SHA3_384_RATE 104 +#define SHA3_512_RATE 72 + +// Context for incremental API +typedef struct { + uint64_t ctx[26]; +} shake128incctx; + +// Context for non-incremental API +typedef struct { + uint64_t ctx[25]; +} shake128ctx; + +// Context for incremental API +typedef struct { + uint64_t ctx[26]; +} shake256incctx; + +// Context for non-incremental API +typedef struct { + uint64_t ctx[25]; +} shake256ctx; + +// Context for incremental API +typedef struct { + uint64_t ctx[26]; +} sha3_256incctx; + +// Context for incremental API +typedef struct { + uint64_t ctx[26]; +} sha3_384incctx; + +// Context for incremental API +typedef struct { + uint64_t ctx[26]; +} sha3_512incctx; + +void shake128_absorb(shake128ctx *state, const uint8_t *input, size_t inlen); + +void shake128_squeezeblocks(uint8_t *output, size_t nblocks, shake128ctx *state); + +void shake128_inc_init(shake128incctx *state); +void shake128_inc_absorb(shake128incctx *state, const uint8_t *input, size_t inlen); +void shake128_inc_finalize(shake128incctx *state); +void shake128_inc_squeeze(uint8_t *output, size_t outlen, shake128incctx *state); + +void shake256_absorb(shake256ctx *state, const uint8_t *input, size_t inlen); +void shake256_squeezeblocks(uint8_t *output, size_t nblocks, shake256ctx *state); + +void shake256_inc_init(shake256incctx *state); +void shake256_inc_absorb(shake256incctx *state, const uint8_t *input, size_t inlen); +void shake256_inc_finalize(shake256incctx *state); +void shake256_inc_squeeze(uint8_t *output, size_t outlen, shake256incctx *state); + +void shake128(uint8_t *output, size_t outlen, const uint8_t *input, size_t inlen); + +void shake256(uint8_t *output, size_t outlen, const uint8_t *input, size_t inlen); + +void sha3_256_inc_init(sha3_256incctx *state); +void sha3_256_inc_absorb(sha3_256incctx *state, const uint8_t *input, size_t inlen); +void sha3_256_inc_finalize(uint8_t *output, sha3_256incctx *state); + +void sha3_256(uint8_t *output, const uint8_t *input, size_t inlen); + +void sha3_384_inc_init(sha3_384incctx *state); +void sha3_384_inc_absorb(sha3_384incctx *state, const uint8_t *input, size_t inlen); +void sha3_384_inc_finalize(uint8_t *output, sha3_384incctx *state); + +void sha3_384(uint8_t *output, const uint8_t *input, size_t inlen); + +void sha3_512_inc_init(sha3_512incctx *state); +void sha3_512_inc_absorb(sha3_512incctx *state, const uint8_t *input, size_t inlen); +void sha3_512_inc_finalize(uint8_t *output, sha3_512incctx *state); + +void sha3_512(uint8_t *output, const uint8_t *input, size_t inlen); + +#endif diff --git a/src/kem/hqc/hqc_ref/src/common/code.c b/src/kem/hqc/hqc_ref/src/common/code.c new file mode 100644 index 0000000000..cb216f939c --- /dev/null +++ b/src/kem/hqc/hqc_ref/src/common/code.c @@ -0,0 +1,62 @@ +/** + * @file code.c + * @brief Implementation of concatenated code + */ + +#include "code.h" +#include +#include "crypto_memset.h" +#include "parameters.h" +#include "reed_muller.h" +#include "reed_solomon.h" +#ifdef VERBOSE +#include +#include "vector.h" +#endif + +/** + * + * @brief Encoding the message m to a code word em using the concatenated code + * + * First we encode the message using the Reed-Solomon code, then with the duplicated Reed-Muller code we obtain + * a concatenated code word. + * + * @param[out] em Pointer to an array that is a code word + * @param[in] m Pointer to an array that is the message + */ +void code_encode(uint64_t *em, const uint64_t *m) { + uint64_t tmp[VEC_N1_SIZE_64] = {0}; + + reed_solomon_encode(tmp, m); + reed_muller_encode(em, tmp); + +#ifdef VERBOSE + printf("\n\nReed-Solomon code word: "); + vect_print(tmp, VEC_N1_SIZE_BYTES); + printf("\n\nConcatenated code word: "); + vect_print(em, VEC_N1N2_SIZE_BYTES); +#endif + // Zeroize sensitive data + memset_zero(tmp, sizeof tmp); +} + +/** + * @brief Decoding the code word em to a message m using the concatenated code + * + * @param[out] m Pointer to an array that is the message + * @param[in] em Pointer to an array that is the code word + */ +void code_decode(uint64_t *m, const uint64_t *em) { + uint64_t tmp[VEC_N1_SIZE_64] = {0}; + + reed_muller_decode(tmp, em); + reed_solomon_decode(m, tmp); + +#ifdef VERBOSE + printf("\n\nReed-Muller decoding result (the input for the Reed-Solomon decoding algorithm): "); + vect_print(tmp, VEC_N1_SIZE_BYTES); +#endif + + // Zeroize sensitive data + memset_zero(tmp, sizeof tmp); +} diff --git a/src/kem/hqc/hqc_ref/src/common/code.h b/src/kem/hqc/hqc_ref/src/common/code.h new file mode 100644 index 0000000000..ef8439aded --- /dev/null +++ b/src/kem/hqc/hqc_ref/src/common/code.h @@ -0,0 +1,16 @@ +/** + * @file code.h + * @brief Header file of code.c + */ + +#ifndef HQC_CODE_H +#define HQC_CODE_H + +#include +#include +#include "parameters.h" + +void code_encode(uint64_t *em, const uint64_t *m); +void code_decode(uint64_t *m, const uint64_t *em); + +#endif // HQC_CODE_H diff --git a/src/kem/hqc/hqc_ref/src/common/crypto_memset.c b/src/kem/hqc/hqc_ref/src/common/crypto_memset.c new file mode 100644 index 0000000000..422133aea9 --- /dev/null +++ b/src/kem/hqc/hqc_ref/src/common/crypto_memset.c @@ -0,0 +1,7 @@ +/** + * @file crypto_memset.c + * @brief Implementation of safe memset + */ +#include + +void *(*volatile memset_volatile)(void *, int, size_t) = memset; diff --git a/src/kem/hqc/hqc_ref/src/common/crypto_memset.h b/src/kem/hqc/hqc_ref/src/common/crypto_memset.h new file mode 100644 index 0000000000..744d49de86 --- /dev/null +++ b/src/kem/hqc/hqc_ref/src/common/crypto_memset.h @@ -0,0 +1,22 @@ +/** + * @file crypto_memset.h + * @brief Header file for crypto_memset.c + */ + +#ifndef HQC_CRYPTO_MEMSET_H +#define HQC_CRYPTO_MEMSET_H + +#include + +/** + * safer call to memset https://github.com/veorq/cryptocoding#problem-4 + */ +extern void *(*volatile memset_volatile)(void *, int, size_t); + +/** + * @def memset_zero + * @brief Securely zero a memory region. + */ +#define memset_zero(ptr, len) memset_volatile((ptr), 0, (len)) + +#endif // HQC_CRYPTO_MEMSET_H diff --git a/src/kem/hqc/pqclean_hqc-128_clean/fft.c b/src/kem/hqc/hqc_ref/src/common/fft.c similarity index 71% rename from src/kem/hqc/pqclean_hqc-128_clean/fft.c rename to src/kem/hqc/hqc_ref/src/common/fft.c index 386e0af435..552bf709dc 100644 --- a/src/kem/hqc/pqclean_hqc-128_clean/fft.c +++ b/src/kem/hqc/hqc_ref/src/common/fft.c @@ -1,8 +1,3 @@ -#include "fft.h" -#include "gf.h" -#include "parameters.h" -#include -#include /** * @file fft.c * @brief Implementation of the additive FFT and its transpose. @@ -14,8 +9,17 @@ * https://binary.cr.yp.to/mcbits-20130616.pdf */ +#include "fft.h" +#include +#include +#include "gf.h" +#include "parameters.h" +static void compute_fft_betas(uint16_t *betas); +static void compute_subset_sums(uint16_t *subset_sums, const uint16_t *set, uint16_t set_size); +static void radix(uint16_t *f0, uint16_t *f1, const uint16_t *f, uint32_t m_f); static void radix_big(uint16_t *f0, uint16_t *f1, const uint16_t *f, uint32_t m_f); +static void fft_rec(uint16_t *w, uint16_t *f, size_t f_coeffs, uint8_t m, uint32_t m_f, const uint16_t *betas); /** * @brief Computes the basis of betas (omitting 1) used in the additive FFT and its transpose @@ -29,8 +33,6 @@ static void compute_fft_betas(uint16_t *betas) { } } - - /** * @brief Computes the subset sums of the given set * @@ -52,8 +54,6 @@ static void compute_subset_sums(uint16_t *subset_sums, const uint16_t *set, uint } } - - /** * @brief Computes the radix conversion of a polynomial f in GF(2^m)[x] * @@ -68,55 +68,66 @@ static void compute_subset_sums(uint16_t *subset_sums, const uint16_t *set, uint */ static void radix(uint16_t *f0, uint16_t *f1, const uint16_t *f, uint32_t m_f) { switch (m_f) { - case 4: - f0[4] = f[8] ^ f[12]; - f0[6] = f[12] ^ f[14]; - f0[7] = f[14] ^ f[15]; - f1[5] = f[11] ^ f[13]; - f1[6] = f[13] ^ f[14]; - f1[7] = f[15]; - f0[5] = f[10] ^ f[12] ^ f1[5]; - f1[4] = f[9] ^ f[13] ^ f0[5]; - - f0[0] = f[0]; - f1[3] = f[7] ^ f[11] ^ f[15]; - f0[3] = f[6] ^ f[10] ^ f[14] ^ f1[3]; - f0[2] = f[4] ^ f0[4] ^ f0[3] ^ f1[3]; - f1[1] = f[3] ^ f[5] ^ f[9] ^ f[13] ^ f1[3]; - f1[2] = f[3] ^ f1[1] ^ f0[3]; - f0[1] = f[2] ^ f0[2] ^ f1[1]; - f1[0] = f[1] ^ f0[1]; - break; - - case 3: - f0[0] = f[0]; - f0[2] = f[4] ^ f[6]; - f0[3] = f[6] ^ f[7]; - f1[1] = f[3] ^ f[5] ^ f[7]; - f1[2] = f[5] ^ f[6]; - f1[3] = f[7]; - f0[1] = f[2] ^ f0[2] ^ f1[1]; - f1[0] = f[1] ^ f0[1]; - break; - - case 2: - f0[0] = f[0]; - f0[1] = f[2] ^ f[3]; - f1[0] = f[1] ^ f0[1]; - f1[1] = f[3]; - break; - - case 1: - f0[0] = f[0]; - f1[0] = f[1]; - break; - - default: - radix_big(f0, f1, f, m_f); - break; + case 4: + f0[4] = f[8] ^ f[12]; + f0[6] = f[12] ^ f[14]; + f0[7] = f[14] ^ f[15]; + f1[5] = f[11] ^ f[13]; + f1[6] = f[13] ^ f[14]; + f1[7] = f[15]; + f0[5] = f[10] ^ f[12] ^ f1[5]; + f1[4] = f[9] ^ f[13] ^ f0[5]; + + f0[0] = f[0]; + f1[3] = f[7] ^ f[11] ^ f[15]; + f0[3] = f[6] ^ f[10] ^ f[14] ^ f1[3]; + f0[2] = f[4] ^ f0[4] ^ f0[3] ^ f1[3]; + f1[1] = f[3] ^ f[5] ^ f[9] ^ f[13] ^ f1[3]; + f1[2] = f[3] ^ f1[1] ^ f0[3]; + f0[1] = f[2] ^ f0[2] ^ f1[1]; + f1[0] = f[1] ^ f0[1]; + break; + + case 3: + f0[0] = f[0]; + f0[2] = f[4] ^ f[6]; + f0[3] = f[6] ^ f[7]; + f1[1] = f[3] ^ f[5] ^ f[7]; + f1[2] = f[5] ^ f[6]; + f1[3] = f[7]; + f0[1] = f[2] ^ f0[2] ^ f1[1]; + f1[0] = f[1] ^ f0[1]; + break; + + case 2: + f0[0] = f[0]; + f0[1] = f[2] ^ f[3]; + f1[0] = f[1] ^ f0[1]; + f1[1] = f[3]; + break; + + case 1: + f0[0] = f[0]; + f1[0] = f[1]; + break; + + default: + radix_big(f0, f1, f, m_f); + break; } } +/** + * @brief Radix conversion for large polynomials in GF(2^m)[x]. + * + * Generalized radix step when the polynomial size 2^m_f exceeds + * the small-case thresholds (handled in radix()). + * + * @param[out] f0 Lower-half output array of size 2^{m_f-1} + * @param[out] f1 Upper-half output array of size 2^{m_f-1} + * @param[in] f Input array of size 2^{m_f} + * @param[in] m_f Log₂ of the input size + */ static void radix_big(uint16_t *f0, uint16_t *f1, const uint16_t *f, uint32_t m_f) { uint16_t Q[2 * (1 << (PARAM_FFT - 2)) + 1] = {0}; uint16_t R[2 * (1 << (PARAM_FFT - 2)) + 1] = {0}; @@ -148,12 +159,10 @@ static void radix_big(uint16_t *f0, uint16_t *f1, const uint16_t *f, uint32_t m_ memcpy(f1 + n, Q1, 2 * n); } - - /** * @brief Evaluates f at all subset sums of a given set * - * This function is a subroutine of the function PQCLEAN_HQC128_CLEAN_fft. + * This function is a subroutine of the function fft. * * @param[out] w Array * @param[in] f Array @@ -179,7 +188,7 @@ static void fft_rec(uint16_t *w, uint16_t *f, size_t f_coeffs, uint8_t m, uint32 // Step 1 if (m_f == 1) { for (i = 0; i < m; ++i) { - tmp[i] = PQCLEAN_HQC128_CLEAN_gf_mul(betas[i], f[1]); + tmp[i] = gf_mul(betas[i], f[1]); } w[0] = f[0]; @@ -200,8 +209,8 @@ static void fft_rec(uint16_t *w, uint16_t *f, size_t f_coeffs, uint8_t m, uint32 x = 1; x <<= m_f; for (i = 1; i < x; ++i) { - beta_m_pow = PQCLEAN_HQC128_CLEAN_gf_mul(beta_m_pow, betas[m - 1]); - f[i] = PQCLEAN_HQC128_CLEAN_gf_mul(beta_m_pow, f[i]); + beta_m_pow = gf_mul(beta_m_pow, betas[m - 1]); + f[i] = gf_mul(beta_m_pow, f[i]); } } @@ -210,8 +219,8 @@ static void fft_rec(uint16_t *w, uint16_t *f, size_t f_coeffs, uint8_t m, uint32 // Step 4: compute gammas and deltas for (i = 0; i + 1 < m; ++i) { - gammas[i] = PQCLEAN_HQC128_CLEAN_gf_mul(betas[i], PQCLEAN_HQC128_CLEAN_gf_inverse(betas[m - 1])); - deltas[i] = PQCLEAN_HQC128_CLEAN_gf_square(gammas[i]) ^ gammas[i]; + gammas[i] = gf_mul(betas[i], gf_inverse(betas[m - 1])); + deltas[i] = gf_square(gammas[i]) ^ gammas[i]; } // Compute gammas sums @@ -221,12 +230,12 @@ static void fft_rec(uint16_t *w, uint16_t *f, size_t f_coeffs, uint8_t m, uint32 fft_rec(u, f0, (f_coeffs + 1) / 2, m - 1, m_f - 1, deltas); k = 1; - k <<= ((m - 1) & 0xf); // &0xf is to let the compiler know that m-1 is small. - if (f_coeffs <= 3) { // 3-coefficient polynomial f case: f1 is constant + k <<= ((m - 1) & 0xf); // &0xf is to let the compiler know that m-1 is small. + if (f_coeffs <= 3) { // 3-coefficient polynomial f case: f1 is constant w[0] = u[0]; w[k] = u[0] ^ f1[0]; for (i = 1; i < k; ++i) { - w[i] = u[i] ^ PQCLEAN_HQC128_CLEAN_gf_mul(gammas_sums[i], f1[0]); + w[i] = u[i] ^ gf_mul(gammas_sums[i], f1[0]); w[k + i] = w[i] ^ f1[0]; } } else { @@ -237,14 +246,12 @@ static void fft_rec(uint16_t *w, uint16_t *f, size_t f_coeffs, uint8_t m, uint32 w[0] = u[0]; w[k] ^= u[0]; for (i = 1; i < k; ++i) { - w[i] = u[i] ^ PQCLEAN_HQC128_CLEAN_gf_mul(gammas_sums[i], v[i]); + w[i] = u[i] ^ gf_mul(gammas_sums[i], v[i]); w[k + i] ^= w[i]; } } } - - /** * @brief Evaluates f on all fields elements using an additive FFT algorithm * @@ -264,7 +271,7 @@ static void fft_rec(uint16_t *w, uint16_t *f, size_t f_coeffs, uint8_t m, uint32 * @param[in] f Array of 2^PARAM_FFT elements * @param[in] f_coeffs Number coefficients of f (i.e. deg(f)+1) */ -void PQCLEAN_HQC128_CLEAN_fft(uint16_t *w, const uint16_t *f, size_t f_coeffs) { +void fft(uint16_t *w, const uint16_t *f, size_t f_coeffs) { uint16_t betas[PARAM_M - 1] = {0}; uint16_t betas_sums[1 << (PARAM_M - 1)] = {0}; uint16_t f0[1 << (PARAM_FFT - 1)] = {0}; @@ -290,7 +297,7 @@ void PQCLEAN_HQC128_CLEAN_fft(uint16_t *w, const uint16_t *f, size_t f_coeffs) { // Step 4: Compute deltas for (i = 0; i < PARAM_M - 1; ++i) { - deltas[i] = PQCLEAN_HQC128_CLEAN_gf_square(betas[i]) ^ betas[i]; + deltas[i] = gf_square(betas[i]) ^ betas[i]; } // Step 5 @@ -309,21 +316,19 @@ void PQCLEAN_HQC128_CLEAN_fft(uint16_t *w, const uint16_t *f, size_t f_coeffs) { // Find other roots for (i = 1; i < k; ++i) { - w[i] = u[i] ^ PQCLEAN_HQC128_CLEAN_gf_mul(betas_sums[i], v[i]); + w[i] = u[i] ^ gf_mul(betas_sums[i], v[i]); w[k + i] ^= w[i]; } } - - /** - * @brief Retrieves the error polynomial error from the evaluations w of the ELP (Error Locator Polynomial) on all field elements. + * @brief Retrieves the error polynomial error from the evaluations w of the ELP (Error Locator Polynomial) on all field + * elements. * * @param[out] error Array with the error - * @param[out] error_compact Array with the error in a compact form * @param[in] w Array of size 2^PARAM_M */ -void PQCLEAN_HQC128_CLEAN_fft_retrieve_error_poly(uint8_t *error, const uint16_t *w) { +void fft_retrieve_error_poly(uint8_t *error, const uint16_t *w) { uint16_t gammas[PARAM_M - 1] = {0}; uint16_t gammas_sums[1 << (PARAM_M - 1)] = {0}; uint16_t k; @@ -333,14 +338,14 @@ void PQCLEAN_HQC128_CLEAN_fft_retrieve_error_poly(uint8_t *error, const uint16_t compute_subset_sums(gammas_sums, gammas, PARAM_M - 1); k = 1 << (PARAM_M - 1); - error[0] ^= 1 ^ ((uint16_t) - w[0] >> 15); - error[0] ^= 1 ^ ((uint16_t) - w[k] >> 15); + error[0] ^= 1 ^ ((uint16_t)-w[0] >> 15); + error[0] ^= 1 ^ ((uint16_t)-w[k] >> 15); for (i = 1; i < k; ++i) { index = PARAM_GF_MUL_ORDER - gf_log[gammas_sums[i]]; - error[index] ^= 1 ^ ((uint16_t) - w[i] >> 15); + error[index] ^= 1 ^ ((uint16_t)-w[i] >> 15); index = PARAM_GF_MUL_ORDER - gf_log[gammas_sums[i] ^ 1]; - error[index] ^= 1 ^ ((uint16_t) - w[k + i] >> 15); + error[index] ^= 1 ^ ((uint16_t)-w[k + i] >> 15); } } diff --git a/src/kem/hqc/hqc_ref/src/common/fft.h b/src/kem/hqc/hqc_ref/src/common/fft.h new file mode 100644 index 0000000000..a0f0648502 --- /dev/null +++ b/src/kem/hqc/hqc_ref/src/common/fft.h @@ -0,0 +1,15 @@ +/** + * @file fft.h + * @brief Header file of fft.c + */ + +#ifndef HQC_FFT_H +#define HQC_FFT_H + +#include +#include + +void fft(uint16_t *w, const uint16_t *f, size_t f_coeffs); +void fft_retrieve_error_poly(uint8_t *error, const uint16_t *w); + +#endif // HQC_FFT_H diff --git a/src/kem/hqc/hqc_ref/src/common/hqc-1/api.h b/src/kem/hqc/hqc_ref/src/common/hqc-1/api.h new file mode 100644 index 0000000000..07a1196b37 --- /dev/null +++ b/src/kem/hqc/hqc_ref/src/common/hqc-1/api.h @@ -0,0 +1,23 @@ +/** + * @file api.h + * @brief NIST KEM API used by the HQC-KEM IND-CCA2 scheme + */ + +#ifndef HQC_API_H +#define HQC_API_H + +#define CRYPTO_ALGNAME "HQC-1" + +#define CRYPTO_SECRETKEYBYTES 2321 +#define CRYPTO_PUBLICKEYBYTES 2241 +#define CRYPTO_BYTES 32 +#define CRYPTO_CIPHERTEXTBYTES 4433 + +// As a technicality, the public key is appended to the secret key in order to respect the NIST API. +// Without this constraint, CRYPTO_SECRETKEYBYTES would be defined as 32 + +int crypto_kem_keypair(unsigned char *pk, unsigned char *sk); +int crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk); +int crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk); + +#endif // HQC_API_H diff --git a/src/kem/hqc/hqc_ref/src/common/hqc-3/api.h b/src/kem/hqc/hqc_ref/src/common/hqc-3/api.h new file mode 100644 index 0000000000..8bffd04869 --- /dev/null +++ b/src/kem/hqc/hqc_ref/src/common/hqc-3/api.h @@ -0,0 +1,23 @@ +/** + * @file api.h + * @brief NIST KEM API used by the HQC-KEM IND-CCA2 scheme + */ + +#ifndef HQC_API_H +#define HQC_API_H + +#define CRYPTO_ALGNAME "HQC-3" + +#define CRYPTO_SECRETKEYBYTES 4602 +#define CRYPTO_PUBLICKEYBYTES 4514 +#define CRYPTO_BYTES 32 +#define CRYPTO_CIPHERTEXTBYTES 8978 + +// As a technicality, the public key is appended to the secret key in order to respect the NIST API. +// Without this constraint, CRYPTO_SECRETKEYBYTES would be defined as 32 + +int crypto_kem_keypair(unsigned char *pk, unsigned char *sk); +int crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk); +int crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk); + +#endif // HQC_API_H diff --git a/src/kem/hqc/hqc_ref/src/common/hqc-5/api.h b/src/kem/hqc/hqc_ref/src/common/hqc-5/api.h new file mode 100644 index 0000000000..3f2b5eca8a --- /dev/null +++ b/src/kem/hqc/hqc_ref/src/common/hqc-5/api.h @@ -0,0 +1,23 @@ +/** + * @file api.h + * @brief NIST KEM API used by the HQC-KEM IND-CCA2 scheme + */ + +#ifndef HQC_API_H +#define HQC_API_H + +#define CRYPTO_ALGNAME "HQC-5" + +#define CRYPTO_SECRETKEYBYTES 7333 +#define CRYPTO_PUBLICKEYBYTES 7237 +#define CRYPTO_BYTES 32 +#define CRYPTO_CIPHERTEXTBYTES 14421 + +// As a technicality, the public key is appended to the secret key in order to respect the NIST API. +// Without this constraint, CRYPTO_SECRETKEYBYTES would be defined as 32 + +int crypto_kem_keypair(unsigned char *pk, unsigned char *sk); +int crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk); +int crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk); + +#endif // HQC_API_H diff --git a/src/kem/hqc/hqc_ref/src/common/kem.c b/src/kem/hqc/hqc_ref/src/common/kem.c new file mode 100644 index 0000000000..1e06fd8c75 --- /dev/null +++ b/src/kem/hqc/hqc_ref/src/common/kem.c @@ -0,0 +1,305 @@ +/** + * @file kem.c + * @brief Implementation of api.h + */ + +#include +#include + +#include "api.h" +#include "crypto_memset.h" +#include "hqc.h" +#include "parameters.h" +#include "parsing.h" +#include "symmetric.h" +#include "vector.h" + +#include "oqs_adapter_macros.h" + +#ifdef VERBOSE +#include +#endif + +/** + * @brief Generates a keypair for the KEM (Key Encapsulation Mechanism) scheme. + * + * This function generates a public/private keypair used for key encapsulation + * and decapsulation. The encapsulation key (`ek`) is used to encapsulate a + * shared secret, while the decapsulation key (`dk`) is used to recover it. + * + * @param[out] ek_kem Pointer to the output buffer where the encapsulation key + * will be stored. + * @param[out] dk_kem Pointer to the output buffer where the decapsulation key + * will be stored. + * + * @return 0 on success. + * + * @pre The PRNG **must be seeded** with ::prng_init() before calling this + * function. + * @warning This function calls ::prng_get_bytes() to sample `seed_kem`. If the + * PRNG has not been properly seeded beforehand, the generated keys will be + * insecure/predictable. + * @note An example of correct seeding is provided in `main_hqc.c` (see + * `init_randomness()`), which seeds the PRNG using `syscall(SYS_getrandom, + * ...)` (32 bytes) by default.. + * @see prng_init, prng_get_bytes, main_hqc.c + */ +int OQS_MAKE_FN(KEM_PREFIX, crypto_kem_keypair)(uint8_t* ek_kem, + uint8_t* dk_kem) { +#ifdef VERBOSE + printf("### KEYGEN ###\n"); +#endif + + uint8_t seed_kem[SEED_BYTES] = {0}; + uint8_t sigma[PARAM_SECURITY_BYTES] = {0}; + uint8_t seed_pke[SEED_BYTES] = {0}; + shake256_xof_ctx ctx_kem; + + uint8_t ek_pke[PUBLIC_KEY_BYTES] = {0}; + uint8_t dk_pke[SEED_BYTES] = {0}; + + // Sample seed_kem + prng_get_bytes(seed_kem, SEED_BYTES); + + // Compute seed_pke and randomness sigma + xof_init(&ctx_kem, seed_kem, SEED_BYTES); + xof_get_bytes(&ctx_kem, seed_pke, SEED_BYTES); + xof_get_bytes(&ctx_kem, sigma, PARAM_SECURITY_BYTES); + + // Compute HQC-PKE keypair + hqc_pke_keygen(ek_pke, dk_pke, seed_pke); + + // Compute HQC-KEM keypair + memcpy(ek_kem, ek_pke, PUBLIC_KEY_BYTES); + memcpy(dk_kem, ek_kem, PUBLIC_KEY_BYTES); + memcpy(dk_kem + PUBLIC_KEY_BYTES, dk_pke, SEED_BYTES); + memcpy(dk_kem + PUBLIC_KEY_BYTES + SEED_BYTES, sigma, PARAM_SECURITY_BYTES); + memcpy(dk_kem + PUBLIC_KEY_BYTES + SEED_BYTES + PARAM_SECURITY_BYTES, + seed_kem, SEED_BYTES); + +#ifdef VERBOSE + printf("\n\nseed_kem: "); + for (int i = 0; i < SEED_BYTES; ++i) { + printf("%02x", seed_kem[i]); + } + printf("\n\nseed_pke: "); + for (int i = 0; i < SEED_BYTES; ++i) { + printf("%02x", seed_pke[i]); + } + printf("\n\nsigma: "); + for (int i = 0; i < PARAM_SECURITY_BYTES; ++i) { + printf("%02x", sigma[i]); + } +#endif + + // Zeroize sensitive data + memset_zero(seed_kem, sizeof seed_kem); + memset_zero(sigma, sizeof sigma); + memset_zero(seed_pke, sizeof seed_pke); + memset_zero(dk_pke, sizeof dk_pke); + + return 0; +} + +/** + * @brief Performs key encapsulation using the KEM scheme. + * + * This function uses the encapsulation key (`ek`) to generate a ciphertext + * (`c_kem`) and a shared secret (`K`).. + * + * @param[out] c_kem Pointer to the output buffer where the KEM ciphertext + * will be stored. + * @param[out] K Pointer to the output buffer where the shared secret will + * be stored. + * @param[in] ek_kem Pointer to the encapsulation key. + * + * @return Returns 0 on success. + * + * @pre The PRNG **must be seeded** with ::prng_init() before calling this + * function. + * @warning This function calls ::prng_get_bytes() to sample `seed_kem`. If the + * PRNG has not been properly seeded beforehand, the generated keys will be + * insecure/predictable. + * @note An example of correct seeding is provided in `main_hqc.c` (see + * `init_randomness()`), which seeds the PRNG using `syscall(SYS_getrandom, + * ...)` (32 bytes) by default.. + * @see prng_init, prng_get_bytes, main_hqc.c + */ +int OQS_MAKE_FN(KEM_PREFIX, crypto_kem_enc)(uint8_t* c_kem, uint8_t* K, + const uint8_t* ek_kem) { +#ifdef VERBOSE + printf("\n\n\n\n### ENCAPS ###"); +#endif + + uint8_t m[PARAM_SECURITY_BYTES] = {0}; + uint8_t K_theta[SHARED_SECRET_BYTES + SEED_BYTES] = {0}; + uint8_t theta[SEED_BYTES] = {0}; + uint8_t hash_ek_kem[SEED_BYTES] = {0}; + ciphertext_kem_t c_kem_t = {0}; + + // Sample message m and salt + prng_get_bytes(m, PARAM_SECURITY_BYTES); + prng_get_bytes(c_kem_t.salt, SALT_BYTES); + + // Compute shared key K and ciphertext c_kem + hash_h(hash_ek_kem, ek_kem); + hash_g(K_theta, hash_ek_kem, m, c_kem_t.salt); + memcpy(theta, K_theta + SEED_BYTES, SEED_BYTES); + hqc_pke_encrypt(&c_kem_t.c_pke, ek_kem, (uint64_t*)m, theta); + + hqc_c_kem_to_string(c_kem, &c_kem_t); + memcpy(K, K_theta, SHARED_SECRET_BYTES); + +#ifdef VERBOSE + printf("\n\nek_kem: "); + for (int i = 0; i < PUBLIC_KEY_BYTES; ++i) { + printf("%02x", ek_kem[i]); + } + printf("\n\nm: "); + vect_print((uint64_t*)m, PARAM_SECURITY_BYTES); + printf("\n\nsalt: "); + for (int i = 0; i < SALT_BYTES; ++i) { + printf("%02x", c_kem_t.salt[i]); + } + printf("\n\nH(ek_kem): "); + for (int i = 0; i < SEED_BYTES; ++i) { + printf("%02x", hash_ek_kem[i]); + } + printf("\n\ntheta: "); + for (int i = 0; i < SEED_BYTES; ++i) { + printf("%02x", theta[i]); + } + printf("\n\nc_kem: "); + for (int i = 0; i < CIPHERTEXT_BYTES; ++i) { + printf("%02x", c_kem[i]); + } + printf("\n\nK: "); + for (int i = 0; i < SHARED_SECRET_BYTES; ++i) { + printf("%02x", K[i]); + } +#endif + + // Zeroize sensitive data + memset_zero(m, sizeof m); + memset_zero(K_theta, sizeof K_theta); + memset_zero(theta, sizeof theta); + + return 0; +} + +/** + * @brief Performs key decapsulation using the KEM scheme. + * + * This function uses the decapsulation key (`dk`) to recover the shared secret + * (`K_prime`) from the given KEM ciphertext (`c_kem`), which was generated + * during encapsulation. + * + * @param[out] K_prime Pointer to the output buffer where the recovered shared + * secret will be stored. + * @param[in] c_kem Pointer to the input KEM ciphertext. + * @param[in] dk_kem Pointer to the decapsulation key. + * + * @return Returns 0 on success. + */ +int OQS_MAKE_FN(KEM_PREFIX, crypto_kem_dec)(uint8_t* K_prime, + const uint8_t* c_kem, + const uint8_t* dk_kem) { +#ifdef VERBOSE + printf("\n\n\n\n### DECAPS ###"); +#endif + + uint8_t ek_pke[PUBLIC_KEY_BYTES] = {0}; + uint8_t dk_pke[SEED_BYTES] = {0}; + uint8_t sigma[PARAM_SECURITY_BYTES] = {0}; + uint8_t m_prime[PARAM_SECURITY_BYTES] = {0}; + uint8_t hash_ek_kem[SEED_BYTES] = {0}; + uint8_t K_theta_prime[SHARED_SECRET_BYTES + SEED_BYTES] = {0}; + uint8_t K_bar[SHARED_SECRET_BYTES] = {0}; + uint8_t theta_prime[SEED_BYTES] = {0}; + ciphertext_kem_t c_kem_t = {0}; + ciphertext_kem_t c_kem_prime_t = {0}; + uint8_t result; + + // Parse decapsulation key dk_kem + memcpy(ek_pke, dk_kem, PUBLIC_KEY_BYTES); + memcpy(dk_pke, dk_kem + PUBLIC_KEY_BYTES, SEED_BYTES); + memcpy(sigma, dk_kem + PUBLIC_KEY_BYTES + SEED_BYTES, PARAM_SECURITY_BYTES); + + // Parse ciphertext c_kem + hqc_c_kem_from_string(&c_kem_t.c_pke, c_kem_t.salt, c_kem); + + // Compute message m_prime + result = hqc_pke_decrypt((uint64_t*)m_prime, dk_pke, &c_kem_t.c_pke); + + // Compute shared key K_prime and ciphertext c_kem_prime + hash_h(hash_ek_kem, ek_pke); + hash_g(K_theta_prime, hash_ek_kem, m_prime, c_kem_t.salt); + memcpy(K_prime, K_theta_prime, SHARED_SECRET_BYTES); + memcpy(theta_prime, K_theta_prime + SHARED_SECRET_BYTES, SEED_BYTES); + + hqc_pke_encrypt(&c_kem_prime_t.c_pke, ek_pke, (uint64_t*)m_prime, + theta_prime); + memcpy(c_kem_prime_t.salt, c_kem_t.salt, SALT_BYTES); + + // Compute rejection key K_bar + hash_j(K_bar, hash_ek_kem, sigma, &c_kem_t); + result |= vect_compare((uint8_t*)c_kem_t.c_pke.u, + (uint8_t*)c_kem_prime_t.c_pke.u, VEC_N_SIZE_BYTES); + result |= + vect_compare((uint8_t*)c_kem_t.c_pke.v, (uint8_t*)c_kem_prime_t.c_pke.v, + VEC_N1N2_SIZE_BYTES); + result |= vect_compare(c_kem_t.salt, c_kem_prime_t.salt, SALT_BYTES); + result -= 1; + for (size_t i = 0; i < SHARED_SECRET_BYTES; ++i) { + K_prime[i] = (K_prime[i] & result) ^ (K_bar[i] & ~result); + } + +#ifdef VERBOSE + printf("\n\nek_pke: "); + for (int i = 0; i < PUBLIC_KEY_BYTES; ++i) { + printf("%02x", ek_pke[i]); + } + printf("\n\ndk_pke: "); + for (int i = 0; i < SEED_BYTES; ++i) { + printf("%02x", dk_pke[i]); + } + printf("\n\nc_kem: "); + for (int i = 0; i < CIPHERTEXT_BYTES; ++i) { + printf("%02x", c_kem[i]); + } + printf("\n\nm_prime: "); + vect_print((uint64_t*)m_prime, PARAM_SECURITY_BYTES); + printf("\n\nH(ek_kem): "); + for (int i = 0; i < SEED_BYTES; ++i) { + printf("%02x", hash_ek_kem[i]); + } + printf("\n\ntheta_prime: "); + for (int i = 0; i < SEED_BYTES; ++i) { + printf("%02x", theta_prime[i]); + } + printf("\n\n\n# Checking Ciphertext - Begin #"); + printf("\n\nc_kem_prime_t.c_pke.u: "); + vect_print(c_kem_prime_t.c_pke.u, VEC_N_SIZE_BYTES); + printf("\n\nc_kem_prime_t.c_pke.v: "); + vect_print(c_kem_prime_t.c_pke.v, VEC_N1N2_SIZE_BYTES); + printf("\n\nsalt: "); + for (int i = 0; i < SALT_BYTES; ++i) { + printf("%02x", c_kem_prime_t.salt[i]); + } + printf("\n\n# Checking Ciphertext - End #\n"); + printf("\n\nK_prime: "); + for (int i = 0; i < SHARED_SECRET_BYTES; ++i) { + printf("%02x", K_prime[i]); + } +#endif + + // Zeroize sensitive data + memset_zero(dk_pke, sizeof dk_pke); + memset_zero(sigma, sizeof sigma); + memset_zero(m_prime, sizeof m_prime); + memset_zero(K_theta_prime, sizeof K_theta_prime); + memset_zero(K_bar, sizeof K_bar); + memset_zero(theta_prime, sizeof theta_prime); + + return 0; +} diff --git a/src/kem/hqc/hqc_ref/src/common/reed_muller.h b/src/kem/hqc/hqc_ref/src/common/reed_muller.h new file mode 100644 index 0000000000..d4c22b4ec0 --- /dev/null +++ b/src/kem/hqc/hqc_ref/src/common/reed_muller.h @@ -0,0 +1,16 @@ +/** + * @file reed_muller.h + * @brief Header file of reed_muller.c + */ + +#ifndef HQC_REED_MULLER_H +#define HQC_REED_MULLER_H + +#include +#include +#include "parameters.h" + +void reed_muller_encode(uint64_t* cdw, const uint64_t* msg); +void reed_muller_decode(uint64_t* msg, const uint64_t* cdw); + +#endif // HQC_REED_MULLER_H diff --git a/src/kem/hqc/hqc_ref/src/common/symmetric.c b/src/kem/hqc/hqc_ref/src/common/symmetric.c new file mode 100644 index 0000000000..ba6e126a14 --- /dev/null +++ b/src/kem/hqc/hqc_ref/src/common/symmetric.c @@ -0,0 +1,161 @@ +/** + * @file symmetric.c + * @brief Cryptographic primitives: a SHAKE-256–based pseudo-random number generator (PRNG) and extendable-output + * function (XOF), plus hash functions built on SHA3-256 and SHA3-512. + */ + +#include "symmetric.h" +#include + +/** + * @typedef shake256_prng_ctx + * @brief Incremental SHAKE-256 prng context. + * + */ +shake256incctx shake256_prng_ctx; + +/** + * @brief SHAKE-256 with incremental API and domain separation + * + * Derived from function SHAKE_256 in fips202.c + * + * @param[in] entropy_input Pointer to input entropy bytes + * @param[in] personalization_string Pointer to the personalization string + * @param[in] enlen Length of entropy string in bytes + * @param[in] perlen Length of the personalization string in bytes + */ +void prng_init(uint8_t *entropy_input, uint8_t *personalization_string, uint32_t enlen, uint32_t perlen) { + uint8_t domain = HQC_PRNG_DOMAIN; + shake256_inc_init(&shake256_prng_ctx); + shake256_inc_absorb(&shake256_prng_ctx, entropy_input, enlen); + shake256_inc_absorb(&shake256_prng_ctx, personalization_string, perlen); + shake256_inc_absorb(&shake256_prng_ctx, &domain, 1); + shake256_inc_finalize(&shake256_prng_ctx); +} + +/** + * @brief A SHAKE-256 based PRNG + * + * Derived from function SHAKE_256 in fips202.c + * + * @param[out] output Pointer to output + * @param[in] outlen length of output in bytes + */ +void prng_get_bytes(uint8_t *output, uint32_t outlen) { + shake256_inc_squeeze(output, outlen, &shake256_prng_ctx); +} + +/** + * @brief Initializes a SHAKE256 XOF context with a given seed. + * + * @param[out] xof_ctx Pointer to the XOF context to be initialized. + * @param[in] seed Pointer to the input seed. + * @param[in] seed_size Size of the seed in bytes. + */ +void xof_init(shake256_xof_ctx *xof_ctx, const uint8_t *seed, uint32_t seed_size) { + uint8_t xof_domain = HQC_XOF_DOMAIN; + shake256_inc_init(xof_ctx); + shake256_inc_absorb(xof_ctx, seed, seed_size); + shake256_inc_absorb(xof_ctx, &xof_domain, 1); + shake256_inc_finalize(xof_ctx); +} + +/** + * @brief Extracts pseudorandom bytes from a SHAKE256 XOF context. + * + * @param[in,out] xof_ctx Pointer to the initialized XOF context. + * @param[out] output Pointer to the buffer where the output bytes will be written. + * @param[in] output_size Number of bytes to extract. + * + * @details This function squeezes the specified number of pseudorandom bytes from + * the SHAKE256 XOF context and stores them in the provided output buffer. + * The context must have been initialized beforehand using `xof_init()`. + */ +void xof_get_bytes(shake256_xof_ctx *xof_ctx, uint8_t *output, uint32_t output_size) { + const uint8_t bsize = sizeof(uint64_t); + const uint8_t remainder = output_size % bsize; + uint8_t tmp[sizeof(uint64_t)]; + shake256_inc_squeeze(output, output_size - remainder, xof_ctx); + if (remainder != 0) { + shake256_inc_squeeze(tmp, bsize, xof_ctx); + output += output_size - remainder; + for (uint8_t i = 0; i < remainder; i++) { + output[i] = tmp[i]; + } + } +} + +/** + * @brief Computes the hash function I (SHA3-512) with domain separation. + * + * @param[out] output Pointer to the buffer where the 64-byte hash output will be stored. + * @param[in] seed Pointer to the input seed to be hashed. + * + * @details This function implements the random oracle `I` as specified, + * using the SHA3-512 hash function. It produces a 64-byte output from the given seed. + */ +void hash_i(uint8_t *output, const uint8_t *seed) { + sha3_512_ctx i_hash_ctx = {0}; + uint8_t i_domain = HQC_I_FCT_DOMAIN; + sha3_512_inc_init(&i_hash_ctx); + sha3_512_inc_absorb(&i_hash_ctx, seed, SEED_BYTES); + sha3_512_inc_absorb(&i_hash_ctx, &i_domain, 1); + sha3_512_inc_finalize(output, &i_hash_ctx); +} + +/** + * @brief Compute the hash function H (SHA3-256) with domain separation. + * + * @param[out] output Buffer (32 bytes) to receive the hash output. + * @param[in] ek_kem Encapsulation key of the KEM. + */ +void hash_h(uint8_t *output, const uint8_t ek_kem[PUBLIC_KEY_BYTES]) { + sha3_256_ctx h_hash_ctx = {0}; + uint8_t h_domain = HQC_H_FCT_DOMAIN; + sha3_256_inc_init(&h_hash_ctx); + sha3_256_inc_absorb(&h_hash_ctx, ek_kem, PUBLIC_KEY_BYTES); + sha3_256_inc_absorb(&h_hash_ctx, &h_domain, 1); + sha3_256_inc_finalize(output, &h_hash_ctx); +} + +/** + * @brief Compute the hash function G (SHA3-512) with domain separation. + * + * @param[out] output Buffer (64 bytes) to receive the hash output. + * @param[in] hash_ek_kem Hash of the KEM encapsulation key. + * @param[in] m Message bytes. + * @param[in] salt Salt value. + */ +void hash_g(uint8_t *output, const uint8_t hash_ek_kem[SEED_BYTES], const uint8_t m[PARAM_SECURITY_BYTES], + const uint8_t salt[SALT_BYTES]) { + sha3_512_ctx g_hash_ctx = {0}; + uint8_t i_domain = HQC_G_FCT_DOMAIN; + sha3_512_inc_init(&g_hash_ctx); + sha3_512_inc_absorb(&g_hash_ctx, hash_ek_kem, SEED_BYTES); + sha3_512_inc_absorb(&g_hash_ctx, m, PARAM_SECURITY_BYTES); + sha3_512_inc_absorb(&g_hash_ctx, salt, SALT_BYTES); + sha3_512_inc_absorb(&g_hash_ctx, &i_domain, 1); + sha3_512_inc_finalize(output, &g_hash_ctx); +} + +/** + * @brief Compute the hash function J (SHA3-256) with domain separation. + * + * @param[out] output Buffer (32 bytes) to receive the hash output. + * @param[in] hash_ek_kem Hash of the KEM encapsulation key. + * @param[in] sigma The string sigma. + * @param[in] c_kem Pointer to ciphertext struct (includes c_pke.u, c_pke.v, and salt). + */ +void hash_j(uint8_t *output, const uint8_t hash_ek_kem[SEED_BYTES], const uint8_t sigma[PARAM_SECURITY_BYTES], + const ciphertext_kem_t *c_kem) { + sha3_256_ctx k_hash_ctx = {0}; + uint8_t k_domain = HQC_J_FCT_DOMAIN; + sha3_256_inc_init(&k_hash_ctx); + sha3_256_inc_absorb(&k_hash_ctx, hash_ek_kem, SEED_BYTES); + sha3_256_inc_absorb(&k_hash_ctx, sigma, PARAM_SECURITY_BYTES); + sha3_256_inc_absorb(&k_hash_ctx, (uint8_t *)c_kem->c_pke.u, VEC_N_SIZE_BYTES); + sha3_256_inc_absorb(&k_hash_ctx, (uint8_t *)c_kem->c_pke.v, VEC_N1N2_SIZE_BYTES); + sha3_256_inc_absorb(&k_hash_ctx, c_kem->salt, SALT_BYTES); + sha3_256_inc_absorb(&k_hash_ctx, &k_domain, 1); + sha3_256_inc_finalize(output, &k_hash_ctx); +} diff --git a/src/kem/hqc/hqc_ref/src/common/symmetric.h b/src/kem/hqc/hqc_ref/src/common/symmetric.h new file mode 100644 index 0000000000..cd7e2ea1e1 --- /dev/null +++ b/src/kem/hqc/hqc_ref/src/common/symmetric.h @@ -0,0 +1,84 @@ +/** + * @file symmetric.h + * @brief Header file of symmetric.c + */ + +#ifndef HQC_SYMMETRIC_H +#define HQC_SYMMETRIC_H + +#include +#include "data_structures.h" +#include "fips202.h" +#include "parameters.h" + +/** + * @typedef sha3_512_ctx + * @brief Incremental SHA3-512 hashing context. + * + * Alias for the low-level `sha3_512incctx`, used to + * accumulate input and squeeze out a 512-bit digest. + */ +typedef sha3_512incctx sha3_512_ctx; + +/** + * @typedef sha3_256_ctx + * @brief Incremental SHA3-256 hashing context. + * + * Alias for the low-level `sha3_256incctx`, used to + * accumulate input and squeeze out a 256-bit digest. + */ +typedef sha3_256incctx sha3_256_ctx; + +/** + * @typedef shake256_xof_ctx + * @brief Incremental SHAKE-256 extendable-output context. + * + * Alias for `shake256incctx`, used to absorb input and + * generate arbitrary-length XOF output. + */ +typedef shake256incctx shake256_xof_ctx; + +/** @def HQC_PRNG_DOMAIN + * @brief Domain separator for HQC prng function. + */ +#define HQC_PRNG_DOMAIN 0 + +/** @def HQC_XOF_DOMAIN + * @brief Domain separator for HQC extendable-output function. + */ +#define HQC_XOF_DOMAIN 1 + +/** @def HQC_G_FCT_DOMAIN + * @brief Domain separator for the G(·) function in HQC. + */ +#define HQC_G_FCT_DOMAIN 0 + +/** @def HQC_H_FCT_DOMAIN + * @brief Domain separator for the H(·) function in HQC. + */ +#define HQC_H_FCT_DOMAIN 1 + +/** @def HQC_I_FCT_DOMAIN + * @brief Domain separator for the I(·) function in HQC. + */ +#define HQC_I_FCT_DOMAIN 2 + +/** @def HQC_J_FCT_DOMAIN + * @brief Domain separator for the J(·) function in HQC. + */ +#define HQC_J_FCT_DOMAIN 3 + +void prng_init(uint8_t *entropy_input, uint8_t *personalization_string, uint32_t enlen, uint32_t perlen); +void prng_get_bytes(uint8_t *output, uint32_t outlen); + +void xof_init(shake256_xof_ctx *xof_ctx, const uint8_t *seed, uint32_t seed_size); +void xof_get_bytes(shake256_xof_ctx *xof_ctx, uint8_t *output, uint32_t output_size); + +void hash_g(uint8_t *output, const uint8_t h_ek[SEED_BYTES], const uint8_t m[VEC_K_SIZE_BYTES], + const uint8_t salt[SALT_BYTES]); +void hash_h(uint8_t *output, const uint8_t pk[PUBLIC_KEY_BYTES]); +void hash_i(uint8_t *output, const uint8_t *seed); +void hash_j(uint8_t *output, const uint8_t h_ek[SEED_BYTES], const uint8_t sigma[VEC_K_SIZE_BYTES], + const ciphertext_kem_t *c_kem); + +#endif // HQC_SYMMETRIC_H diff --git a/src/kem/hqc/hqc_ref/src/ref/data_structures.h b/src/kem/hqc/hqc_ref/src/ref/data_structures.h new file mode 100644 index 0000000000..c60292730c --- /dev/null +++ b/src/kem/hqc/hqc_ref/src/ref/data_structures.h @@ -0,0 +1,46 @@ +/** + * @file data_structures.h + * @brief HQC-PKE and HQC-KEM ciphertext data structures. + */ + +#ifndef HQC_DATA_STRUCTURES_H +#define HQC_DATA_STRUCTURES_H + +#include +#include "parameters.h" + +/** + * @brief Public-key encryption ciphertext. + * + * - u: length VEC_N_SIZE_64 words + * - v: length VEC_N_SIZE_64 words + */ +typedef struct { + uint64_t u[VEC_N_SIZE_64]; /**< first vector half */ + uint64_t v[VEC_N_SIZE_64]; /**< second vector half */ +} ciphertext_pke_t; + +/** + * @brief Key-encapsulation mechanism ciphertext. + * + * Wraps a PKE ciphertext along with the salt used in the KEM: + * - c_pke: the ciphertext for PKE + * - salt: additional randomness (SALT_BYTES bytes) + */ +typedef struct { + ciphertext_pke_t c_pke; /**< embedded PKE ciphertext */ + uint8_t salt[SALT_BYTES]; /**< per-encapsulation salt */ +} ciphertext_kem_t; + +/** + * @brief 128-bit codeword representation. + * + * A Reed-Muller RM(1,7) codeword is 128 bits long. This union allows + * viewing the same data as an array of bytes or 32-bit words. + */ +typedef union { + uint8_t u8[16]; /**< Byte-wise access (16 bytes) */ + uint32_t u32[4]; /**< Word-wise access (4 32-bit words) */ +} rm_codeword_t; + +#endif // HQC_DATA_STRUCTURES_H diff --git a/src/kem/hqc/hqc_ref/src/ref/gf.c b/src/kem/hqc/hqc_ref/src/ref/gf.c new file mode 100644 index 0000000000..7021029057 --- /dev/null +++ b/src/kem/hqc/hqc_ref/src/ref/gf.c @@ -0,0 +1,198 @@ +/** + * @file gf.c + * @brief Galois field implementation with multiplication using the pclmulqdq instruction + */ + +#include "gf.h" +#include +#include "parameters.h" + +static uint16_t gf_reduce(uint16_t x); +void gf_carryless_mul(uint8_t *c, uint8_t a, uint8_t b); + +/** + * @brief Generates exp and log lookup tables of GF(2^8). + * + * @note this function is not used in the code; it was used to generate + * the lookup table for GF(2^8). + * + * The logarithm of 0 is defined as 2^8 by convention.
+ * The last two elements of the exp table are needed by the gf_mul function from gf_lutmul.c + * (for example if both elements to multiply are zero). + * @param[out] exp Array of size 2^8 + 2 receiving the powers of the primitive element + * @param[out] log Array of size 2^8 receiving the logarithms of the elements of GF(2^m) + * @param[in] m Parameter of Galois field GF(2^m) + */ +void gf_generate(uint16_t *exp, uint16_t *log, const int16_t m) { + uint16_t elt = 1; + uint16_t alpha = 2; // primitive element of GF(2^8) + uint16_t gf_poly = PARAM_GF_POLY; + + for (size_t i = 0; i < (1U << m) - 1; ++i) { + exp[i] = elt; + log[elt] = i; + + elt *= alpha; + if (elt >= 1 << m) + elt ^= gf_poly; + } + + exp[(1 << m) - 1] = 1; + exp[1 << m] = 2; + exp[(1 << m) + 1] = 4; + log[0] = 0; // by convention +} + +/** + * @brief Feedback bit positions used for modular reduction by PARAM_GF_POLY = 0x11D. + * + * These values are derived from the binary form of the polynomial: + * 0x11D = 0b100011101 → bits set at positions: 8, 4, 3, 1, 0 + * + * To reduce a polynomial modulo this irreducible polynomial: + * - Bit 8 (the leading term) is handled via shifting: mod = x >> 8 + * - Bit 0 (constant term) is handled by the initial XOR + * + * The remaining set bits at positions 4, 3, and 2 define where the shifted + * high bits (mod) must be XORed back into the result. These represent the + * feedback positions used during reduction. + */ +static const uint8_t gf_reduction_taps[] = {4, 3, 2}; + +/** + * @brief Reduce a polynomial modulo PARAM_GF_POLY in GF(2^8). + * + * This function performs modular reduction of a 16-bit polynomial `x` + * by the irreducible polynomial PARAM_GF_POLY = 0x11D + * (i.e., x⁸ + x⁴ + x³ + x + 1), used in GF(2^8). + * + * It assumes the input polynomial has degree ≤ 14 and uses a fixed + * number of reduction steps and fixed feedback tap positions + * ({4, 3, 2}) to produce a result of degree < 8. + * + * @param x 16-bit input polynomial to reduce (deg(x) ≤ 14) + * @return Reduced 8-bit polynomial modulo PARAM_GF_POLY (deg(x) < 8) + */ +uint16_t gf_reduce(uint16_t x) { + uint64_t mod; + const int reduction_steps = 2; // For deg(x) = 2 * (8 - 1) = 14, reduce twice to bring degree < 8 + const size_t gf_reduction_tap_count = 3; // Number of feedback positions + + for (int i = 0; i < reduction_steps; ++i) { + mod = x >> PARAM_M; // Extract upper bits + x &= (1 << PARAM_M) - 1; // Keep lower bits + x ^= mod; // Pre-XOR with no shift + + uint16_t z1 = 0; + for (size_t j = gf_reduction_tap_count; j; --j) { + uint16_t z2 = gf_reduction_taps[j - 1]; + uint16_t dist = z2 - z1; + mod <<= dist; + x ^= mod; + z1 = z2; + } + } + + return x; +} + +/** + * Carryless multiplication of two polynomials a and b. + * + * Implementation of the algorithm mul1 in https://hal.inria.fr/inria-00188261v4/document + * with s = 2 and w = 8 + * + * @param[out] c polynomial c = a * b + * @param[in] a The first polynomial + * @param[in] b The second polynomial + */ +void gf_carryless_mul(uint8_t *c, uint8_t a, uint8_t b) { + uint16_t h = 0, l = 0, g, u[4]; + u[0] = 0; + u[1] = b & ((1UL << 7) - 1UL); + u[2] = u[1] << 1; + u[3] = u[2] ^ u[1]; + + g = 0; + uint16_t tmp1 = a & 3; + + for (int i = 0; i < 4; i++) { + uint32_t tmp2 = tmp1 - i; + g ^= (u[i] & -(1 - ((tmp2 | -tmp2) >> 31))); + } + + l = g; + h = 0; + + for (uint8_t i = 2; i < 8; i += 2) { + g = 0; + uint16_t tmp3 = (a >> i) & 3; + for (int j = 0; j < 4; ++j) { + uint32_t tmp2 = tmp3 - j; + g ^= (u[j] & -(1 - ((tmp2 | -tmp2) >> 31))); + } + + l ^= g << i; + h ^= g >> (8 - i); + } + + uint16_t mask = (-((b >> 7) & 1)); + l ^= ((a << 7) & mask); + h ^= ((a >> (1)) & mask); + + c[0] = l; + c[1] = h; +} + +/** + * Multiplies two elements of GF(2^GF_M). + * @returns the product a*b + * @param[in] a Element of GF(2^GF_M) + * @param[in] b Element of GF(2^GF_M) + */ +uint16_t gf_mul(uint16_t a, uint16_t b) { + uint8_t c[2] = {0}; + gf_carryless_mul(c, (uint8_t)a, (uint8_t)b); + uint16_t tmp = (uint16_t)(c[0] ^ (c[1] << 8)); + return gf_reduce(tmp); +} + +/** + * Squares an element of GF(2^GF_M). + * @returns a^2 + * @param[in] a Element of GF(2^GF_M) + */ +uint16_t gf_square(uint16_t a) { + uint32_t b = a; + uint32_t s = b & 1; + for (size_t i = 1; i < PARAM_M; ++i) { + b <<= 1; + s ^= b & (1 << 2 * i); + } + + return gf_reduce(s); +} + +/** + * Computes the inverse of an element of GF(2^8), + * using the addition chain 1 2 3 4 7 11 15 30 60 120 127 254 + * @returns the inverse of a + * @param[in] a Element of GF(2^GF_M) + */ +uint16_t gf_inverse(uint16_t a) { + uint16_t inv = a; + uint16_t tmp1, tmp2; + + inv = gf_square(a); /* a^2 */ + tmp1 = gf_mul(inv, a); /* a^3 */ + inv = gf_square(inv); /* a^4 */ + tmp2 = gf_mul(inv, tmp1); /* a^7 */ + tmp1 = gf_mul(inv, tmp2); /* a^11 */ + inv = gf_mul(tmp1, inv); /* a^15 */ + inv = gf_square(inv); /* a^30 */ + inv = gf_square(inv); /* a^60 */ + inv = gf_square(inv); /* a^120 */ + inv = gf_mul(inv, tmp2); /* a^127 */ + inv = gf_square(inv); /* a^254 */ + return inv; +} diff --git a/src/kem/hqc/hqc_ref/src/ref/gf.h b/src/kem/hqc/hqc_ref/src/ref/gf.h new file mode 100644 index 0000000000..f00fecc1f8 --- /dev/null +++ b/src/kem/hqc/hqc_ref/src/ref/gf.h @@ -0,0 +1,55 @@ +/** + * @file gf.h + * @brief Header file of gf.c + */ + +#ifndef HQC_GF_H +#define HQC_GF_H + +#include +#include + +/** + * Powers of the root alpha of 1 + x^2 + x^3 + x^4 + x^8. + * The last two elements are needed by the gf_mul function + * (for example if both elements to multiply are zero). + */ +static const uint16_t gf_exp[258] = { + 1, 2, 4, 8, 16, 32, 64, 128, 29, 58, 116, 232, 205, 135, 19, 38, 76, 152, 45, 90, 180, 117, + 234, 201, 143, 3, 6, 12, 24, 48, 96, 192, 157, 39, 78, 156, 37, 74, 148, 53, 106, 212, 181, 119, + 238, 193, 159, 35, 70, 140, 5, 10, 20, 40, 80, 160, 93, 186, 105, 210, 185, 111, 222, 161, 95, 190, + 97, 194, 153, 47, 94, 188, 101, 202, 137, 15, 30, 60, 120, 240, 253, 231, 211, 187, 107, 214, 177, 127, + 254, 225, 223, 163, 91, 182, 113, 226, 217, 175, 67, 134, 17, 34, 68, 136, 13, 26, 52, 104, 208, 189, + 103, 206, 129, 31, 62, 124, 248, 237, 199, 147, 59, 118, 236, 197, 151, 51, 102, 204, 133, 23, 46, 92, + 184, 109, 218, 169, 79, 158, 33, 66, 132, 21, 42, 84, 168, 77, 154, 41, 82, 164, 85, 170, 73, 146, + 57, 114, 228, 213, 183, 115, 230, 209, 191, 99, 198, 145, 63, 126, 252, 229, 215, 179, 123, 246, 241, 255, + 227, 219, 171, 75, 150, 49, 98, 196, 149, 55, 110, 220, 165, 87, 174, 65, 130, 25, 50, 100, 200, 141, + 7, 14, 28, 56, 112, 224, 221, 167, 83, 166, 81, 162, 89, 178, 121, 242, 249, 239, 195, 155, 43, 86, + 172, 69, 138, 9, 18, 36, 72, 144, 61, 122, 244, 245, 247, 243, 251, 235, 203, 139, 11, 22, 44, 88, + 176, 125, 250, 233, 207, 131, 27, 54, 108, 216, 173, 71, 142, 1, 2, 4}; + +/** + * Logarithm of elements of GF(2^8) to the base alpha (root of 1 + x^2 + x^3 + x^4 + x^8). + * The logarithm of 0 is set to 0 by convention. + */ +static const uint16_t gf_log[256] = { + 0, 0, 1, 25, 2, 50, 26, 198, 3, 223, 51, 238, 27, 104, 199, 75, 4, 100, 224, 14, 52, 141, + 239, 129, 28, 193, 105, 248, 200, 8, 76, 113, 5, 138, 101, 47, 225, 36, 15, 33, 53, 147, 142, 218, + 240, 18, 130, 69, 29, 181, 194, 125, 106, 39, 249, 185, 201, 154, 9, 120, 77, 228, 114, 166, 6, 191, + 139, 98, 102, 221, 48, 253, 226, 152, 37, 179, 16, 145, 34, 136, 54, 208, 148, 206, 143, 150, 219, 189, + 241, 210, 19, 92, 131, 56, 70, 64, 30, 66, 182, 163, 195, 72, 126, 110, 107, 58, 40, 84, 250, 133, + 186, 61, 202, 94, 155, 159, 10, 21, 121, 43, 78, 212, 229, 172, 115, 243, 167, 87, 7, 112, 192, 247, + 140, 128, 99, 13, 103, 74, 222, 237, 49, 197, 254, 24, 227, 165, 153, 119, 38, 184, 180, 124, 17, 68, + 146, 217, 35, 32, 137, 46, 55, 63, 209, 91, 149, 188, 207, 205, 144, 135, 151, 178, 220, 252, 190, 97, + 242, 86, 211, 171, 20, 42, 93, 158, 132, 60, 57, 83, 71, 109, 65, 162, 31, 45, 67, 216, 183, 123, + 164, 118, 196, 23, 73, 236, 127, 12, 111, 246, 108, 161, 59, 82, 41, 157, 85, 170, 251, 96, 134, 177, + 187, 204, 62, 90, 203, 89, 95, 176, 156, 169, 160, 81, 11, 245, 22, 235, 122, 117, 44, 215, 79, 174, + 213, 233, 230, 231, 173, 232, 116, 214, 244, 234, 168, 80, 88, 175}; + +void gf_generate(uint16_t *exp, uint16_t *log, const int16_t m); + +uint16_t gf_mul(uint16_t a, uint16_t b); +uint16_t gf_square(uint16_t a); +uint16_t gf_inverse(uint16_t a); + +#endif // HQC_GF_H diff --git a/src/kem/hqc/hqc_ref/src/ref/gf2x.c b/src/kem/hqc/hqc_ref/src/ref/gf2x.c new file mode 100644 index 0000000000..26e4449e04 --- /dev/null +++ b/src/kem/hqc/hqc_ref/src/ref/gf2x.c @@ -0,0 +1,160 @@ +/** + * @file gf2x.c + * @brief Implementation of carry-less multiplication of two polynomials over GF(2) mod X^n - 1. + * + * @details + * The temporary buffer requirement for recursive Karatsuba is computed as follows: + * - At each recursion level on words of length n, karatsuba_mul needs 8*n words. + * (z0, z2, zmid each 2*n, plus ta and tb of n each: total 8*n.) + * - Child calls operate on half the length (n/2), needing 8*(n/2) words, placed immediately after. + * - Summing across levels n + n/2 + n/4 + ... < 2*n, so total < 8*n * 2 = 16*n words. + * - We set TMP_BUFFER_WORDS = 16 * VEC_N_SIZE_64 to guarantee enough space for all recursion levels. + */ + +#include "gf2x.h" +#include +#include +#include "parameters.h" + +/** @def KARATSUBA_THRESHOLD + * @brief Input size (in words) below which schoolbook_mul is used. + */ +#define KARATSUBA_THRESHOLD 16 + +/** @def TMP_BUFFER_WORDS + * @brief Total size in 64-bit words for the temporary buffer used by recursive Karatsuba. + */ +#define TMP_BUFFER_WORDS (16 * VEC_N_SIZE_64) + +/** + * @brief Schoolbook multiplication over GF(2). + * + * Computes r = a * b where a, b are length-n words, result is 2*n words. + * + * @param[out] r Result buffer, size 2*n words. + * @param[in] a Operand a, size n words. + * @param[in] b Operand b, size n words. + * @param[in] n Number of 64-bit words in a and b. + */ +static void schoolbook_mul(uint64_t *r, const uint64_t *a, const uint64_t *b, size_t n) { + memset(r, 0, 2 * n * sizeof(uint64_t)); + for (size_t i = 0; i < n; i++) { + uint64_t ai = a[i]; + for (int bit = 0; bit < 64; bit++) { + uint64_t mask = -((ai >> bit) & 1ULL); + size_t base = i; + int sh = bit; + int inv = 64 - sh; + if (sh == 0) { + for (size_t j = 0; j < n; j++) { + r[base + j] ^= b[j] & mask; + } + } else { + for (size_t j = 0; j < n; j++) { + r[base + j] ^= (b[j] << sh) & mask; + r[base + j + 1] ^= (b[j] >> inv) & mask; + } + } + } + } +} + +/** + * @brief Karatsuba multiplication using a caller-supplied temporary buffer. + * + * If n <= KARATSUBA_THRESHOLD, falls back to schoolbook_mul. + * Otherwise splits operands in half and applies recursion. + * + * @param[out] r Result buffer, size 2*n words. + * @param[in] a Operand a, size n words. + * @param[in] b Operand b, size n words. + * @param[in] n Number of 64-bit words in a and b. + * @param[in] tmp_buffer Temporary buffer, size >= 8*n words (child calls use remainder). + */ +static void karatsuba_mul(uint64_t *r, const uint64_t *a, const uint64_t *b, size_t n, uint64_t *tmp_buffer) { + if (n <= KARATSUBA_THRESHOLD) { + schoolbook_mul(r, a, b, n); + return; + } + + size_t m = n >> 1; + size_t n0 = m; + size_t n1 = n - m; + + /* take successive chunks of tmp_buffer for each intermediate result */ + uint64_t *z0 = tmp_buffer; /* low-half product, size 2*n words */ + uint64_t *z2 = z0 + 2 * n; /* high-half product, size 2*n words */ + uint64_t *zmid = z2 + 2 * n; /* middle product, size 2*n words */ + + /* ta and tb hold the sums of low and high halves: */ + /* ta[i] = a0[i] XOR a1[i], tb[i] = b0[i] XOR b1[i] for i < n1 */ + uint64_t *ta = zmid + 2 * n; + uint64_t *tb = ta + n; + + /* buffer for child recursions */ + uint64_t *child_buffer = tmp_buffer + 8 * n; + + /* 1) low * low */ + karatsuba_mul(z0, a, b, n0, child_buffer); + + /* 2) high * high */ + karatsuba_mul(z2, a + m, b + m, n1, child_buffer); + + /* 3) (a0+a1)*(b0+b1) */ + for (size_t i = 0; i < n1; i++) { + uint64_t loa = (i < n0 ? a[i] : 0); + uint64_t lob = (i < n0 ? b[i] : 0); + ta[i] = loa ^ a[m + i]; + tb[i] = lob ^ b[m + i]; + } + karatsuba_mul(zmid, ta, tb, n1, child_buffer); + + /* 4) assemble into r */ + memset(r, 0, 2 * n * sizeof(uint64_t)); + for (size_t i = 0; i < 2 * n0; i++) r[i] ^= z0[i]; + for (size_t i = 0; i < 2 * n1; i++) r[2 * m + i] ^= z2[i]; + for (size_t i = 0; i < 2 * n1; i++) { + uint64_t z0i = (i < 2 * n0 ? z0[i] : 0); + uint64_t z2i = (i < 2 * n1 ? z2[i] : 0); + uint64_t mid = zmid[i] ^ z0i ^ z2i; + r[m + i] ^= mid; + } +} + +/** + * @brief Modular reduction of a degree < 2*n polynomial mod (X^n - 1). + * + * Folds the high half of the full product back into the low half + * and masks any excess bits in the last word. + * + * @param[out] o Result buffer, size VEC_N_SIZE_64 words. + * @param[in] a Input buffer, size 2*VEC_N_SIZE_64 words. + */ +static void reduce(uint64_t *o, const uint64_t *a) { + for (size_t i = 0; i < VEC_N_SIZE_64; i++) { + uint64_t r = a[i + VEC_N_SIZE_64 - 1] >> (PARAM_N & 0x3F); + uint64_t carry = a[i + VEC_N_SIZE_64] << (64 - (PARAM_N & 0x3F)); + o[i] = a[i] ^ r ^ carry; + } + o[VEC_N_SIZE_64 - 1] &= BITMASK(PARAM_N, 64); +} + +/** + * @brief Carry-less multiplication mod (X^PARAM_N - 1). + * + * Computes o = a1 * a2, each operand of VEC_N_SIZE_64 words, then reduces. + * + * @param[out] o Result buffer, size VEC_N_SIZE_64 words. + * @param[in] a1 Operand polynomial a(x). + * @param[in] a2 Operand polynomial b(x). + */ +void vect_mul(uint64_t *o, const uint64_t *a1, const uint64_t *a2) { + uint64_t unreduced[2 * VEC_N_SIZE_64]; + uint64_t tmp_buffer[TMP_BUFFER_WORDS]; + + /* multiply via Karatsuba into unreduced */ + karatsuba_mul(unreduced, a1, a2, VEC_N_SIZE_64, tmp_buffer); + + /* reduce modulo X^n - 1 */ + reduce(o, unreduced); +} diff --git a/src/kem/hqc/hqc_ref/src/ref/gf2x.h b/src/kem/hqc/hqc_ref/src/ref/gf2x.h new file mode 100644 index 0000000000..b1ef4e180f --- /dev/null +++ b/src/kem/hqc/hqc_ref/src/ref/gf2x.h @@ -0,0 +1,13 @@ +/** + * @file gf2x.h + * @brief Header file for gf2x.c + */ + +#ifndef HQC_GF2X_H +#define HQC_GF2X_H + +#include + +void vect_mul(uint64_t *o, const uint64_t *v1, const uint64_t *v2); + +#endif // HQC_GF2X_H diff --git a/src/kem/hqc/hqc_ref/src/ref/hqc-1/parameters.h b/src/kem/hqc/hqc_ref/src/ref/hqc-1/parameters.h new file mode 100644 index 0000000000..e333cd33df --- /dev/null +++ b/src/kem/hqc/hqc_ref/src/ref/hqc-1/parameters.h @@ -0,0 +1,57 @@ +/** +* @file parameters.h +* @brief Parameters of the HQC-KEM IND-CCA2 scheme + */ + +#ifndef HQC_PARAMETERS_H +#define HQC_PARAMETERS_H + +#include "api.h" + +#define CEIL_DIVIDE(a, b) (((a) / (b)) + ((a) % (b) == 0 ? 0 : 1)) /*!< Divide a by b and ceil the result*/ +#define BITMASK(a, size) ((1UL << (a % size)) - 1) /*!< Create a mask*/ + +#define PARAM_N 17669 ///< Define the parameter n of the scheme +#define PARAM_N1 46 ///< Define the parameter n1 of the scheme (length of Reed–Solomon code) +#define PARAM_N2 384 ///< Define the parameter n2 of the scheme (length of Duplicated Reed–Muller code) +#define PARAM_N1N2 17664 ///< Define the length in bits of the concatenated code +#define PARAM_OMEGA 66 ///< Define the parameter omega of the scheme +#define PARAM_OMEGA_E 75 ///< Define the parameter omega_e of the scheme +#define PARAM_OMEGA_R 75 ///< Define the parameter omega_r of the scheme +#define PARAM_SECURITY 128 ///< Define the security level corresponding to the chosen parameters +#define PARAM_SECURITY_BYTES 16 ///< Define the security level in bytes +#define PARAM_DFR_EXP 128 ///< Define the decryption failure rate exponent + +#define SECRET_KEY_BYTES CRYPTO_SECRETKEYBYTES ///< Define the size of the secret key in bytes +#define PUBLIC_KEY_BYTES CRYPTO_PUBLICKEYBYTES ///< Define the size of the public key in bytes +#define SHARED_SECRET_BYTES CRYPTO_BYTES ///< Define the size of the shared secret in bytes +#define CIPHERTEXT_BYTES CRYPTO_CIPHERTEXTBYTES ///< Define the size of the ciphertext in bytes + +#define VEC_N_SIZE_BYTES CEIL_DIVIDE(PARAM_N, 8) ///< Size of array to store PARAM_N bits in bytes +#define VEC_K_SIZE_BYTES PARAM_K ///< Size of array to store PARAM_K bits in bytes +#define VEC_N1_SIZE_BYTES PARAM_N1 ///< Size of array to store PARAM_N1 bits in bytes +#define VEC_N1N2_SIZE_BYTES CEIL_DIVIDE(PARAM_N1N2, 8) ///< Size of array to store PARAM_N1N2 bits in bytes + +#define VEC_N_SIZE_64 CEIL_DIVIDE(PARAM_N, 64) ///< Size of array to store PARAM_N bits in 64-bit words +#define VEC_N1_SIZE_64 CEIL_DIVIDE(PARAM_N1, 8) ///< Size of array to store PARAM_N1 bits in 64-bit words +#define VEC_N1N2_SIZE_64 CEIL_DIVIDE(PARAM_N1N2, 64) ///< Size of array to store PARAM_N1N2 bits in 64-bit words + +#define PARAM_DELTA 15 ///< Define the error-correcting capacity (delta) of the Reed–Solomon code +#define PARAM_M 8 ///< Define the degree m of the Galois field GF(2^m) +#define PARAM_GF_POLY 0x11D ///< Generator polynomial of GF(2^PARAM_M) in hexadecimal form +#define PARAM_GF_MUL_ORDER 255 ///< Size of the multiplicative group of GF(2^PARAM_M) (2^PARAM_M−1) +#define PARAM_K 16 ///< Define the size of the information bits of the Reed–Solomon code +#define PARAM_G 31 ///< Define the size of the generator polynomial of the Reed–Solomon code +#define PARAM_FFT 4 ///< Exponent for additive FFT (2^PARAM_FFT points) + +#define 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 ///< Coefficients of the Reed–Solomon generator polynomial + +#define SEED_BYTES 32 ///< Define the size of the seed in bytes +#define SALT_BYTES 16 ///< Define the size of a salt in bytes + +#define PARAM_N_MU 243079ULL ///< Define a precomputed multiplier for Barrett reduction mu = floor(2^32 / PARAM_N) +#define UTILS_REJECTION_THRESHOLD 16767881 ///< Rejection threshold for uniform sampling in [0, PARAM_N) + +#endif // HQC_PARAMETERS_H diff --git a/src/kem/hqc/hqc_ref/src/ref/hqc-1/reed_solomon.h b/src/kem/hqc/hqc_ref/src/ref/hqc-1/reed_solomon.h new file mode 100644 index 0000000000..c835689889 --- /dev/null +++ b/src/kem/hqc/hqc_ref/src/ref/hqc-1/reed_solomon.h @@ -0,0 +1,88 @@ +/** + * @file reed_solomon.h + * @brief Header file of reed_solomon.c + */ + +#ifndef HQC_REED_SOLOMON_H +#define HQC_REED_SOLOMON_H + +#include +#include +#include "parameters.h" + +/** + * @brief Precomputed Galois‐field powers for Reed–Solomon operations. + * + * In GF(2^8) with primitive element \f$\alpha\f$, this table holds + * \f$\alpha^{i \cdot j}\f$ for + * - row index \e i in [0 … 29], + * - column index \e j in [0 … 44]. + */ +static const uint16_t alpha_ij_pow[30][45] = { + {2, 4, 8, 16, 32, 64, 128, 29, 58, 116, 232, 205, 135, 19, 38, 76, 152, 45, 90, 180, 117, 234, 201, + 143, 3, 6, 12, 24, 48, 96, 192, 157, 39, 78, 156, 37, 74, 148, 53, 106, 212, 181, 119, 238, 193}, + {4, 16, 64, 29, 116, 205, 19, 76, 45, 180, 234, 143, 6, 24, 96, 157, 78, 37, 148, 106, 181, 238, 159, + 70, 5, 20, 80, 93, 105, 185, 222, 95, 97, 153, 94, 101, 137, 30, 120, 253, 211, 107, 177, 254, 223}, + {8, 64, 58, 205, 38, 45, 117, 143, 12, 96, 39, 37, 53, 181, 193, 70, 10, 80, 186, 185, 161, 97, 47, + 101, 15, 120, 231, 107, 127, 223, 182, 217, 134, 68, 26, 208, 206, 62, 237, 59, 197, 102, 23, 184, 169}, + {16, 29, 205, 76, 180, 143, 24, 157, 37, 106, 238, 70, 20, 93, 185, 95, 153, 101, 30, 253, 107, 254, 91, + 217, 17, 13, 208, 129, 248, 59, 151, 133, 184, 79, 132, 168, 82, 73, 228, 230, 198, 252, 123, 227, 150}, + {32, 116, 38, 180, 3, 96, 156, 106, 193, 5, 160, 185, 190, 94, 15, 253, 214, 223, 226, 17, 26, 103, 124, + 59, 51, 46, 169, 132, 77, 85, 114, 230, 145, 215, 255, 150, 55, 174, 100, 28, 167, 89, 239, 172, 36}, + {64, 205, 45, 143, 96, 37, 181, 70, 80, 185, 97, 101, 120, 107, 223, 217, 68, 208, 62, 59, 102, 184, 33, + 168, 85, 228, 191, 252, 241, 150, 110, 130, 7, 221, 89, 195, 138, 61, 251, 44, 207, 173, 8, 58, 38}, + {128, 19, 117, 24, 156, 181, 140, 93, 161, 94, 60, 107, 163, 67, 26, 129, 147, 102, 109, 132, 41, 57, 209, + 252, 255, 98, 87, 200, 224, 89, 155, 18, 245, 11, 233, 173, 16, 232, 45, 3, 157, 53, 159, 40, 185}, + {29, 76, 143, 157, 106, 70, 93, 95, 101, 253, 254, 217, 13, 129, 59, 133, 79, 168, 73, 230, 252, 227, 149, + 130, 28, 81, 195, 18, 247, 44, 27, 2, 58, 152, 3, 39, 212, 140, 186, 190, 202, 231, 225, 175, 26}, + {58, 45, 12, 37, 193, 80, 161, 101, 231, 223, 134, 208, 237, 102, 169, 168, 146, 191, 179, 150, 87, 7, 166, + 195, 36, 251, 125, 173, 64, 38, 143, 39, 181, 10, 185, 47, 120, 127, 217, 26, 62, 197, 184, 21, 85}, + {116, 180, 96, 106, 5, 185, 94, 253, 223, 17, 103, 59, 46, 132, 85, 230, 215, 150, 174, 28, 89, 172, 244, + 44, 108, 32, 38, 3, 156, 193, 160, 190, 15, 214, 226, 26, 124, 51, 169, 77, 114, 145, 255, 55, 100}, + {232, 234, 39, 238, 160, 97, 60, 254, 134, 103, 118, 184, 84, 57, 145, 227, 220, 7, 162, 172, 245, 176, 71, + 58, 180, 192, 181, 40, 95, 15, 177, 175, 208, 147, 46, 21, 73, 99, 241, 55, 200, 166, 43, 122, 44}, + {205, 143, 37, 70, 185, 101, 107, 217, 208, 59, 184, 168, 228, 252, 150, 130, 221, 195, 61, 44, 173, 58, 117, + 39, 193, 186, 47, 231, 182, 26, 237, 23, 21, 146, 145, 219, 87, 56, 242, 36, 139, 54, 64, 45, 96}, + {135, 6, 53, 20, 190, 120, 163, 13, 237, 46, 84, 228, 229, 98, 100, 81, 69, 251, 131, 32, 45, 192, 238, + 186, 94, 187, 217, 189, 236, 169, 82, 209, 241, 220, 28, 242, 72, 22, 173, 116, 201, 37, 140, 222, 15}, + {19, 24, 181, 93, 94, 107, 67, 129, 102, 132, 57, 252, 98, 200, 89, 18, 11, 173, 232, 3, 53, 40, 194, + 231, 226, 189, 197, 158, 170, 145, 75, 25, 166, 69, 235, 54, 29, 234, 37, 5, 95, 120, 91, 52, 59}, + {38, 96, 193, 185, 15, 223, 26, 59, 169, 85, 145, 150, 100, 89, 36, 44, 1, 38, 96, 193, 185, 15, 223, + 26, 59, 169, 85, 145, 150, 100, 89, 36, 44, 1, 38, 96, 193, 185, 15, 223, 26, 59, 169, 85, 145}, + {76, 157, 70, 95, 253, 217, 129, 133, 168, 230, 227, 130, 81, 18, 44, 2, 152, 39, 140, 190, 231, 175, 31, + 23, 77, 209, 219, 25, 162, 36, 88, 4, 45, 78, 5, 97, 211, 67, 62, 46, 154, 191, 171, 50, 89}, + {152, 78, 10, 153, 214, 68, 147, 79, 146, 215, 220, 221, 69, 11, 1, 152, 78, 10, 153, 214, 68, 147, 79, + 146, 215, 220, 221, 69, 11, 1, 152, 78, 10, 153, 214, 68, 147, 79, 146, 215, 220, 221, 69, 11, 1}, + {45, 37, 80, 101, 223, 208, 102, 168, 191, 150, 7, 195, 251, 173, 38, 39, 10, 47, 127, 26, 197, 21, 115, + 219, 100, 242, 245, 54, 205, 96, 70, 97, 107, 68, 59, 33, 228, 241, 130, 89, 61, 207, 58, 12, 193}, + {90, 148, 186, 30, 226, 62, 109, 73, 179, 174, 162, 61, 131, 232, 96, 140, 153, 127, 52, 51, 168, 99, 98, + 56, 172, 22, 8, 234, 212, 185, 240, 67, 237, 79, 114, 241, 25, 121, 245, 108, 19, 39, 20, 188, 223}, + {180, 106, 185, 253, 17, 59, 132, 230, 150, 28, 172, 44, 32, 3, 193, 190, 214, 26, 51, 77, 145, 55, 167, + 36, 233, 116, 96, 5, 94, 223, 103, 46, 85, 215, 174, 89, 244, 108, 38, 156, 160, 15, 226, 124, 169}, + {117, 181, 161, 107, 26, 102, 41, 252, 87, 89, 245, 173, 45, 53, 185, 231, 68, 197, 168, 145, 110, 166, 61, + 54, 38, 37, 186, 120, 134, 59, 21, 191, 196, 221, 36, 207, 205, 39, 80, 15, 217, 237, 33, 115, 150}, + {234, 238, 97, 254, 103, 184, 57, 227, 7, 172, 176, 58, 192, 40, 15, 175, 147, 21, 99, 55, 166, 122, 216, + 45, 106, 222, 107, 52, 133, 85, 123, 50, 195, 11, 32, 12, 140, 188, 182, 124, 158, 115, 49, 224, 36}, + {201, 159, 47, 91, 124, 33, 209, 149, 166, 244, 71, 117, 238, 194, 223, 31, 79, 115, 98, 167, 61, 216, 90, + 181, 190, 254, 206, 218, 213, 150, 224, 72, 54, 152, 106, 161, 177, 189, 184, 114, 171, 56, 18, 131, 38}, + {143, 70, 101, 217, 59, 168, 252, 130, 195, 44, 58, 39, 186, 231, 26, 23, 146, 219, 56, 36, 54, 45, 181, + 97, 223, 62, 33, 191, 110, 89, 251, 8, 12, 10, 15, 134, 197, 41, 179, 100, 86, 125, 205, 37, 185}, + {3, 5, 15, 17, 51, 85, 255, 28, 36, 108, 180, 193, 94, 226, 59, 77, 215, 100, 172, 233, 38, 106, 190, + 223, 124, 132, 145, 174, 239, 44, 116, 156, 185, 214, 103, 169, 230, 55, 89, 235, 32, 96, 160, 253, 26}, + {6, 20, 120, 13, 46, 228, 98, 81, 251, 32, 192, 186, 187, 189, 169, 209, 220, 242, 22, 116, 37, 222, 254, + 62, 132, 63, 130, 43, 250, 38, 212, 194, 182, 147, 77, 179, 141, 9, 54, 180, 159, 101, 67, 151, 85}, + {12, 80, 231, 208, 169, 191, 87, 195, 125, 38, 181, 47, 217, 197, 85, 219, 221, 245, 8, 96, 186, 107, 206, + 33, 145, 130, 86, 207, 45, 193, 101, 134, 102, 146, 150, 166, 251, 64, 39, 185, 127, 62, 21, 252, 100}, + {24, 93, 107, 129, 132, 252, 200, 18, 173, 3, 40, 231, 189, 158, 145, 25, 69, 54, 234, 5, 120, 52, 218, + 191, 174, 43, 207, 90, 35, 15, 136, 92, 115, 220, 239, 125, 76, 238, 101, 17, 133, 228, 149, 121, 44}, + {48, 105, 127, 248, 77, 241, 224, 247, 64, 156, 95, 182, 236, 170, 150, 162, 11, 205, 212, 94, 134, 133, 213, + 110, 239, 250, 45, 35, 30, 26, 218, 99, 130, 69, 108, 143, 40, 211, 206, 132, 229, 7, 144, 2, 96}, + {96, 185, 223, 59, 85, 150, 89, 44, 38, 193, 15, 26, 169, 145, 100, 36, 1, 96, 185, 223, 59, 85, 150, + 89, 44, 38, 193, 15, 26, 169, 145, 100, 36, 1, 96, 185, 223, 59, 85, 150, 89, 44, 38, 193, 15}}; + +void reed_solomon_encode(uint64_t* cdw, const uint64_t* msg); +void reed_solomon_decode(uint64_t* msg, uint64_t* cdw); + +void compute_generator_poly(uint16_t* poly); + +#endif // HQC_REED_SOLOMOM_H diff --git a/src/kem/hqc/hqc_ref/src/ref/hqc-3/parameters.h b/src/kem/hqc/hqc_ref/src/ref/hqc-3/parameters.h new file mode 100644 index 0000000000..f34f912a0e --- /dev/null +++ b/src/kem/hqc/hqc_ref/src/ref/hqc-3/parameters.h @@ -0,0 +1,57 @@ +/** +* @file parameters.h +* @brief Parameters of the HQC-KEM IND-CCA2 scheme + */ + +#ifndef HQC_PARAMETERS_H +#define HQC_PARAMETERS_H + +#include "api.h" + +#define CEIL_DIVIDE(a, b) (((a) / (b)) + ((a) % (b) == 0 ? 0 : 1)) /*!< Divide a by b and ceil the result*/ +#define BITMASK(a, size) ((1UL << (a % size)) - 1) /*!< Create a mask*/ + +#define PARAM_N 35851 ///< Define the parameter n of the scheme +#define PARAM_N1 56 ///< Define the parameter n1 of the scheme (length of Reed-Solomon code) +#define PARAM_N2 640 ///< Define the parameter n2 of the scheme (length of Duplicated Reed-Muller code) +#define PARAM_N1N2 35840 ///< Define the length in bits of the concatenated code +#define PARAM_OMEGA 100 ///< Define the parameter omega of the scheme +#define PARAM_OMEGA_E 114 ///< Define the parameter omega_e of the scheme +#define PARAM_OMEGA_R 114 ///< Define the parameter omega_r of the scheme +#define PARAM_SECURITY 192 ///< Define the security level corresponding to the chosen parameters +#define PARAM_SECURITY_BYTES 24 ///< Define the security level in bytes +#define PARAM_DFR_EXP 192 ///< Define the decryption failure rate corresponding to the chosen parameters + +#define SECRET_KEY_BYTES CRYPTO_SECRETKEYBYTES ///< Define the size of the secret key in bytes +#define PUBLIC_KEY_BYTES CRYPTO_PUBLICKEYBYTES ///< Define the size of the public key in bytes +#define SHARED_SECRET_BYTES CRYPTO_BYTES ///< Define the size of the shared secret in bytes +#define CIPHERTEXT_BYTES CRYPTO_CIPHERTEXTBYTES ///< Define the size of the ciphertext in bytes + +#define VEC_N_SIZE_BYTES CEIL_DIVIDE(PARAM_N, 8) ///< Size of array to store PARAM_N bits in bytes +#define VEC_K_SIZE_BYTES PARAM_K ///< Size of array to store PARAM_K bits in bytes +#define VEC_N1_SIZE_BYTES PARAM_N1 ///< Size of array to store PARAM_N1 bits in bytes +#define VEC_N1N2_SIZE_BYTES CEIL_DIVIDE(PARAM_N1N2, 8) ///< Size of array to store PARAM_N1N2 bits in bytes + +#define VEC_N_SIZE_64 CEIL_DIVIDE(PARAM_N, 64) ///< Size of array to store PARAM_N bits in 64-bit words +#define VEC_N1_SIZE_64 CEIL_DIVIDE(PARAM_N1, 8) ///< Size of array to store PARAM_N1 bits in 64-bit words +#define VEC_N1N2_SIZE_64 CEIL_DIVIDE(PARAM_N1N2, 64) ///< Size of array to store PARAM_N1N2 bits in 64-bit words + +#define PARAM_DELTA 16 ///< Define the error-correcting capacity (delta) of the Reed-Solomon code +#define PARAM_M 8 ///< Define the degree m of the Galois field GF(2^m) +#define PARAM_GF_POLY 0x11D ///< Generator polynomial of GF(2^PARAM_M) in hexadecimal form +#define PARAM_GF_MUL_ORDER 255 ///< Size of the multiplicative group of GF(2^PARAM_M) (i.e., 2^PARAM_M−1) +#define PARAM_K 24 ///< Define the size of the information bits of the Reed-Solomon code +#define PARAM_G 33 ///< Define the size of the generator polynomial of the Reed-Solomon code +#define PARAM_FFT 5 ///< Exponent for additive FFT (2^PARAM_FFT points) + +#define 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 ///< Coefficients of the Reed-Solomon generator polynomial + +#define SEED_BYTES 32 ///< Define the size of the seed in bytes +#define SALT_BYTES 16 ///< Define the size of a salt in bytes + +#define PARAM_N_MU 119800ULL ///< Define a precomputed multiplier for Barrett reduction mu = floor(2^32 / PARAM_N) +#define UTILS_REJECTION_THRESHOLD 16742417 ///< Rejection threshold for uniform sampling in [0, PARAM_N) + +#endif // HQC_PARAMETERS_H diff --git a/src/kem/hqc/hqc_ref/src/ref/hqc-3/reed_solomon.h b/src/kem/hqc/hqc_ref/src/ref/hqc-3/reed_solomon.h new file mode 100644 index 0000000000..14b09373b6 --- /dev/null +++ b/src/kem/hqc/hqc_ref/src/ref/hqc-3/reed_solomon.h @@ -0,0 +1,124 @@ +/** + * @file reed_solomon.h + * @brief Header file of reed_solomon.c + */ + +#ifndef HQC_REED_SOLOMON_H +#define HQC_REED_SOLOMON_H + +#include +#include +#include "parameters.h" + +/** + * @brief Precomputed Galois‐field powers for Reed–Solomon operations. + * + * In GF(2^8) with primitive element \f$\alpha\f$, this table holds + * \f$\alpha^{i \cdot j}\f$ for + * - row index \e i in [0 … 31], + * - column index \e j in [0 … 54]. + */ +static const uint16_t alpha_ij_pow[32][55] = { + {2, 4, 8, 16, 32, 64, 128, 29, 58, 116, 232, 205, 135, 19, 38, 76, 152, 45, 90, + 180, 117, 234, 201, 143, 3, 6, 12, 24, 48, 96, 192, 157, 39, 78, 156, 37, 74, 148, + 53, 106, 212, 181, 119, 238, 193, 159, 35, 70, 140, 5, 10, 20, 40, 80, 160}, + {4, 16, 64, 29, 116, 205, 19, 76, 45, 180, 234, 143, 6, 24, 96, 157, 78, 37, 148, + 106, 181, 238, 159, 70, 5, 20, 80, 93, 105, 185, 222, 95, 97, 153, 94, 101, 137, 30, + 120, 253, 211, 107, 177, 254, 223, 91, 113, 217, 67, 17, 68, 13, 52, 208, 103}, + {8, 64, 58, 205, 38, 45, 117, 143, 12, 96, 39, 37, 53, 181, 193, 70, 10, 80, 186, + 185, 161, 97, 47, 101, 15, 120, 231, 107, 127, 223, 182, 217, 134, 68, 26, 208, 206, 62, + 237, 59, 197, 102, 23, 184, 169, 33, 21, 168, 41, 85, 146, 228, 115, 191, 145}, + {16, 29, 205, 76, 180, 143, 24, 157, 37, 106, 238, 70, 20, 93, 185, 95, 153, 101, 30, + 253, 107, 254, 91, 217, 17, 13, 208, 129, 248, 59, 151, 133, 184, 79, 132, 168, 82, 73, + 228, 230, 198, 252, 123, 227, 150, 149, 165, 130, 200, 28, 221, 81, 121, 195, 172}, + {32, 116, 38, 180, 3, 96, 156, 106, 193, 5, 160, 185, 190, 94, 15, 253, 214, 223, 226, + 17, 26, 103, 124, 59, 51, 46, 169, 132, 77, 85, 114, 230, 145, 215, 255, 150, 55, 174, + 100, 28, 167, 89, 239, 172, 36, 244, 235, 44, 233, 108, 1, 32, 116, 38, 180}, + {64, 205, 45, 143, 96, 37, 181, 70, 80, 185, 97, 101, 120, 107, 223, 217, 68, 208, 62, + 59, 102, 184, 33, 168, 85, 228, 191, 252, 241, 150, 110, 130, 7, 221, 89, 195, 138, 61, + 251, 44, 207, 173, 8, 58, 38, 117, 12, 39, 53, 193, 10, 186, 161, 47, 15}, + {128, 19, 117, 24, 156, 181, 140, 93, 161, 94, 60, 107, 163, 67, 26, 129, 147, 102, 109, + 132, 41, 57, 209, 252, 255, 98, 87, 200, 224, 89, 155, 18, 245, 11, 233, 173, 16, 232, + 45, 3, 157, 53, 159, 40, 185, 194, 137, 231, 254, 226, 68, 189, 248, 197, 46}, + {29, 76, 143, 157, 106, 70, 93, 95, 101, 253, 254, 217, 13, 129, 59, 133, 79, 168, 73, + 230, 252, 227, 149, 130, 28, 81, 195, 18, 247, 44, 27, 2, 58, 152, 3, 39, 212, 140, + 186, 190, 202, 231, 225, 175, 26, 31, 118, 23, 158, 77, 146, 209, 229, 219, 55}, + {58, 45, 12, 37, 193, 80, 161, 101, 231, 223, 134, 208, 237, 102, 169, 168, 146, 191, 179, + 150, 87, 7, 166, 195, 36, 251, 125, 173, 64, 38, 143, 39, 181, 10, 185, 47, 120, 127, + 217, 26, 62, 197, 184, 21, 85, 115, 252, 219, 110, 100, 221, 242, 138, 245, 44}, + {116, 180, 96, 106, 5, 185, 94, 253, 223, 17, 103, 59, 46, 132, 85, 230, 215, 150, 174, + 28, 89, 172, 244, 44, 108, 32, 38, 3, 156, 193, 160, 190, 15, 214, 226, 26, 124, 51, + 169, 77, 114, 145, 255, 55, 100, 167, 239, 36, 235, 233, 1, 116, 180, 96, 106}, + {232, 234, 39, 238, 160, 97, 60, 254, 134, 103, 118, 184, 84, 57, 145, 227, 220, 7, 162, + 172, 245, 176, 71, 58, 180, 192, 181, 40, 95, 15, 177, 175, 208, 147, 46, 21, 73, 99, + 241, 55, 200, 166, 43, 122, 44, 216, 128, 45, 48, 106, 10, 222, 202, 107, 226}, + {205, 143, 37, 70, 185, 101, 107, 217, 208, 59, 184, 168, 228, 252, 150, 130, 221, 195, 61, + 44, 173, 58, 117, 39, 193, 186, 47, 231, 182, 26, 237, 23, 21, 146, 145, 219, 87, 56, + 242, 36, 139, 54, 64, 45, 96, 181, 80, 97, 120, 223, 68, 62, 102, 33, 85}, + {135, 6, 53, 20, 190, 120, 163, 13, 237, 46, 84, 228, 229, 98, 100, 81, 69, 251, 131, + 32, 45, 192, 238, 186, 94, 187, 217, 189, 236, 169, 82, 209, 241, 220, 28, 242, 72, 22, + 173, 116, 201, 37, 140, 222, 15, 254, 34, 62, 204, 132, 146, 63, 75, 130, 167}, + {19, 24, 181, 93, 94, 107, 67, 129, 102, 132, 57, 252, 98, 200, 89, 18, 11, 173, 232, + 3, 53, 40, 194, 231, 226, 189, 197, 158, 170, 145, 75, 25, 166, 69, 235, 54, 29, 234, + 37, 5, 95, 120, 91, 52, 59, 218, 82, 191, 227, 174, 221, 43, 247, 207, 32}, + {38, 96, 193, 185, 15, 223, 26, 59, 169, 85, 145, 150, 100, 89, 36, 44, 1, 38, 96, + 193, 185, 15, 223, 26, 59, 169, 85, 145, 150, 100, 89, 36, 44, 1, 38, 96, 193, 185, + 15, 223, 26, 59, 169, 85, 145, 150, 100, 89, 36, 44, 1, 38, 96, 193, 185}, + {76, 157, 70, 95, 253, 217, 129, 133, 168, 230, 227, 130, 81, 18, 44, 2, 152, 39, 140, + 190, 231, 175, 31, 23, 77, 209, 219, 25, 162, 36, 88, 4, 45, 78, 5, 97, 211, 67, + 62, 46, 154, 191, 171, 50, 89, 72, 176, 8, 90, 156, 10, 194, 187, 134, 124}, + {152, 78, 10, 153, 214, 68, 147, 79, 146, 215, 220, 221, 69, 11, 1, 152, 78, 10, 153, + 214, 68, 147, 79, 146, 215, 220, 221, 69, 11, 1, 152, 78, 10, 153, 214, 68, 147, 79, + 146, 215, 220, 221, 69, 11, 1, 152, 78, 10, 153, 214, 68, 147, 79, 146, 215}, + {45, 37, 80, 101, 223, 208, 102, 168, 191, 150, 7, 195, 251, 173, 38, 39, 10, 47, 127, + 26, 197, 21, 115, 219, 100, 242, 245, 54, 205, 96, 70, 97, 107, 68, 59, 33, 228, 241, + 130, 89, 61, 207, 58, 12, 193, 161, 231, 134, 237, 169, 146, 179, 87, 166, 36}, + {90, 148, 186, 30, 226, 62, 109, 73, 179, 174, 162, 61, 131, 232, 96, 140, 153, 127, 52, + 51, 168, 99, 98, 56, 172, 22, 8, 234, 212, 185, 240, 67, 237, 79, 114, 241, 25, 121, + 245, 108, 19, 39, 20, 188, 223, 189, 133, 41, 63, 55, 221, 9, 176, 64, 3}, + {180, 106, 185, 253, 17, 59, 132, 230, 150, 28, 172, 44, 32, 3, 193, 190, 214, 26, 51, + 77, 145, 55, 167, 36, 233, 116, 96, 5, 94, 223, 103, 46, 85, 215, 174, 89, 244, 108, + 38, 156, 160, 15, 226, 124, 169, 114, 255, 100, 239, 235, 1, 180, 106, 185, 253}, + {117, 181, 161, 107, 26, 102, 41, 252, 87, 89, 245, 173, 45, 53, 185, 231, 68, 197, 168, + 145, 110, 166, 61, 54, 38, 37, 186, 120, 134, 59, 21, 191, 196, 221, 36, 207, 205, 39, + 80, 15, 217, 237, 33, 115, 150, 56, 138, 125, 58, 96, 10, 101, 182, 62, 169}, + {234, 238, 97, 254, 103, 184, 57, 227, 7, 172, 176, 58, 192, 40, 15, 175, 147, 21, 99, + 55, 166, 122, 216, 45, 106, 222, 107, 52, 133, 85, 123, 50, 195, 11, 32, 12, 140, 188, + 182, 124, 158, 115, 49, 224, 36, 131, 19, 37, 105, 253, 68, 151, 154, 252, 174}, + {201, 159, 47, 91, 124, 33, 209, 149, 166, 244, 71, 117, 238, 194, 223, 31, 79, 115, 98, + 167, 61, 216, 90, 181, 190, 254, 206, 218, 213, 150, 224, 72, 54, 152, 106, 161, 177, 189, + 184, 114, 171, 56, 18, 131, 38, 148, 111, 107, 104, 46, 146, 227, 14, 138, 233}, + {143, 70, 101, 217, 59, 168, 252, 130, 195, 44, 58, 39, 186, 231, 26, 23, 146, 219, 56, + 36, 54, 45, 181, 97, 223, 62, 33, 191, 110, 89, 251, 8, 12, 10, 15, 134, 197, 41, + 179, 100, 86, 125, 205, 37, 185, 107, 208, 184, 228, 150, 221, 61, 173, 117, 193}, + {3, 5, 15, 17, 51, 85, 255, 28, 36, 108, 180, 193, 94, 226, 59, 77, 215, 100, 172, + 233, 38, 106, 190, 223, 124, 132, 145, 174, 239, 44, 116, 156, 185, 214, 103, 169, 230, 55, + 89, 235, 32, 96, 160, 253, 26, 46, 114, 150, 167, 244, 1, 3, 5, 15, 17}, + {6, 20, 120, 13, 46, 228, 98, 81, 251, 32, 192, 186, 187, 189, 169, 209, 220, 242, 22, + 116, 37, 222, 254, 62, 132, 63, 130, 43, 250, 38, 212, 194, 182, 147, 77, 179, 141, 9, + 54, 180, 159, 101, 67, 151, 85, 227, 112, 61, 142, 3, 10, 60, 136, 23, 114}, + {12, 80, 231, 208, 169, 191, 87, 195, 125, 38, 181, 47, 217, 197, 85, 219, 221, 245, 8, + 96, 186, 107, 206, 33, 145, 130, 86, 207, 45, 193, 101, 134, 102, 146, 150, 166, 251, 64, + 39, 185, 127, 62, 21, 252, 100, 138, 54, 117, 70, 15, 68, 23, 228, 196, 89}, + {24, 93, 107, 129, 132, 252, 200, 18, 173, 3, 40, 231, 189, 158, 145, 25, 69, 54, 234, + 5, 120, 52, 218, 191, 174, 43, 207, 90, 35, 15, 136, 92, 115, 220, 239, 125, 76, 238, + 101, 17, 133, 228, 149, 121, 44, 135, 212, 47, 175, 51, 146, 49, 162, 139, 116}, + {48, 105, 127, 248, 77, 241, 224, 247, 64, 156, 95, 182, 236, 170, 150, 162, 11, 205, 212, + 94, 134, 133, 213, 110, 239, 250, 45, 35, 30, 26, 218, 99, 130, 69, 108, 143, 40, 211, + 206, 132, 229, 7, 144, 2, 96, 210, 254, 237, 154, 255, 221, 243, 128, 37, 190}, + {96, 185, 223, 59, 85, 150, 89, 44, 38, 193, 15, 26, 169, 145, 100, 36, 1, 96, 185, + 223, 59, 85, 150, 89, 44, 38, 193, 15, 26, 169, 145, 100, 36, 1, 96, 185, 223, 59, + 85, 150, 89, 44, 38, 193, 15, 26, 169, 145, 100, 36, 1, 96, 185, 223, 59}, + {192, 222, 182, 151, 114, 110, 155, 27, 143, 160, 177, 237, 82, 75, 89, 88, 152, 70, 240, + 103, 21, 123, 224, 251, 116, 212, 101, 136, 218, 145, 200, 144, 8, 78, 190, 217, 204, 183, + 87, 172, 216, 12, 105, 225, 59, 170, 98, 242, 250, 180, 10, 211, 31, 168, 255}, + {157, 95, 217, 133, 230, 130, 18, 2, 39, 190, 175, 23, 209, 25, 36, 4, 78, 97, 67, + 46, 191, 50, 72, 8, 156, 194, 134, 92, 99, 100, 144, 16, 37, 153, 17, 184, 198, 200, + 61, 32, 74, 47, 34, 109, 145, 141, 122, 64, 148, 94, 68, 218, 63, 7, 244}}; + +void reed_solomon_encode(uint64_t* cdw, const uint64_t* msg); +void reed_solomon_decode(uint64_t* msg, uint64_t* cdw); + +void compute_generator_poly(uint16_t* poly); + +#endif // HQC_REED_SOLOMON_H diff --git a/src/kem/hqc/hqc_ref/src/ref/hqc-5/parameters.h b/src/kem/hqc/hqc_ref/src/ref/hqc-5/parameters.h new file mode 100644 index 0000000000..34e5bf5eb6 --- /dev/null +++ b/src/kem/hqc/hqc_ref/src/ref/hqc-5/parameters.h @@ -0,0 +1,57 @@ +/** +* @file parameters.h +* @brief Parameters of the HQC-KEM IND-CCA2 scheme + */ + +#ifndef HQC_PARAMETERS_H +#define HQC_PARAMETERS_H + +#include "api.h" + +#define CEIL_DIVIDE(a, b) (((a) / (b)) + ((a) % (b) == 0 ? 0 : 1)) /*!< Divide a by b and ceil the result*/ +#define BITMASK(a, size) ((1UL << (a % size)) - 1) /*!< Create a mask*/ + +#define PARAM_N 57637 ///< Define the parameter n of the scheme +#define PARAM_N1 90 ///< Define the parameter n1 of the scheme (length of Reed-Solomon code) +#define PARAM_N2 640 ///< Define the parameter n2 of the scheme (length of Duplicated Reed-Muller code) +#define PARAM_N1N2 57600 ///< Define the length in bits of the concatenated code +#define PARAM_OMEGA 131 ///< Define the parameter omega of the scheme +#define PARAM_OMEGA_E 149 ///< Define the parameter omega_e of the scheme +#define PARAM_OMEGA_R 149 ///< Define the parameter omega_r of the scheme +#define PARAM_SECURITY 256 ///< Define the security level corresponding to the chosen parameters +#define PARAM_SECURITY_BYTES 32 ///< Define the security level in bytes +#define PARAM_DFR_EXP 256 ///< Define the decryption failure rate corresponding to the chosen parameters + +#define SECRET_KEY_BYTES CRYPTO_SECRETKEYBYTES ///< Define the size of the secret key in bytes +#define PUBLIC_KEY_BYTES CRYPTO_PUBLICKEYBYTES ///< Define the size of the public key in bytes +#define SHARED_SECRET_BYTES CRYPTO_BYTES ///< Define the size of the shared secret in bytes +#define CIPHERTEXT_BYTES CRYPTO_CIPHERTEXTBYTES ///< Define the size of the ciphertext in bytes + +#define VEC_N_SIZE_BYTES CEIL_DIVIDE(PARAM_N, 8) ///< Size of array to store PARAM_N bits in bytes +#define VEC_K_SIZE_BYTES PARAM_K ///< Size of array to store PARAM_K bits in bytes +#define VEC_N1_SIZE_BYTES PARAM_N1 ///< Size of array to store PARAM_N1 bits in bytes +#define VEC_N1N2_SIZE_BYTES CEIL_DIVIDE(PARAM_N1N2, 8) ///< Size of array to store PARAM_N1N2 bits in bytes + +#define VEC_N_SIZE_64 CEIL_DIVIDE(PARAM_N, 64) ///< Size of array to store PARAM_N bits in 64-bit words +#define VEC_N1_SIZE_64 CEIL_DIVIDE(PARAM_N1, 8) ///< Size of array to store PARAM_N1 bits in 64-bit words +#define VEC_N1N2_SIZE_64 CEIL_DIVIDE(PARAM_N1N2, 64) ///< Size of array to store PARAM_N1N2 bits in 64-bit words + +#define PARAM_DELTA 29 ///< Define the error-correcting capacity (delta) of the Reed-Solomon code +#define PARAM_M 8 ///< Define the degree m of the Galois field GF(2^m) +#define PARAM_GF_POLY 0x11D ///< Generator polynomial of GF(2^PARAM_M) in hexadecimal form +#define PARAM_GF_MUL_ORDER 255 ///< Size of the multiplicative group of GF(2^PARAM_M) (2^PARAM_M−1) +#define PARAM_K 32 ///< Define the size of the information bits of the Reed-Solomon code +#define PARAM_G 59 ///< Define the size of the generator polynomial of the Reed-Solomon code +#define PARAM_FFT 5 ///< Exponent for additive FFT (2^PARAM_FFT points) + +#define 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 ///< Coefficients of the Reed-Solomon generator polynomial + +#define SEED_BYTES 32 ///< Define the size of the seed in bytes +#define SALT_BYTES 16 ///< Define the size of a salt in bytes + +#define PARAM_N_MU 74517ULL ///< Define a precomputed multiplier for Barrett reduction mu = floor(2^32 / PARAM_N) +#define UTILS_REJECTION_THRESHOLD 16772367 ///< Rejection threshold for uniform sampling in [0, PARAM_N) + +#endif // HQC_PARAMETERS_H diff --git a/src/kem/hqc/hqc_ref/src/ref/hqc-5/reed_solomon.h b/src/kem/hqc/hqc_ref/src/ref/hqc-5/reed_solomon.h new file mode 100644 index 0000000000..20e2d9aaf5 --- /dev/null +++ b/src/kem/hqc/hqc_ref/src/ref/hqc-5/reed_solomon.h @@ -0,0 +1,260 @@ +/** + * @file reed_solomon.h + * @brief Header file of reed_solomon.c + */ + +#ifndef HQC_REED_SOLOMON_H +#define HQC_REED_SOLOMON_H + +#include +#include +#include "parameters.h" + +/** + * @brief Precomputed Galois‐field powers for Reed–Solomon operations. + * + * In GF(2^8) with primitive element \f$\alpha\f$, this table holds + * \f$\alpha^{i \cdot j}\f$ for + * - row index \e i in [0 … 57], + * - column index \e j in [0 … 88]. + */ +static const uint16_t alpha_ij_pow[58][89] = { + {2, 4, 8, 16, 32, 64, 128, 29, 58, 116, 232, 205, 135, 19, 38, 76, 152, 45, 90, 180, 117, 234, 201, + 143, 3, 6, 12, 24, 48, 96, 192, 157, 39, 78, 156, 37, 74, 148, 53, 106, 212, 181, 119, 238, 193, 159, + 35, 70, 140, 5, 10, 20, 40, 80, 160, 93, 186, 105, 210, 185, 111, 222, 161, 95, 190, 97, 194, 153, 47, + 94, 188, 101, 202, 137, 15, 30, 60, 120, 240, 253, 231, 211, 187, 107, 214, 177, 127, 254, 225}, + {4, 16, 64, 29, 116, 205, 19, 76, 45, 180, 234, 143, 6, 24, 96, 157, 78, 37, 148, 106, 181, 238, 159, + 70, 5, 20, 80, 93, 105, 185, 222, 95, 97, 153, 94, 101, 137, 30, 120, 253, 211, 107, 177, 254, 223, 91, + 113, 217, 67, 17, 68, 13, 52, 208, 103, 129, 62, 248, 199, 59, 236, 151, 102, 133, 46, 184, 218, 79, 33, + 132, 42, 168, 154, 82, 85, 73, 57, 228, 183, 230, 191, 198, 63, 252, 215, 123, 241, 227, 171}, + {8, 64, 58, 205, 38, 45, 117, 143, 12, 96, 39, 37, 53, 181, 193, 70, 10, 80, 186, 185, 161, 97, 47, + 101, 15, 120, 231, 107, 127, 223, 182, 217, 134, 68, 26, 208, 206, 62, 237, 59, 197, 102, 23, 184, 169, 33, + 21, 168, 41, 85, 146, 228, 115, 191, 145, 252, 179, 241, 219, 150, 196, 110, 87, 130, 100, 7, 56, 221, 166, + 89, 242, 195, 86, 138, 36, 61, 245, 251, 139, 44, 125, 207, 54, 173, 1, 8, 64, 58, 205}, + {16, 29, 205, 76, 180, 143, 24, 157, 37, 106, 238, 70, 20, 93, 185, 95, 153, 101, 30, 253, 107, 254, 91, + 217, 17, 13, 208, 129, 248, 59, 151, 133, 184, 79, 132, 168, 82, 73, 228, 230, 198, 252, 123, 227, 150, 149, + 165, 130, 200, 28, 221, 81, 121, 195, 172, 18, 61, 247, 203, 44, 250, 27, 173, 2, 32, 58, 135, 152, 117, + 3, 48, 39, 74, 212, 193, 140, 40, 186, 111, 190, 47, 202, 60, 231, 214, 225, 182, 175, 34}, + {32, 116, 38, 180, 3, 96, 156, 106, 193, 5, 160, 185, 190, 94, 15, 253, 214, 223, 226, 17, 26, 103, 124, + 59, 51, 46, 169, 132, 77, 85, 114, 230, 145, 215, 255, 150, 55, 174, 100, 28, 167, 89, 239, 172, 36, 244, + 235, 44, 233, 108, 1, 32, 116, 38, 180, 3, 96, 156, 106, 193, 5, 160, 185, 190, 94, 15, 253, 214, 223, + 226, 17, 26, 103, 124, 59, 51, 46, 169, 132, 77, 85, 114, 230, 145, 215, 255, 150, 55, 174}, + {64, 205, 45, 143, 96, 37, 181, 70, 80, 185, 97, 101, 120, 107, 223, 217, 68, 208, 62, 59, 102, 184, 33, + 168, 85, 228, 191, 252, 241, 150, 110, 130, 7, 221, 89, 195, 138, 61, 251, 44, 207, 173, 8, 58, 38, 117, + 12, 39, 53, 193, 10, 186, 161, 47, 15, 231, 127, 182, 134, 26, 206, 237, 197, 23, 169, 21, 41, 146, 115, + 145, 179, 219, 196, 87, 100, 56, 166, 242, 86, 36, 245, 139, 125, 54, 1, 64, 205, 45, 143}, + {128, 19, 117, 24, 156, 181, 140, 93, 161, 94, 60, 107, 163, 67, 26, 129, 147, 102, 109, 132, 41, 57, 209, + 252, 255, 98, 87, 200, 224, 89, 155, 18, 245, 11, 233, 173, 16, 232, 45, 3, 157, 53, 159, 40, 185, 194, + 137, 231, 254, 226, 68, 189, 248, 197, 46, 158, 168, 170, 183, 145, 123, 75, 110, 25, 28, 166, 249, 69, 61, + 235, 176, 54, 2, 29, 38, 234, 48, 37, 119, 5, 186, 95, 188, 120, 214, 91, 134, 52, 31}, + {29, 76, 143, 157, 106, 70, 93, 95, 101, 253, 254, 217, 13, 129, 59, 133, 79, 168, 73, 230, 252, 227, 149, + 130, 28, 81, 195, 18, 247, 44, 27, 2, 58, 152, 3, 39, 212, 140, 186, 190, 202, 231, 225, 175, 26, 31, + 118, 23, 158, 77, 146, 209, 229, 219, 55, 25, 56, 162, 155, 36, 243, 88, 54, 4, 116, 45, 6, 78, 181, + 5, 105, 97, 137, 211, 223, 67, 52, 62, 236, 46, 33, 154, 57, 191, 215, 171, 110, 50, 112}, + {58, 45, 12, 37, 193, 80, 161, 101, 231, 223, 134, 208, 237, 102, 169, 168, 146, 191, 179, 150, 87, 7, 166, + 195, 36, 251, 125, 173, 64, 38, 143, 39, 181, 10, 185, 47, 120, 127, 217, 26, 62, 197, 184, 21, 85, 115, + 252, 219, 110, 100, 221, 242, 138, 245, 44, 54, 8, 205, 117, 96, 53, 70, 186, 97, 15, 107, 182, 68, 206, + 59, 23, 33, 41, 228, 145, 241, 196, 130, 56, 89, 86, 61, 139, 207, 1, 58, 45, 12, 37}, + {116, 180, 96, 106, 5, 185, 94, 253, 223, 17, 103, 59, 46, 132, 85, 230, 215, 150, 174, 28, 89, 172, 244, + 44, 108, 32, 38, 3, 156, 193, 160, 190, 15, 214, 226, 26, 124, 51, 169, 77, 114, 145, 255, 55, 100, 167, + 239, 36, 235, 233, 1, 116, 180, 96, 106, 5, 185, 94, 253, 223, 17, 103, 59, 46, 132, 85, 230, 215, 150, + 174, 28, 89, 172, 244, 44, 108, 32, 38, 3, 156, 193, 160, 190, 15, 214, 226, 26, 124, 51}, + {232, 234, 39, 238, 160, 97, 60, 254, 134, 103, 118, 184, 84, 57, 145, 227, 220, 7, 162, 172, 245, 176, 71, + 58, 180, 192, 181, 40, 95, 15, 177, 175, 208, 147, 46, 21, 73, 99, 241, 55, 200, 166, 43, 122, 44, 216, + 128, 45, 48, 106, 10, 222, 202, 107, 226, 52, 237, 133, 66, 85, 209, 123, 196, 50, 167, 195, 144, 11, 54, + 32, 76, 12, 148, 140, 185, 188, 211, 182, 13, 124, 102, 158, 82, 115, 215, 49, 130, 224, 249}, + {205, 143, 37, 70, 185, 101, 107, 217, 208, 59, 184, 168, 228, 252, 150, 130, 221, 195, 61, 44, 173, 58, 117, + 39, 193, 186, 47, 231, 182, 26, 237, 23, 21, 146, 145, 219, 87, 56, 242, 36, 139, 54, 64, 45, 96, 181, + 80, 97, 120, 223, 68, 62, 102, 33, 85, 191, 241, 110, 7, 89, 138, 251, 207, 8, 38, 12, 53, 10, 161, + 15, 127, 134, 206, 197, 169, 41, 115, 179, 196, 100, 166, 86, 245, 125, 1, 205, 143, 37, 70}, + {135, 6, 53, 20, 190, 120, 163, 13, 237, 46, 84, 228, 229, 98, 100, 81, 69, 251, 131, 32, 45, 192, 238, + 186, 94, 187, 217, 189, 236, 169, 82, 209, 241, 220, 28, 242, 72, 22, 173, 116, 201, 37, 140, 222, 15, 254, + 34, 62, 204, 132, 146, 63, 75, 130, 167, 43, 245, 250, 4, 38, 24, 212, 80, 194, 253, 182, 52, 147, 184, + 77, 183, 179, 149, 141, 89, 9, 203, 54, 128, 180, 39, 159, 210, 101, 214, 67, 206, 151, 158}, + {19, 24, 181, 93, 94, 107, 67, 129, 102, 132, 57, 252, 98, 200, 89, 18, 11, 173, 232, 3, 53, 40, 194, + 231, 226, 189, 197, 158, 170, 145, 75, 25, 166, 69, 235, 54, 29, 234, 37, 5, 95, 120, 91, 52, 59, 218, + 82, 191, 227, 174, 221, 43, 247, 207, 32, 90, 39, 35, 111, 15, 225, 136, 237, 92, 77, 115, 246, 220, 56, + 239, 122, 125, 4, 76, 96, 238, 105, 101, 177, 17, 62, 133, 42, 228, 215, 149, 7, 121, 72}, + {38, 96, 193, 185, 15, 223, 26, 59, 169, 85, 145, 150, 100, 89, 36, 44, 1, 38, 96, 193, 185, 15, 223, + 26, 59, 169, 85, 145, 150, 100, 89, 36, 44, 1, 38, 96, 193, 185, 15, 223, 26, 59, 169, 85, 145, 150, + 100, 89, 36, 44, 1, 38, 96, 193, 185, 15, 223, 26, 59, 169, 85, 145, 150, 100, 89, 36, 44, 1, 38, + 96, 193, 185, 15, 223, 26, 59, 169, 85, 145, 150, 100, 89, 36, 44, 1, 38, 96, 193, 185}, + {76, 157, 70, 95, 253, 217, 129, 133, 168, 230, 227, 130, 81, 18, 44, 2, 152, 39, 140, 190, 231, 175, 31, + 23, 77, 209, 219, 25, 162, 36, 88, 4, 45, 78, 5, 97, 211, 67, 62, 46, 154, 191, 171, 50, 89, 72, + 176, 8, 90, 156, 10, 194, 187, 134, 124, 92, 41, 99, 75, 100, 178, 144, 125, 16, 180, 37, 20, 153, 107, + 17, 248, 184, 82, 198, 150, 200, 121, 61, 250, 32, 117, 74, 40, 47, 214, 34, 237, 109, 164}, + {152, 78, 10, 153, 214, 68, 147, 79, 146, 215, 220, 221, 69, 11, 1, 152, 78, 10, 153, 214, 68, 147, 79, + 146, 215, 220, 221, 69, 11, 1, 152, 78, 10, 153, 214, 68, 147, 79, 146, 215, 220, 221, 69, 11, 1, 152, + 78, 10, 153, 214, 68, 147, 79, 146, 215, 220, 221, 69, 11, 1, 152, 78, 10, 153, 214, 68, 147, 79, 146, + 215, 220, 221, 69, 11, 1, 152, 78, 10, 153, 214, 68, 147, 79, 146, 215, 220, 221, 69, 11}, + {45, 37, 80, 101, 223, 208, 102, 168, 191, 150, 7, 195, 251, 173, 38, 39, 10, 47, 127, 26, 197, 21, 115, + 219, 100, 242, 245, 54, 205, 96, 70, 97, 107, 68, 59, 33, 228, 241, 130, 89, 61, 207, 58, 12, 193, 161, + 231, 134, 237, 169, 146, 179, 87, 166, 36, 125, 64, 143, 181, 185, 120, 217, 62, 184, 85, 252, 110, 221, 138, + 44, 8, 117, 53, 186, 15, 182, 206, 23, 41, 145, 196, 56, 86, 139, 1, 45, 37, 80, 101}, + {90, 148, 186, 30, 226, 62, 109, 73, 179, 174, 162, 61, 131, 232, 96, 140, 153, 127, 52, 51, 168, 99, 98, + 56, 172, 22, 8, 234, 212, 185, 240, 67, 237, 79, 114, 241, 25, 121, 245, 108, 19, 39, 20, 188, 223, 189, + 133, 41, 63, 55, 221, 9, 176, 64, 3, 238, 161, 211, 34, 59, 66, 183, 219, 200, 239, 251, 71, 152, 37, + 160, 137, 182, 129, 92, 85, 229, 165, 166, 72, 233, 58, 24, 35, 97, 214, 13, 197, 42, 209}, + {180, 106, 185, 253, 17, 59, 132, 230, 150, 28, 172, 44, 32, 3, 193, 190, 214, 26, 51, 77, 145, 55, 167, + 36, 233, 116, 96, 5, 94, 223, 103, 46, 85, 215, 174, 89, 244, 108, 38, 156, 160, 15, 226, 124, 169, 114, + 255, 100, 239, 235, 1, 180, 106, 185, 253, 17, 59, 132, 230, 150, 28, 172, 44, 32, 3, 193, 190, 214, 26, + 51, 77, 145, 55, 167, 36, 233, 116, 96, 5, 94, 223, 103, 46, 85, 215, 174, 89, 244, 108}, + {117, 181, 161, 107, 26, 102, 41, 252, 87, 89, 245, 173, 45, 53, 185, 231, 68, 197, 168, 145, 110, 166, 61, + 54, 38, 37, 186, 120, 134, 59, 21, 191, 196, 221, 36, 207, 205, 39, 80, 15, 217, 237, 33, 115, 150, 56, + 138, 125, 58, 96, 10, 101, 182, 62, 169, 228, 219, 7, 86, 44, 64, 12, 70, 47, 223, 206, 184, 146, 241, + 100, 195, 139, 8, 143, 193, 97, 127, 208, 23, 85, 179, 130, 242, 251, 1, 117, 181, 161, 107}, + {234, 238, 97, 254, 103, 184, 57, 227, 7, 172, 176, 58, 192, 40, 15, 175, 147, 21, 99, 55, 166, 122, 216, + 45, 106, 222, 107, 52, 133, 85, 123, 50, 195, 11, 32, 12, 140, 188, 182, 124, 158, 115, 49, 224, 36, 131, + 19, 37, 105, 253, 68, 151, 154, 252, 174, 121, 251, 2, 201, 193, 194, 225, 206, 109, 114, 219, 14, 69, 125, + 116, 157, 80, 30, 67, 59, 42, 198, 110, 81, 244, 173, 90, 212, 161, 214, 104, 23, 170, 246}, + {201, 159, 47, 91, 124, 33, 209, 149, 166, 244, 71, 117, 238, 194, 223, 31, 79, 115, 98, 167, 61, 216, 90, + 181, 190, 254, 206, 218, 213, 150, 224, 72, 54, 152, 106, 161, 177, 189, 184, 114, 171, 56, 18, 131, 38, 148, + 111, 107, 104, 46, 146, 227, 14, 138, 233, 135, 37, 210, 211, 26, 133, 170, 241, 141, 172, 125, 232, 78, 186, + 253, 136, 102, 164, 123, 100, 43, 88, 58, 157, 160, 120, 34, 151, 41, 215, 25, 195, 22, 128}, + {143, 70, 101, 217, 59, 168, 252, 130, 195, 44, 58, 39, 186, 231, 26, 23, 146, 219, 56, 36, 54, 45, 181, + 97, 223, 62, 33, 191, 110, 89, 251, 8, 12, 10, 15, 134, 197, 41, 179, 100, 86, 125, 205, 37, 185, 107, + 208, 184, 228, 150, 221, 61, 173, 117, 193, 47, 182, 237, 21, 145, 87, 242, 139, 64, 96, 80, 120, 68, 102, + 85, 241, 7, 138, 207, 38, 53, 161, 127, 206, 169, 115, 196, 166, 245, 1, 143, 70, 101, 217}, + {3, 5, 15, 17, 51, 85, 255, 28, 36, 108, 180, 193, 94, 226, 59, 77, 215, 100, 172, 233, 38, 106, 190, + 223, 124, 132, 145, 174, 239, 44, 116, 156, 185, 214, 103, 169, 230, 55, 89, 235, 32, 96, 160, 253, 26, 46, + 114, 150, 167, 244, 1, 3, 5, 15, 17, 51, 85, 255, 28, 36, 108, 180, 193, 94, 226, 59, 77, 215, 100, + 172, 233, 38, 106, 190, 223, 124, 132, 145, 174, 239, 44, 116, 156, 185, 214, 103, 169, 230, 55}, + {6, 20, 120, 13, 46, 228, 98, 81, 251, 32, 192, 186, 187, 189, 169, 209, 220, 242, 22, 116, 37, 222, 254, + 62, 132, 63, 130, 43, 250, 38, 212, 194, 182, 147, 77, 179, 141, 9, 54, 180, 159, 101, 67, 151, 85, 227, + 112, 61, 142, 3, 10, 60, 136, 23, 114, 49, 166, 243, 16, 96, 93, 211, 208, 218, 230, 110, 121, 11, 58, + 156, 111, 127, 31, 66, 145, 65, 155, 125, 19, 106, 97, 91, 199, 168, 215, 200, 138, 27, 90}, + {12, 80, 231, 208, 169, 191, 87, 195, 125, 38, 181, 47, 217, 197, 85, 219, 221, 245, 8, 96, 186, 107, 206, + 33, 145, 130, 86, 207, 45, 193, 101, 134, 102, 146, 150, 166, 251, 64, 39, 185, 127, 62, 21, 252, 100, 138, + 54, 117, 70, 15, 68, 23, 228, 196, 89, 139, 58, 37, 161, 223, 237, 168, 179, 7, 36, 173, 143, 10, 120, + 26, 184, 115, 110, 242, 44, 205, 53, 97, 182, 59, 41, 241, 56, 61, 1, 12, 80, 231, 208}, + {24, 93, 107, 129, 132, 252, 200, 18, 173, 3, 40, 231, 189, 158, 145, 25, 69, 54, 234, 5, 120, 52, 218, + 191, 174, 43, 207, 90, 35, 15, 136, 92, 115, 220, 239, 125, 76, 238, 101, 17, 133, 228, 149, 121, 44, 135, + 212, 47, 175, 51, 146, 49, 162, 139, 116, 148, 97, 113, 236, 85, 171, 83, 251, 128, 156, 161, 163, 147, 41, + 255, 224, 245, 16, 157, 185, 254, 248, 168, 123, 28, 61, 2, 48, 186, 214, 31, 21, 229, 141}, + {48, 105, 127, 248, 77, 241, 224, 247, 64, 156, 95, 182, 236, 170, 150, 162, 11, 205, 212, 94, 134, 133, 213, + 110, 239, 250, 45, 35, 30, 26, 218, 99, 130, 69, 108, 143, 40, 211, 206, 132, 229, 7, 144, 2, 96, 210, + 254, 237, 154, 255, 221, 243, 128, 37, 190, 113, 197, 73, 49, 89, 22, 135, 181, 188, 17, 23, 183, 220, 195, + 233, 90, 70, 60, 52, 169, 198, 25, 138, 216, 3, 80, 187, 129, 21, 215, 14, 61, 4, 192}, + {96, 185, 223, 59, 85, 150, 89, 44, 38, 193, 15, 26, 169, 145, 100, 36, 1, 96, 185, 223, 59, 85, 150, + 89, 44, 38, 193, 15, 26, 169, 145, 100, 36, 1, 96, 185, 223, 59, 85, 150, 89, 44, 38, 193, 15, 26, + 169, 145, 100, 36, 1, 96, 185, 223, 59, 85, 150, 89, 44, 38, 193, 15, 26, 169, 145, 100, 36, 1, 96, + 185, 223, 59, 85, 150, 89, 44, 38, 193, 15, 26, 169, 145, 100, 36, 1, 96, 185, 223, 59}, + {192, 222, 182, 151, 114, 110, 155, 27, 143, 160, 177, 237, 82, 75, 89, 88, 152, 70, 240, 103, 21, 123, 224, + 251, 116, 212, 101, 136, 218, 145, 200, 144, 8, 78, 190, 217, 204, 183, 87, 172, 216, 12, 105, 225, 59, 170, + 98, 242, 250, 180, 10, 211, 31, 168, 255, 83, 139, 135, 238, 15, 52, 158, 252, 14, 244, 64, 74, 153, 134, + 46, 209, 130, 9, 142, 96, 111, 91, 197, 57, 55, 195, 131, 201, 80, 214, 248, 41, 171, 162}, + {157, 95, 217, 133, 230, 130, 18, 2, 39, 190, 175, 23, 209, 25, 36, 4, 78, 97, 67, 46, 191, 50, 72, + 8, 156, 194, 134, 92, 99, 100, 144, 16, 37, 153, 17, 184, 198, 200, 61, 32, 74, 47, 34, 109, 145, 141, + 122, 64, 148, 94, 68, 218, 63, 7, 244, 128, 53, 188, 136, 169, 126, 14, 245, 29, 106, 101, 13, 79, 252, + 28, 247, 58, 212, 202, 26, 158, 229, 56, 243, 116, 181, 137, 52, 33, 215, 112, 251, 232, 119}, + {39, 97, 134, 184, 145, 7, 245, 58, 181, 15, 208, 21, 241, 166, 44, 45, 10, 107, 237, 85, 196, 195, 54, + 12, 185, 182, 102, 115, 130, 36, 8, 37, 47, 68, 169, 252, 56, 251, 205, 193, 120, 206, 168, 219, 89, 125, + 117, 80, 127, 59, 146, 110, 86, 173, 96, 161, 217, 23, 191, 100, 61, 64, 53, 101, 26, 33, 179, 221, 139, + 38, 70, 231, 62, 41, 150, 242, 207, 143, 186, 223, 197, 228, 87, 138, 1, 39, 97, 134, 184}, + {78, 153, 68, 79, 215, 221, 11, 152, 10, 214, 147, 146, 220, 69, 1, 78, 153, 68, 79, 215, 221, 11, 152, + 10, 214, 147, 146, 220, 69, 1, 78, 153, 68, 79, 215, 221, 11, 152, 10, 214, 147, 146, 220, 69, 1, 78, + 153, 68, 79, 215, 221, 11, 152, 10, 214, 147, 146, 220, 69, 1, 78, 153, 68, 79, 215, 221, 11, 152, 10, + 214, 147, 146, 220, 69, 1, 78, 153, 68, 79, 215, 221, 11, 152, 10, 214, 147, 146, 220, 69}, + {156, 94, 26, 132, 255, 89, 233, 3, 185, 226, 46, 145, 28, 235, 38, 5, 214, 59, 114, 174, 36, 32, 106, + 15, 103, 77, 150, 239, 108, 96, 190, 17, 169, 215, 167, 44, 180, 160, 223, 51, 230, 100, 244, 116, 193, 253, + 124, 85, 55, 172, 1, 156, 94, 26, 132, 255, 89, 233, 3, 185, 226, 46, 145, 28, 235, 38, 5, 214, 59, + 114, 174, 36, 32, 106, 15, 103, 77, 150, 239, 108, 96, 190, 17, 169, 215, 167, 44, 180, 160}, + {37, 101, 208, 168, 150, 195, 173, 39, 47, 26, 21, 219, 242, 54, 96, 97, 68, 33, 241, 89, 207, 12, 161, + 134, 169, 179, 166, 125, 143, 185, 217, 184, 252, 221, 44, 117, 186, 182, 23, 145, 56, 139, 45, 80, 223, 102, + 191, 7, 251, 38, 10, 127, 197, 115, 100, 245, 205, 70, 107, 59, 228, 130, 61, 58, 193, 231, 237, 146, 87, + 36, 64, 181, 120, 62, 85, 110, 138, 8, 53, 15, 206, 41, 196, 86, 1, 37, 101, 208, 168}, + {74, 137, 206, 82, 55, 138, 16, 212, 120, 124, 73, 87, 72, 29, 193, 211, 147, 228, 25, 244, 205, 140, 177, + 197, 230, 141, 251, 76, 40, 223, 204, 198, 56, 11, 180, 186, 113, 92, 252, 167, 176, 143, 111, 67, 169, 123, + 162, 207, 24, 190, 68, 66, 227, 242, 108, 157, 47, 52, 84, 150, 155, 142, 37, 202, 103, 41, 149, 69, 8, + 106, 60, 62, 170, 165, 36, 128, 238, 231, 199, 114, 130, 122, 232, 70, 214, 236, 115, 200, 243}, + {148, 30, 62, 73, 174, 61, 232, 140, 127, 51, 99, 56, 22, 234, 185, 67, 79, 241, 121, 108, 39, 188, 189, + 41, 55, 9, 64, 238, 211, 59, 183, 200, 251, 152, 160, 182, 92, 229, 166, 233, 24, 97, 13, 42, 150, 43, + 2, 53, 60, 124, 146, 65, 122, 205, 5, 254, 102, 198, 112, 44, 201, 111, 134, 158, 255, 242, 216, 78, 101, + 103, 82, 110, 18, 128, 193, 187, 118, 115, 141, 235, 45, 93, 113, 184, 215, 81, 207, 48, 194}, + {53, 120, 237, 228, 100, 251, 45, 186, 217, 169, 241, 242, 173, 37, 15, 62, 146, 130, 245, 38, 80, 182, 184, + 179, 89, 54, 39, 101, 206, 85, 87, 61, 205, 10, 223, 23, 252, 166, 207, 96, 47, 208, 41, 110, 36, 58, + 70, 127, 102, 145, 221, 125, 12, 97, 26, 168, 196, 138, 64, 193, 107, 197, 191, 56, 44, 143, 161, 68, 21, + 150, 86, 8, 181, 231, 59, 115, 7, 139, 117, 185, 134, 33, 219, 195, 1, 53, 120, 237, 228}, + {106, 253, 59, 230, 28, 44, 3, 190, 26, 77, 55, 36, 116, 5, 223, 46, 215, 89, 108, 156, 15, 124, 114, + 100, 235, 180, 185, 17, 132, 150, 172, 32, 193, 214, 51, 145, 167, 233, 96, 94, 103, 85, 174, 244, 38, 160, + 226, 169, 255, 239, 1, 106, 253, 59, 230, 28, 44, 3, 190, 26, 77, 55, 36, 116, 5, 223, 46, 215, 89, + 108, 156, 15, 124, 114, 100, 235, 180, 185, 17, 132, 150, 172, 32, 193, 214, 51, 145, 167, 233}, + {212, 211, 197, 198, 167, 207, 157, 202, 62, 114, 200, 139, 201, 95, 26, 154, 220, 61, 19, 160, 217, 158, 171, + 86, 32, 159, 127, 133, 229, 89, 216, 74, 120, 147, 230, 56, 176, 24, 47, 103, 170, 130, 243, 90, 185, 34, + 42, 196, 18, 116, 10, 91, 109, 241, 239, 2, 181, 187, 151, 145, 83, 131, 39, 137, 124, 228, 141, 11, 143, + 190, 52, 41, 165, 122, 38, 93, 175, 33, 75, 172, 64, 35, 254, 23, 215, 178, 173, 148, 240}, + {181, 107, 102, 252, 89, 173, 53, 231, 197, 145, 166, 54, 37, 120, 59, 191, 221, 207, 39, 15, 237, 115, 56, + 125, 96, 101, 62, 228, 7, 44, 12, 47, 206, 146, 100, 139, 143, 97, 208, 85, 130, 251, 117, 161, 26, 41, + 87, 245, 45, 185, 68, 168, 110, 61, 38, 186, 134, 21, 196, 36, 205, 80, 217, 33, 150, 138, 58, 10, 182, + 169, 219, 86, 64, 70, 223, 184, 241, 195, 8, 193, 127, 23, 179, 242, 1, 181, 107, 102, 252}, + {119, 177, 23, 123, 239, 8, 159, 225, 184, 255, 43, 64, 140, 91, 169, 171, 69, 58, 20, 226, 33, 49, 18, + 205, 160, 67, 21, 149, 144, 38, 105, 34, 168, 220, 244, 45, 111, 13, 41, 174, 243, 117, 95, 104, 85, 25, + 203, 143, 194, 103, 146, 200, 22, 12, 94, 31, 228, 14, 176, 96, 202, 248, 115, 112, 233, 39, 30, 147, 191, + 167, 27, 37, 240, 236, 145, 81, 216, 53, 211, 51, 252, 178, 142, 181, 214, 133, 179, 249, 4}, + {238, 254, 184, 227, 172, 58, 40, 175, 21, 55, 122, 45, 222, 52, 85, 50, 11, 12, 188, 124, 115, 224, 131, + 37, 253, 151, 252, 121, 2, 193, 225, 109, 219, 69, 116, 80, 67, 42, 110, 244, 90, 161, 104, 170, 100, 22, + 24, 101, 248, 230, 221, 27, 74, 231, 51, 229, 242, 4, 159, 223, 218, 171, 138, 232, 160, 134, 84, 220, 245, + 180, 95, 208, 73, 200, 44, 48, 202, 237, 209, 167, 54, 148, 211, 102, 215, 249, 8, 35, 163}, + {193, 223, 169, 150, 36, 38, 185, 26, 85, 100, 44, 96, 15, 59, 145, 89, 1, 193, 223, 169, 150, 36, 38, + 185, 26, 85, 100, 44, 96, 15, 59, 145, 89, 1, 193, 223, 169, 150, 36, 38, 185, 26, 85, 100, 44, 96, + 15, 59, 145, 89, 1, 193, 223, 169, 150, 36, 38, 185, 26, 85, 100, 44, 96, 15, 59, 145, 89, 1, 193, + 223, 169, 150, 36, 38, 185, 26, 85, 100, 44, 96, 15, 59, 145, 89, 1, 193, 223, 169, 150}, + {159, 91, 33, 149, 244, 117, 194, 31, 115, 167, 216, 181, 254, 218, 150, 72, 152, 161, 189, 114, 56, 131, 148, + 107, 46, 227, 138, 135, 210, 26, 170, 141, 125, 78, 253, 102, 123, 43, 58, 160, 34, 41, 25, 22, 96, 30, + 236, 252, 249, 32, 10, 175, 84, 87, 235, 6, 101, 199, 198, 89, 2, 35, 182, 66, 55, 245, 234, 153, 62, + 230, 83, 173, 119, 225, 169, 49, 144, 45, 95, 103, 228, 112, 27, 53, 214, 92, 219, 9, 19}, + {35, 113, 21, 165, 235, 12, 137, 118, 252, 239, 128, 80, 34, 82, 100, 176, 78, 231, 133, 255, 138, 19, 111, + 208, 114, 112, 54, 212, 254, 169, 98, 122, 117, 153, 124, 191, 162, 2, 70, 226, 42, 87, 203, 24, 15, 236, + 229, 195, 29, 160, 68, 164, 200, 125, 156, 211, 23, 227, 9, 38, 222, 189, 228, 224, 108, 181, 225, 79, 196, + 244, 234, 47, 248, 99, 89, 4, 140, 217, 84, 174, 139, 48, 30, 197, 215, 155, 58, 93, 136}, + {70, 217, 168, 130, 44, 39, 231, 23, 219, 36, 45, 97, 62, 191, 89, 8, 10, 134, 41, 100, 125, 37, 107, + 184, 150, 61, 117, 47, 237, 145, 242, 64, 80, 68, 85, 7, 207, 53, 127, 169, 196, 245, 143, 101, 59, 252, + 195, 58, 186, 26, 146, 56, 54, 181, 223, 33, 110, 251, 12, 15, 197, 179, 86, 205, 185, 208, 228, 221, 173, + 193, 182, 21, 87, 139, 96, 120, 102, 241, 138, 38, 161, 206, 115, 166, 1, 70, 217, 168, 130}, + {140, 67, 41, 200, 233, 53, 254, 158, 110, 235, 48, 120, 204, 227, 36, 90, 153, 237, 63, 239, 58, 105, 104, + 228, 167, 142, 70, 175, 154, 100, 250, 148, 127, 79, 55, 251, 24, 60, 102, 255, 18, 45, 194, 248, 145, 249, + 29, 186, 52, 114, 221, 71, 35, 217, 77, 50, 125, 74, 177, 169, 149, 243, 12, 30, 51, 241, 9, 152, 97, + 124, 198, 242, 128, 93, 26, 57, 224, 173, 159, 226, 168, 25, 176, 37, 214, 218, 196, 247, 6}, + {5, 17, 85, 28, 108, 193, 226, 77, 100, 233, 106, 223, 132, 174, 44, 156, 214, 169, 55, 235, 96, 253, 46, + 150, 244, 3, 15, 51, 255, 36, 180, 94, 59, 215, 172, 38, 190, 124, 145, 239, 116, 185, 103, 230, 89, 32, + 160, 26, 114, 167, 1, 5, 17, 85, 28, 108, 193, 226, 77, 100, 233, 106, 223, 132, 174, 44, 156, 214, 169, + 55, 235, 96, 253, 46, 150, 244, 3, 15, 51, 255, 36, 180, 94, 59, 215, 172, 38, 190, 124}, + {10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, + 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, + 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, + 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221}, + {20, 13, 228, 81, 32, 186, 189, 209, 242, 116, 222, 62, 63, 43, 38, 194, 147, 179, 9, 180, 101, 151, 227, + 61, 3, 60, 23, 49, 243, 96, 211, 218, 110, 11, 156, 127, 66, 65, 125, 106, 91, 168, 200, 27, 193, 175, + 164, 56, 71, 5, 68, 57, 83, 8, 160, 104, 115, 178, 29, 185, 129, 198, 195, 135, 190, 237, 229, 69, 45, + 94, 236, 241, 72, 201, 15, 204, 75, 245, 24, 253, 184, 149, 203, 39, 214, 158, 87, 88, 148}, + {40, 52, 115, 121, 116, 161, 248, 229, 138, 180, 202, 102, 75, 247, 96, 187, 79, 87, 176, 106, 182, 154, 14, + 173, 5, 136, 228, 162, 128, 185, 31, 63, 86, 152, 94, 197, 227, 122, 12, 253, 109, 110, 22, 74, 223, 84, + 200, 54, 35, 17, 146, 83, 16, 186, 103, 99, 195, 19, 194, 59, 246, 72, 143, 60, 46, 196, 203, 78, 127, + 132, 25, 207, 238, 175, 85, 224, 2, 80, 104, 230, 242, 232, 95, 237, 215, 9, 117, 137, 204}, + {80, 208, 191, 195, 38, 47, 197, 219, 245, 96, 107, 33, 130, 207, 193, 134, 146, 166, 64, 185, 62, 252, 138, + 117, 15, 23, 196, 139, 37, 223, 168, 7, 173, 10, 26, 115, 242, 205, 97, 59, 241, 61, 12, 231, 169, 87, + 125, 181, 217, 85, 221, 8, 186, 206, 145, 86, 45, 101, 102, 150, 251, 39, 127, 21, 100, 54, 70, 68, 228, + 89, 58, 161, 237, 179, 36, 143, 120, 184, 110, 44, 53, 182, 41, 56, 1, 80, 208, 191, 195}, + {160, 103, 145, 172, 180, 15, 46, 55, 44, 106, 226, 85, 167, 32, 185, 124, 215, 36, 3, 253, 169, 174, 233, + 193, 17, 114, 89, 116, 190, 59, 255, 244, 96, 214, 132, 100, 108, 5, 26, 230, 239, 38, 94, 51, 150, 235, + 156, 223, 77, 28, 1, 160, 103, 145, 172, 180, 15, 46, 55, 44, 106, 226, 85, 167, 32, 185, 124, 215, 36, + 3, 253, 169, 174, 233, 193, 17, 114, 89, 116, 190, 59, 255, 244, 96, 214, 132, 100, 108, 5}, + {93, 129, 252, 18, 3, 231, 158, 25, 54, 5, 52, 191, 43, 90, 15, 92, 220, 125, 238, 17, 228, 121, 135, + 47, 51, 49, 139, 148, 113, 85, 83, 128, 161, 147, 255, 245, 157, 254, 168, 28, 2, 186, 31, 229, 36, 6, + 211, 33, 50, 108, 10, 104, 99, 86, 180, 30, 184, 165, 250, 193, 34, 213, 242, 19, 94, 102, 98, 11, 53, + 226, 170, 166, 29, 95, 59, 227, 247, 39, 225, 77, 56, 4, 105, 62, 215, 72, 12, 187, 66}, + {186, 62, 179, 61, 96, 127, 168, 56, 8, 185, 237, 241, 245, 39, 223, 41, 221, 64, 161, 59, 219, 251, 37, + 182, 85, 166, 58, 97, 197, 150, 139, 53, 217, 146, 89, 205, 47, 102, 196, 44, 181, 134, 228, 242, 38, 101, + 23, 110, 125, 193, 68, 115, 195, 45, 15, 184, 87, 207, 70, 26, 191, 86, 117, 120, 169, 130, 54, 10, 208, + 145, 138, 143, 231, 33, 100, 173, 80, 206, 252, 36, 12, 107, 21, 7, 1, 186, 62, 179, 61}, + {105, 248, 241, 247, 156, 182, 170, 162, 205, 94, 133, 110, 250, 35, 26, 99, 69, 143, 211, 132, 7, 2, 210, + 237, 255, 243, 37, 113, 73, 89, 135, 188, 23, 220, 233, 70, 52, 198, 138, 3, 187, 21, 14, 4, 185, 199, + 227, 251, 74, 226, 146, 178, 19, 101, 46, 165, 207, 140, 104, 145, 9, 6, 107, 42, 28, 8, 111, 147, 219, + 235, 148, 217, 57, 121, 38, 202, 92, 87, 131, 5, 208, 63, 18, 12, 214, 84, 56, 16, 222}}; + +void reed_solomon_encode(uint64_t* cdw, const uint64_t* msg); +void reed_solomon_decode(uint64_t* msg, uint64_t* cdw); + +void compute_generator_poly(uint16_t* poly); + +#endif // HQC_REED_SOLOMON_H diff --git a/src/kem/hqc/hqc_ref/src/ref/hqc.c b/src/kem/hqc/hqc_ref/src/ref/hqc.c new file mode 100644 index 0000000000..63e6b0626a --- /dev/null +++ b/src/kem/hqc/hqc_ref/src/ref/hqc.c @@ -0,0 +1,207 @@ +/** + * @file hqc.c + * @brief High-level HQC-PKE API implementation + */ + +#include "hqc.h" +#include +#include +#include "code.h" +#include "crypto_memset.h" +#include "gf2x.h" +#include "parameters.h" +#include "symmetric.h" +#include "vector.h" +#ifdef VERBOSE +#include +#endif + +/** + * @brief Generates a key pair for the HQC public-key encryption (PKE) scheme. + * + * This function creates a public encryption key (`ek_pke`) and a private decryption key (`dk_pke`) + * for use in the HQC PKE scheme. The key generation process is seeded with the given `seed` input. + * + * @param[out] ek_pke Pointer to the buffer that will receive the encryption key. + * @param[out] dk_pke Pointer to the buffer that will receive the decryption key. + * @param[in] seed Pointer to the seed used to deterministically generate the key pair. + * + */ +void hqc_pke_keygen(uint8_t *ek_pke, uint8_t *dk_pke, uint8_t *seed) { + uint8_t keypair_seed[2 * SEED_BYTES] = {0}; + uint8_t *seed_dk = keypair_seed; + uint8_t *seed_ek = keypair_seed + SEED_BYTES; + shake256_xof_ctx dk_xof_ctx = {0}; + shake256_xof_ctx ek_xof_ctx = {0}; + + uint64_t x[VEC_N_SIZE_64] = {0}; + uint64_t y[VEC_N_SIZE_64] = {0}; + uint64_t h[VEC_N_SIZE_64] = {0}; + uint64_t s[VEC_N_SIZE_64] = {0}; + + // Derive keypair seeds + hash_i(keypair_seed, seed); + + // Compute decryption key + xof_init(&dk_xof_ctx, seed_dk, SEED_BYTES); + vect_sample_fixed_weight1(&dk_xof_ctx, y, PARAM_OMEGA); + vect_sample_fixed_weight1(&dk_xof_ctx, x, PARAM_OMEGA); + + // Compute encryption key + xof_init(&ek_xof_ctx, seed_ek, SEED_BYTES); + vect_set_random(&ek_xof_ctx, h); + vect_mul(s, y, h); + vect_add(s, x, s, VEC_N_SIZE_64); + + // Parse encryption key to string + memcpy(ek_pke, seed_ek, SEED_BYTES); + memcpy(ek_pke + SEED_BYTES, s, VEC_N_SIZE_BYTES); + + // Parse decryption key to string + memcpy(dk_pke, seed_dk, SEED_BYTES); + +#ifdef VERBOSE + printf("\n\nseed_dk: "); + for (int i = 0; i < SEED_BYTES; ++i) printf("%02x", seed_dk[i]); + printf("\n\nseed_ek: "); + for (int i = 0; i < SEED_BYTES; ++i) printf("%02x", seed_ek[i]); + printf("\n\ny: "); + vect_print(y, VEC_N_SIZE_BYTES); + printf("\n\nx: "); + vect_print(x, VEC_N_SIZE_BYTES); + printf("\n\nh: "); + vect_print(h, VEC_N_SIZE_BYTES); + printf("\n\ns: "); + vect_print(s, VEC_N_SIZE_BYTES); +#endif + + // Zeroize sensitive data + memset_zero(keypair_seed, sizeof keypair_seed); + memset_zero(x, sizeof x); + memset_zero(y, sizeof y); + memset_zero(&dk_xof_ctx, sizeof dk_xof_ctx); +} + +/** + * @brief Encrypts a message using the HQC public-key encryption (PKE) scheme. + * + * This function performs encryption in the HQC PKE scheme. It uses the given encryption key (`ek_pke`) + * and encryption randomness (`theta`) to encrypt the message `m`, producing a ciphertext `c_pke`. + * + * @param[out] c_pke Pointer to the output ciphertext structure (PKE ciphertext). + * @param[in] ek_pke Pointer to the encryption key. + * @param[in] m Pointer to the message to be encrypted. + * @param[in] theta Pointer to the encryption randomness used during encryption. + * + */ +void hqc_pke_encrypt(ciphertext_pke_t *c_pke, const uint8_t *ek_pke, const uint64_t *m, const uint8_t *theta) { + shake256_xof_ctx theta_xof_ctx = {0}; + uint64_t h[VEC_N_SIZE_64] = {0}; + uint64_t s[VEC_N_SIZE_64] = {0}; + uint64_t r1[VEC_N_SIZE_64] = {0}; + uint64_t r2[VEC_N_SIZE_64] = {0}; + uint64_t e[VEC_N_SIZE_64] = {0}; + uint64_t tmp[VEC_N_SIZE_64] = {0}; + + // Initialize Xof using theta + xof_init(&theta_xof_ctx, theta, SEED_BYTES); + + // Retrieve h and s from public key + hqc_ek_pke_from_string(h, s, ek_pke); + + // Generate re, e and r1 + vect_sample_fixed_weight2(&theta_xof_ctx, r2, PARAM_OMEGA_R); + vect_sample_fixed_weight2(&theta_xof_ctx, e, PARAM_OMEGA_E); + vect_sample_fixed_weight2(&theta_xof_ctx, r1, PARAM_OMEGA_R); + + // Compute u = r1 + r2.h + vect_mul(c_pke->u, r2, h); + vect_add(c_pke->u, r1, c_pke->u, VEC_N_SIZE_64); + + // Compute v = C.encode(m) + code_encode(c_pke->v, m); + + // Compute v = C.encode(m) + Truncate(s.r2 + e) + vect_mul(tmp, r2, s); + vect_add(tmp, e, tmp, VEC_N_SIZE_64); + vect_truncate(tmp); + vect_add(c_pke->v, c_pke->v, tmp, VEC_N1N2_SIZE_64); + +#ifdef VERBOSE + printf("\n\nh: "); + vect_print(h, VEC_N_SIZE_BYTES); + printf("\n\ns: "); + vect_print(s, VEC_N_SIZE_BYTES); + printf("\n\nr1: "); + vect_print(r1, VEC_N_SIZE_BYTES); + printf("\n\nr2: "); + vect_print(r2, VEC_N_SIZE_BYTES); + printf("\n\ne: "); + vect_print(e, VEC_N_SIZE_BYTES); + printf("\n\nTruncate(s.r2 + e): "); + vect_print(tmp, VEC_N1N2_SIZE_BYTES); + printf("\n\nc_pke->u: "); + vect_print(c_pke->u, VEC_N_SIZE_BYTES); + printf("\n\nc_pke->v: "); + vect_print(c_pke->v, VEC_N1N2_SIZE_BYTES); +#endif + + // Zeroize sensitive data + memset_zero(r1, sizeof r1); + memset_zero(r2, sizeof r2); + memset_zero(e, sizeof e); + memset_zero(tmp, sizeof tmp); + memset_zero(&theta_xof_ctx, sizeof theta_xof_ctx); +} + +/** + * @brief Decrypts a ciphertext using the HQC public-key encryption (PKE) scheme. + * + * This function performs decryption in the HQC PKE scheme. It uses the given decryption key (`dk_pke`) + * to decrypt the ciphertext `c_pke`, recovering the original message `m`. + * + * @param[out] m Pointer to the output buffer where the decrypted message will be stored. + * @param[in] dk_pke Pointer to the decryption key. + * @param[in] c_pke Pointer to the input ciphertext structure (PKE ciphertext). + * + * @return Returns 0 on success. + * + */ +uint8_t hqc_pke_decrypt(uint64_t *m, const uint8_t *dk_pke, const ciphertext_pke_t *c_pke) { + uint64_t y[VEC_N_SIZE_64] = {0}; + uint64_t tmp1[VEC_N_SIZE_64] = {0}; + uint64_t tmp2[VEC_N_SIZE_64] = {0}; + + // Parse decryption key dk_pke + hqc_dk_pke_from_string(y, dk_pke); + + // Compute u.y + vect_mul(tmp1, y, c_pke->u); + // Truncate(u.y) + vect_truncate(tmp1); + // Compute v - Truncate(u.y) + vect_add(tmp2, c_pke->v, tmp1, VEC_N1N2_SIZE_64); + +#ifdef VERBOSE + printf("\n\nc_pke.u: "); + vect_print(c_pke->u, VEC_N_SIZE_BYTES); + printf("\n\nc_pke.v: "); + vect_print(c_pke->v, VEC_N1N2_SIZE_BYTES); + printf("\n\ny: "); + vect_print(y, VEC_N_SIZE_BYTES); + printf("\n\nTruncate(u.y): "); + vect_print(tmp1, VEC_N1N2_SIZE_BYTES); + printf("\n\nv - Truncate(u.y): "); + vect_print(tmp2, VEC_N1N2_SIZE_BYTES); +#endif + + // Compute plaintext m + code_decode(m, tmp2); + + // Zeroize sensitive data + memset_zero(y, sizeof y); + memset_zero(tmp1, sizeof tmp1); + memset_zero(tmp2, sizeof tmp2); + + return 0; +} diff --git a/src/kem/hqc/hqc_ref/src/ref/hqc.h b/src/kem/hqc/hqc_ref/src/ref/hqc.h new file mode 100644 index 0000000000..7e37a0d4bf --- /dev/null +++ b/src/kem/hqc/hqc_ref/src/ref/hqc.h @@ -0,0 +1,20 @@ +/** + * @file hqc.h + * @brief Header file for hqc.c + */ + +#ifndef HQC_HQC_H +#define HQC_HQC_H + +#if defined(__i386__) || defined(__x86_64__) +#include +#endif +#include +#include "parameters.h" +#include "parsing.h" + +void hqc_pke_keygen(uint8_t *ek_pke, uint8_t *dk_pke, uint8_t *seed); +void hqc_pke_encrypt(ciphertext_pke_t *c_pke, const uint8_t *ek_pke, const uint64_t *m, const uint8_t *theta); +uint8_t hqc_pke_decrypt(uint64_t *m, const uint8_t *dk_pke, const ciphertext_pke_t *c_pke); + +#endif // HQC_HQC_H diff --git a/src/kem/hqc/hqc_ref/src/ref/parsing.c b/src/kem/hqc/hqc_ref/src/ref/parsing.c new file mode 100644 index 0000000000..abd0ec733a --- /dev/null +++ b/src/kem/hqc/hqc_ref/src/ref/parsing.c @@ -0,0 +1,67 @@ +/** + * @file parsing.c + * @brief Functions to parse secret key, public key and ciphertext of the HQC scheme + */ + +#include "parsing.h" +#include +#include +#include "crypto_memset.h" +#include "symmetric.h" +#include "vector.h" + +/** + * @brief Deserializes a decryption key into its internal vectorized form. + * + * @param[out] y Pointer to the output buffer where the internal vectorized key will be stored. + * @param[in] dk_pke Pointer to the serialized decryption key. + */ +void hqc_dk_pke_from_string(uint64_t *y, const uint8_t *dk_pke) { + shake256_xof_ctx dk_xof_ctx = {0}; + xof_init(&dk_xof_ctx, dk_pke, SEED_BYTES); + vect_sample_fixed_weight1(&dk_xof_ctx, y, PARAM_OMEGA); + + // Zeroize sensitive data + memset_zero(&dk_xof_ctx, sizeof dk_xof_ctx); +} + +/** + * @brief Deserializes an encryption key into its internal representation. + * + * @param[out] h Pointer to the output buffer for `h` the first internal component of the key. + * @param[out] s Pointer to the output buffer for `s` the second internal component of the key. + * @param[in] ek_pke Pointer to the serialized encryption key. + */ +void hqc_ek_pke_from_string(uint64_t *h, uint64_t *s, const uint8_t *ek_pke) { + shake256_xof_ctx ek_xof_ctx = {0}; + + xof_init(&ek_xof_ctx, ek_pke, SEED_BYTES); + vect_set_random(&ek_xof_ctx, h); + + memcpy(s, ek_pke + SEED_BYTES, VEC_N_SIZE_BYTES); +} + +/** + * @brief Serializes a KEM ciphertext structure into a byte array. + * + * @param[out] ct Pointer to the output buffer where the serialized ciphertext will be stored. + * @param[in] c_kem Pointer to the KEM ciphertext structure to be serialized. + */ +void hqc_c_kem_to_string(uint8_t *ct, const ciphertext_kem_t *c_kem) { + memcpy(ct, c_kem->c_pke.u, VEC_N_SIZE_BYTES); + memcpy(ct + VEC_N_SIZE_BYTES, c_kem->c_pke.v, VEC_N1N2_SIZE_BYTES); + memcpy(ct + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES, c_kem->salt, SALT_BYTES); +} + +/** + * @brief Deserializes a KEM ciphertext byte array into its structured components. + * + * @param[out] c_pke Pointer to the output buffer where the deserialized PKE ciphertext will be stored. + * @param[out] salt Pointer to the output buffer where the extracted salt will be stored. + * @param[in] ct Pointer to the serialized KEM ciphertext. + */ +void hqc_c_kem_from_string(ciphertext_pke_t *c_pke, uint8_t *salt, const uint8_t *ct) { + memcpy(c_pke->u, ct, VEC_N_SIZE_BYTES); + memcpy(c_pke->v, ct + VEC_N_SIZE_BYTES, VEC_N1N2_SIZE_BYTES); + memcpy(salt, ct + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES, SALT_BYTES); +} diff --git a/src/kem/hqc/hqc_ref/src/ref/parsing.h b/src/kem/hqc/hqc_ref/src/ref/parsing.h new file mode 100644 index 0000000000..07f4d16f40 --- /dev/null +++ b/src/kem/hqc/hqc_ref/src/ref/parsing.h @@ -0,0 +1,22 @@ +/** + * @file parsing.h + * @brief Header file for parsing.c + */ + +#ifndef HQC_PARSING_H +#define HQC_PARSING_H + +#if defined(__i386__) || defined(__x86_64__) +#include +#endif +#include +#include "data_structures.h" +#include "parameters.h" + +void hqc_dk_pke_from_string(uint64_t *y, const uint8_t *dk_pke); +void hqc_ek_pke_from_string(uint64_t *h, uint64_t *s, const uint8_t *ek_pke); + +void hqc_c_kem_to_string(uint8_t *ct, const ciphertext_kem_t *c_kem); +void hqc_c_kem_from_string(ciphertext_pke_t *c_pke, uint8_t *salt, const uint8_t *ct); + +#endif // HQC_PARSING_H diff --git a/src/kem/hqc/hqc_ref/src/ref/reed_muller.c b/src/kem/hqc/hqc_ref/src/ref/reed_muller.c new file mode 100644 index 0000000000..82760e4250 --- /dev/null +++ b/src/kem/hqc/hqc_ref/src/ref/reed_muller.c @@ -0,0 +1,213 @@ +/** + * @file reed_muller.c + * @brief Constant time implementation of Reed-Muller code RM(1,7) + */ + +#include "reed_muller.h" +#include +#include +#include "data_structures.h" +#include "parameters.h" + +/** + * @brief Number of repeated 128-bit codeword blocks. + * + * Calculates the ceiling of PARAM_N2/128 to determine how many + * copies of each 128-bit codeword are used in the code expansion. + */ +#define MULTIPLICITY CEIL_DIVIDE(PARAM_N2, 128) + +/** + * @typedef rm_expanded_cdw + * @brief Internal representation of a codeword with each bit expanded to a 16-bit signed value. + */ +typedef int16_t rm_expanded_cdw[128]; + +// clang-format off +/** + * @def BIT0MASK(x) + * @brief Broadcast the least significant bit of \p x to a 32-bit mask. + * + * @param x An integer expression; only bit 0 is examined. + * @return A 32-bit value of all ones (if \p x&1 == 1) or all zeros (if \p x&1 == 0). + */ +#define BIT0MASK(x) (int32_t)(-((x) & 1)) +// clang-format on + +void encode(rm_codeword_t *word, int32_t message); +void hadamard(rm_expanded_cdw *src, rm_expanded_cdw *dst); +void expand_and_sum(rm_expanded_cdw *dest, rm_codeword_t src[]); +int32_t find_peaks(rm_expanded_cdw *transform); + +/** + * @brief Encode a single byte into a single codeword using RM(1,7) + * + * Encoding matrix of this code: + * bit pattern (note that bits are numbered big endian) + * 0 aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa + * 1 cccccccc cccccccc cccccccc cccccccc + * 2 f0f0f0f0 f0f0f0f0 f0f0f0f0 f0f0f0f0 + * 3 ff00ff00 ff00ff00 ff00ff00 ff00ff00 + * 4 ffff0000 ffff0000 ffff0000 ffff0000 + * 5 ffffffff 00000000 ffffffff 00000000 + * 6 ffffffff ffffffff 00000000 00000000 + * 7 ffffffff ffffffff ffffffff ffffffff + * + * @param[out] word An RM(1,7) codeword + * @param[in] message A message + */ +void encode(rm_codeword_t *word, int32_t message) { + int32_t first_word; + + first_word = BIT0MASK(message >> 7); + + first_word ^= BIT0MASK(message >> 0) & 0xaaaaaaaa; + first_word ^= BIT0MASK(message >> 1) & 0xcccccccc; + first_word ^= BIT0MASK(message >> 2) & 0xf0f0f0f0; + first_word ^= BIT0MASK(message >> 3) & 0xff00ff00; + first_word ^= BIT0MASK(message >> 4) & 0xffff0000; + + word->u32[0] = first_word; + + first_word ^= BIT0MASK(message >> 5); + word->u32[1] = first_word; + first_word ^= BIT0MASK(message >> 6); + word->u32[3] = first_word; + first_word ^= BIT0MASK(message >> 5); + word->u32[2] = first_word; + return; +} + +/** + * @brief Hadamard transform + * + * Perform hadamard transform of src and store result in dst + * src is overwritten + * + * @param[out] src Structure that contain the expanded codeword + * @param[out] dst Structure that contain the expanded codeword + */ +void hadamard(rm_expanded_cdw *src, rm_expanded_cdw *dst) { + // the passes move data: + // src -> dst -> src -> dst -> src -> dst -> src -> dst + // using p1 and p2 alternately + rm_expanded_cdw *p1 = src; + rm_expanded_cdw *p2 = dst; + for (int32_t pass = 0; pass < 7; pass++) { + for (int32_t i = 0; i < 64; i++) { + (*p2)[i] = (*p1)[2 * i] + (*p1)[2 * i + 1]; + (*p2)[i + 64] = (*p1)[2 * i] - (*p1)[2 * i + 1]; + } + // swap p1, p2 for next round + rm_expanded_cdw *p3 = p1; + p1 = p2; + p2 = p3; + } +} + +/** + * @brief Add multiple codewords into expanded codeword + * + * Accesses memory in order + * Note: this does not write the codewords as -1 or +1 as the green machine does + * instead, just 0 and 1 is used. + * The resulting hadamard transform has: + * all values are halved + * the first entry is 64 too high + * + * @param[out] dest Structure that contain the expanded codeword + * @param[in] src Structure that contain the codeword + */ +void expand_and_sum(rm_expanded_cdw *dest, rm_codeword_t src[]) { + // start with the first copy + for (int32_t part = 0; part < 4; part++) { + for (int32_t bit = 0; bit < 32; bit++) { + (*dest)[part * 32 + bit] = src[0].u32[part] >> bit & 1; + } + } + // sum the rest of the copies + for (int32_t copy = 1; copy < MULTIPLICITY; copy++) { + for (int32_t part = 0; part < 4; part++) { + for (int32_t bit = 0; bit < 32; bit++) { + (*dest)[part * 32 + bit] += src[copy].u32[part] >> bit & 1; + } + } + } +} + +/** + * @brief Finding the location of the highest value + * + * This is the final step of the green machine: find the location of the highest value, + * and add 128 if the peak is positive + * if there are two identical peaks, the peak with smallest value + * in the lowest 7 bits it taken + * @param[in] transform Structure that contain the expanded codeword + */ +int32_t find_peaks(rm_expanded_cdw *transform) { + int32_t peak_abs_value = 0; + int32_t peak_value = 0; + int32_t peak_pos = 0; + for (int32_t i = 0; i < 128; i++) { + // get absolute value + int32_t t = (*transform)[i]; + int32_t pos_mask = -(t > 0); + int32_t absolute = (pos_mask & t) | (~pos_mask & -t); + peak_value = absolute > peak_abs_value ? t : peak_value; + peak_pos = absolute > peak_abs_value ? i : peak_pos; + peak_abs_value = absolute > peak_abs_value ? absolute : peak_abs_value; + } + // set bit 7 + peak_pos |= 128 * (peak_value > 0); + return peak_pos; +} + +/** + * @brief Encodes the received word + * + * The message consists of N1 bytes each byte is encoded into PARAM_N2 bits, + * or MULTIPLICITY repeats of 128 bits + * + * @param[out] cdw Array of size VEC_N1N2_SIZE_64 receiving the encoded message + * @param[in] msg Array of size VEC_N1_SIZE_64 storing the message + */ +void reed_muller_encode(uint64_t *cdw, const uint64_t *msg) { + uint8_t *message_array = (uint8_t *)msg; + rm_codeword_t *codeArray = (rm_codeword_t *)cdw; + for (size_t i = 0; i < VEC_N1_SIZE_BYTES; i++) { + // fill entries i * MULTIPLICITY to (i+1) * MULTIPLICITY + int32_t pos = i * MULTIPLICITY; + // encode first word + encode(&codeArray[pos], message_array[i]); + // copy to other identical codewords + for (size_t copy = 1; copy < MULTIPLICITY; copy++) { + memcpy(&codeArray[pos + copy], &codeArray[pos], sizeof(rm_codeword_t)); + } + } +} + +/** + * @brief Decodes the received word + * + * Decoding uses fast hadamard transform, for a more complete picture on Reed-Muller decoding, see MacWilliams, Florence + * Jessie, and Neil James Alexander Sloane. The theory of error-correcting codes codes @cite macwilliams1977theory + * + * @param[out] msg Array of size VEC_N1_SIZE_64 receiving the decoded message + * @param[in] cdw Array of size VEC_N1N2_SIZE_64 storing the received word + */ +void reed_muller_decode(uint64_t *msg, const uint64_t *cdw) { + uint8_t *message_array = (uint8_t *)msg; + rm_codeword_t *codeArray = (rm_codeword_t *)cdw; + rm_expanded_cdw expanded; + for (size_t i = 0; i < VEC_N1_SIZE_BYTES; i++) { + // collect the codewords + expand_and_sum(&expanded, &codeArray[i * MULTIPLICITY]); + // apply hadamard transform + rm_expanded_cdw transform; + hadamard(&expanded, &transform); + // fix the first entry to get the half Hadamard transform + transform[0] -= 64 * MULTIPLICITY; + // finish the decoding + message_array[i] = find_peaks(&transform); + } +} diff --git a/src/kem/hqc/hqc_ref/src/ref/reed_solomon.c b/src/kem/hqc/hqc_ref/src/ref/reed_solomon.c new file mode 100644 index 0000000000..fb6300f76d --- /dev/null +++ b/src/kem/hqc/hqc_ref/src/ref/reed_solomon.c @@ -0,0 +1,449 @@ +/** + * @file reed_solomon.c + * @brief Constant time implementation of Reed-Solomon codes + */ + +#include "reed_solomon.h" +#include +#include +#include +#include "crypto_memset.h" +#include "fft.h" +#include "gf.h" +#include "parameters.h" +#ifdef VERBOSE +#include +#include +#endif + +static uint16_t mod(uint16_t i, uint16_t modulus); +static void compute_syndromes(uint16_t *syndromes, uint8_t *cdw); +static uint16_t compute_elp(uint16_t *sigma, const uint16_t *syndromes); +static void compute_roots(uint8_t *error, uint16_t *sigma); +static void compute_z_poly(uint16_t *z, const uint16_t *sigma, const uint16_t degree, const uint16_t *syndromes); +static void compute_error_values(uint16_t *error_values, const uint16_t *z, const uint8_t *error); +static void correct_errors(uint8_t *cdw, const uint16_t *error_values); + +/** + * Returns i modulo the given modulus. + * i must be less than 2*modulus. + * Therefore, the return value is either i or i-modulus. + * @returns i mod (modulus) + * @param[in] i The integer whose modulo is taken + * @param[in] modulus The modulus + */ +static uint16_t mod(uint16_t i, uint16_t modulus) { + uint16_t tmp = i - modulus; + + // mask = 0xffff if(i < PARAM_GF_MUL_ORDER) + int16_t mask = -(tmp >> 15); + + return tmp + (mask & modulus); +} + +/** + * @brief Computes the generator polynomial of the primitive Reed-Solomon code with given parameters. + * + * Code length is 2^m-1.
+ * PARAM_DELTA is the targeted correction capacity of the code + * and receives the real correction capacity (which is at least equal to the target).
+ * gf_exp and gf_log are arrays giving antilog and log of GF(2^m) elements. + * + * @param[out] poly Array of size (2*PARAM_DELTA + 1) receiving the coefficients of the generator polynomial + */ +void compute_generator_poly(uint16_t *poly) { + poly[0] = 1; + int tmp_degree = 0; + + for (uint16_t i = 1; i < (2 * PARAM_DELTA + 1); ++i) { + for (size_t j = tmp_degree; j; --j) { + poly[j] = gf_exp[mod(gf_log[poly[j]] + i, PARAM_GF_MUL_ORDER)] ^ poly[j - 1]; + } + + poly[0] = gf_exp[mod(gf_log[poly[0]] + i, PARAM_GF_MUL_ORDER)]; + poly[++tmp_degree] = 1; + } + + printf("\n"); + for (int i = 0; i < (PARAM_G); ++i) { + printf("%d, ", poly[i]); + } + printf("\n"); +} + +/** + * @brief Encodes a message message of PARAM_K bits to a Reed-Solomon codeword codeword of PARAM_N1 bytes + * + * Following @cite lin1983error (Chapter 4 - Cyclic Codes), + * We perform a systematic encoding using a linear (PARAM_N1 - PARAM_K)-stage shift register + * with feedback connections based on the generator polynomial PARAM_RS_POLY of the Reed-Solomon code. + * + * @param[out] cdw Array of size VEC_N1_SIZE_64 receiving the encoded message + * @param[in] msg Array of size VEC_K_SIZE_64 storing the message + */ +void reed_solomon_encode(uint64_t *cdw, const uint64_t *msg) { + size_t i, j, k; + uint8_t gate_value = 0; + + uint16_t tmp[PARAM_G] = {0}; + uint16_t PARAM_RS_POLY[] = {RS_POLY_COEFS}; + + uint8_t msg_bytes[PARAM_K] = {0}; + uint8_t cdw_bytes[PARAM_N1] = {0}; + + memcpy(msg_bytes, msg, PARAM_K); + + for (i = 0; i < PARAM_K; ++i) { + gate_value = msg_bytes[PARAM_K - 1 - i] ^ cdw_bytes[PARAM_N1 - PARAM_K - 1]; + + for (j = 0; j < PARAM_G; ++j) { + tmp[j] = gf_mul(gate_value, PARAM_RS_POLY[j]); + } + + for (k = PARAM_N1 - PARAM_K - 1; k; --k) { + cdw_bytes[k] = cdw_bytes[k - 1] ^ tmp[k]; + } + + cdw_bytes[0] = tmp[0]; + } + + memcpy(cdw_bytes + PARAM_N1 - PARAM_K, msg_bytes, PARAM_K); + memcpy(cdw, cdw_bytes, PARAM_N1); +} + +/** + * @brief Computes 2 * PARAM_DELTA syndromes + * + * @param[out] syndromes Array of size 2 * PARAM_DELTA receiving the computed syndromes + * @param[in] cdw Array of size PARAM_N1 storing the received vector + */ +void compute_syndromes(uint16_t *syndromes, uint8_t *cdw) { + for (size_t i = 0; i < 2 * PARAM_DELTA; ++i) { + for (size_t j = 1; j < PARAM_N1; ++j) { + syndromes[i] ^= gf_mul(cdw[j], alpha_ij_pow[i][j - 1]); + } + syndromes[i] ^= cdw[0]; + } +} + +/** + * @brief Computes the error locator polynomial (ELP) sigma + * + * This is a constant time implementation of Berlekamp's algorithm (see @cite lin1983error (Chapter 6 - BCH + * Codes).
We use the letter p for rho which is initialized at -1.
The array X_sigma_p represents the + * polynomial X^(mu-rho)*sigma_p(X).
Instead of maintaining a list of sigmas, we update in place both sigma and + * X_sigma_p.
sigma_copy serves as a temporary save of sigma in case X_sigma_p needs to be updated.
We can + * properly correct only if the degree of sigma does not exceed PARAM_DELTA. This means only the first PARAM_DELTA + 1 + * coefficients of sigma are of value and we only need to save its first PARAM_DELTA - 1 coefficients. + * + * @returns the degree of the ELP sigma + * @param[out] sigma Array of size (at least) PARAM_DELTA receiving the ELP + * @param[in] syndromes Array of size (at least) 2*PARAM_DELTA storing the syndromes + */ +static uint16_t compute_elp(uint16_t *sigma, const uint16_t *syndromes) { + uint16_t deg_sigma = 0; + uint16_t deg_sigma_p = 0; + uint16_t deg_sigma_copy = 0; + uint16_t sigma_copy[PARAM_DELTA + 1] = {0}; + uint16_t X_sigma_p[PARAM_DELTA + 1] = {0, 1}; + uint16_t pp = (uint16_t)-1; // 2*rho + uint16_t d_p = 1; + uint16_t d = syndromes[0]; + + uint16_t mask1, mask2, mask12; + uint16_t deg_X, deg_X_sigma_p; + uint16_t dd; + uint16_t mu; + + uint16_t i; + + sigma[0] = 1; + for (mu = 0; (mu < (2 * PARAM_DELTA)); ++mu) { + // Save sigma in case we need it to update X_sigma_p + memcpy(sigma_copy, sigma, 2 * (PARAM_DELTA)); + deg_sigma_copy = deg_sigma; + + dd = gf_mul(d, gf_inverse(d_p)); + + for (i = 1; (i <= mu + 1) && (i <= PARAM_DELTA); ++i) { + sigma[i] ^= gf_mul(dd, X_sigma_p[i]); + } + + deg_X = mu - pp; + deg_X_sigma_p = deg_X + deg_sigma_p; + + // mask1 = 0xffff if(d != 0) and 0 otherwise + mask1 = -((uint16_t)-d >> 15); + + // mask2 = 0xffff if(deg_X_sigma_p > deg_sigma) and 0 otherwise + mask2 = -((uint16_t)(deg_sigma - deg_X_sigma_p) >> 15); + + // mask12 = 0xffff if the deg_sigma increased and 0 otherwise + volatile uint16_t mask12__ = mask1 & mask2; + mask12 = mask12__; + deg_sigma ^= mask12 & (deg_X_sigma_p ^ deg_sigma); + + if (mu == (2 * PARAM_DELTA - 1)) { + break; + } + + pp ^= mask12 & (mu ^ pp); + d_p ^= mask12 & (d ^ d_p); + for (i = PARAM_DELTA; i; --i) { + X_sigma_p[i] = (mask12 & sigma_copy[i - 1]) ^ (~mask12 & X_sigma_p[i - 1]); + } + + deg_sigma_p ^= mask12 & (deg_sigma_copy ^ deg_sigma_p); + d = syndromes[mu + 1]; + + for (i = 1; (i <= mu + 1) && (i <= PARAM_DELTA); ++i) { + d ^= gf_mul(sigma[i], syndromes[mu + 1 - i]); + } + } + + return deg_sigma; +} + +/** + * @brief Computes the error polynomial error from the error locator polynomial sigma + * + * See function fft for more details. + * + * @param[out] error Array of 2^PARAM_M elements receiving the error polynomial + * @param[in] sigma Array of 2^PARAM_FFT elements storing the error locator polynomial + */ +static void compute_roots(uint8_t *error, uint16_t *sigma) { + uint16_t w[1 << PARAM_M] = {0}; + + fft(w, sigma, PARAM_DELTA + 1); + fft_retrieve_error_poly(error, w); +} + +/** + * @brief Computes the polynomial z(x) + * + * See @cite lin1983error (Chapter 6 - BCH Codes) for more details. + * + * @param[out] z Array of PARAM_DELTA + 1 elements receiving the polynomial z(x) + * @param[in] sigma Array of 2^PARAM_FFT elements storing the error locator polynomial + * @param[in] degree Integer that is the degree of polynomial sigma + * @param[in] syndromes Array of 2 * PARAM_DELTA storing the syndromes + */ +static void compute_z_poly(uint16_t *z, const uint16_t *sigma, const uint16_t degree, const uint16_t *syndromes) { + size_t i, j; + uint16_t mask; + + z[0] = 1; + + for (i = 1; i < PARAM_DELTA + 1; ++i) { + mask = -((uint16_t)(i - degree - 1) >> 15); + z[i] = mask & sigma[i]; + } + + z[1] ^= syndromes[0]; + + for (i = 2; i <= PARAM_DELTA; ++i) { + mask = -((uint16_t)(i - degree - 1) >> 15); + z[i] ^= mask & syndromes[i - 1]; + + for (j = 1; j < i; ++j) { + z[i] ^= mask & gf_mul(sigma[j], syndromes[i - j - 1]); + } + } +} + +/** + * @brief Computes the error values + * + * See @cite lin1983error (Chapter 6 - BCH Codes) for more details. + * + * @param[out] error_values Array of PARAM_DELTA elements receiving the error values + * @param[in] z Array of PARAM_DELTA + 1 elements storing the polynomial z(x) + * @param[in] error Array storing the error + */ +static void compute_error_values(uint16_t *error_values, const uint16_t *z, const uint8_t *error) { + uint16_t beta_j[PARAM_DELTA] = {0}; + uint16_t e_j[PARAM_DELTA] = {0}; + + uint16_t delta_counter; + uint16_t delta_real_value; + uint16_t found; + uint16_t mask1; + uint16_t mask2; + uint16_t tmp1; + uint16_t tmp2; + uint16_t inverse; + uint16_t inverse_power_j; + + // Compute the beta_{j_i} page 31 of the documentation + delta_counter = 0; + for (size_t i = 0; i < PARAM_N1; i++) { + found = 0; + mask1 = (uint16_t)(-((int32_t)error[i]) >> 31); // error[i] != 0 + for (size_t j = 0; j < PARAM_DELTA; j++) { + mask2 = ~((uint16_t)(-((int32_t)j ^ delta_counter) >> 31)); // j == delta_counter + beta_j[j] += mask1 & mask2 & gf_exp[i]; + found += mask1 & mask2 & 1; + } + delta_counter += found; + } + delta_real_value = delta_counter; + + // Compute the e_{j_i} page 31 of the documentation + for (size_t i = 0; i < PARAM_DELTA; ++i) { + tmp1 = 1; + tmp2 = 1; + inverse = gf_inverse(beta_j[i]); + inverse_power_j = 1; + + for (size_t j = 1; j <= PARAM_DELTA; ++j) { + inverse_power_j = gf_mul(inverse_power_j, inverse); + tmp1 ^= gf_mul(inverse_power_j, z[j]); + } + for (size_t k = 1; k < PARAM_DELTA; ++k) { + tmp2 = gf_mul(tmp2, (1 ^ gf_mul(inverse, beta_j[(i + k) % PARAM_DELTA]))); + } + mask1 = (uint16_t)(((int16_t)i - delta_real_value) >> 15); // i < delta_real_value + e_j[i] = mask1 & gf_mul(tmp1, gf_inverse(tmp2)); + } + + // Place the delta e_{j_i} values at the right coordinates of the output vector + delta_counter = 0; + for (size_t i = 0; i < PARAM_N1; ++i) { + found = 0; + mask1 = (uint16_t)(-((int32_t)error[i]) >> 31); // error[i] != 0 + for (size_t j = 0; j < PARAM_DELTA; j++) { + mask2 = ~((uint16_t)(-((int32_t)j ^ delta_counter) >> 31)); // j == delta_counter + error_values[i] += mask1 & mask2 & e_j[j]; + found += mask1 & mask2 & 1; + } + delta_counter += found; + } +} + +/** + * @brief Correct the errors + * + * @param[out] cdw Array of PARAM_N1 elements receiving the corrected vector + * @param[in] error_values Array of PARAM_DELTA elements storing the error values + */ +static void correct_errors(uint8_t *cdw, const uint16_t *error_values) { + for (size_t i = 0; i < PARAM_N1; ++i) { + cdw[i] ^= error_values[i]; + } +} + +/** + * @brief Decodes the received word + * + * This function relies on six steps: + * -# Compute the 2·PARAM_DELTA syndromes. + * -# Compute the error-locator polynomial σ(x). + * -# Use an additive FFT to find the roots of σ(x) (the error locations) and take their inverses. + * -# Compute the error-evaluator polynomial z(x). + * -# Compute the error values at each located position. + * -# Correct the received polynomial by subtracting the error values. + * + * For a more complete picture on Reed-Solomon decoding, see Shu. Lin and Daniel J. Costello in Error Control Coding: + * Fundamentals and Applications @cite lin1983error + * + * @param[out] msg Array of size VEC_K_SIZE_64 receiving the decoded message + * @param[in] cdw Array of size VEC_N1_SIZE_64 storing the received word + */ +void reed_solomon_decode(uint64_t *msg, uint64_t *cdw) { + uint8_t cdw_bytes[PARAM_N1] = {0}; + uint16_t syndromes[2 * PARAM_DELTA] = {0}; + uint16_t sigma[1 << PARAM_FFT] = {0}; + uint8_t error[1 << PARAM_M] = {0}; + uint16_t z[PARAM_N1] = {0}; + uint16_t error_values[PARAM_N1] = {0}; + uint16_t deg; + + // Copy the vector in an array of bytes + memcpy(cdw_bytes, cdw, PARAM_N1); + + // Calculate the 2*PARAM_DELTA syndromes + compute_syndromes(syndromes, cdw_bytes); + + // Compute the error locator polynomial sigma + // Sigma's degree is at most PARAM_DELTA but the FFT requires the extra room + deg = compute_elp(sigma, syndromes); + + // Compute the error polynomial error + compute_roots(error, sigma); + + // Compute the polynomial z(x) + compute_z_poly(z, sigma, deg, syndromes); + + // Compute the error values + compute_error_values(error_values, z, error); + + // Correct the errors + correct_errors(cdw_bytes, error_values); + + // Retrieve the message from the decoded codeword + memcpy(msg, cdw_bytes + (PARAM_G - 1), PARAM_K); + +#ifdef VERBOSE + printf("\n\nThe syndromes: "); + for (size_t i = 0; i < 2 * PARAM_DELTA; ++i) { + printf("%u ", syndromes[i]); + } + printf("\n\nThe error locator polynomial: sigma(x) = "); + bool first_coeff = true; + if (sigma[0]) { + printf("%u", sigma[0]); + first_coeff = false; + } + for (size_t i = 1; i < (1 << PARAM_FFT); ++i) { + if (sigma[i] == 0) + continue; + if (!first_coeff) + printf(" + "); + first_coeff = false; + if (sigma[i] != 1) + printf("%u ", sigma[i]); + if (i == 1) + printf("x"); + else + printf("x^%zu", i); + } + if (first_coeff) + printf("0"); + + printf("\n\nThe polynomial: z(x) = "); + bool first_coeff_1 = true; + if (z[0]) { + printf("%u", z[0]); + first_coeff_1 = false; + } + for (size_t i = 1; i < (PARAM_DELTA + 1); ++i) { + if (z[i] == 0) + continue; + if (!first_coeff_1) + printf(" + "); + first_coeff_1 = false; + if (z[i] != 1) + printf("%u ", z[i]); + if (i == 1) + printf("x"); + else + printf("x^%zu", i); + } + if (first_coeff_1) + printf("0"); + + printf("\n\nThe pairs of (error locator numbers, error values): "); + size_t j = 0; + for (size_t i = 0; i < PARAM_N1; ++i) { + if (error[i]) { + printf("(%zu, %d) ", i, error_values[j]); + j++; + } + } + printf("\n"); +#endif + + // Zeroize sensitive data + memset_zero(cdw_bytes, sizeof cdw_bytes); +} diff --git a/src/kem/hqc/hqc_ref/src/ref/vector.c b/src/kem/hqc/hqc_ref/src/ref/vector.c new file mode 100644 index 0000000000..686a2fdede --- /dev/null +++ b/src/kem/hqc/hqc_ref/src/ref/vector.c @@ -0,0 +1,304 @@ +/** + * @file vector.c + * @brief Implementation of vectors sampling and some utilities for the HQC scheme + */ + +#include "vector.h" +#include +#include +#include +#include "parameters.h" + +static inline uint32_t compare_u32(const uint32_t v1, const uint32_t v2); + +/** + * @brief Constant-time comparison of two integers v1 and v2 + * + * Returns 1 if v1 is equal to v2 and 0 otherwise + * https://gist.github.com/sneves/10845247 + * + * @param[in] v1 + * @param[in] v2 + */ +static inline uint32_t compare_u32(const uint32_t v1, const uint32_t v2) { + return 1 ^ (((v1 - v2) | (v2 - v1)) >> 31); +} + +/** + * @brief Constant-time Barrett reduction modulo PARAM_N. + * + * Reduces \p x modulo PARAM_N using the precomputed value PARAM_N_MU = ⌊2^32 / PARAM_N⌋. + * + * @param[in] x Input value to reduce. + * @return x mod PARAM_N in constant time. + */ +static inline uint32_t barrett_reduce(uint32_t x) { + uint64_t q = ((uint64_t)x * PARAM_N_MU) >> 32; + uint32_t r = x - (uint32_t)(q * PARAM_N); + + uint32_t reduce_flag = (((r - PARAM_N) >> 31) ^ 1); + uint32_t mask = -reduce_flag; + r -= mask & PARAM_N; + return r; +} + +/** + * @brief Generates a random support set with uniform and unbiased sampling. + * + * This function implements a rejection sampling algorithm to generate `weight` + * distinct indices uniformly at random from the interval [0, PARAM_N). + * It ensures that the output is non-biased and the values are uniformly distributed. + * + * Internally, it samples 24-bit random values and rejects any value ≥ UTILS_REJECTION_THRESHOLD, + * where the threshold is precomputed as: + * \f[ + * t = \left\lfloor \frac{2^{24}}{\text{PARAM\_N}} \right\rfloor \times \text{PARAM\_N} + * \f] + * + * @param[in,out] ctx SHAKE256 XOF context used for random byte generation. + * @param[out] support Output array to store the `weight` unique indices. + * @param[in] weight Desired Hamming weight. + */ +void vect_generate_random_support1(shake256_xof_ctx *ctx, uint32_t *support, uint16_t weight) { + size_t random_bytes_size = 3 * weight; + uint8_t rand_bytes[3 * PARAM_OMEGA_R] = {0}; + uint8_t inc; + size_t i, j; + + i = 0; + j = random_bytes_size; + while (i < weight) { + do { + if (j == random_bytes_size) { + xof_get_bytes(ctx, rand_bytes, random_bytes_size); + j = 0; + } + + support[i] = ((uint32_t)rand_bytes[j++]) << 16; + support[i] |= ((uint32_t)rand_bytes[j++]) << 8; + support[i] |= rand_bytes[j++]; + + } while (support[i] >= UTILS_REJECTION_THRESHOLD); + + support[i] = barrett_reduce(support[i]); + + inc = 1; + for (size_t k = 0; k < i; k++) { + if (support[k] == support[i]) { + inc = 0; + } + } + i += inc; + } +} + +/** + * @brief Generates a random support set of distinct indices. + * + * This implements the **GenerateRandomSupport** algorithm from the specification. + * + * @param[in,out] ctx Initialized SHAKE256 XOF context used for randomness. + * @param[out] support Output array of unique indices (the support set). + * @param[in] weight Number of elements to generate (Hamming weight). + */ +void vect_generate_random_support2(shake256_xof_ctx *ctx, uint32_t *support, uint16_t weight) { + uint32_t rand_u32[PARAM_OMEGA_R] = {0}; + + xof_get_bytes(ctx, (uint8_t *)&rand_u32, 4 * weight); + + for (size_t i = 0; i < weight; ++i) { + uint64_t buff = rand_u32[i]; + support[i] = i + ((buff * (PARAM_N - i)) >> 32); + } + + for (int32_t i = (weight - 1); i-- > 0;) { + uint32_t found = 0; + + for (size_t j = i + 1; j < weight; ++j) { + found |= compare_u32(support[j], support[i]); + } + + uint32_t mask = -found; + support[i] = (mask & i) ^ (~mask & support[i]); + } +} + +/** + * @brief Sets bits in a vector based on a support set. + * + * Writes `weight` positions from `support` into the bit-vector `v`. + * Each index in `support` sets a corresponding bit in `v`. + * + * @param[out] v Output vector. + * @param[in] support Array of bit indices to set. + * @param[in] weight Number of positions to set. + */ +void vect_write_support_to_vector(uint64_t *v, uint32_t *support, uint16_t weight) { + uint32_t index_tab[PARAM_OMEGA_R] = {0}; + uint64_t bit_tab[PARAM_OMEGA_R] = {0}; + + for (size_t i = 0; i < weight; i++) { + index_tab[i] = support[i] >> 6; + int32_t pos = support[i] & 0x3f; + bit_tab[i] = ((uint64_t)1) << pos; + } + + uint64_t val = 0; + for (uint32_t i = 0; i < VEC_N_SIZE_64; i++) { + val = 0; + for (uint32_t j = 0; j < weight; j++) { + uint32_t tmp = i - index_tab[j]; + int val1 = 1 ^ ((tmp | -tmp) >> 31); + uint64_t mask = -val1; + val |= (bit_tab[j] & mask); + } + v[i] |= val; + } +} + +/** + * @brief Generate a random binary vector of fixed Hamming weight. + * + * It samples a binary vector with exactly `weight` bits set to 1, where the + * positions are chosen **uniformly at random** without bias. + * + * This sampling procedure is used **exclusively during key generation** to generate + * the vectors **x** and **y** + * + * @param[in,out] ctx Pointer to a previously initialized SHAKE-256 XOF context. + * @param[out] v Pointer to an array of ⌈PARAM_N/64⌉ 64-bit words. + * On return, **v** is a bitmask with exactly `weight` + * bits set to 1. + * @param[in] weight Desired Hamming weight. + */ +void vect_sample_fixed_weight1(shake256_xof_ctx *ctx, uint64_t *v, uint16_t weight) { + uint32_t support[PARAM_OMEGA_R] = {0}; + vect_generate_random_support1(ctx, support, weight); + vect_write_support_to_vector(v, support, weight); +} + +/** + * @brief Generate a random binary vector of fixed Hamming weight. + * + * Implementation of Algorithm 5 in https://eprint.iacr.org/2021/1631.pdf + * This sampling procedure is used **exclusively during encryption** to generate + * the vectors **r1**, **r2**, and **e**. + * + * @param[in,out] ctx Pointer to a previously initialized SHAKE-256 XOF context. + * @param[out] v Pointer to an array of ⌈PARAM_N/64⌉ 64-bit words. + * On return, **v** is a mask with exactly **weight** + * bits set to 1. + * @param[in] weight Desired Hamming weight. + */ +void vect_sample_fixed_weight2(shake256_xof_ctx *ctx, uint64_t *v, uint16_t weight) { + uint32_t support[PARAM_OMEGA_R] = {0}; + vect_generate_random_support2(ctx, support, weight); + vect_write_support_to_vector(v, support, weight); +} + +/** + * @brief Generates a random vector of dimension PARAM_N + * + * This function generates a random binary vector of dimension PARAM_N. It generates a random + * array of bytes using the xof, and drop the extra bits using a mask. + * + * @param[in] ctx Pointer to the context of the xof + * @param[in] v Pointer to an array + */ +void vect_set_random(shake256_xof_ctx *ctx, uint64_t *v) { + xof_get_bytes(ctx, (uint8_t *)v, VEC_N_SIZE_BYTES); + v[VEC_N_SIZE_64 - 1] &= BITMASK(PARAM_N, 64); +} + +/** + * @brief Adds two vectors + * + * @param[out] o Pointer to an array that is the result + * @param[in] v1 Pointer to an array that is the first vector + * @param[in] v2 Pointer to an array that is the second vector + * @param[in] size Integer that is the size of the vectors + */ +void vect_add(uint64_t *o, const uint64_t *v1, const uint64_t *v2, uint32_t size) { + for (uint32_t i = 0; i < size; ++i) { + o[i] = v1[i] ^ v2[i]; + } +} + +/** + * @brief Compares two vectors + * + * Function borrowed from liboqs: + * https://github.com/open-quantum-safe/liboqs/commit/cce1bfde4e52c524b087b9687020d283fbde0f24 + * + * @param[in] v1 Pointer to an array that is first vector + * @param[in] v2 Pointer to an array that is second vector + * @param[in] size Integer that is the size of the vectors + * @returns 0 if the vectors are equals and 1 otherwise + */ +uint8_t vect_compare(const uint8_t *v1, const uint8_t *v2, uint32_t size) { + uint16_t r = 0x0100; + + for (size_t i = 0; i < size; i++) { + r |= v1[i] ^ v2[i]; + } + + return (r - 1) >> 8; +} + +/** + * Truncate the bit-array v in-place to PARAM_N1N2 bits, + * zeroing out all bits beyond that. + * + * @param[in,out] v Pointer to the uint64_t array containing the bits. + */ +void vect_truncate(uint64_t *v) { + size_t orig_words = (PARAM_N + 63) / 64; + size_t new_full_words = PARAM_N1N2 / 64; + size_t remaining_bits = PARAM_N1N2 % 64; + + // Mask the last word if there's a partial word + if (remaining_bits > 0) { + uint64_t mask = (UINT64_C(1) << remaining_bits) - 1; + v[new_full_words] &= mask; + new_full_words++; // keep that partial word + } + + // Zero out all subsequent words up to the original length + for (size_t i = new_full_words; i < orig_words; i++) { + v[i] = 0; + } +} + +/** + * @brief Prints a given number of bytes + * + * @param[in] v Pointer to an array of bytes + * @param[in] size Integer that is number of bytes to be displayed + */ +void vect_print(const uint64_t *v, const uint32_t size) { + if (size == VEC_K_SIZE_BYTES) { + uint8_t tmp[VEC_K_SIZE_BYTES] = {0}; + memcpy(tmp, v, VEC_K_SIZE_BYTES); + for (uint32_t i = 0; i < VEC_K_SIZE_BYTES; ++i) { + printf("%02x", tmp[i]); + } + } else if (size == VEC_N_SIZE_BYTES) { + uint8_t tmp[VEC_N_SIZE_BYTES] = {0}; + memcpy(tmp, v, VEC_N_SIZE_BYTES); + for (uint32_t i = 0; i < VEC_N_SIZE_BYTES; ++i) { + printf("%02x", tmp[i]); + } + } else if (size == VEC_N1N2_SIZE_BYTES) { + uint8_t tmp[VEC_N1N2_SIZE_BYTES] = {0}; + memcpy(tmp, v, VEC_N1N2_SIZE_BYTES); + for (uint32_t i = 0; i < VEC_N1N2_SIZE_BYTES; ++i) { + printf("%02x", tmp[i]); + } + } else if (size == VEC_N1_SIZE_BYTES) { + uint8_t tmp[VEC_N1_SIZE_BYTES] = {0}; + memcpy(tmp, v, VEC_N1_SIZE_BYTES); + for (uint32_t i = 0; i < VEC_N1_SIZE_BYTES; ++i) { + printf("%02x", tmp[i]); + } + } +} diff --git a/src/kem/hqc/hqc_ref/src/ref/vector.h b/src/kem/hqc/hqc_ref/src/ref/vector.h new file mode 100644 index 0000000000..afdceaa240 --- /dev/null +++ b/src/kem/hqc/hqc_ref/src/ref/vector.h @@ -0,0 +1,28 @@ +/** + * @file vector.h + * @brief Header file for vector.c + */ + +#ifndef HQC_VECTOR_H +#define HQC_VECTOR_H + +#if defined(__i386__) || defined(__x86_64__) +#include +#endif +#include +#include "symmetric.h" + +void vect_generate_random_support1(shake256_xof_ctx *ctx, uint32_t *support, uint16_t weight); +void vect_generate_random_support2(shake256_xof_ctx *ctx, uint32_t *support, uint16_t weight); +void vect_write_support_to_vector(uint64_t *v, uint32_t *support, uint16_t weight); +void vect_sample_fixed_weight1(shake256_xof_ctx *ctx, uint64_t *v, uint16_t weight); +void vect_sample_fixed_weight2(shake256_xof_ctx *ctx, uint64_t *v, uint16_t weight); +void vect_set_random(shake256_xof_ctx *ctx, uint64_t *v); + +void vect_add(uint64_t *o, const uint64_t *v1, const uint64_t *v2, uint32_t size); +uint8_t vect_compare(const uint8_t *v1, const uint8_t *v2, uint32_t size); +void vect_truncate(uint64_t *v); + +void vect_print(const uint64_t *v, const uint32_t size); + +#endif // HQC_VECTOR_H diff --git a/src/kem/hqc/kem_hqc.h b/src/kem/hqc/kem_hqc.h index 12d6d13c08..d2d7de8d0e 100644 --- a/src/kem/hqc/kem_hqc.h +++ b/src/kem/hqc/kem_hqc.h @@ -6,10 +6,10 @@ #include #if defined(OQS_ENABLE_KEM_hqc_128) -#define OQS_KEM_hqc_128_length_public_key 2249 -#define OQS_KEM_hqc_128_length_secret_key 2305 +#define OQS_KEM_hqc_128_length_public_key 2241 +#define OQS_KEM_hqc_128_length_secret_key 2321 #define OQS_KEM_hqc_128_length_ciphertext 4433 -#define OQS_KEM_hqc_128_length_shared_secret 64 +#define OQS_KEM_hqc_128_length_shared_secret 32 #define OQS_KEM_hqc_128_length_keypair_seed 0 #define OQS_KEM_hqc_128_length_encaps_seed 0 OQS_KEM *OQS_KEM_hqc_128_new(void); @@ -21,10 +21,10 @@ OQS_API OQS_STATUS OQS_KEM_hqc_128_decaps(uint8_t *shared_secret, const uint8_t #endif #if defined(OQS_ENABLE_KEM_hqc_192) -#define OQS_KEM_hqc_192_length_public_key 4522 -#define OQS_KEM_hqc_192_length_secret_key 4586 +#define OQS_KEM_hqc_192_length_public_key 4514 +#define OQS_KEM_hqc_192_length_secret_key 4602 #define OQS_KEM_hqc_192_length_ciphertext 8978 -#define OQS_KEM_hqc_192_length_shared_secret 64 +#define OQS_KEM_hqc_192_length_shared_secret 32 #define OQS_KEM_hqc_192_length_keypair_seed 0 #define OQS_KEM_hqc_192_length_encaps_seed 0 OQS_KEM *OQS_KEM_hqc_192_new(void); @@ -36,10 +36,10 @@ OQS_API OQS_STATUS OQS_KEM_hqc_192_decaps(uint8_t *shared_secret, const uint8_t #endif #if defined(OQS_ENABLE_KEM_hqc_256) -#define OQS_KEM_hqc_256_length_public_key 7245 -#define OQS_KEM_hqc_256_length_secret_key 7317 +#define OQS_KEM_hqc_256_length_public_key 7237 +#define OQS_KEM_hqc_256_length_secret_key 7333 #define OQS_KEM_hqc_256_length_ciphertext 14421 -#define OQS_KEM_hqc_256_length_shared_secret 64 +#define OQS_KEM_hqc_256_length_shared_secret 32 #define OQS_KEM_hqc_256_length_keypair_seed 0 #define OQS_KEM_hqc_256_length_encaps_seed 0 OQS_KEM *OQS_KEM_hqc_256_new(void); diff --git a/src/kem/hqc/kem_hqc_128.c b/src/kem/hqc/kem_hqc_128.c index 6c4d956c79..8193e66d5b 100644 --- a/src/kem/hqc/kem_hqc_128.c +++ b/src/kem/hqc/kem_hqc_128.c @@ -4,16 +4,19 @@ #include +#include "oqs_adapter.h" + #if defined(OQS_ENABLE_KEM_hqc_128) OQS_KEM *OQS_KEM_hqc_128_new(void) { - OQS_KEM *kem = OQS_MEM_malloc(sizeof(OQS_KEM)); if (kem == NULL) { return NULL; } kem->method_name = OQS_KEM_alg_hqc_128; - kem->alg_version = "hqc-submission_2023-04-30 via https://github.com/SWilson4/package-pqclean/tree/9b509aa7/hqc"; + kem->alg_version = + "HQC reference implementation via https://gitlab.com/pqc-hqc/hqc " + "commit f46e5422 (v5.0.0, Aug. 22, 2025)"; kem->claimed_nist_level = 1; kem->ind_cca = true; @@ -34,22 +37,25 @@ OQS_KEM *OQS_KEM_hqc_128_new(void) { return kem; } -extern int PQCLEAN_HQC128_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk); -extern int PQCLEAN_HQC128_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk); -extern int PQCLEAN_HQC128_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk); - -OQS_API OQS_STATUS OQS_KEM_hqc_128_keypair_derand(uint8_t *public_key, uint8_t *secret_key, const uint8_t *seed) { +OQS_API OQS_STATUS OQS_KEM_hqc_128_keypair_derand(uint8_t *public_key, + uint8_t *secret_key, + const uint8_t *seed) { (void)public_key; (void)secret_key; (void)seed; return OQS_ERROR; } -OQS_API OQS_STATUS OQS_KEM_hqc_128_keypair(uint8_t *public_key, uint8_t *secret_key) { - return (OQS_STATUS) PQCLEAN_HQC128_CLEAN_crypto_kem_keypair(public_key, secret_key); +OQS_API OQS_STATUS OQS_KEM_hqc_128_keypair(uint8_t *public_key, + uint8_t *secret_key) { + return (OQS_STATUS)OQS_MAKE_FN(KEM_PREFIX, crypto_kem_keypair)(public_key, + secret_key); } -OQS_API OQS_STATUS OQS_KEM_hqc_128_encaps_derand(uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key, const uint8_t *seed) { +OQS_API OQS_STATUS OQS_KEM_hqc_128_encaps_derand(uint8_t *ciphertext, + uint8_t *shared_secret, + const uint8_t *public_key, + const uint8_t *seed) { (void)ciphertext; (void)shared_secret; (void)public_key; @@ -57,12 +63,18 @@ OQS_API OQS_STATUS OQS_KEM_hqc_128_encaps_derand(uint8_t *ciphertext, uint8_t *s return OQS_ERROR; } -OQS_API OQS_STATUS OQS_KEM_hqc_128_encaps(uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key) { - return (OQS_STATUS) PQCLEAN_HQC128_CLEAN_crypto_kem_enc(ciphertext, shared_secret, public_key); +OQS_API OQS_STATUS OQS_KEM_hqc_128_encaps(uint8_t *ciphertext, + uint8_t *shared_secret, + const uint8_t *public_key) { + return (OQS_STATUS)OQS_MAKE_FN(KEM_PREFIX, crypto_kem_enc)( + ciphertext, shared_secret, public_key); } -OQS_API OQS_STATUS OQS_KEM_hqc_128_decaps(uint8_t *shared_secret, const uint8_t *ciphertext, const uint8_t *secret_key) { - return (OQS_STATUS) PQCLEAN_HQC128_CLEAN_crypto_kem_dec(shared_secret, ciphertext, secret_key); +OQS_API OQS_STATUS OQS_KEM_hqc_128_decaps(uint8_t *shared_secret, + const uint8_t *ciphertext, + const uint8_t *secret_key) { + return (OQS_STATUS)OQS_MAKE_FN(KEM_PREFIX, crypto_kem_dec)( + shared_secret, ciphertext, secret_key); } #endif diff --git a/src/kem/hqc/kem_hqc_192.c b/src/kem/hqc/kem_hqc_192.c index 3f5ca22220..ed61bed621 100644 --- a/src/kem/hqc/kem_hqc_192.c +++ b/src/kem/hqc/kem_hqc_192.c @@ -4,16 +4,19 @@ #include +#include "oqs_adapter.h" + #if defined(OQS_ENABLE_KEM_hqc_192) OQS_KEM *OQS_KEM_hqc_192_new(void) { - OQS_KEM *kem = OQS_MEM_malloc(sizeof(OQS_KEM)); if (kem == NULL) { return NULL; } kem->method_name = OQS_KEM_alg_hqc_192; - kem->alg_version = "hqc-submission_2023-04-30 via https://github.com/SWilson4/package-pqclean/tree/9b509aa7/hqc"; + kem->alg_version = + "HQC reference implementation via https://gitlab.com/pqc-hqc/hqc " + "commit f46e5422 (v5.0.0, Aug. 22, 2025)"; kem->claimed_nist_level = 3; kem->ind_cca = true; @@ -34,22 +37,25 @@ OQS_KEM *OQS_KEM_hqc_192_new(void) { return kem; } -extern int PQCLEAN_HQC192_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk); -extern int PQCLEAN_HQC192_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk); -extern int PQCLEAN_HQC192_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk); - -OQS_API OQS_STATUS OQS_KEM_hqc_192_keypair_derand(uint8_t *public_key, uint8_t *secret_key, const uint8_t *seed) { +OQS_API OQS_STATUS OQS_KEM_hqc_192_keypair_derand(uint8_t *public_key, + uint8_t *secret_key, + const uint8_t *seed) { (void)public_key; (void)secret_key; (void)seed; return OQS_ERROR; } -OQS_API OQS_STATUS OQS_KEM_hqc_192_keypair(uint8_t *public_key, uint8_t *secret_key) { - return (OQS_STATUS) PQCLEAN_HQC192_CLEAN_crypto_kem_keypair(public_key, secret_key); +OQS_API OQS_STATUS OQS_KEM_hqc_192_keypair(uint8_t *public_key, + uint8_t *secret_key) { + return (OQS_STATUS)OQS_MAKE_FN(KEM_PREFIX, crypto_kem_keypair)(public_key, + secret_key); } -OQS_API OQS_STATUS OQS_KEM_hqc_192_encaps_derand(uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key, const uint8_t *seed) { +OQS_API OQS_STATUS OQS_KEM_hqc_192_encaps_derand(uint8_t *ciphertext, + uint8_t *shared_secret, + const uint8_t *public_key, + const uint8_t *seed) { (void)ciphertext; (void)shared_secret; (void)public_key; @@ -57,12 +63,18 @@ OQS_API OQS_STATUS OQS_KEM_hqc_192_encaps_derand(uint8_t *ciphertext, uint8_t *s return OQS_ERROR; } -OQS_API OQS_STATUS OQS_KEM_hqc_192_encaps(uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key) { - return (OQS_STATUS) PQCLEAN_HQC192_CLEAN_crypto_kem_enc(ciphertext, shared_secret, public_key); +OQS_API OQS_STATUS OQS_KEM_hqc_192_encaps(uint8_t *ciphertext, + uint8_t *shared_secret, + const uint8_t *public_key) { + return (OQS_STATUS)OQS_MAKE_FN(KEM_PREFIX, crypto_kem_enc)( + ciphertext, shared_secret, public_key); } -OQS_API OQS_STATUS OQS_KEM_hqc_192_decaps(uint8_t *shared_secret, const uint8_t *ciphertext, const uint8_t *secret_key) { - return (OQS_STATUS) PQCLEAN_HQC192_CLEAN_crypto_kem_dec(shared_secret, ciphertext, secret_key); +OQS_API OQS_STATUS OQS_KEM_hqc_192_decaps(uint8_t *shared_secret, + const uint8_t *ciphertext, + const uint8_t *secret_key) { + return (OQS_STATUS)OQS_MAKE_FN(KEM_PREFIX, crypto_kem_dec)( + shared_secret, ciphertext, secret_key); } #endif diff --git a/src/kem/hqc/kem_hqc_256.c b/src/kem/hqc/kem_hqc_256.c index b081be1a69..ce048a6e2a 100644 --- a/src/kem/hqc/kem_hqc_256.c +++ b/src/kem/hqc/kem_hqc_256.c @@ -4,16 +4,19 @@ #include +#include "oqs_adapter.h" + #if defined(OQS_ENABLE_KEM_hqc_256) OQS_KEM *OQS_KEM_hqc_256_new(void) { - OQS_KEM *kem = OQS_MEM_malloc(sizeof(OQS_KEM)); if (kem == NULL) { return NULL; } kem->method_name = OQS_KEM_alg_hqc_256; - kem->alg_version = "hqc-submission_2023-04-30 via https://github.com/SWilson4/package-pqclean/tree/9b509aa7/hqc"; + kem->alg_version = + "HQC reference implementation via https://gitlab.com/pqc-hqc/hqc " + "commit f46e5422 (v5.0.0, Aug. 22, 2025)"; kem->claimed_nist_level = 5; kem->ind_cca = true; @@ -34,22 +37,25 @@ OQS_KEM *OQS_KEM_hqc_256_new(void) { return kem; } -extern int PQCLEAN_HQC256_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk); -extern int PQCLEAN_HQC256_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk); -extern int PQCLEAN_HQC256_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk); - -OQS_API OQS_STATUS OQS_KEM_hqc_256_keypair_derand(uint8_t *public_key, uint8_t *secret_key, const uint8_t *seed) { +OQS_API OQS_STATUS OQS_KEM_hqc_256_keypair_derand(uint8_t *public_key, + uint8_t *secret_key, + const uint8_t *seed) { (void)public_key; (void)secret_key; (void)seed; return OQS_ERROR; } -OQS_API OQS_STATUS OQS_KEM_hqc_256_keypair(uint8_t *public_key, uint8_t *secret_key) { - return (OQS_STATUS) PQCLEAN_HQC256_CLEAN_crypto_kem_keypair(public_key, secret_key); +OQS_API OQS_STATUS OQS_KEM_hqc_256_keypair(uint8_t *public_key, + uint8_t *secret_key) { + return (OQS_STATUS)OQS_MAKE_FN(KEM_PREFIX, crypto_kem_keypair)(public_key, + secret_key); } -OQS_API OQS_STATUS OQS_KEM_hqc_256_encaps_derand(uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key, const uint8_t *seed) { +OQS_API OQS_STATUS OQS_KEM_hqc_256_encaps_derand(uint8_t *ciphertext, + uint8_t *shared_secret, + const uint8_t *public_key, + const uint8_t *seed) { (void)ciphertext; (void)shared_secret; (void)public_key; @@ -57,12 +63,18 @@ OQS_API OQS_STATUS OQS_KEM_hqc_256_encaps_derand(uint8_t *ciphertext, uint8_t *s return OQS_ERROR; } -OQS_API OQS_STATUS OQS_KEM_hqc_256_encaps(uint8_t *ciphertext, uint8_t *shared_secret, const uint8_t *public_key) { - return (OQS_STATUS) PQCLEAN_HQC256_CLEAN_crypto_kem_enc(ciphertext, shared_secret, public_key); +OQS_API OQS_STATUS OQS_KEM_hqc_256_encaps(uint8_t *ciphertext, + uint8_t *shared_secret, + const uint8_t *public_key) { + return (OQS_STATUS)OQS_MAKE_FN(KEM_PREFIX, crypto_kem_enc)( + ciphertext, shared_secret, public_key); } -OQS_API OQS_STATUS OQS_KEM_hqc_256_decaps(uint8_t *shared_secret, const uint8_t *ciphertext, const uint8_t *secret_key) { - return (OQS_STATUS) PQCLEAN_HQC256_CLEAN_crypto_kem_dec(shared_secret, ciphertext, secret_key); +OQS_API OQS_STATUS OQS_KEM_hqc_256_decaps(uint8_t *shared_secret, + const uint8_t *ciphertext, + const uint8_t *secret_key) { + return (OQS_STATUS)OQS_MAKE_FN(KEM_PREFIX, crypto_kem_dec)( + shared_secret, ciphertext, secret_key); } #endif diff --git a/src/kem/hqc/oqs_adapter/oqs_adapter.h b/src/kem/hqc/oqs_adapter/oqs_adapter.h new file mode 100644 index 0000000000..c3d8013bd5 --- /dev/null +++ b/src/kem/hqc/oqs_adapter/oqs_adapter.h @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT + +#ifndef OQS_ADAPTER_H_ +#define OQS_ADAPTER_H_ + +#include + +#include "oqs_adapter_macros.h" + +extern int OQS_MAKE_FN(KEM_PREFIX, crypto_kem_keypair)(uint8_t* ek_kem, + uint8_t* dk_kem); +extern int OQS_MAKE_FN(KEM_PREFIX, crypto_kem_enc)(uint8_t* c_kem, uint8_t* K, + const uint8_t* ek_kem); +extern int OQS_MAKE_FN(KEM_PREFIX, crypto_kem_dec)(uint8_t* K_prime, + const uint8_t* c_kem, + const uint8_t* dk_kem); + +#endif diff --git a/src/kem/hqc/oqs_adapter/oqs_adapter_macros.h b/src/kem/hqc/oqs_adapter/oqs_adapter_macros.h new file mode 100644 index 0000000000..9fb299b987 --- /dev/null +++ b/src/kem/hqc/oqs_adapter/oqs_adapter_macros.h @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT + +#ifndef OQS_ADAPTER_MACROS_H_ +#define OQS_ADAPTER_MACROS_H_ + +#ifndef KEM_PREFIX +#define KEM_PREFIX common +#endif + +#define CONCAT(a, b) a##_##b +#define EXPAND_CONCAT(a, b) CONCAT(a, b) +#define OQS_MAKE_FN(prefix, name) EXPAND_CONCAT(prefix, name) +#define OQS_MAKE_FN_STR(prefix) #prefix + +#endif diff --git a/src/kem/hqc/pqclean_hqc-128_clean/LICENSE b/src/kem/hqc/pqclean_hqc-128_clean/LICENSE deleted file mode 100644 index d5d21fff6d..0000000000 --- a/src/kem/hqc/pqclean_hqc-128_clean/LICENSE +++ /dev/null @@ -1 +0,0 @@ -Public Domain diff --git a/src/kem/hqc/pqclean_hqc-128_clean/api.h b/src/kem/hqc/pqclean_hqc-128_clean/api.h deleted file mode 100644 index a361da11ce..0000000000 --- a/src/kem/hqc/pqclean_hqc-128_clean/api.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef PQCLEAN_HQC128_CLEAN_API_H -#define PQCLEAN_HQC128_CLEAN_API_H -/** - * @file api.h - * @brief NIST KEM API used by the HQC_KEM IND-CCA2 scheme - */ - -#include - -#define PQCLEAN_HQC128_CLEAN_CRYPTO_ALGNAME "HQC-128" - -#define PQCLEAN_HQC128_CLEAN_CRYPTO_SECRETKEYBYTES 2305 -#define PQCLEAN_HQC128_CLEAN_CRYPTO_PUBLICKEYBYTES 2249 -#define PQCLEAN_HQC128_CLEAN_CRYPTO_BYTES 64 -#define PQCLEAN_HQC128_CLEAN_CRYPTO_CIPHERTEXTBYTES 4433 - -// As a technicality, the public key is appended to the secret key in order to respect the NIST API. -// Without this constraint, PQCLEAN_HQC128_CLEAN_CRYPTO_SECRETKEYBYTES would be defined as 32 - -int PQCLEAN_HQC128_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk); - -int PQCLEAN_HQC128_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk); - -int PQCLEAN_HQC128_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk); - - -#endif diff --git a/src/kem/hqc/pqclean_hqc-128_clean/code.c b/src/kem/hqc/pqclean_hqc-128_clean/code.c deleted file mode 100644 index 4499c01600..0000000000 --- a/src/kem/hqc/pqclean_hqc-128_clean/code.c +++ /dev/null @@ -1,46 +0,0 @@ -#include "code.h" -#include "parameters.h" -#include "reed_muller.h" -#include "reed_solomon.h" -#include -/** - * @file code.c - * @brief Implementation of concatenated code - */ - - - -/** - * - * @brief Encoding the message m to a code word em using the concatenated code - * - * First we encode the message using the Reed-Solomon code, then with the duplicated Reed-Muller code we obtain - * a concatenated code word. - * - * @param[out] em Pointer to an array that is the tensor code word - * @param[in] m Pointer to an array that is the message - */ -void PQCLEAN_HQC128_CLEAN_code_encode(uint64_t *em, const uint8_t *m) { - uint8_t tmp[VEC_N1_SIZE_BYTES] = {0}; - - PQCLEAN_HQC128_CLEAN_reed_solomon_encode(tmp, m); - PQCLEAN_HQC128_CLEAN_reed_muller_encode(em, tmp); - -} - - - -/** - * @brief Decoding the code word em to a message m using the concatenated code - * - * @param[out] m Pointer to an array that is the message - * @param[in] em Pointer to an array that is the code word - */ -void PQCLEAN_HQC128_CLEAN_code_decode(uint8_t *m, const uint64_t *em) { - uint8_t tmp[VEC_N1_SIZE_BYTES] = {0}; - - PQCLEAN_HQC128_CLEAN_reed_muller_decode(tmp, em); - PQCLEAN_HQC128_CLEAN_reed_solomon_decode(m, tmp); - - -} diff --git a/src/kem/hqc/pqclean_hqc-128_clean/code.h b/src/kem/hqc/pqclean_hqc-128_clean/code.h deleted file mode 100644 index e6fd629e9f..0000000000 --- a/src/kem/hqc/pqclean_hqc-128_clean/code.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef CODE_H -#define CODE_H - - -/** - * @file code.h - * @brief Header file of code.c - */ - -#include - -void PQCLEAN_HQC128_CLEAN_code_encode(uint64_t *em, const uint8_t *message); - -void PQCLEAN_HQC128_CLEAN_code_decode(uint8_t *m, const uint64_t *em); - - -#endif diff --git a/src/kem/hqc/pqclean_hqc-128_clean/domains.h b/src/kem/hqc/pqclean_hqc-128_clean/domains.h deleted file mode 100644 index 20c782ccae..0000000000 --- a/src/kem/hqc/pqclean_hqc-128_clean/domains.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef DOMAINS_H -#define DOMAINS_H - - -/** - * @file domains.h - * @brief SHAKE-256 domains separation header grouping all domains to avoid collisions - */ - - -#define PRNG_DOMAIN 1 -#define SEEDEXPANDER_DOMAIN 2 -#define G_FCT_DOMAIN 3 -#define K_FCT_DOMAIN 4 - -#endif diff --git a/src/kem/hqc/pqclean_hqc-128_clean/fft.h b/src/kem/hqc/pqclean_hqc-128_clean/fft.h deleted file mode 100644 index 7d9f2367e5..0000000000 --- a/src/kem/hqc/pqclean_hqc-128_clean/fft.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef FFT_H -#define FFT_H - - -/** - * @file fft.h - * @brief Header file of fft.c - */ - -#include -#include - -void PQCLEAN_HQC128_CLEAN_fft(uint16_t *w, const uint16_t *f, size_t f_coeffs); - -void PQCLEAN_HQC128_CLEAN_fft_retrieve_error_poly(uint8_t *error, const uint16_t *w); - - -#endif diff --git a/src/kem/hqc/pqclean_hqc-128_clean/gf.c b/src/kem/hqc/pqclean_hqc-128_clean/gf.c deleted file mode 100644 index 0d7387e687..0000000000 --- a/src/kem/hqc/pqclean_hqc-128_clean/gf.c +++ /dev/null @@ -1,170 +0,0 @@ -#include "gf.h" -#include "parameters.h" -#include -#include -/** - * @file gf.c - * @brief Galois field implementation - */ - - -/** - * @brief Computes the number of trailing zero bits. - * - * @returns The number of trailing zero bits in a. - * @param[in] a An operand - */ -static uint16_t trailing_zero_bits_count(uint16_t a) { - uint16_t tmp = 0; - uint16_t mask = 0xFFFF; - for (size_t i = 0; i < 14; ++i) { - tmp += ((1 - ((a >> i) & 0x0001)) & mask); - mask &= - (1 - ((a >> i) & 0x0001)); - } - return tmp; -} - - - -/** - * Reduces polynomial x modulo primitive polynomial GF_POLY. - * @returns x mod GF_POLY - * @param[in] x Polynomial of degree less than 64 - * @param[in] deg_x The degree of polynomial x - */ -static uint16_t gf_reduce(uint64_t x, size_t deg_x) { - uint16_t z1, z2, rmdr, dist; - uint64_t mod; - - // Deduce the number of steps of reduction - size_t steps = CEIL_DIVIDE(deg_x - (PARAM_M - 1), PARAM_GF_POLY_M2); - - // Reduce - for (size_t i = 0; i < steps; ++i) { - mod = x >> PARAM_M; - x &= (1 << PARAM_M) - 1; - x ^= mod; - - z1 = 0; - rmdr = PARAM_GF_POLY ^ 1; - for (size_t j = PARAM_GF_POLY_WT - 2; j; --j) { - z2 = trailing_zero_bits_count(rmdr); - dist = z2 - z1; - mod <<= dist; - x ^= mod; - rmdr ^= 1 << z2; - z1 = z2; - } - } - - return (uint16_t)x; -} - - - -/** - * Carryless multiplication of two polynomials a and b. - * - * Implementation of the algorithm mul1 in https://hal.inria.fr/inria-00188261v4/document - * with s = 2 and w = 8 - * - * @param[out] The polynomial c = a * b - * @param[in] a The first polynomial - * @param[in] b The second polynomial - */ -static void gf_carryless_mul(uint8_t c[2], uint8_t a, uint8_t b) { - uint16_t h = 0, l = 0, g = 0, u[4]; - uint32_t tmp1, tmp2; - uint16_t mask; - u[0] = 0; - u[1] = b & 0x7F; - u[2] = u[1] << 1; - u[3] = u[2] ^ u[1]; - tmp1 = a & 3; - - for (size_t i = 0; i < 4; i++) { - tmp2 = (uint32_t)(tmp1 - i); - g ^= (u[i] & (uint32_t)(0 - (1 - ((uint32_t)(tmp2 | (0 - tmp2)) >> 31)))); - } - - l = g; - h = 0; - - for (size_t i = 2; i < 8; i += 2) { - g = 0; - tmp1 = (a >> i) & 3; - for (size_t j = 0; j < 4; ++j) { - tmp2 = (uint32_t)(tmp1 - j); - g ^= (u[j] & (uint32_t)(0 - (1 - ((uint32_t)(tmp2 | (0 - tmp2)) >> 31)))); - } - - l ^= g << i; - h ^= g >> (8 - i); - } - - mask = (-((b >> 7) & 1)); - l ^= ((a << 7) & mask); - h ^= ((a >> 1) & mask); - - c[0] = (uint8_t)l; - c[1] = (uint8_t)h; -} - - - -/** - * Multiplies two elements of GF(2^GF_M). - * @returns the product a*b - * @param[in] a Element of GF(2^GF_M) - * @param[in] b Element of GF(2^GF_M) - */ -uint16_t PQCLEAN_HQC128_CLEAN_gf_mul(uint16_t a, uint16_t b) { - uint8_t c[2] = {0}; - gf_carryless_mul(c, (uint8_t) a, (uint8_t) b); - uint16_t tmp = c[0] ^ (c[1] << 8); - return gf_reduce(tmp, 2 * (PARAM_M - 1)); -} - - - -/** - * @brief Squares an element of GF(2^PARAM_M). - * @returns a^2 - * @param[in] a Element of GF(2^PARAM_M) - */ -uint16_t PQCLEAN_HQC128_CLEAN_gf_square(uint16_t a) { - uint32_t b = a; - uint32_t s = b & 1; - for (size_t i = 1; i < PARAM_M; ++i) { - b <<= 1; - s ^= b & (1 << 2 * i); - } - - return gf_reduce(s, 2 * (PARAM_M - 1)); -} - - - -/** - * @brief Computes the inverse of an element of GF(2^PARAM_M), - * using the addition chain 1 2 3 4 7 11 15 30 60 120 127 254 - * @returns the inverse of a if a != 0 or 0 if a = 0 - * @param[in] a Element of GF(2^PARAM_M) - */ -uint16_t PQCLEAN_HQC128_CLEAN_gf_inverse(uint16_t a) { - uint16_t inv = a; - uint16_t tmp1, tmp2; - - inv = PQCLEAN_HQC128_CLEAN_gf_square(a); /* a^2 */ - tmp1 = PQCLEAN_HQC128_CLEAN_gf_mul(inv, a); /* a^3 */ - inv = PQCLEAN_HQC128_CLEAN_gf_square(inv); /* a^4 */ - tmp2 = PQCLEAN_HQC128_CLEAN_gf_mul(inv, tmp1); /* a^7 */ - tmp1 = PQCLEAN_HQC128_CLEAN_gf_mul(inv, tmp2); /* a^11 */ - inv = PQCLEAN_HQC128_CLEAN_gf_mul(tmp1, inv); /* a^15 */ - inv = PQCLEAN_HQC128_CLEAN_gf_square(inv); /* a^30 */ - inv = PQCLEAN_HQC128_CLEAN_gf_square(inv); /* a^60 */ - inv = PQCLEAN_HQC128_CLEAN_gf_square(inv); /* a^120 */ - inv = PQCLEAN_HQC128_CLEAN_gf_mul(inv, tmp2); /* a^127 */ - inv = PQCLEAN_HQC128_CLEAN_gf_square(inv); /* a^254 */ - return inv; -} diff --git a/src/kem/hqc/pqclean_hqc-128_clean/gf.h b/src/kem/hqc/pqclean_hqc-128_clean/gf.h deleted file mode 100644 index 61a3034240..0000000000 --- a/src/kem/hqc/pqclean_hqc-128_clean/gf.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef GF_H -#define GF_H - - -/** - * @file gf.h - * @brief Header file of gf.c - */ - -#include - - -/** - * Powers of the root alpha of 1 + x^2 + x^3 + x^4 + x^8. - * The last two elements are needed by the PQCLEAN_HQC128_CLEAN_gf_mul function - * (for example if both elements to multiply are zero). - */ -static const uint16_t gf_exp [258] = { 1, 2, 4, 8, 16, 32, 64, 128, 29, 58, 116, 232, 205, 135, 19, 38, 76, 152, 45, 90, 180, 117, 234, 201, 143, 3, 6, 12, 24, 48, 96, 192, 157, 39, 78, 156, 37, 74, 148, 53, 106, 212, 181, 119, 238, 193, 159, 35, 70, 140, 5, 10, 20, 40, 80, 160, 93, 186, 105, 210, 185, 111, 222, 161, 95, 190, 97, 194, 153, 47, 94, 188, 101, 202, 137, 15, 30, 60, 120, 240, 253, 231, 211, 187, 107, 214, 177, 127, 254, 225, 223, 163, 91, 182, 113, 226, 217, 175, 67, 134, 17, 34, 68, 136, 13, 26, 52, 104, 208, 189, 103, 206, 129, 31, 62, 124, 248, 237, 199, 147, 59, 118, 236, 197, 151, 51, 102, 204, 133, 23, 46, 92, 184, 109, 218, 169, 79, 158, 33, 66, 132, 21, 42, 84, 168, 77, 154, 41, 82, 164, 85, 170, 73, 146, 57, 114, 228, 213, 183, 115, 230, 209, 191, 99, 198, 145, 63, 126, 252, 229, 215, 179, 123, 246, 241, 255, 227, 219, 171, 75, 150, 49, 98, 196, 149, 55, 110, 220, 165, 87, 174, 65, 130, 25, 50, 100, 200, 141, 7, 14, 28, 56, 112, 224, 221, 167, 83, 166, 81, 162, 89, 178, 121, 242, 249, 239, 195, 155, 43, 86, 172, 69, 138, 9, 18, 36, 72, 144, 61, 122, 244, 245, 247, 243, 251, 235, 203, 139, 11, 22, 44, 88, 176, 125, 250, 233, 207, 131, 27, 54, 108, 216, 173, 71, 142, 1, 2, 4 }; - - - -/** - * Logarithm of elements of GF(2^8) to the base alpha (root of 1 + x^2 + x^3 + x^4 + x^8). - * The logarithm of 0 is set to 0 by convention. - */ -static const uint16_t gf_log [256] = { 0, 0, 1, 25, 2, 50, 26, 198, 3, 223, 51, 238, 27, 104, 199, 75, 4, 100, 224, 14, 52, 141, 239, 129, 28, 193, 105, 248, 200, 8, 76, 113, 5, 138, 101, 47, 225, 36, 15, 33, 53, 147, 142, 218, 240, 18, 130, 69, 29, 181, 194, 125, 106, 39, 249, 185, 201, 154, 9, 120, 77, 228, 114, 166, 6, 191, 139, 98, 102, 221, 48, 253, 226, 152, 37, 179, 16, 145, 34, 136, 54, 208, 148, 206, 143, 150, 219, 189, 241, 210, 19, 92, 131, 56, 70, 64, 30, 66, 182, 163, 195, 72, 126, 110, 107, 58, 40, 84, 250, 133, 186, 61, 202, 94, 155, 159, 10, 21, 121, 43, 78, 212, 229, 172, 115, 243, 167, 87, 7, 112, 192, 247, 140, 128, 99, 13, 103, 74, 222, 237, 49, 197, 254, 24, 227, 165, 153, 119, 38, 184, 180, 124, 17, 68, 146, 217, 35, 32, 137, 46, 55, 63, 209, 91, 149, 188, 207, 205, 144, 135, 151, 178, 220, 252, 190, 97, 242, 86, 211, 171, 20, 42, 93, 158, 132, 60, 57, 83, 71, 109, 65, 162, 31, 45, 67, 216, 183, 123, 164, 118, 196, 23, 73, 236, 127, 12, 111, 246, 108, 161, 59, 82, 41, 157, 85, 170, 251, 96, 134, 177, 187, 204, 62, 90, 203, 89, 95, 176, 156, 169, 160, 81, 11, 245, 22, 235, 122, 117, 44, 215, 79, 174, 213, 233, 230, 231, 173, 232, 116, 214, 244, 234, 168, 80, 88, 175 }; - - - -uint16_t PQCLEAN_HQC128_CLEAN_gf_mul(uint16_t a, uint16_t b); - -uint16_t PQCLEAN_HQC128_CLEAN_gf_square(uint16_t a); - -uint16_t PQCLEAN_HQC128_CLEAN_gf_inverse(uint16_t a); - - -#endif diff --git a/src/kem/hqc/pqclean_hqc-128_clean/gf2x.c b/src/kem/hqc/pqclean_hqc-128_clean/gf2x.c deleted file mode 100644 index c66d9f230f..0000000000 --- a/src/kem/hqc/pqclean_hqc-128_clean/gf2x.c +++ /dev/null @@ -1,198 +0,0 @@ -#include "gf2x.h" -#include "parameters.h" -#include -#include -/** - * @file gf2x.c - * @brief Implementation of multiplication of two polynomials - */ - - -/** - * @brief Caryless multiplication of two words of 64 bits - * - * Implemntation of the algorithm mul1 in https://hal.inria.fr/inria-00188261v4/document. - * With w = 64 and s = 4 - * - * @param[out] c The result c = a * b - * @param[in] a The first value a - * @param[in] b The second value b - */ -static void base_mul(uint64_t *c, uint64_t a, uint64_t b) { - uint64_t h = 0; - uint64_t l = 0; - uint64_t g; - uint64_t u[16] = {0}; - uint64_t mask_tab[4] = {0}; - uint64_t tmp1, tmp2; - - // Step 1 - u[0] = 0; - u[1] = b & (((uint64_t)1 << (64 - 4)) - 1); - u[2] = u[1] << 1; - u[3] = u[2] ^ u[1]; - u[4] = u[2] << 1; - u[5] = u[4] ^ u[1]; - u[6] = u[3] << 1; - u[7] = u[6] ^ u[1]; - u[8] = u[4] << 1; - u[9] = u[8] ^ u[1]; - u[10] = u[5] << 1; - u[11] = u[10] ^ u[1]; - u[12] = u[6] << 1; - u[13] = u[12] ^ u[1]; - u[14] = u[7] << 1; - u[15] = u[14] ^ u[1]; - - g = 0; - tmp1 = a & 0x0f; - - for (size_t i = 0; i < 16; ++i) { - tmp2 = tmp1 - i; - g ^= (u[i] & (uint64_t)(0 - (1 - ((uint64_t)(tmp2 | (0 - tmp2)) >> 63)))); - } - - l = g; - h = 0; - - // Step 2 - for (size_t i = 4; i < 64; i += 4) { - g = 0; - tmp1 = (a >> i) & 0x0f; - for (size_t j = 0; j < 16; ++j) { - tmp2 = tmp1 - j; - g ^= (u[j] & (uint64_t)(0 - (1 - ((uint64_t)(tmp2 | (0 - tmp2)) >> 63)))); - } - - l ^= g << i; - h ^= g >> (64 - i); - } - - // Step 3 - mask_tab [0] = 0 - ((b >> 60) & 1); - mask_tab [1] = 0 - ((b >> 61) & 1); - mask_tab [2] = 0 - ((b >> 62) & 1); - mask_tab [3] = 0 - ((b >> 63) & 1); - - l ^= ((a << 60) & mask_tab[0]); - h ^= ((a >> 4) & mask_tab[0]); - - l ^= ((a << 61) & mask_tab[1]); - h ^= ((a >> 3) & mask_tab[1]); - - l ^= ((a << 62) & mask_tab[2]); - h ^= ((a >> 2) & mask_tab[2]); - - l ^= ((a << 63) & mask_tab[3]); - h ^= ((a >> 1) & mask_tab[3]); - - c[0] = l; - c[1] = h; -} - -static void karatsuba_add1(uint64_t *alh, uint64_t *blh, const uint64_t *a, const uint64_t *b, size_t size_l, size_t size_h) { - for (size_t i = 0; i < size_h; ++i) { - alh[i] = a[i] ^ a[i + size_l]; - blh[i] = b[i] ^ b[i + size_l]; - } - - if (size_h < size_l) { - alh[size_h] = a[size_h]; - blh[size_h] = b[size_h]; - } -} - -static void karatsuba_add2(uint64_t *o, uint64_t *tmp1, const uint64_t *tmp2, size_t size_l, size_t size_h) { - for (size_t i = 0; i < (2 * size_l); ++i) { - tmp1[i] = tmp1[i] ^ o[i]; - } - - for (size_t i = 0; i < ( 2 * size_h); ++i) { - tmp1[i] = tmp1[i] ^ tmp2[i]; - } - - for (size_t i = 0; i < (2 * size_l); ++i) { - o[i + size_l] = o[i + size_l] ^ tmp1[i]; - } -} - -/** - * Karatsuba multiplication of a and b, Implementation inspired from the NTL library. - * - * @param[out] o Polynomial - * @param[in] a Polynomial - * @param[in] b Polynomial - * @param[in] size Length of polynomial - * @param[in] stack Length of polynomial - */ -static void karatsuba(uint64_t *o, const uint64_t *a, const uint64_t *b, size_t size, uint64_t *stack) { - size_t size_l, size_h; - const uint64_t *ah, *bh; - - if (size == 1) { - base_mul(o, a[0], b[0]); - return; - } - - size_h = size / 2; - size_l = (size + 1) / 2; - - uint64_t *alh = stack; - uint64_t *blh = alh + size_l; - uint64_t *tmp1 = blh + size_l; - uint64_t *tmp2 = o + 2 * size_l; - - stack += 4 * size_l; - - ah = a + size_l; - bh = b + size_l; - - karatsuba(o, a, b, size_l, stack); - - karatsuba(tmp2, ah, bh, size_h, stack); - - karatsuba_add1(alh, blh, a, b, size_l, size_h); - - karatsuba(tmp1, alh, blh, size_l, stack); - - karatsuba_add2(o, tmp1, tmp2, size_l, size_h); -} - -/** - * @brief Compute o(x) = a(x) mod \f$ X^n - 1\f$ - * - * This function computes the modular reduction of the polynomial a(x) - * - * @param[in] a Pointer to the polynomial a(x) - * @param[out] o Pointer to the result - */ -static void reduce(uint64_t *o, const uint64_t *a) { - uint64_t r; - uint64_t carry; - - for (size_t i = 0; i < VEC_N_SIZE_64; ++i) { - r = a[i + VEC_N_SIZE_64 - 1] >> (PARAM_N & 0x3F); - carry = a[i + VEC_N_SIZE_64] << (64 - (PARAM_N & 0x3F)); - o[i] = a[i] ^ r ^ carry; - } - - o[VEC_N_SIZE_64 - 1] &= RED_MASK; -} - -/** - * @brief Multiply two polynomials modulo \f$ X^n - 1\f$. - * - * This functions multiplies polynomials v1 and v2. - * The multiplication is done modulo \f$ X^n - 1\f$. - * - * @param[out] o Product of v1 and v2 - * @param[in] v1 Pointer to the first polynomial - * @param[in] v2 Pointer to the second polynomial - */ -void PQCLEAN_HQC128_CLEAN_vect_mul(uint64_t *o, const uint64_t *v1, const uint64_t *v2) { - uint64_t stack[VEC_N_SIZE_64 << 3] = {0}; - uint64_t o_karat[VEC_N_SIZE_64 << 1] = {0}; - - karatsuba(o_karat, v1, v2, VEC_N_SIZE_64, stack); - reduce(o, o_karat); -} diff --git a/src/kem/hqc/pqclean_hqc-128_clean/gf2x.h b/src/kem/hqc/pqclean_hqc-128_clean/gf2x.h deleted file mode 100644 index 8325bfca8f..0000000000 --- a/src/kem/hqc/pqclean_hqc-128_clean/gf2x.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef GF2X_H -#define GF2X_H -/** - * @file gf2x.h - * @brief Header file for gf2x.c - */ - -#include - -void PQCLEAN_HQC128_CLEAN_vect_mul(uint64_t *o, const uint64_t *v1, const uint64_t *v2); - - -#endif diff --git a/src/kem/hqc/pqclean_hqc-128_clean/hqc.c b/src/kem/hqc/pqclean_hqc-128_clean/hqc.c deleted file mode 100644 index eae0ff825b..0000000000 --- a/src/kem/hqc/pqclean_hqc-128_clean/hqc.c +++ /dev/null @@ -1,146 +0,0 @@ -#include "code.h" -#include "gf2x.h" -#include "hqc.h" -#include "parameters.h" -#include "parsing.h" -#include "randombytes.h" -#include "shake_prng.h" -#include "vector.h" -#include -/** - * @file hqc.c - * @brief Implementation of hqc.h - */ - - - -/** - * @brief Keygen of the HQC_PKE IND_CPA scheme - * - * The public key is composed of the syndrome s as well as the seed used to generate the vector h. - * - * The secret key is composed of the seed used to generate vectors x and y. - * As a technicality, the public key is appended to the secret key in order to respect NIST API. - * - * @param[out] pk String containing the public key - * @param[out] sk String containing the secret key - */ -void PQCLEAN_HQC128_CLEAN_hqc_pke_keygen(uint8_t *pk, uint8_t *sk) { - seedexpander_state sk_seedexpander; - seedexpander_state pk_seedexpander; - uint8_t sk_seed[SEED_BYTES] = {0}; - uint8_t sigma[VEC_K_SIZE_BYTES] = {0}; - uint8_t pk_seed[SEED_BYTES] = {0}; - uint64_t x[VEC_N_SIZE_64] = {0}; - uint64_t y[VEC_N_SIZE_64] = {0}; - uint64_t h[VEC_N_SIZE_64] = {0}; - uint64_t s[VEC_N_SIZE_64] = {0}; - - // Create seed_expanders for public key and secret key - randombytes(sk_seed, SEED_BYTES); - randombytes(sigma, VEC_K_SIZE_BYTES); - PQCLEAN_HQC128_CLEAN_seedexpander_init(&sk_seedexpander, sk_seed, SEED_BYTES); - - randombytes(pk_seed, SEED_BYTES); - PQCLEAN_HQC128_CLEAN_seedexpander_init(&pk_seedexpander, pk_seed, SEED_BYTES); - - // Compute secret key - PQCLEAN_HQC128_CLEAN_vect_set_random_fixed_weight(&sk_seedexpander, x, PARAM_OMEGA); - PQCLEAN_HQC128_CLEAN_vect_set_random_fixed_weight(&sk_seedexpander, y, PARAM_OMEGA); - - // Compute public key - PQCLEAN_HQC128_CLEAN_vect_set_random(&pk_seedexpander, h); - PQCLEAN_HQC128_CLEAN_vect_mul(s, y, h); - PQCLEAN_HQC128_CLEAN_vect_add(s, x, s, VEC_N_SIZE_64); - - // Parse keys to string - PQCLEAN_HQC128_CLEAN_hqc_public_key_to_string(pk, pk_seed, s); - PQCLEAN_HQC128_CLEAN_hqc_secret_key_to_string(sk, sk_seed, sigma, pk); - - PQCLEAN_HQC128_CLEAN_seedexpander_release(&pk_seedexpander); - PQCLEAN_HQC128_CLEAN_seedexpander_release(&sk_seedexpander); -} - - - -/** - * @brief Encryption of the HQC_PKE IND_CPA scheme - * - * The cihertext is composed of vectors u and v. - * - * @param[out] u Vector u (first part of the ciphertext) - * @param[out] v Vector v (second part of the ciphertext) - * @param[in] m Vector representing the message to encrypt - * @param[in] theta Seed used to derive randomness required for encryption - * @param[in] pk String containing the public key - */ -void PQCLEAN_HQC128_CLEAN_hqc_pke_encrypt(uint64_t *u, uint64_t *v, uint8_t *m, uint8_t *theta, const uint8_t *pk) { - seedexpander_state vec_seedexpander; - uint64_t h[VEC_N_SIZE_64] = {0}; - uint64_t s[VEC_N_SIZE_64] = {0}; - uint64_t r1[VEC_N_SIZE_64] = {0}; - uint64_t r2[VEC_N_SIZE_64] = {0}; - uint64_t e[VEC_N_SIZE_64] = {0}; - uint64_t tmp1[VEC_N_SIZE_64] = {0}; - uint64_t tmp2[VEC_N_SIZE_64] = {0}; - - // Create seed_expander from theta - PQCLEAN_HQC128_CLEAN_seedexpander_init(&vec_seedexpander, theta, SEED_BYTES); - - // Retrieve h and s from public key - PQCLEAN_HQC128_CLEAN_hqc_public_key_from_string(h, s, pk); - - // Generate r1, r2 and e - PQCLEAN_HQC128_CLEAN_vect_set_random_fixed_weight(&vec_seedexpander, r1, PARAM_OMEGA_R); - PQCLEAN_HQC128_CLEAN_vect_set_random_fixed_weight(&vec_seedexpander, r2, PARAM_OMEGA_R); - PQCLEAN_HQC128_CLEAN_vect_set_random_fixed_weight(&vec_seedexpander, e, PARAM_OMEGA_E); - - // Compute u = r1 + r2.h - PQCLEAN_HQC128_CLEAN_vect_mul(u, r2, h); - PQCLEAN_HQC128_CLEAN_vect_add(u, r1, u, VEC_N_SIZE_64); - - // Compute v = m.G by encoding the message - PQCLEAN_HQC128_CLEAN_code_encode(v, m); - PQCLEAN_HQC128_CLEAN_vect_resize(tmp1, PARAM_N, v, PARAM_N1N2); - - // Compute v = m.G + s.r2 + e - PQCLEAN_HQC128_CLEAN_vect_mul(tmp2, r2, s); - PQCLEAN_HQC128_CLEAN_vect_add(tmp2, e, tmp2, VEC_N_SIZE_64); - PQCLEAN_HQC128_CLEAN_vect_add(tmp2, tmp1, tmp2, VEC_N_SIZE_64); - PQCLEAN_HQC128_CLEAN_vect_resize(v, PARAM_N1N2, tmp2, PARAM_N); - - PQCLEAN_HQC128_CLEAN_seedexpander_release(&vec_seedexpander); -} - - - -/** - * @brief Decryption of the HQC_PKE IND_CPA scheme - * - * @param[out] m Vector representing the decrypted message - * @param[in] u Vector u (first part of the ciphertext) - * @param[in] v Vector v (second part of the ciphertext) - * @param[in] sk String containing the secret key - * @returns 0 - */ -uint8_t PQCLEAN_HQC128_CLEAN_hqc_pke_decrypt(uint8_t *m, uint8_t *sigma, const uint64_t *u, const uint64_t *v, const uint8_t *sk) { - uint64_t x[VEC_N_SIZE_64] = {0}; - uint64_t y[VEC_N_SIZE_64] = {0}; - uint8_t pk[PUBLIC_KEY_BYTES] = {0}; - uint64_t tmp1[VEC_N_SIZE_64] = {0}; - uint64_t tmp2[VEC_N_SIZE_64] = {0}; - - // Retrieve x, y, pk from secret key - PQCLEAN_HQC128_CLEAN_hqc_secret_key_from_string(x, y, sigma, pk, sk); - - // Compute v - u.y - PQCLEAN_HQC128_CLEAN_vect_resize(tmp1, PARAM_N, v, PARAM_N1N2); - PQCLEAN_HQC128_CLEAN_vect_mul(tmp2, y, u); - PQCLEAN_HQC128_CLEAN_vect_add(tmp2, tmp1, tmp2, VEC_N_SIZE_64); - - - // Compute m by decoding v - u.y - PQCLEAN_HQC128_CLEAN_code_decode(m, tmp2); - - return 0; -} diff --git a/src/kem/hqc/pqclean_hqc-128_clean/hqc.h b/src/kem/hqc/pqclean_hqc-128_clean/hqc.h deleted file mode 100644 index 7e96ee8f92..0000000000 --- a/src/kem/hqc/pqclean_hqc-128_clean/hqc.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef HQC_H -#define HQC_H - - -/** - * @file hqc.h - * @brief Functions of the HQC_PKE IND_CPA scheme - */ - -#include - -void PQCLEAN_HQC128_CLEAN_hqc_pke_keygen(uint8_t *pk, uint8_t *sk); - -void PQCLEAN_HQC128_CLEAN_hqc_pke_encrypt(uint64_t *u, uint64_t *v, uint8_t *m, unsigned char *theta, const unsigned char *pk); - -uint8_t PQCLEAN_HQC128_CLEAN_hqc_pke_decrypt(uint8_t *m, uint8_t *sigma, const uint64_t *u, const uint64_t *v, const unsigned char *sk); - - -#endif diff --git a/src/kem/hqc/pqclean_hqc-128_clean/kem.c b/src/kem/hqc/pqclean_hqc-128_clean/kem.c deleted file mode 100644 index e0a4681fd9..0000000000 --- a/src/kem/hqc/pqclean_hqc-128_clean/kem.c +++ /dev/null @@ -1,138 +0,0 @@ -#include "api.h" -#include "domains.h" -#include "fips202.h" -#include "hqc.h" -#include "parameters.h" -#include "parsing.h" -#include "randombytes.h" -#include "shake_ds.h" -#include "vector.h" -#include -#include -/** - * @file kem.c - * @brief Implementation of api.h - */ - - - -/** - * @brief Keygen of the HQC_KEM IND_CAA2 scheme - * - * The public key is composed of the syndrome s as well as the seed used to generate the vector h. - * - * The secret key is composed of the seed used to generate vectors x and y. - * As a technicality, the public key is appended to the secret key in order to respect NIST API. - * - * @param[out] pk String containing the public key - * @param[out] sk String containing the secret key - * @returns 0 if keygen is successful - */ -int PQCLEAN_HQC128_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk) { - - PQCLEAN_HQC128_CLEAN_hqc_pke_keygen(pk, sk); - return 0; -} - - - -/** - * @brief Encapsulation of the HQC_KEM IND_CAA2 scheme - * - * @param[out] ct String containing the ciphertext - * @param[out] ss String containing the shared secret - * @param[in] pk String containing the public key - * @returns 0 if encapsulation is successful - */ -int PQCLEAN_HQC128_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk) { - - uint8_t theta[SHAKE256_512_BYTES] = {0}; - uint64_t u[VEC_N_SIZE_64] = {0}; - uint64_t v[VEC_N1N2_SIZE_64] = {0}; - uint8_t mc[VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES] = {0}; - uint8_t tmp[VEC_K_SIZE_BYTES + PUBLIC_KEY_BYTES + SALT_SIZE_BYTES] = {0}; - uint8_t *m = tmp; - uint8_t *salt = tmp + VEC_K_SIZE_BYTES + PUBLIC_KEY_BYTES; - shake256incctx shake256state; - - // Computing m - randombytes(m, VEC_K_SIZE_BYTES); - - // Computing theta - randombytes(salt, SALT_SIZE_BYTES); - memcpy(tmp + VEC_K_SIZE_BYTES, pk, PUBLIC_KEY_BYTES); - PQCLEAN_HQC128_CLEAN_shake256_512_ds(&shake256state, theta, tmp, VEC_K_SIZE_BYTES + PUBLIC_KEY_BYTES + SALT_SIZE_BYTES, G_FCT_DOMAIN); - - // Encrypting m - PQCLEAN_HQC128_CLEAN_hqc_pke_encrypt(u, v, m, theta, pk); - - // Computing shared secret - memcpy(mc, m, VEC_K_SIZE_BYTES); - PQCLEAN_HQC128_CLEAN_store8_arr(mc + VEC_K_SIZE_BYTES, VEC_N_SIZE_BYTES, u, VEC_N_SIZE_64); - PQCLEAN_HQC128_CLEAN_store8_arr(mc + VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES, VEC_N1N2_SIZE_BYTES, v, VEC_N1N2_SIZE_64); - PQCLEAN_HQC128_CLEAN_shake256_512_ds(&shake256state, ss, mc, VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES, K_FCT_DOMAIN); - - // Computing ciphertext - PQCLEAN_HQC128_CLEAN_hqc_ciphertext_to_string(ct, u, v, salt); - - - return 0; -} - - - -/** - * @brief Decapsulation of the HQC_KEM IND_CAA2 scheme - * - * @param[out] ss String containing the shared secret - * @param[in] ct String containing the cipĥertext - * @param[in] sk String containing the secret key - * @returns 0 if decapsulation is successful, -1 otherwise - */ -int PQCLEAN_HQC128_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) { - - uint8_t result; - uint64_t u[VEC_N_SIZE_64] = {0}; - uint64_t v[VEC_N1N2_SIZE_64] = {0}; - const uint8_t *pk = sk + SEED_BYTES + VEC_K_SIZE_BYTES; - uint8_t sigma[VEC_K_SIZE_BYTES] = {0}; - uint8_t theta[SHAKE256_512_BYTES] = {0}; - uint64_t u2[VEC_N_SIZE_64] = {0}; - uint64_t v2[VEC_N1N2_SIZE_64] = {0}; - uint8_t mc[VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES] = {0}; - uint8_t tmp[VEC_K_SIZE_BYTES + PUBLIC_KEY_BYTES + SALT_SIZE_BYTES] = {0}; - uint8_t *m = tmp; - uint8_t *salt = tmp + VEC_K_SIZE_BYTES + PUBLIC_KEY_BYTES; - shake256incctx shake256state; - - // Retrieving u, v and d from ciphertext - PQCLEAN_HQC128_CLEAN_hqc_ciphertext_from_string(u, v, salt, ct); - - // Decrypting - result = PQCLEAN_HQC128_CLEAN_hqc_pke_decrypt(m, sigma, u, v, sk); - - // Computing theta - memcpy(tmp + VEC_K_SIZE_BYTES, pk, PUBLIC_KEY_BYTES); - PQCLEAN_HQC128_CLEAN_shake256_512_ds(&shake256state, theta, tmp, VEC_K_SIZE_BYTES + PUBLIC_KEY_BYTES + SALT_SIZE_BYTES, G_FCT_DOMAIN); - - // Encrypting m' - PQCLEAN_HQC128_CLEAN_hqc_pke_encrypt(u2, v2, m, theta, pk); - - // Check if c != c' - result |= PQCLEAN_HQC128_CLEAN_vect_compare((uint8_t *)u, (uint8_t *)u2, VEC_N_SIZE_BYTES); - result |= PQCLEAN_HQC128_CLEAN_vect_compare((uint8_t *)v, (uint8_t *)v2, VEC_N1N2_SIZE_BYTES); - - result -= 1; - - for (size_t i = 0; i < VEC_K_SIZE_BYTES; ++i) { - mc[i] = (m[i] & result) ^ (sigma[i] & ~result); - } - - // Computing shared secret - PQCLEAN_HQC128_CLEAN_store8_arr(mc + VEC_K_SIZE_BYTES, VEC_N_SIZE_BYTES, u, VEC_N_SIZE_64); - PQCLEAN_HQC128_CLEAN_store8_arr(mc + VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES, VEC_N1N2_SIZE_BYTES, v, VEC_N1N2_SIZE_64); - PQCLEAN_HQC128_CLEAN_shake256_512_ds(&shake256state, ss, mc, VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES, K_FCT_DOMAIN); - - - return (result & 1) - 1; -} diff --git a/src/kem/hqc/pqclean_hqc-128_clean/parameters.h b/src/kem/hqc/pqclean_hqc-128_clean/parameters.h deleted file mode 100644 index f4ec3e806c..0000000000 --- a/src/kem/hqc/pqclean_hqc-128_clean/parameters.h +++ /dev/null @@ -1,96 +0,0 @@ -#ifndef HQC_PARAMETERS_H -#define HQC_PARAMETERS_H - - -/** - * @file parameters.h - * @brief Parameters of the HQC_KEM IND-CCA2 scheme - */ -#include "api.h" - - -#define CEIL_DIVIDE(a, b) (((a)+(b)-1)/(b)) /*!< Divide a by b and ceil the result*/ - -/* - #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 -*/ - -#define PARAM_N 17669 -#define PARAM_N1 46 -#define PARAM_N2 384 -#define PARAM_N1N2 17664 -#define PARAM_OMEGA 66 -#define PARAM_OMEGA_E 75 -#define PARAM_OMEGA_R 75 - -#define SECRET_KEY_BYTES PQCLEAN_HQC128_CLEAN_CRYPTO_SECRETKEYBYTES -#define PUBLIC_KEY_BYTES PQCLEAN_HQC128_CLEAN_CRYPTO_PUBLICKEYBYTES -#define SHARED_SECRET_BYTES PQCLEAN_HQC128_CLEAN_CRYPTO_BYTES -#define CIPHERTEXT_BYTES PQCLEAN_HQC128_CLEAN_CRYPTO_CIPHERTEXTBYTES - -#define VEC_N_SIZE_BYTES CEIL_DIVIDE(PARAM_N, 8) -#define VEC_K_SIZE_BYTES PARAM_K -#define VEC_N1_SIZE_BYTES PARAM_N1 -#define VEC_N1N2_SIZE_BYTES CEIL_DIVIDE(PARAM_N1N2, 8) - -#define VEC_N_SIZE_64 CEIL_DIVIDE(PARAM_N, 64) -#define VEC_K_SIZE_64 CEIL_DIVIDE(PARAM_K, 8) -#define VEC_N1_SIZE_64 CEIL_DIVIDE(PARAM_N1, 8) -#define VEC_N1N2_SIZE_64 CEIL_DIVIDE(PARAM_N1N2, 64) - -#define PARAM_DELTA 15 -#define PARAM_M 8 -#define PARAM_GF_POLY 0x11D -#define PARAM_GF_POLY_WT 5 -#define PARAM_GF_POLY_M2 4 -#define PARAM_GF_MUL_ORDER 255 -#define PARAM_K 16 -#define PARAM_G 31 -#define PARAM_FFT 4 -#define 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 RED_MASK 0x1f -#define SHAKE256_512_BYTES 64 -#define SEED_BYTES 40 -#define SALT_SIZE_BYTES 16 - -#endif diff --git a/src/kem/hqc/pqclean_hqc-128_clean/parsing.c b/src/kem/hqc/pqclean_hqc-128_clean/parsing.c deleted file mode 100644 index 20dce664bb..0000000000 --- a/src/kem/hqc/pqclean_hqc-128_clean/parsing.c +++ /dev/null @@ -1,173 +0,0 @@ -#include "parameters.h" -#include "parsing.h" -#include "vector.h" -#include -#include -/** - * @file parsing.c - * @brief Functions to parse secret key, public key and ciphertext of the HQC scheme - */ - - -static uint64_t load8(const uint8_t *in) { - uint64_t ret = in[7]; - - for (int8_t i = 6; i >= 0; --i) { - ret <<= 8; - ret |= in[i]; - } - - return ret; -} - -void PQCLEAN_HQC128_CLEAN_load8_arr(uint64_t *out64, size_t outlen, const uint8_t *in8, size_t inlen) { - size_t index_in = 0; - size_t index_out = 0; - - // first copy by 8 bytes - if (inlen >= 8 && outlen >= 1) { - while (index_out < outlen && index_in + 8 <= inlen) { - out64[index_out] = load8(in8 + index_in); - - index_in += 8; - index_out += 1; - } - } - - // we now need to do the last 7 bytes if necessary - if (index_in >= inlen || index_out >= outlen) { - return; - } - out64[index_out] = in8[inlen - 1]; - for (int8_t i = (int8_t)(inlen - index_in) - 2; i >= 0; --i) { - out64[index_out] <<= 8; - out64[index_out] |= in8[index_in + i]; - } -} - -void PQCLEAN_HQC128_CLEAN_store8_arr(uint8_t *out8, size_t outlen, const uint64_t *in64, size_t inlen) { - for (size_t index_out = 0, index_in = 0; index_out < outlen && index_in < inlen;) { - out8[index_out] = (in64[index_in] >> ((index_out % 8) * 8)) & 0xFF; - ++index_out; - if (index_out % 8 == 0) { - ++index_in; - } - } -} - -/** - * @brief Parse a secret key into a string - * - * The secret key is composed of the seed used to generate vectors x and y. - * As technicality, the public key is appended to the secret key in order to respect NIST API. - * - * @param[out] sk String containing the secret key - * @param[in] sk_seed Seed used to generate the secret key - * @param[in] sigma String used in HHK transform - * @param[in] pk String containing the public key - */ -void PQCLEAN_HQC128_CLEAN_hqc_secret_key_to_string(uint8_t *sk, const uint8_t *sk_seed, const uint8_t *sigma, const uint8_t *pk) { - memcpy(sk, sk_seed, SEED_BYTES); - memcpy(sk + SEED_BYTES, sigma, VEC_K_SIZE_BYTES); - memcpy(sk + SEED_BYTES + VEC_K_SIZE_BYTES, pk, PUBLIC_KEY_BYTES); -} - - - -/** - * @brief Parse a secret key from a string - * - * The secret key is composed of the seed used to generate vectors x and y. - * As technicality, the public key is appended to the secret key in order to respect NIST API. - * - * @param[out] x uint64_t representation of vector x - * @param[out] y uint64_t representation of vector y - * @param[out] pk String containing the public key - * @param[in] sk String containing the secret key - */ -void PQCLEAN_HQC128_CLEAN_hqc_secret_key_from_string(uint64_t *x, uint64_t *y, uint8_t *sigma, uint8_t *pk, const uint8_t *sk) { - seedexpander_state sk_seedexpander; - - memcpy(sigma, sk + SEED_BYTES, VEC_K_SIZE_BYTES); - PQCLEAN_HQC128_CLEAN_seedexpander_init(&sk_seedexpander, sk, SEED_BYTES); - - PQCLEAN_HQC128_CLEAN_vect_set_random_fixed_weight(&sk_seedexpander, x, PARAM_OMEGA); - PQCLEAN_HQC128_CLEAN_vect_set_random_fixed_weight(&sk_seedexpander, y, PARAM_OMEGA); - memcpy(pk, sk + SEED_BYTES + VEC_K_SIZE_BYTES, PUBLIC_KEY_BYTES); - - PQCLEAN_HQC128_CLEAN_seedexpander_release(&sk_seedexpander); -} - - - -/** - * @brief Parse a public key into a string - * - * The public key is composed of the syndrome s as well as the seed used to generate the vector h - * - * @param[out] pk String containing the public key - * @param[in] pk_seed Seed used to generate the public key - * @param[in] s uint64_t representation of vector s - */ -void PQCLEAN_HQC128_CLEAN_hqc_public_key_to_string(uint8_t *pk, const uint8_t *pk_seed, const uint64_t *s) { - memcpy(pk, pk_seed, SEED_BYTES); - PQCLEAN_HQC128_CLEAN_store8_arr(pk + SEED_BYTES, VEC_N_SIZE_BYTES, s, VEC_N_SIZE_64); -} - - - -/** - * @brief Parse a public key from a string - * - * The public key is composed of the syndrome s as well as the seed used to generate the vector h - * - * @param[out] h uint64_t representation of vector h - * @param[out] s uint64_t representation of vector s - * @param[in] pk String containing the public key - */ -void PQCLEAN_HQC128_CLEAN_hqc_public_key_from_string(uint64_t *h, uint64_t *s, const uint8_t *pk) { - seedexpander_state pk_seedexpander; - - PQCLEAN_HQC128_CLEAN_seedexpander_init(&pk_seedexpander, pk, SEED_BYTES); - PQCLEAN_HQC128_CLEAN_vect_set_random(&pk_seedexpander, h); - - PQCLEAN_HQC128_CLEAN_load8_arr(s, VEC_N_SIZE_64, pk + SEED_BYTES, VEC_N_SIZE_BYTES); - - PQCLEAN_HQC128_CLEAN_seedexpander_release(&pk_seedexpander); -} - - - -/** - * @brief Parse a ciphertext into a string - * - * The ciphertext is composed of vectors u, v and salt. - * - * @param[out] ct String containing the ciphertext - * @param[in] u uint64_t representation of vector u - * @param[in] v uint64_t representation of vector v - * @param[in] salt String containing a salt - */ -void PQCLEAN_HQC128_CLEAN_hqc_ciphertext_to_string(uint8_t *ct, const uint64_t *u, const uint64_t *v, const uint8_t *salt) { - PQCLEAN_HQC128_CLEAN_store8_arr(ct, VEC_N_SIZE_BYTES, u, VEC_N_SIZE_64); - PQCLEAN_HQC128_CLEAN_store8_arr(ct + VEC_N_SIZE_BYTES, VEC_N1N2_SIZE_BYTES, v, VEC_N1N2_SIZE_64); - memcpy(ct + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES, salt, SALT_SIZE_BYTES); -} - - - -/** - * @brief Parse a ciphertext from a string - * - * The ciphertext is composed of vectors u, v and salt. - * - * @param[out] u uint64_t representation of vector u - * @param[out] v uint64_t representation of vector v - * @param[out] d String containing the hash d - * @param[in] ct String containing the ciphertext - */ -void PQCLEAN_HQC128_CLEAN_hqc_ciphertext_from_string(uint64_t *u, uint64_t *v, uint8_t *salt, const uint8_t *ct) { - PQCLEAN_HQC128_CLEAN_load8_arr(u, VEC_N_SIZE_64, ct, VEC_N_SIZE_BYTES); - PQCLEAN_HQC128_CLEAN_load8_arr(v, VEC_N1N2_SIZE_64, ct + VEC_N_SIZE_BYTES, VEC_N1N2_SIZE_BYTES); - memcpy(salt, ct + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES, SALT_SIZE_BYTES); -} diff --git a/src/kem/hqc/pqclean_hqc-128_clean/parsing.h b/src/kem/hqc/pqclean_hqc-128_clean/parsing.h deleted file mode 100644 index f0a0f1667e..0000000000 --- a/src/kem/hqc/pqclean_hqc-128_clean/parsing.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef PARSING_H -#define PARSING_H - - -/** - * @file parsing.h - * @brief Header file for parsing.c - */ - -#include -#include - -void PQCLEAN_HQC128_CLEAN_load8_arr(uint64_t *out64, size_t outlen, const uint8_t *in8, size_t inlen); - -void PQCLEAN_HQC128_CLEAN_store8_arr(uint8_t *out8, size_t outlen, const uint64_t *in64, size_t inlen); - - -void PQCLEAN_HQC128_CLEAN_hqc_secret_key_to_string(uint8_t *sk, const uint8_t *sk_seed, const uint8_t *sigma, const uint8_t *pk); - -void PQCLEAN_HQC128_CLEAN_hqc_secret_key_from_string(uint64_t *x, uint64_t *y, uint8_t *sigma, uint8_t *pk, const uint8_t *sk); - - -void PQCLEAN_HQC128_CLEAN_hqc_public_key_to_string(uint8_t *pk, const uint8_t *pk_seed, const uint64_t *s); - -void PQCLEAN_HQC128_CLEAN_hqc_public_key_from_string(uint64_t *h, uint64_t *s, const uint8_t *pk); - - -void PQCLEAN_HQC128_CLEAN_hqc_ciphertext_to_string(uint8_t *ct, const uint64_t *u, const uint64_t *v, const uint8_t *salt); - -void PQCLEAN_HQC128_CLEAN_hqc_ciphertext_from_string(uint64_t *u, uint64_t *v, uint8_t *salt, const uint8_t *ct); - - -#endif diff --git a/src/kem/hqc/pqclean_hqc-128_clean/reed_muller.c b/src/kem/hqc/pqclean_hqc-128_clean/reed_muller.c deleted file mode 100644 index 695fc6b297..0000000000 --- a/src/kem/hqc/pqclean_hqc-128_clean/reed_muller.c +++ /dev/null @@ -1,193 +0,0 @@ -#include "parameters.h" -#include "reed_muller.h" -#include -#include -/** - * @file reed_muller.c - * @brief Constant time implementation of Reed-Muller code RM(1,7) - */ - - -// number of repeated code words -#define MULTIPLICITY CEIL_DIVIDE(PARAM_N2, 128) - -// copy bit 0 into all bits of a 32 bit value -#define BIT0MASK(x) (uint32_t)(-((x) & 1)) - -/** - * @brief Encode a single byte into a single codeword using RM(1,7) - * - * Encoding matrix of this code: - * bit pattern (note that bits are numbered big endian) - * 0 aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa - * 1 cccccccc cccccccc cccccccc cccccccc - * 2 f0f0f0f0 f0f0f0f0 f0f0f0f0 f0f0f0f0 - * 3 ff00ff00 ff00ff00 ff00ff00 ff00ff00 - * 4 ffff0000 ffff0000 ffff0000 ffff0000 - * 5 ffffffff 00000000 ffffffff 00000000 - * 6 ffffffff ffffffff 00000000 00000000 - * 7 ffffffff ffffffff ffffffff ffffffff - * - * @param[out] word An RM(1,7) codeword - * @param[in] message A message - */ -static void encode(uint64_t *cword, uint8_t message) { - uint32_t first_word; - // bit 7 flips all the bits, do that first to save work - first_word = BIT0MASK(message >> 7); - // bits 0, 1, 2, 3, 4 are the same for all four longs - // (Warning: in the bit matrix above, low bits are at the left!) - first_word ^= BIT0MASK(message >> 0) & 0xaaaaaaaa; - first_word ^= BIT0MASK(message >> 1) & 0xcccccccc; - first_word ^= BIT0MASK(message >> 2) & 0xf0f0f0f0; - first_word ^= BIT0MASK(message >> 3) & 0xff00ff00; - first_word ^= BIT0MASK(message >> 4) & 0xffff0000; - // we can store this in the first quarter - cword[0] = first_word; - // bit 5 flips entries 1 and 3; bit 6 flips 2 and 3 - first_word ^= BIT0MASK(message >> 5); - cword[0] |= (uint64_t)first_word << 32; - first_word ^= BIT0MASK(message >> 6); - cword[1] = (uint64_t)first_word << 32; - first_word ^= BIT0MASK(message >> 5); - cword[1] |= first_word; -} - - - -/** - * @brief Hadamard transform - * - * Perform hadamard transform of src and store result in dst - * src is overwritten - * - * @param[out] src Structure that contain the expanded codeword - * @param[out] dst Structure that contain the expanded codeword - */ -static void hadamard(uint16_t src[128], uint16_t dst[128]) { - // the passes move data: - // src -> dst -> src -> dst -> src -> dst -> src -> dst - // using p1 and p2 alternately - uint16_t *p1 = src; - uint16_t *p2 = dst; - uint16_t *p3; - for (size_t pass = 0; pass < 7; ++pass) { - for (size_t i = 0; i < 64; ++i) { - p2[i] = p1[2 * i] + p1[2 * i + 1]; - p2[i + 64] = p1[2 * i] - p1[2 * i + 1]; - } - // swap p1, p2 for next round - p3 = p1; - p1 = p2; - p2 = p3; - } -} - - - -/** - * @brief Add multiple codewords into expanded codeword - * - * Accesses memory in order - * Note: this does not write the codewords as -1 or +1 as the green machine does - * instead, just 0 and 1 is used. - * The resulting hadamard transform has: - * all values are halved - * the first entry is 64 too high - * - * @param[out] dest Structure that contain the expanded codeword - * @param[in] src Structure that contain the codeword - */ -static void expand_and_sum(uint16_t dest[128], const uint64_t src[2 * MULTIPLICITY]) { - // start with the first copy - for (size_t part = 0; part < 2; ++part) { - for (size_t bit = 0; bit < 64; ++bit) { - dest[part * 64 + bit] = ((src[part] >> bit) & 1); - } - } - // sum the rest of the copies - for (size_t copy = 1; copy < MULTIPLICITY; ++copy) { - for (size_t part = 0; part < 2; ++part) { - for (size_t bit = 0; bit < 64; ++bit) { - dest[part * 64 + bit] += (uint16_t) ((src[2 * copy + part] >> bit) & 1); - } - } - } -} - - - -/** - * @brief Finding the location of the highest value - * - * This is the final step of the green machine: find the location of the highest value, - * and add 128 if the peak is positive - * if there are two identical peaks, the peak with smallest value - * in the lowest 7 bits it taken - * @param[in] transform Structure that contain the expanded codeword - */ -static uint8_t find_peaks(const uint16_t transform[128]) { - uint16_t peak_abs = 0; - uint16_t peak = 0; - uint16_t pos = 0; - uint16_t t, abs, mask; - for (uint16_t i = 0; i < 128; ++i) { - t = transform[i]; - abs = t ^ ((uint16_t)(-(t >> 15)) & (t ^ -t)); // t = abs(t) - mask = -(((uint16_t)(peak_abs - abs)) >> 15); - peak ^= mask & (peak ^ t); - pos ^= mask & (pos ^ i); - peak_abs ^= mask & (peak_abs ^ abs); - } - // set bit 7 - pos |= 128 & (uint16_t)((peak >> 15) - 1); - return (uint8_t) pos; -} - - - -/** - * @brief Encodes the received word - * - * The message consists of N1 bytes each byte is encoded into PARAM_N2 bits, - * or MULTIPLICITY repeats of 128 bits - * - * @param[out] cdw Array of size VEC_N1N2_SIZE_64 receiving the encoded message - * @param[in] msg Array of size VEC_N1_SIZE_64 storing the message - */ -void PQCLEAN_HQC128_CLEAN_reed_muller_encode(uint64_t *cdw, const uint8_t *msg) { - for (size_t i = 0; i < VEC_N1_SIZE_BYTES; ++i) { - // encode first word - encode(&cdw[2 * i * MULTIPLICITY], msg[i]); - // copy to other identical codewords - for (size_t copy = 1; copy < MULTIPLICITY; ++copy) { - memcpy(&cdw[2 * i * MULTIPLICITY + 2 * copy], &cdw[2 * i * MULTIPLICITY], 16); - } - } -} - - - -/** - * @brief Decodes the received word - * - * Decoding uses fast hadamard transform, for a more complete picture on Reed-Muller decoding, see MacWilliams, Florence Jessie, and Neil James Alexander Sloane. - * The theory of error-correcting codes codes @cite macwilliams1977theory - * - * @param[out] msg Array of size VEC_N1_SIZE_64 receiving the decoded message - * @param[in] cdw Array of size VEC_N1N2_SIZE_64 storing the received word - */ -void PQCLEAN_HQC128_CLEAN_reed_muller_decode(uint8_t *msg, const uint64_t *cdw) { - uint16_t expanded[128]; - uint16_t transform[128]; - for (size_t i = 0; i < VEC_N1_SIZE_BYTES; ++i) { - // collect the codewords - expand_and_sum(expanded, &cdw[2 * i * MULTIPLICITY]); - // apply hadamard transform - hadamard(expanded, transform); - // fix the first entry to get the half Hadamard transform - transform[0] -= 64 * MULTIPLICITY; - // finish the decoding - msg[i] = find_peaks(transform); - } -} diff --git a/src/kem/hqc/pqclean_hqc-128_clean/reed_muller.h b/src/kem/hqc/pqclean_hqc-128_clean/reed_muller.h deleted file mode 100644 index fb93fc7a04..0000000000 --- a/src/kem/hqc/pqclean_hqc-128_clean/reed_muller.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef REED_MULLER_H -#define REED_MULLER_H - - -/** - * @file reed_muller.h - * @brief Header file of reed_muller.c - */ - -#include - -void PQCLEAN_HQC128_CLEAN_reed_muller_encode(uint64_t *cdw, const uint8_t *msg); - -void PQCLEAN_HQC128_CLEAN_reed_muller_decode(uint8_t *msg, const uint64_t *cdw); - - -#endif diff --git a/src/kem/hqc/pqclean_hqc-128_clean/reed_solomon.c b/src/kem/hqc/pqclean_hqc-128_clean/reed_solomon.c deleted file mode 100644 index 70c78ef125..0000000000 --- a/src/kem/hqc/pqclean_hqc-128_clean/reed_solomon.c +++ /dev/null @@ -1,335 +0,0 @@ -#include "fft.h" -#include "gf.h" -#include "parameters.h" -#include "reed_solomon.h" -#include -#include -/** - * @file reed_solomon.c - * @brief Constant time implementation of Reed-Solomon codes - */ - - -/** - * @brief Encodes a message message of PARAM_K bits to a Reed-Solomon codeword codeword of PARAM_N1 bytes - * - * Following @cite lin1983error (Chapter 4 - Cyclic Codes), - * We perform a systematic encoding using a linear (PARAM_N1 - PARAM_K)-stage shift register - * with feedback connections based on the generator polynomial PARAM_RS_POLY of the Reed-Solomon code. - * - * @param[out] cdw Array of size VEC_N1_SIZE_64 receiving the encoded message - * @param[in] msg Array of size VEC_K_SIZE_64 storing the message - */ -void PQCLEAN_HQC128_CLEAN_reed_solomon_encode(uint8_t *cdw, const uint8_t *msg) { - uint8_t gate_value = 0; - - uint16_t tmp[PARAM_G] = {0}; - uint16_t PARAM_RS_POLY [] = {RS_POLY_COEFS}; - - memset(cdw, 0, PARAM_N1); - - for (size_t i = 0; i < PARAM_K; ++i) { - gate_value = msg[PARAM_K - 1 - i] ^ cdw[PARAM_N1 - PARAM_K - 1]; - - for (size_t j = 0; j < PARAM_G; ++j) { - tmp[j] = PQCLEAN_HQC128_CLEAN_gf_mul(gate_value, PARAM_RS_POLY[j]); - } - - for (size_t k = PARAM_N1 - PARAM_K - 1; k; --k) { - cdw[k] = (uint8_t)(cdw[k - 1] ^ tmp[k]); - } - - cdw[0] = (uint8_t)tmp[0]; - } - - memcpy(cdw + PARAM_N1 - PARAM_K, msg, PARAM_K); -} - - - -/** - * @brief Computes 2 * PARAM_DELTA syndromes - * - * @param[out] syndromes Array of size 2 * PARAM_DELTA receiving the computed syndromes - * @param[in] cdw Array of size PARAM_N1 storing the received vector - */ -static void compute_syndromes(uint16_t *syndromes, uint8_t *cdw) { - for (size_t i = 0; i < 2 * PARAM_DELTA; ++i) { - for (size_t j = 1; j < PARAM_N1; ++j) { - syndromes[i] ^= PQCLEAN_HQC128_CLEAN_gf_mul(cdw[j], alpha_ij_pow[i][j - 1]); - } - syndromes[i] ^= cdw[0]; - } -} - - - -/** - * @brief Computes the error locator polynomial (ELP) sigma - * - * This is a constant time implementation of Berlekamp's simplified algorithm (see @cite lin1983error (Chapter 6 - BCH Codes).
- * We use the letter p for rho which is initialized at -1.
- * The array X_sigma_p represents the polynomial X^(mu-rho)*sigma_p(X).
- * Instead of maintaining a list of sigmas, we update in place both sigma and X_sigma_p.
- * sigma_copy serves as a temporary save of sigma in case X_sigma_p needs to be updated.
- * We can properly correct only if the degree of sigma does not exceed PARAM_DELTA. - * This means only the first PARAM_DELTA + 1 coefficients of sigma are of value - * and we only need to save its first PARAM_DELTA - 1 coefficients. - * - * @returns the degree of the ELP sigma - * @param[out] sigma Array of size (at least) PARAM_DELTA receiving the ELP - * @param[in] syndromes Array of size (at least) 2*PARAM_DELTA storing the syndromes - */ -static uint16_t compute_elp(uint16_t *sigma, const uint16_t *syndromes) { - uint16_t deg_sigma = 0; - uint16_t deg_sigma_p = 0; - uint16_t deg_sigma_copy = 0; - uint16_t sigma_copy[PARAM_DELTA + 1] = {0}; - uint16_t X_sigma_p[PARAM_DELTA + 1] = {0, 1}; - uint16_t pp = (uint16_t) -1; // 2*rho - uint16_t d_p = 1; - uint16_t d = syndromes[0]; - - uint16_t mask1, mask2, mask12; - uint16_t deg_X, deg_X_sigma_p; - uint16_t dd; - uint16_t mu; - - uint16_t i; - - sigma[0] = 1; - for (mu = 0; (mu < (2 * PARAM_DELTA)); ++mu) { - // Save sigma in case we need it to update X_sigma_p - memcpy(sigma_copy, sigma, 2 * (PARAM_DELTA)); - deg_sigma_copy = deg_sigma; - - dd = PQCLEAN_HQC128_CLEAN_gf_mul(d, PQCLEAN_HQC128_CLEAN_gf_inverse(d_p)); - - for (i = 1; (i <= mu + 1) && (i <= PARAM_DELTA); ++i) { - sigma[i] ^= PQCLEAN_HQC128_CLEAN_gf_mul(dd, X_sigma_p[i]); - } - - deg_X = mu - pp; - deg_X_sigma_p = deg_X + deg_sigma_p; - - // mask1 = 0xffff if(d != 0) and 0 otherwise - mask1 = -((uint16_t) - d >> 15); - - // mask2 = 0xffff if(deg_X_sigma_p > deg_sigma) and 0 otherwise - mask2 = -((uint16_t) (deg_sigma - deg_X_sigma_p) >> 15); - - // mask12 = 0xffff if the deg_sigma increased and 0 otherwise - mask12 = mask1 & mask2; - deg_sigma ^= mask12 & (deg_X_sigma_p ^ deg_sigma); - - if (mu == (2 * PARAM_DELTA - 1)) { - break; - } - - pp ^= mask12 & (mu ^ pp); - d_p ^= mask12 & (d ^ d_p); - for (i = PARAM_DELTA; i; --i) { - X_sigma_p[i] = (mask12 & sigma_copy[i - 1]) ^ (~mask12 & X_sigma_p[i - 1]); - } - - deg_sigma_p ^= mask12 & (deg_sigma_copy ^ deg_sigma_p); - d = syndromes[mu + 1]; - - for (i = 1; (i <= mu + 1) && (i <= PARAM_DELTA); ++i) { - d ^= PQCLEAN_HQC128_CLEAN_gf_mul(sigma[i], syndromes[mu + 1 - i]); - } - } - - return deg_sigma; -} - - - -/** - * @brief Computes the error polynomial error from the error locator polynomial sigma - * - * See function PQCLEAN_HQC128_CLEAN_fft for more details. - * - * @param[out] error Array of 2^PARAM_M elements receiving the error polynomial - * @param[out] error_compact Array of PARAM_DELTA + PARAM_N1 elements receiving a compact representation of the vector error - * @param[in] sigma Array of 2^PARAM_FFT elements storing the error locator polynomial - */ -static void compute_roots(uint8_t *error, uint16_t *sigma) { - uint16_t w[1 << PARAM_M] = {0}; - - PQCLEAN_HQC128_CLEAN_fft(w, sigma, PARAM_DELTA + 1); - PQCLEAN_HQC128_CLEAN_fft_retrieve_error_poly(error, w); -} - - - -/** - * @brief Computes the polynomial z(x) - * - * See @cite lin1983error (Chapter 6 - BCH Codes) for more details. - * - * @param[out] z Array of PARAM_DELTA + 1 elements receiving the polynomial z(x) - * @param[in] sigma Array of 2^PARAM_FFT elements storing the error locator polynomial - * @param[in] degree Integer that is the degree of polynomial sigma - * @param[in] syndromes Array of 2 * PARAM_DELTA storing the syndromes - */ -static void compute_z_poly(uint16_t *z, const uint16_t *sigma, uint16_t degree, const uint16_t *syndromes) { - size_t i, j; - uint16_t mask; - - z[0] = 1; - - for (i = 1; i < PARAM_DELTA + 1; ++i) { - mask = -((uint16_t) (i - degree - 1) >> 15); - z[i] = mask & sigma[i]; - } - - z[1] ^= syndromes[0]; - - for (i = 2; i <= PARAM_DELTA; ++i) { - mask = -((uint16_t) (i - degree - 1) >> 15); - z[i] ^= mask & syndromes[i - 1]; - - for (j = 1; j < i; ++j) { - z[i] ^= mask & PQCLEAN_HQC128_CLEAN_gf_mul(sigma[j], syndromes[i - j - 1]); - } - } -} - - - -/** - * @brief Computes the error values - * - * See @cite lin1983error (Chapter 6 - BCH Codes) for more details. - * - * @param[out] error_values Array of PARAM_DELTA elements receiving the error values - * @param[in] z Array of PARAM_DELTA + 1 elements storing the polynomial z(x) - * @param[in] z_degree Integer that is the degree of polynomial z(x) - * @param[in] error_compact Array of PARAM_DELTA + PARAM_N1 storing compact representation of the error - */ -static void compute_error_values(uint16_t *error_values, const uint16_t *z, const uint8_t *error) { - uint16_t beta_j[PARAM_DELTA] = {0}; - uint16_t e_j[PARAM_DELTA] = {0}; - - uint16_t delta_counter; - uint16_t delta_real_value; - uint16_t found; - uint16_t mask1; - uint16_t mask2; - uint16_t tmp1; - uint16_t tmp2; - uint16_t inverse; - uint16_t inverse_power_j; - - // Compute the beta_{j_i} page 31 of the documentation - delta_counter = 0; - for (size_t i = 0; i < PARAM_N1; i++) { - found = 0; - mask1 = (uint16_t) (-((int32_t)error[i]) >> 31); // error[i] != 0 - for (size_t j = 0; j < PARAM_DELTA; j++) { - mask2 = ~((uint16_t) (-((int32_t) j ^ delta_counter) >> 31)); // j == delta_counter - beta_j[j] += mask1 & mask2 & gf_exp[i]; - found += mask1 & mask2 & 1; - } - delta_counter += found; - } - delta_real_value = delta_counter; - - // Compute the e_{j_i} page 31 of the documentation - for (size_t i = 0; i < PARAM_DELTA; ++i) { - tmp1 = 1; - tmp2 = 1; - inverse = PQCLEAN_HQC128_CLEAN_gf_inverse(beta_j[i]); - inverse_power_j = 1; - - for (size_t j = 1; j <= PARAM_DELTA; ++j) { - inverse_power_j = PQCLEAN_HQC128_CLEAN_gf_mul(inverse_power_j, inverse); - tmp1 ^= PQCLEAN_HQC128_CLEAN_gf_mul(inverse_power_j, z[j]); - } - for (size_t k = 1; k < PARAM_DELTA; ++k) { - tmp2 = PQCLEAN_HQC128_CLEAN_gf_mul(tmp2, (1 ^ PQCLEAN_HQC128_CLEAN_gf_mul(inverse, beta_j[(i + k) % PARAM_DELTA]))); - } - mask1 = (uint16_t) (((int16_t) i - delta_real_value) >> 15); // i < delta_real_value - e_j[i] = mask1 & PQCLEAN_HQC128_CLEAN_gf_mul(tmp1, PQCLEAN_HQC128_CLEAN_gf_inverse(tmp2)); - } - - // Place the delta e_{j_i} values at the right coordinates of the output vector - delta_counter = 0; - for (size_t i = 0; i < PARAM_N1; ++i) { - found = 0; - mask1 = (uint16_t) (-((int32_t)error[i]) >> 31); // error[i] != 0 - for (size_t j = 0; j < PARAM_DELTA; j++) { - mask2 = ~((uint16_t) (-((int32_t) j ^ delta_counter) >> 31)); // j == delta_counter - error_values[i] += mask1 & mask2 & e_j[j]; - found += mask1 & mask2 & 1; - } - delta_counter += found; - } -} - - - -/** - * @brief Correct the errors - * - * @param[out] cdw Array of PARAM_N1 elements receiving the corrected vector - * @param[in] error Array of the error vector - * @param[in] error_values Array of PARAM_DELTA elements storing the error values - */ -static void correct_errors(uint8_t *cdw, const uint16_t *error_values) { - for (size_t i = 0; i < PARAM_N1; ++i) { - cdw[i] ^= error_values[i]; - } -} - - - -/** - * @brief Decodes the received word - * - * This function relies on six steps: - *
    - *
  1. The first step, is the computation of the 2*PARAM_DELTA syndromes. - *
  2. The second step is the computation of the error-locator polynomial sigma. - *
  3. The third step, done by additive FFT, is finding the error-locator numbers by calculating the roots of the polynomial sigma and takings their inverses. - *
  4. The fourth step, is the polynomial z(x). - *
  5. The fifth step, is the computation of the error values. - *
  6. The sixth step is the correction of the errors in the received polynomial. - *
- * For a more complete picture on Reed-Solomon decoding, see Shu. Lin and Daniel J. Costello in Error Control Coding: Fundamentals and Applications @cite lin1983error - * - * @param[out] msg Array of size VEC_K_SIZE_64 receiving the decoded message - * @param[in] cdw Array of size VEC_N1_SIZE_64 storing the received word - */ -void PQCLEAN_HQC128_CLEAN_reed_solomon_decode(uint8_t *msg, uint8_t *cdw) { - uint16_t syndromes[2 * PARAM_DELTA] = {0}; - uint16_t sigma[1 << PARAM_FFT] = {0}; - uint8_t error[1 << PARAM_M] = {0}; - uint16_t z[PARAM_N1] = {0}; - uint16_t error_values[PARAM_N1] = {0}; - uint16_t deg; - - // Calculate the 2*PARAM_DELTA syndromes - compute_syndromes(syndromes, cdw); - - // Compute the error locator polynomial sigma - // Sigma's degree is at most PARAM_DELTA but the FFT requires the extra room - deg = compute_elp(sigma, syndromes); - - // Compute the error polynomial error - compute_roots(error, sigma); - - // Compute the polynomial z(x) - compute_z_poly(z, sigma, deg, syndromes); - - // Compute the error values - compute_error_values(error_values, z, error); - - // Correct the errors - correct_errors(cdw, error_values); - - // Retrieve the message from the decoded codeword - memcpy(msg, cdw + (PARAM_G - 1), PARAM_K); - -} diff --git a/src/kem/hqc/pqclean_hqc-128_clean/reed_solomon.h b/src/kem/hqc/pqclean_hqc-128_clean/reed_solomon.h deleted file mode 100644 index ad59774fde..0000000000 --- a/src/kem/hqc/pqclean_hqc-128_clean/reed_solomon.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef REED_SOLOMON_H -#define REED_SOLOMON_H - - -/** - * @file reed_solomon.h - * @brief Header file of reed_solomon.c - */ - -#include - -static const uint16_t alpha_ij_pow [30][45] = {{2, 4, 8, 16, 32, 64, 128, 29, 58, 116, 232, 205, 135, 19, 38, 76, 152, 45, 90, 180, 117, 234, 201, 143, 3, 6, 12, 24, 48, 96, 192, 157, 39, 78, 156, 37, 74, 148, 53, 106, 212, 181, 119, 238, 193}, {4, 16, 64, 29, 116, 205, 19, 76, 45, 180, 234, 143, 6, 24, 96, 157, 78, 37, 148, 106, 181, 238, 159, 70, 5, 20, 80, 93, 105, 185, 222, 95, 97, 153, 94, 101, 137, 30, 120, 253, 211, 107, 177, 254, 223}, {8, 64, 58, 205, 38, 45, 117, 143, 12, 96, 39, 37, 53, 181, 193, 70, 10, 80, 186, 185, 161, 97, 47, 101, 15, 120, 231, 107, 127, 223, 182, 217, 134, 68, 26, 208, 206, 62, 237, 59, 197, 102, 23, 184, 169}, {16, 29, 205, 76, 180, 143, 24, 157, 37, 106, 238, 70, 20, 93, 185, 95, 153, 101, 30, 253, 107, 254, 91, 217, 17, 13, 208, 129, 248, 59, 151, 133, 184, 79, 132, 168, 82, 73, 228, 230, 198, 252, 123, 227, 150}, {32, 116, 38, 180, 3, 96, 156, 106, 193, 5, 160, 185, 190, 94, 15, 253, 214, 223, 226, 17, 26, 103, 124, 59, 51, 46, 169, 132, 77, 85, 114, 230, 145, 215, 255, 150, 55, 174, 100, 28, 167, 89, 239, 172, 36}, {64, 205, 45, 143, 96, 37, 181, 70, 80, 185, 97, 101, 120, 107, 223, 217, 68, 208, 62, 59, 102, 184, 33, 168, 85, 228, 191, 252, 241, 150, 110, 130, 7, 221, 89, 195, 138, 61, 251, 44, 207, 173, 8, 58, 38}, {128, 19, 117, 24, 156, 181, 140, 93, 161, 94, 60, 107, 163, 67, 26, 129, 147, 102, 109, 132, 41, 57, 209, 252, 255, 98, 87, 200, 224, 89, 155, 18, 245, 11, 233, 173, 16, 232, 45, 3, 157, 53, 159, 40, 185}, {29, 76, 143, 157, 106, 70, 93, 95, 101, 253, 254, 217, 13, 129, 59, 133, 79, 168, 73, 230, 252, 227, 149, 130, 28, 81, 195, 18, 247, 44, 27, 2, 58, 152, 3, 39, 212, 140, 186, 190, 202, 231, 225, 175, 26}, {58, 45, 12, 37, 193, 80, 161, 101, 231, 223, 134, 208, 237, 102, 169, 168, 146, 191, 179, 150, 87, 7, 166, 195, 36, 251, 125, 173, 64, 38, 143, 39, 181, 10, 185, 47, 120, 127, 217, 26, 62, 197, 184, 21, 85}, {116, 180, 96, 106, 5, 185, 94, 253, 223, 17, 103, 59, 46, 132, 85, 230, 215, 150, 174, 28, 89, 172, 244, 44, 108, 32, 38, 3, 156, 193, 160, 190, 15, 214, 226, 26, 124, 51, 169, 77, 114, 145, 255, 55, 100}, {232, 234, 39, 238, 160, 97, 60, 254, 134, 103, 118, 184, 84, 57, 145, 227, 220, 7, 162, 172, 245, 176, 71, 58, 180, 192, 181, 40, 95, 15, 177, 175, 208, 147, 46, 21, 73, 99, 241, 55, 200, 166, 43, 122, 44}, {205, 143, 37, 70, 185, 101, 107, 217, 208, 59, 184, 168, 228, 252, 150, 130, 221, 195, 61, 44, 173, 58, 117, 39, 193, 186, 47, 231, 182, 26, 237, 23, 21, 146, 145, 219, 87, 56, 242, 36, 139, 54, 64, 45, 96}, {135, 6, 53, 20, 190, 120, 163, 13, 237, 46, 84, 228, 229, 98, 100, 81, 69, 251, 131, 32, 45, 192, 238, 186, 94, 187, 217, 189, 236, 169, 82, 209, 241, 220, 28, 242, 72, 22, 173, 116, 201, 37, 140, 222, 15}, {19, 24, 181, 93, 94, 107, 67, 129, 102, 132, 57, 252, 98, 200, 89, 18, 11, 173, 232, 3, 53, 40, 194, 231, 226, 189, 197, 158, 170, 145, 75, 25, 166, 69, 235, 54, 29, 234, 37, 5, 95, 120, 91, 52, 59}, {38, 96, 193, 185, 15, 223, 26, 59, 169, 85, 145, 150, 100, 89, 36, 44, 1, 38, 96, 193, 185, 15, 223, 26, 59, 169, 85, 145, 150, 100, 89, 36, 44, 1, 38, 96, 193, 185, 15, 223, 26, 59, 169, 85, 145}, {76, 157, 70, 95, 253, 217, 129, 133, 168, 230, 227, 130, 81, 18, 44, 2, 152, 39, 140, 190, 231, 175, 31, 23, 77, 209, 219, 25, 162, 36, 88, 4, 45, 78, 5, 97, 211, 67, 62, 46, 154, 191, 171, 50, 89}, {152, 78, 10, 153, 214, 68, 147, 79, 146, 215, 220, 221, 69, 11, 1, 152, 78, 10, 153, 214, 68, 147, 79, 146, 215, 220, 221, 69, 11, 1, 152, 78, 10, 153, 214, 68, 147, 79, 146, 215, 220, 221, 69, 11, 1}, {45, 37, 80, 101, 223, 208, 102, 168, 191, 150, 7, 195, 251, 173, 38, 39, 10, 47, 127, 26, 197, 21, 115, 219, 100, 242, 245, 54, 205, 96, 70, 97, 107, 68, 59, 33, 228, 241, 130, 89, 61, 207, 58, 12, 193}, {90, 148, 186, 30, 226, 62, 109, 73, 179, 174, 162, 61, 131, 232, 96, 140, 153, 127, 52, 51, 168, 99, 98, 56, 172, 22, 8, 234, 212, 185, 240, 67, 237, 79, 114, 241, 25, 121, 245, 108, 19, 39, 20, 188, 223}, {180, 106, 185, 253, 17, 59, 132, 230, 150, 28, 172, 44, 32, 3, 193, 190, 214, 26, 51, 77, 145, 55, 167, 36, 233, 116, 96, 5, 94, 223, 103, 46, 85, 215, 174, 89, 244, 108, 38, 156, 160, 15, 226, 124, 169}, {117, 181, 161, 107, 26, 102, 41, 252, 87, 89, 245, 173, 45, 53, 185, 231, 68, 197, 168, 145, 110, 166, 61, 54, 38, 37, 186, 120, 134, 59, 21, 191, 196, 221, 36, 207, 205, 39, 80, 15, 217, 237, 33, 115, 150}, {234, 238, 97, 254, 103, 184, 57, 227, 7, 172, 176, 58, 192, 40, 15, 175, 147, 21, 99, 55, 166, 122, 216, 45, 106, 222, 107, 52, 133, 85, 123, 50, 195, 11, 32, 12, 140, 188, 182, 124, 158, 115, 49, 224, 36}, {201, 159, 47, 91, 124, 33, 209, 149, 166, 244, 71, 117, 238, 194, 223, 31, 79, 115, 98, 167, 61, 216, 90, 181, 190, 254, 206, 218, 213, 150, 224, 72, 54, 152, 106, 161, 177, 189, 184, 114, 171, 56, 18, 131, 38}, {143, 70, 101, 217, 59, 168, 252, 130, 195, 44, 58, 39, 186, 231, 26, 23, 146, 219, 56, 36, 54, 45, 181, 97, 223, 62, 33, 191, 110, 89, 251, 8, 12, 10, 15, 134, 197, 41, 179, 100, 86, 125, 205, 37, 185}, {3, 5, 15, 17, 51, 85, 255, 28, 36, 108, 180, 193, 94, 226, 59, 77, 215, 100, 172, 233, 38, 106, 190, 223, 124, 132, 145, 174, 239, 44, 116, 156, 185, 214, 103, 169, 230, 55, 89, 235, 32, 96, 160, 253, 26}, {6, 20, 120, 13, 46, 228, 98, 81, 251, 32, 192, 186, 187, 189, 169, 209, 220, 242, 22, 116, 37, 222, 254, 62, 132, 63, 130, 43, 250, 38, 212, 194, 182, 147, 77, 179, 141, 9, 54, 180, 159, 101, 67, 151, 85}, {12, 80, 231, 208, 169, 191, 87, 195, 125, 38, 181, 47, 217, 197, 85, 219, 221, 245, 8, 96, 186, 107, 206, 33, 145, 130, 86, 207, 45, 193, 101, 134, 102, 146, 150, 166, 251, 64, 39, 185, 127, 62, 21, 252, 100}, {24, 93, 107, 129, 132, 252, 200, 18, 173, 3, 40, 231, 189, 158, 145, 25, 69, 54, 234, 5, 120, 52, 218, 191, 174, 43, 207, 90, 35, 15, 136, 92, 115, 220, 239, 125, 76, 238, 101, 17, 133, 228, 149, 121, 44}, {48, 105, 127, 248, 77, 241, 224, 247, 64, 156, 95, 182, 236, 170, 150, 162, 11, 205, 212, 94, 134, 133, 213, 110, 239, 250, 45, 35, 30, 26, 218, 99, 130, 69, 108, 143, 40, 211, 206, 132, 229, 7, 144, 2, 96}, {96, 185, 223, 59, 85, 150, 89, 44, 38, 193, 15, 26, 169, 145, 100, 36, 1, 96, 185, 223, 59, 85, 150, 89, 44, 38, 193, 15, 26, 169, 145, 100, 36, 1, 96, 185, 223, 59, 85, 150, 89, 44, 38, 193, 15}}; - -void PQCLEAN_HQC128_CLEAN_reed_solomon_encode(uint8_t *cdw, const uint8_t *msg); - -void PQCLEAN_HQC128_CLEAN_reed_solomon_decode(uint8_t *msg, uint8_t *cdw); - - -#endif diff --git a/src/kem/hqc/pqclean_hqc-128_clean/shake_ds.c b/src/kem/hqc/pqclean_hqc-128_clean/shake_ds.c deleted file mode 100644 index 7e2f9234db..0000000000 --- a/src/kem/hqc/pqclean_hqc-128_clean/shake_ds.c +++ /dev/null @@ -1,40 +0,0 @@ -#include "shake_ds.h" - - -/** - * @file shake_ds.c - * @brief Implementation SHAKE-256 with incremental API and domain separation - */ - - - -/** - * @brief SHAKE-256 with incremental API and domain separation - * - * Derived from function SHAKE_256 in fips202.c - * - * @param[out] state Internal state of SHAKE - * @param[in] output Pointer to output - * @param[in] input Pointer to input - * @param[in] inlen length of input in bytes - * @param[in] domain byte for domain separation - */ -void PQCLEAN_HQC128_CLEAN_shake256_512_ds(shake256incctx *state, uint8_t *output, const uint8_t *input, size_t inlen, uint8_t domain) { - /* Init state */ - shake256_inc_init(state); - - /* Absorb input */ - shake256_inc_absorb(state, input, inlen); - - /* Absorb domain separation byte */ - shake256_inc_absorb(state, &domain, 1); - - /* Finalize */ - shake256_inc_finalize(state); - - /* Squeeze output */ - shake256_inc_squeeze(output, 512 / 8, state); - - /* Release ctx */ - shake256_inc_ctx_release(state); -} diff --git a/src/kem/hqc/pqclean_hqc-128_clean/shake_ds.h b/src/kem/hqc/pqclean_hqc-128_clean/shake_ds.h deleted file mode 100644 index 822a82dccd..0000000000 --- a/src/kem/hqc/pqclean_hqc-128_clean/shake_ds.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef SHAKE_DS_H -#define SHAKE_DS_H - - -/** - * @file shake_ds.h - * @brief Header file of shake_ds.c - */ -#include "fips202.h" -#include -#include - -void PQCLEAN_HQC128_CLEAN_shake256_512_ds(shake256incctx *state, uint8_t *output, const uint8_t *input, size_t inlen, uint8_t domain); - - -#endif diff --git a/src/kem/hqc/pqclean_hqc-128_clean/shake_prng.c b/src/kem/hqc/pqclean_hqc-128_clean/shake_prng.c deleted file mode 100644 index 39a2c12cae..0000000000 --- a/src/kem/hqc/pqclean_hqc-128_clean/shake_prng.c +++ /dev/null @@ -1,60 +0,0 @@ -#include "domains.h" -#include "fips202.h" -#include "shake_prng.h" - -/** - * @file shake_prng.c - * @brief Implementation of SHAKE-256 based seed expander - */ - - -/** - * @brief Initialise a SHAKE-256 based seed expander - * - * Derived from function SHAKE_256 in fips202.c - * - * @param[out] state Keccak internal state and a counter - * @param[in] seed A seed - * @param[in] seedlen The seed bytes length - */ -void PQCLEAN_HQC128_CLEAN_seedexpander_init(seedexpander_state *state, const uint8_t *seed, size_t seedlen) { - uint8_t domain = SEEDEXPANDER_DOMAIN; - shake256_inc_init(state); - shake256_inc_absorb(state, seed, seedlen); - shake256_inc_absorb(state, &domain, 1); - shake256_inc_finalize(state); -} - - - -/** - * @brief A SHAKE-256 based seed expander - * - * Derived from function SHAKE_256 in fips202.c - * Squeezes Keccak state by 64-bit blocks (hardware version compatibility) - * - * @param[out] state Internal state of SHAKE - * @param[out] output The XOF data - * @param[in] outlen Number of bytes to return - */ -void PQCLEAN_HQC128_CLEAN_seedexpander(seedexpander_state *state, uint8_t *output, size_t outlen) { - const size_t bsize = sizeof(uint64_t); - const size_t remainder = outlen % bsize; - uint8_t tmp[sizeof(uint64_t)]; - shake256_inc_squeeze(output, outlen - remainder, state); - if (remainder != 0) { - shake256_inc_squeeze(tmp, bsize, state); - output += outlen - remainder; - for (size_t i = 0; i < remainder; ++i) { - output[i] = tmp[i]; - } - } -} - -/** - * @brief Release the seed expander context - * @param[in] state Internal state of the seed expander - */ -void PQCLEAN_HQC128_CLEAN_seedexpander_release(seedexpander_state *state) { - shake256_inc_ctx_release(state); -} diff --git a/src/kem/hqc/pqclean_hqc-128_clean/shake_prng.h b/src/kem/hqc/pqclean_hqc-128_clean/shake_prng.h deleted file mode 100644 index 7c9036fb4e..0000000000 --- a/src/kem/hqc/pqclean_hqc-128_clean/shake_prng.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef SHAKE_PRNG_H -#define SHAKE_PRNG_H - - -/** - * @file shake_prng.h - * @brief Header file of shake_prng.c - */ -#include "fips202.h" -#include -#include - -typedef shake256incctx seedexpander_state; - -void PQCLEAN_HQC128_CLEAN_seedexpander_init(seedexpander_state *state, const uint8_t *seed, size_t seedlen); - -void PQCLEAN_HQC128_CLEAN_seedexpander(seedexpander_state *state, uint8_t *output, size_t outlen); - -void PQCLEAN_HQC128_CLEAN_seedexpander_release(seedexpander_state *state); - - -#endif diff --git a/src/kem/hqc/pqclean_hqc-128_clean/vector.c b/src/kem/hqc/pqclean_hqc-128_clean/vector.c deleted file mode 100644 index c3ff1b7818..0000000000 --- a/src/kem/hqc/pqclean_hqc-128_clean/vector.c +++ /dev/null @@ -1,197 +0,0 @@ -#include "parameters.h" -#include "parsing.h" -#include "randombytes.h" -#include "vector.h" -#include -#include -/** - * @file vector.c - * @brief Implementation of vectors sampling and some utilities for the HQC scheme - */ - - -static uint32_t m_val[75] = { 243079, 243093, 243106, 243120, 243134, 243148, 243161, 243175, 243189, 243203, 243216, 243230, 243244, 243258, 243272, 243285, 243299, 243313, 243327, 243340, 243354, 243368, 243382, 243396, 243409, 243423, 243437, 243451, 243465, 243478, 243492, 243506, 243520, 243534, 243547, 243561, 243575, 243589, 243603, 243616, 243630, 243644, 243658, 243672, 243686, 243699, 243713, 243727, 243741, 243755, 243769, 243782, 243796, 243810, 243824, 243838, 243852, 243865, 243879, 243893, 243907, 243921, 243935, 243949, 243962, 243976, 243990, 244004, 244018, 244032, 244046, 244059, 244073, 244087, 244101 }; - -/** - * @brief Constant-time comparison of two integers v1 and v2 - * - * Returns 1 if v1 is equal to v2 and 0 otherwise - * https://gist.github.com/sneves/10845247 - * - * @param[in] v1 - * @param[in] v2 - */ -static inline uint32_t compare_u32(uint32_t v1, uint32_t v2) { - return 1 ^ ((uint32_t)((v1 - v2) | (v2 - v1)) >> 31); -} - -static uint64_t single_bit_mask(uint32_t pos) { - uint64_t ret = 0; - uint64_t mask = 1; - uint64_t tmp; - - for (size_t i = 0; i < 64; ++i) { - tmp = pos - i; - tmp = 0 - (1 - ((uint64_t)(tmp | (0 - tmp)) >> 63)); - ret |= mask & tmp; - mask <<= 1; - } - - return ret; -} - -static inline uint32_t cond_sub(uint32_t r, uint32_t n) { - uint32_t mask; - r -= n; - mask = 0 - (r >> 31); - return r + (n & mask); -} - -static inline uint32_t reduce(uint32_t a, size_t i) { - uint32_t q, n, r; - q = ((uint64_t) a * m_val[i]) >> 32; - n = (uint32_t)(PARAM_N - i); - r = a - q * n; - return cond_sub(r, n); -} - -/** - * @brief Generates a vector of a given Hamming weight - * - * Implementation of Algorithm 5 in https://eprint.iacr.org/2021/1631.pdf - * - * @param[in] ctx Pointer to the context of the seed expander - * @param[in] v Pointer to an array - * @param[in] weight Integer that is the Hamming weight - */ -void PQCLEAN_HQC128_CLEAN_vect_set_random_fixed_weight(seedexpander_state *ctx, uint64_t *v, uint16_t weight) { - uint8_t rand_bytes[4 * PARAM_OMEGA_R] = {0}; // to be interpreted as PARAM_OMEGA_R 32-bit unsigned ints - uint32_t support[PARAM_OMEGA_R] = {0}; - uint32_t index_tab [PARAM_OMEGA_R] = {0}; - uint64_t bit_tab [PARAM_OMEGA_R] = {0}; - uint32_t pos, found, mask32, tmp; - uint64_t mask64, val; - - PQCLEAN_HQC128_CLEAN_seedexpander(ctx, rand_bytes, 4 * weight); - - for (size_t i = 0; i < weight; ++i) { - support[i] = rand_bytes[4 * i]; - support[i] |= rand_bytes[4 * i + 1] << 8; - support[i] |= (uint32_t)rand_bytes[4 * i + 2] << 16; - support[i] |= (uint32_t)rand_bytes[4 * i + 3] << 24; - support[i] = (uint32_t)(i + reduce(support[i], i)); // use constant-tme reduction - } - - for (size_t i = (weight - 1); i-- > 0;) { - found = 0; - - for (size_t j = i + 1; j < weight; ++j) { - found |= compare_u32(support[j], support[i]); - } - - mask32 = 0 - found; - support[i] = (mask32 & i) ^ (~mask32 & support[i]); - } - - for (size_t i = 0; i < weight; ++i) { - index_tab[i] = support[i] >> 6; - pos = support[i] & 0x3f; - bit_tab[i] = single_bit_mask(pos); // avoid secret shift - } - - for (size_t i = 0; i < VEC_N_SIZE_64; ++i) { - val = 0; - for (size_t j = 0; j < weight; ++j) { - tmp = (uint32_t)(i - index_tab[j]); - tmp = 1 ^ ((uint32_t)(tmp | (0 - tmp)) >> 31); - mask64 = 0 - (uint64_t)tmp; - val |= (bit_tab[j] & mask64); - } - v[i] |= val; - } -} - - - -/** - * @brief Generates a random vector of dimension PARAM_N - * - * This function generates a random binary vector of dimension PARAM_N. It generates a random - * array of bytes using the PQCLEAN_HQC128_CLEAN_seedexpander function, and drop the extra bits using a mask. - * - * @param[in] v Pointer to an array - * @param[in] ctx Pointer to the context of the seed expander - */ -void PQCLEAN_HQC128_CLEAN_vect_set_random(seedexpander_state *ctx, uint64_t *v) { - uint8_t rand_bytes[VEC_N_SIZE_BYTES] = {0}; - - PQCLEAN_HQC128_CLEAN_seedexpander(ctx, rand_bytes, VEC_N_SIZE_BYTES); - - PQCLEAN_HQC128_CLEAN_load8_arr(v, VEC_N_SIZE_64, rand_bytes, VEC_N_SIZE_BYTES); - v[VEC_N_SIZE_64 - 1] &= RED_MASK; -} - - - -/** - * @brief Adds two vectors - * - * @param[out] o Pointer to an array that is the result - * @param[in] v1 Pointer to an array that is the first vector - * @param[in] v2 Pointer to an array that is the second vector - * @param[in] size Integer that is the size of the vectors - */ -void PQCLEAN_HQC128_CLEAN_vect_add(uint64_t *o, const uint64_t *v1, const uint64_t *v2, size_t size) { - for (size_t i = 0; i < size; ++i) { - o[i] = v1[i] ^ v2[i]; - } -} - - - -/** - * @brief Compares two vectors - * - * @param[in] v1 Pointer to an array that is first vector - * @param[in] v2 Pointer to an array that is second vector - * @param[in] size Integer that is the size of the vectors - * @returns 0 if the vectors are equal and 1 otherwise - */ -uint8_t PQCLEAN_HQC128_CLEAN_vect_compare(const uint8_t *v1, const uint8_t *v2, size_t size) { - uint16_t r = 0x0100; - - for (size_t i = 0; i < size; i++) { - r |= v1[i] ^ v2[i]; - } - - return (r - 1) >> 8; -} - - - -/** - * @brief Resize a vector so that it contains size_o bits - * - * @param[out] o Pointer to the output vector - * @param[in] size_o Integer that is the size of the output vector in bits - * @param[in] v Pointer to the input vector - * @param[in] size_v Integer that is the size of the input vector in bits - */ -void PQCLEAN_HQC128_CLEAN_vect_resize(uint64_t *o, uint32_t size_o, const uint64_t *v, uint32_t size_v) { - uint64_t mask = 0x7FFFFFFFFFFFFFFF; - size_t val = 0; - if (size_o < size_v) { - - if (size_o % 64) { - val = 64 - (size_o % 64); - } - - memcpy(o, v, VEC_N1N2_SIZE_BYTES); - - for (size_t i = 0; i < val; ++i) { - o[VEC_N1N2_SIZE_64 - 1] &= (mask >> i); - } - } else { - memcpy(o, v, 8 * CEIL_DIVIDE(size_v, 64)); - } -} diff --git a/src/kem/hqc/pqclean_hqc-128_clean/vector.h b/src/kem/hqc/pqclean_hqc-128_clean/vector.h deleted file mode 100644 index 16b2c920ed..0000000000 --- a/src/kem/hqc/pqclean_hqc-128_clean/vector.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef VECTOR_H -#define VECTOR_H - - -/** - * @file vector.h - * @brief Header file for vector.c - */ -#include "shake_prng.h" -#include -#include - -void PQCLEAN_HQC128_CLEAN_vect_set_random_fixed_weight(seedexpander_state *ctx, uint64_t *v, uint16_t weight); - -void PQCLEAN_HQC128_CLEAN_vect_set_random(seedexpander_state *ctx, uint64_t *v); - - -void PQCLEAN_HQC128_CLEAN_vect_add(uint64_t *o, const uint64_t *v1, const uint64_t *v2, size_t size); - -uint8_t PQCLEAN_HQC128_CLEAN_vect_compare(const uint8_t *v1, const uint8_t *v2, size_t size); - -void PQCLEAN_HQC128_CLEAN_vect_resize(uint64_t *o, uint32_t size_o, const uint64_t *v, uint32_t size_v); - - -#endif diff --git a/src/kem/hqc/pqclean_hqc-192_clean/LICENSE b/src/kem/hqc/pqclean_hqc-192_clean/LICENSE deleted file mode 100644 index d5d21fff6d..0000000000 --- a/src/kem/hqc/pqclean_hqc-192_clean/LICENSE +++ /dev/null @@ -1 +0,0 @@ -Public Domain diff --git a/src/kem/hqc/pqclean_hqc-192_clean/api.h b/src/kem/hqc/pqclean_hqc-192_clean/api.h deleted file mode 100644 index 573a771e4c..0000000000 --- a/src/kem/hqc/pqclean_hqc-192_clean/api.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef PQCLEAN_HQC192_CLEAN_API_H -#define PQCLEAN_HQC192_CLEAN_API_H -/** - * @file api.h - * @brief NIST KEM API used by the HQC_KEM IND-CCA2 scheme - */ - -#include - -#define PQCLEAN_HQC192_CLEAN_CRYPTO_ALGNAME "HQC-192" - -#define PQCLEAN_HQC192_CLEAN_CRYPTO_SECRETKEYBYTES 4586 -#define PQCLEAN_HQC192_CLEAN_CRYPTO_PUBLICKEYBYTES 4522 -#define PQCLEAN_HQC192_CLEAN_CRYPTO_BYTES 64 -#define PQCLEAN_HQC192_CLEAN_CRYPTO_CIPHERTEXTBYTES 8978 - -// As a technicality, the public key is appended to the secret key in order to respect the NIST API. -// Without this constraint, PQCLEAN_HQC192_CLEAN_CRYPTO_SECRETKEYBYTES would be defined as 32 - -int PQCLEAN_HQC192_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk); - -int PQCLEAN_HQC192_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk); - -int PQCLEAN_HQC192_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk); - - -#endif diff --git a/src/kem/hqc/pqclean_hqc-192_clean/code.c b/src/kem/hqc/pqclean_hqc-192_clean/code.c deleted file mode 100644 index ba21fa20b0..0000000000 --- a/src/kem/hqc/pqclean_hqc-192_clean/code.c +++ /dev/null @@ -1,46 +0,0 @@ -#include "code.h" -#include "parameters.h" -#include "reed_muller.h" -#include "reed_solomon.h" -#include -/** - * @file code.c - * @brief Implementation of concatenated code - */ - - - -/** - * - * @brief Encoding the message m to a code word em using the concatenated code - * - * First we encode the message using the Reed-Solomon code, then with the duplicated Reed-Muller code we obtain - * a concatenated code word. - * - * @param[out] em Pointer to an array that is the tensor code word - * @param[in] m Pointer to an array that is the message - */ -void PQCLEAN_HQC192_CLEAN_code_encode(uint64_t *em, const uint8_t *m) { - uint8_t tmp[VEC_N1_SIZE_BYTES] = {0}; - - PQCLEAN_HQC192_CLEAN_reed_solomon_encode(tmp, m); - PQCLEAN_HQC192_CLEAN_reed_muller_encode(em, tmp); - -} - - - -/** - * @brief Decoding the code word em to a message m using the concatenated code - * - * @param[out] m Pointer to an array that is the message - * @param[in] em Pointer to an array that is the code word - */ -void PQCLEAN_HQC192_CLEAN_code_decode(uint8_t *m, const uint64_t *em) { - uint8_t tmp[VEC_N1_SIZE_BYTES] = {0}; - - PQCLEAN_HQC192_CLEAN_reed_muller_decode(tmp, em); - PQCLEAN_HQC192_CLEAN_reed_solomon_decode(m, tmp); - - -} diff --git a/src/kem/hqc/pqclean_hqc-192_clean/code.h b/src/kem/hqc/pqclean_hqc-192_clean/code.h deleted file mode 100644 index 1318bea391..0000000000 --- a/src/kem/hqc/pqclean_hqc-192_clean/code.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef CODE_H -#define CODE_H - - -/** - * @file code.h - * @brief Header file of code.c - */ - -#include - -void PQCLEAN_HQC192_CLEAN_code_encode(uint64_t *em, const uint8_t *message); - -void PQCLEAN_HQC192_CLEAN_code_decode(uint8_t *m, const uint64_t *em); - - -#endif diff --git a/src/kem/hqc/pqclean_hqc-192_clean/domains.h b/src/kem/hqc/pqclean_hqc-192_clean/domains.h deleted file mode 100644 index 20c782ccae..0000000000 --- a/src/kem/hqc/pqclean_hqc-192_clean/domains.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef DOMAINS_H -#define DOMAINS_H - - -/** - * @file domains.h - * @brief SHAKE-256 domains separation header grouping all domains to avoid collisions - */ - - -#define PRNG_DOMAIN 1 -#define SEEDEXPANDER_DOMAIN 2 -#define G_FCT_DOMAIN 3 -#define K_FCT_DOMAIN 4 - -#endif diff --git a/src/kem/hqc/pqclean_hqc-192_clean/fft.c b/src/kem/hqc/pqclean_hqc-192_clean/fft.c deleted file mode 100644 index 1763a94225..0000000000 --- a/src/kem/hqc/pqclean_hqc-192_clean/fft.c +++ /dev/null @@ -1,346 +0,0 @@ -#include "fft.h" -#include "gf.h" -#include "parameters.h" -#include -#include -/** - * @file fft.c - * @brief Implementation of the additive FFT and its transpose. - * This implementation is based on the paper from Gao and Mateer:
- * Shuhong Gao and Todd Mateer, Additive Fast Fourier Transforms over Finite Fields, - * IEEE Transactions on Information Theory 56 (2010), 6265--6272. - * http://www.math.clemson.edu/~sgao/papers/GM10.pdf
- * and includes improvements proposed by Bernstein, Chou and Schwabe here: - * https://binary.cr.yp.to/mcbits-20130616.pdf - */ - - -static void radix_big(uint16_t *f0, uint16_t *f1, const uint16_t *f, uint32_t m_f); - -/** - * @brief Computes the basis of betas (omitting 1) used in the additive FFT and its transpose - * - * @param[out] betas Array of size PARAM_M-1 - */ -static void compute_fft_betas(uint16_t *betas) { - size_t i; - for (i = 0; i < PARAM_M - 1; ++i) { - betas[i] = 1 << (PARAM_M - 1 - i); - } -} - - - -/** - * @brief Computes the subset sums of the given set - * - * The array subset_sums is such that its ith element is - * the subset sum of the set elements given by the binary form of i. - * - * @param[out] subset_sums Array of size 2^set_size receiving the subset sums - * @param[in] set Array of set_size elements - * @param[in] set_size Size of the array set - */ -static void compute_subset_sums(uint16_t *subset_sums, const uint16_t *set, uint16_t set_size) { - uint16_t i, j; - subset_sums[0] = 0; - - for (i = 0; i < set_size; ++i) { - for (j = 0; j < (1 << i); ++j) { - subset_sums[(1 << i) + j] = set[i] ^ subset_sums[j]; - } - } -} - - - -/** - * @brief Computes the radix conversion of a polynomial f in GF(2^m)[x] - * - * Computes f0 and f1 such that f(x) = f0(x^2-x) + x.f1(x^2-x) - * as proposed by Bernstein, Chou and Schwabe: - * https://binary.cr.yp.to/mcbits-20130616.pdf - * - * @param[out] f0 Array half the size of f - * @param[out] f1 Array half the size of f - * @param[in] f Array of size a power of 2 - * @param[in] m_f 2^{m_f} is the smallest power of 2 greater or equal to the number of coefficients of f - */ -static void radix(uint16_t *f0, uint16_t *f1, const uint16_t *f, uint32_t m_f) { - switch (m_f) { - case 4: - f0[4] = f[8] ^ f[12]; - f0[6] = f[12] ^ f[14]; - f0[7] = f[14] ^ f[15]; - f1[5] = f[11] ^ f[13]; - f1[6] = f[13] ^ f[14]; - f1[7] = f[15]; - f0[5] = f[10] ^ f[12] ^ f1[5]; - f1[4] = f[9] ^ f[13] ^ f0[5]; - - f0[0] = f[0]; - f1[3] = f[7] ^ f[11] ^ f[15]; - f0[3] = f[6] ^ f[10] ^ f[14] ^ f1[3]; - f0[2] = f[4] ^ f0[4] ^ f0[3] ^ f1[3]; - f1[1] = f[3] ^ f[5] ^ f[9] ^ f[13] ^ f1[3]; - f1[2] = f[3] ^ f1[1] ^ f0[3]; - f0[1] = f[2] ^ f0[2] ^ f1[1]; - f1[0] = f[1] ^ f0[1]; - break; - - case 3: - f0[0] = f[0]; - f0[2] = f[4] ^ f[6]; - f0[3] = f[6] ^ f[7]; - f1[1] = f[3] ^ f[5] ^ f[7]; - f1[2] = f[5] ^ f[6]; - f1[3] = f[7]; - f0[1] = f[2] ^ f0[2] ^ f1[1]; - f1[0] = f[1] ^ f0[1]; - break; - - case 2: - f0[0] = f[0]; - f0[1] = f[2] ^ f[3]; - f1[0] = f[1] ^ f0[1]; - f1[1] = f[3]; - break; - - case 1: - f0[0] = f[0]; - f1[0] = f[1]; - break; - - default: - radix_big(f0, f1, f, m_f); - break; - } -} - -static void radix_big(uint16_t *f0, uint16_t *f1, const uint16_t *f, uint32_t m_f) { - uint16_t Q[2 * (1 << (PARAM_FFT - 2)) + 1] = {0}; - uint16_t R[2 * (1 << (PARAM_FFT - 2)) + 1] = {0}; - - uint16_t Q0[1 << (PARAM_FFT - 2)] = {0}; - uint16_t Q1[1 << (PARAM_FFT - 2)] = {0}; - uint16_t R0[1 << (PARAM_FFT - 2)] = {0}; - uint16_t R1[1 << (PARAM_FFT - 2)] = {0}; - - size_t i, n; - - n = 1; - n <<= (m_f - 2); - memcpy(Q, f + 3 * n, 2 * n); - memcpy(Q + n, f + 3 * n, 2 * n); - memcpy(R, f, 4 * n); - - for (i = 0; i < n; ++i) { - Q[i] ^= f[2 * n + i]; - R[n + i] ^= Q[i]; - } - - radix(Q0, Q1, Q, m_f - 1); - radix(R0, R1, R, m_f - 1); - - memcpy(f0, R0, 2 * n); - memcpy(f0 + n, Q0, 2 * n); - memcpy(f1, R1, 2 * n); - memcpy(f1 + n, Q1, 2 * n); -} - - - -/** - * @brief Evaluates f at all subset sums of a given set - * - * This function is a subroutine of the function PQCLEAN_HQC192_CLEAN_fft. - * - * @param[out] w Array - * @param[in] f Array - * @param[in] f_coeffs Number of coefficients of f - * @param[in] m Number of betas - * @param[in] m_f Number of coefficients of f (one more than its degree) - * @param[in] betas FFT constants - */ -static void fft_rec(uint16_t *w, uint16_t *f, size_t f_coeffs, uint8_t m, uint32_t m_f, const uint16_t *betas) { - uint16_t f0[1 << (PARAM_FFT - 2)] = {0}; - uint16_t f1[1 << (PARAM_FFT - 2)] = {0}; - uint16_t gammas[PARAM_M - 2] = {0}; - uint16_t deltas[PARAM_M - 2] = {0}; - uint16_t gammas_sums[1 << (PARAM_M - 2)] = {0}; - uint16_t u[1 << (PARAM_M - 2)] = {0}; - uint16_t v[1 << (PARAM_M - 2)] = {0}; - uint16_t tmp[PARAM_M - (PARAM_FFT - 1)] = {0}; - - uint16_t beta_m_pow; - size_t i, j, k; - size_t x; - - // Step 1 - if (m_f == 1) { - for (i = 0; i < m; ++i) { - tmp[i] = PQCLEAN_HQC192_CLEAN_gf_mul(betas[i], f[1]); - } - - w[0] = f[0]; - x = 1; - for (j = 0; j < m; ++j) { - for (k = 0; k < x; ++k) { - w[x + k] = w[k] ^ tmp[j]; - } - x <<= 1; - } - - return; - } - - // Step 2: compute g - if (betas[m - 1] != 1) { - beta_m_pow = 1; - x = 1; - x <<= m_f; - for (i = 1; i < x; ++i) { - beta_m_pow = PQCLEAN_HQC192_CLEAN_gf_mul(beta_m_pow, betas[m - 1]); - f[i] = PQCLEAN_HQC192_CLEAN_gf_mul(beta_m_pow, f[i]); - } - } - - // Step 3 - radix(f0, f1, f, m_f); - - // Step 4: compute gammas and deltas - for (i = 0; i + 1 < m; ++i) { - gammas[i] = PQCLEAN_HQC192_CLEAN_gf_mul(betas[i], PQCLEAN_HQC192_CLEAN_gf_inverse(betas[m - 1])); - deltas[i] = PQCLEAN_HQC192_CLEAN_gf_square(gammas[i]) ^ gammas[i]; - } - - // Compute gammas sums - compute_subset_sums(gammas_sums, gammas, m - 1); - - // Step 5 - fft_rec(u, f0, (f_coeffs + 1) / 2, m - 1, m_f - 1, deltas); - - k = 1; - k <<= ((m - 1) & 0xf); // &0xf is to let the compiler know that m-1 is small. - if (f_coeffs <= 3) { // 3-coefficient polynomial f case: f1 is constant - w[0] = u[0]; - w[k] = u[0] ^ f1[0]; - for (i = 1; i < k; ++i) { - w[i] = u[i] ^ PQCLEAN_HQC192_CLEAN_gf_mul(gammas_sums[i], f1[0]); - w[k + i] = w[i] ^ f1[0]; - } - } else { - fft_rec(v, f1, f_coeffs / 2, m - 1, m_f - 1, deltas); - - // Step 6 - memcpy(w + k, v, 2 * k); - w[0] = u[0]; - w[k] ^= u[0]; - for (i = 1; i < k; ++i) { - w[i] = u[i] ^ PQCLEAN_HQC192_CLEAN_gf_mul(gammas_sums[i], v[i]); - w[k + i] ^= w[i]; - } - } -} - - - -/** - * @brief Evaluates f on all fields elements using an additive FFT algorithm - * - * f_coeffs is the number of coefficients of f (one less than its degree).
- * The FFT proceeds recursively to evaluate f at all subset sums of a basis B.
- * This implementation is based on the paper from Gao and Mateer:
- * Shuhong Gao and Todd Mateer, Additive Fast Fourier Transforms over Finite Fields, - * IEEE Transactions on Information Theory 56 (2010), 6265--6272. - * http://www.math.clemson.edu/~sgao/papers/GM10.pdf
- * and includes improvements proposed by Bernstein, Chou and Schwabe here: - * https://binary.cr.yp.to/mcbits-20130616.pdf
- * Note that on this first call (as opposed to the recursive calls to fft_rec), gammas are equal to betas, - * meaning the first gammas subset sums are actually the subset sums of betas (except 1).
- * Also note that f is altered during computation (twisted at each level). - * - * @param[out] w Array - * @param[in] f Array of 2^PARAM_FFT elements - * @param[in] f_coeffs Number coefficients of f (i.e. deg(f)+1) - */ -void PQCLEAN_HQC192_CLEAN_fft(uint16_t *w, const uint16_t *f, size_t f_coeffs) { - uint16_t betas[PARAM_M - 1] = {0}; - uint16_t betas_sums[1 << (PARAM_M - 1)] = {0}; - uint16_t f0[1 << (PARAM_FFT - 1)] = {0}; - uint16_t f1[1 << (PARAM_FFT - 1)] = {0}; - uint16_t deltas[PARAM_M - 1] = {0}; - uint16_t u[1 << (PARAM_M - 1)] = {0}; - uint16_t v[1 << (PARAM_M - 1)] = {0}; - - size_t i, k; - - // Follows Gao and Mateer algorithm - compute_fft_betas(betas); - - // Step 1: PARAM_FFT > 1, nothing to do - - // Compute gammas sums - compute_subset_sums(betas_sums, betas, PARAM_M - 1); - - // Step 2: beta_m = 1, nothing to do - - // Step 3 - radix(f0, f1, f, PARAM_FFT); - - // Step 4: Compute deltas - for (i = 0; i < PARAM_M - 1; ++i) { - deltas[i] = PQCLEAN_HQC192_CLEAN_gf_square(betas[i]) ^ betas[i]; - } - - // Step 5 - fft_rec(u, f0, (f_coeffs + 1) / 2, PARAM_M - 1, PARAM_FFT - 1, deltas); - fft_rec(v, f1, f_coeffs / 2, PARAM_M - 1, PARAM_FFT - 1, deltas); - - k = 1 << (PARAM_M - 1); - // Step 6, 7 and error polynomial computation - memcpy(w + k, v, 2 * k); - - // Check if 0 is root - w[0] = u[0]; - - // Check if 1 is root - w[k] ^= u[0]; - - // Find other roots - for (i = 1; i < k; ++i) { - w[i] = u[i] ^ PQCLEAN_HQC192_CLEAN_gf_mul(betas_sums[i], v[i]); - w[k + i] ^= w[i]; - } -} - - - -/** - * @brief Retrieves the error polynomial error from the evaluations w of the ELP (Error Locator Polynomial) on all field elements. - * - * @param[out] error Array with the error - * @param[out] error_compact Array with the error in a compact form - * @param[in] w Array of size 2^PARAM_M - */ -void PQCLEAN_HQC192_CLEAN_fft_retrieve_error_poly(uint8_t *error, const uint16_t *w) { - uint16_t gammas[PARAM_M - 1] = {0}; - uint16_t gammas_sums[1 << (PARAM_M - 1)] = {0}; - uint16_t k; - size_t i, index; - - compute_fft_betas(gammas); - compute_subset_sums(gammas_sums, gammas, PARAM_M - 1); - - k = 1 << (PARAM_M - 1); - error[0] ^= 1 ^ ((uint16_t) - w[0] >> 15); - error[0] ^= 1 ^ ((uint16_t) - w[k] >> 15); - - for (i = 1; i < k; ++i) { - index = PARAM_GF_MUL_ORDER - gf_log[gammas_sums[i]]; - error[index] ^= 1 ^ ((uint16_t) - w[i] >> 15); - - index = PARAM_GF_MUL_ORDER - gf_log[gammas_sums[i] ^ 1]; - error[index] ^= 1 ^ ((uint16_t) - w[k + i] >> 15); - } -} diff --git a/src/kem/hqc/pqclean_hqc-192_clean/fft.h b/src/kem/hqc/pqclean_hqc-192_clean/fft.h deleted file mode 100644 index 8337c3ac96..0000000000 --- a/src/kem/hqc/pqclean_hqc-192_clean/fft.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef FFT_H -#define FFT_H - - -/** - * @file fft.h - * @brief Header file of fft.c - */ - -#include -#include - -void PQCLEAN_HQC192_CLEAN_fft(uint16_t *w, const uint16_t *f, size_t f_coeffs); - -void PQCLEAN_HQC192_CLEAN_fft_retrieve_error_poly(uint8_t *error, const uint16_t *w); - - -#endif diff --git a/src/kem/hqc/pqclean_hqc-192_clean/gf.c b/src/kem/hqc/pqclean_hqc-192_clean/gf.c deleted file mode 100644 index 517b76a84c..0000000000 --- a/src/kem/hqc/pqclean_hqc-192_clean/gf.c +++ /dev/null @@ -1,170 +0,0 @@ -#include "gf.h" -#include "parameters.h" -#include -#include -/** - * @file gf.c - * @brief Galois field implementation - */ - - -/** - * @brief Computes the number of trailing zero bits. - * - * @returns The number of trailing zero bits in a. - * @param[in] a An operand - */ -static uint16_t trailing_zero_bits_count(uint16_t a) { - uint16_t tmp = 0; - uint16_t mask = 0xFFFF; - for (size_t i = 0; i < 14; ++i) { - tmp += ((1 - ((a >> i) & 0x0001)) & mask); - mask &= - (1 - ((a >> i) & 0x0001)); - } - return tmp; -} - - - -/** - * Reduces polynomial x modulo primitive polynomial GF_POLY. - * @returns x mod GF_POLY - * @param[in] x Polynomial of degree less than 64 - * @param[in] deg_x The degree of polynomial x - */ -static uint16_t gf_reduce(uint64_t x, size_t deg_x) { - uint16_t z1, z2, rmdr, dist; - uint64_t mod; - - // Deduce the number of steps of reduction - size_t steps = CEIL_DIVIDE(deg_x - (PARAM_M - 1), PARAM_GF_POLY_M2); - - // Reduce - for (size_t i = 0; i < steps; ++i) { - mod = x >> PARAM_M; - x &= (1 << PARAM_M) - 1; - x ^= mod; - - z1 = 0; - rmdr = PARAM_GF_POLY ^ 1; - for (size_t j = PARAM_GF_POLY_WT - 2; j; --j) { - z2 = trailing_zero_bits_count(rmdr); - dist = z2 - z1; - mod <<= dist; - x ^= mod; - rmdr ^= 1 << z2; - z1 = z2; - } - } - - return (uint16_t)x; -} - - - -/** - * Carryless multiplication of two polynomials a and b. - * - * Implementation of the algorithm mul1 in https://hal.inria.fr/inria-00188261v4/document - * with s = 2 and w = 8 - * - * @param[out] The polynomial c = a * b - * @param[in] a The first polynomial - * @param[in] b The second polynomial - */ -static void gf_carryless_mul(uint8_t c[2], uint8_t a, uint8_t b) { - uint16_t h = 0, l = 0, g = 0, u[4]; - uint32_t tmp1, tmp2; - uint16_t mask; - u[0] = 0; - u[1] = b & 0x7F; - u[2] = u[1] << 1; - u[3] = u[2] ^ u[1]; - tmp1 = a & 3; - - for (size_t i = 0; i < 4; i++) { - tmp2 = (uint32_t)(tmp1 - i); - g ^= (u[i] & (uint32_t)(0 - (1 - ((uint32_t)(tmp2 | (0 - tmp2)) >> 31)))); - } - - l = g; - h = 0; - - for (size_t i = 2; i < 8; i += 2) { - g = 0; - tmp1 = (a >> i) & 3; - for (size_t j = 0; j < 4; ++j) { - tmp2 = (uint32_t)(tmp1 - j); - g ^= (u[j] & (uint32_t)(0 - (1 - ((uint32_t)(tmp2 | (0 - tmp2)) >> 31)))); - } - - l ^= g << i; - h ^= g >> (8 - i); - } - - mask = (-((b >> 7) & 1)); - l ^= ((a << 7) & mask); - h ^= ((a >> 1) & mask); - - c[0] = (uint8_t)l; - c[1] = (uint8_t)h; -} - - - -/** - * Multiplies two elements of GF(2^GF_M). - * @returns the product a*b - * @param[in] a Element of GF(2^GF_M) - * @param[in] b Element of GF(2^GF_M) - */ -uint16_t PQCLEAN_HQC192_CLEAN_gf_mul(uint16_t a, uint16_t b) { - uint8_t c[2] = {0}; - gf_carryless_mul(c, (uint8_t) a, (uint8_t) b); - uint16_t tmp = c[0] ^ (c[1] << 8); - return gf_reduce(tmp, 2 * (PARAM_M - 1)); -} - - - -/** - * @brief Squares an element of GF(2^PARAM_M). - * @returns a^2 - * @param[in] a Element of GF(2^PARAM_M) - */ -uint16_t PQCLEAN_HQC192_CLEAN_gf_square(uint16_t a) { - uint32_t b = a; - uint32_t s = b & 1; - for (size_t i = 1; i < PARAM_M; ++i) { - b <<= 1; - s ^= b & (1 << 2 * i); - } - - return gf_reduce(s, 2 * (PARAM_M - 1)); -} - - - -/** - * @brief Computes the inverse of an element of GF(2^PARAM_M), - * using the addition chain 1 2 3 4 7 11 15 30 60 120 127 254 - * @returns the inverse of a if a != 0 or 0 if a = 0 - * @param[in] a Element of GF(2^PARAM_M) - */ -uint16_t PQCLEAN_HQC192_CLEAN_gf_inverse(uint16_t a) { - uint16_t inv = a; - uint16_t tmp1, tmp2; - - inv = PQCLEAN_HQC192_CLEAN_gf_square(a); /* a^2 */ - tmp1 = PQCLEAN_HQC192_CLEAN_gf_mul(inv, a); /* a^3 */ - inv = PQCLEAN_HQC192_CLEAN_gf_square(inv); /* a^4 */ - tmp2 = PQCLEAN_HQC192_CLEAN_gf_mul(inv, tmp1); /* a^7 */ - tmp1 = PQCLEAN_HQC192_CLEAN_gf_mul(inv, tmp2); /* a^11 */ - inv = PQCLEAN_HQC192_CLEAN_gf_mul(tmp1, inv); /* a^15 */ - inv = PQCLEAN_HQC192_CLEAN_gf_square(inv); /* a^30 */ - inv = PQCLEAN_HQC192_CLEAN_gf_square(inv); /* a^60 */ - inv = PQCLEAN_HQC192_CLEAN_gf_square(inv); /* a^120 */ - inv = PQCLEAN_HQC192_CLEAN_gf_mul(inv, tmp2); /* a^127 */ - inv = PQCLEAN_HQC192_CLEAN_gf_square(inv); /* a^254 */ - return inv; -} diff --git a/src/kem/hqc/pqclean_hqc-192_clean/gf.h b/src/kem/hqc/pqclean_hqc-192_clean/gf.h deleted file mode 100644 index 3985472195..0000000000 --- a/src/kem/hqc/pqclean_hqc-192_clean/gf.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef GF_H -#define GF_H - - -/** - * @file gf.h - * @brief Header file of gf.c - */ - -#include - - -/** - * Powers of the root alpha of 1 + x^2 + x^3 + x^4 + x^8. - * The last two elements are needed by the PQCLEAN_HQC192_CLEAN_gf_mul function - * (for example if both elements to multiply are zero). - */ -static const uint16_t gf_exp [258] = { 1, 2, 4, 8, 16, 32, 64, 128, 29, 58, 116, 232, 205, 135, 19, 38, 76, 152, 45, 90, 180, 117, 234, 201, 143, 3, 6, 12, 24, 48, 96, 192, 157, 39, 78, 156, 37, 74, 148, 53, 106, 212, 181, 119, 238, 193, 159, 35, 70, 140, 5, 10, 20, 40, 80, 160, 93, 186, 105, 210, 185, 111, 222, 161, 95, 190, 97, 194, 153, 47, 94, 188, 101, 202, 137, 15, 30, 60, 120, 240, 253, 231, 211, 187, 107, 214, 177, 127, 254, 225, 223, 163, 91, 182, 113, 226, 217, 175, 67, 134, 17, 34, 68, 136, 13, 26, 52, 104, 208, 189, 103, 206, 129, 31, 62, 124, 248, 237, 199, 147, 59, 118, 236, 197, 151, 51, 102, 204, 133, 23, 46, 92, 184, 109, 218, 169, 79, 158, 33, 66, 132, 21, 42, 84, 168, 77, 154, 41, 82, 164, 85, 170, 73, 146, 57, 114, 228, 213, 183, 115, 230, 209, 191, 99, 198, 145, 63, 126, 252, 229, 215, 179, 123, 246, 241, 255, 227, 219, 171, 75, 150, 49, 98, 196, 149, 55, 110, 220, 165, 87, 174, 65, 130, 25, 50, 100, 200, 141, 7, 14, 28, 56, 112, 224, 221, 167, 83, 166, 81, 162, 89, 178, 121, 242, 249, 239, 195, 155, 43, 86, 172, 69, 138, 9, 18, 36, 72, 144, 61, 122, 244, 245, 247, 243, 251, 235, 203, 139, 11, 22, 44, 88, 176, 125, 250, 233, 207, 131, 27, 54, 108, 216, 173, 71, 142, 1, 2, 4 }; - - - -/** - * Logarithm of elements of GF(2^8) to the base alpha (root of 1 + x^2 + x^3 + x^4 + x^8). - * The logarithm of 0 is set to 0 by convention. - */ -static const uint16_t gf_log [256] = { 0, 0, 1, 25, 2, 50, 26, 198, 3, 223, 51, 238, 27, 104, 199, 75, 4, 100, 224, 14, 52, 141, 239, 129, 28, 193, 105, 248, 200, 8, 76, 113, 5, 138, 101, 47, 225, 36, 15, 33, 53, 147, 142, 218, 240, 18, 130, 69, 29, 181, 194, 125, 106, 39, 249, 185, 201, 154, 9, 120, 77, 228, 114, 166, 6, 191, 139, 98, 102, 221, 48, 253, 226, 152, 37, 179, 16, 145, 34, 136, 54, 208, 148, 206, 143, 150, 219, 189, 241, 210, 19, 92, 131, 56, 70, 64, 30, 66, 182, 163, 195, 72, 126, 110, 107, 58, 40, 84, 250, 133, 186, 61, 202, 94, 155, 159, 10, 21, 121, 43, 78, 212, 229, 172, 115, 243, 167, 87, 7, 112, 192, 247, 140, 128, 99, 13, 103, 74, 222, 237, 49, 197, 254, 24, 227, 165, 153, 119, 38, 184, 180, 124, 17, 68, 146, 217, 35, 32, 137, 46, 55, 63, 209, 91, 149, 188, 207, 205, 144, 135, 151, 178, 220, 252, 190, 97, 242, 86, 211, 171, 20, 42, 93, 158, 132, 60, 57, 83, 71, 109, 65, 162, 31, 45, 67, 216, 183, 123, 164, 118, 196, 23, 73, 236, 127, 12, 111, 246, 108, 161, 59, 82, 41, 157, 85, 170, 251, 96, 134, 177, 187, 204, 62, 90, 203, 89, 95, 176, 156, 169, 160, 81, 11, 245, 22, 235, 122, 117, 44, 215, 79, 174, 213, 233, 230, 231, 173, 232, 116, 214, 244, 234, 168, 80, 88, 175 }; - - - -uint16_t PQCLEAN_HQC192_CLEAN_gf_mul(uint16_t a, uint16_t b); - -uint16_t PQCLEAN_HQC192_CLEAN_gf_square(uint16_t a); - -uint16_t PQCLEAN_HQC192_CLEAN_gf_inverse(uint16_t a); - - -#endif diff --git a/src/kem/hqc/pqclean_hqc-192_clean/gf2x.c b/src/kem/hqc/pqclean_hqc-192_clean/gf2x.c deleted file mode 100644 index 255147cb00..0000000000 --- a/src/kem/hqc/pqclean_hqc-192_clean/gf2x.c +++ /dev/null @@ -1,198 +0,0 @@ -#include "gf2x.h" -#include "parameters.h" -#include -#include -/** - * @file gf2x.c - * @brief Implementation of multiplication of two polynomials - */ - - -/** - * @brief Caryless multiplication of two words of 64 bits - * - * Implemntation of the algorithm mul1 in https://hal.inria.fr/inria-00188261v4/document. - * With w = 64 and s = 4 - * - * @param[out] c The result c = a * b - * @param[in] a The first value a - * @param[in] b The second value b - */ -static void base_mul(uint64_t *c, uint64_t a, uint64_t b) { - uint64_t h = 0; - uint64_t l = 0; - uint64_t g; - uint64_t u[16] = {0}; - uint64_t mask_tab[4] = {0}; - uint64_t tmp1, tmp2; - - // Step 1 - u[0] = 0; - u[1] = b & (((uint64_t)1 << (64 - 4)) - 1); - u[2] = u[1] << 1; - u[3] = u[2] ^ u[1]; - u[4] = u[2] << 1; - u[5] = u[4] ^ u[1]; - u[6] = u[3] << 1; - u[7] = u[6] ^ u[1]; - u[8] = u[4] << 1; - u[9] = u[8] ^ u[1]; - u[10] = u[5] << 1; - u[11] = u[10] ^ u[1]; - u[12] = u[6] << 1; - u[13] = u[12] ^ u[1]; - u[14] = u[7] << 1; - u[15] = u[14] ^ u[1]; - - g = 0; - tmp1 = a & 0x0f; - - for (size_t i = 0; i < 16; ++i) { - tmp2 = tmp1 - i; - g ^= (u[i] & (uint64_t)(0 - (1 - ((uint64_t)(tmp2 | (0 - tmp2)) >> 63)))); - } - - l = g; - h = 0; - - // Step 2 - for (size_t i = 4; i < 64; i += 4) { - g = 0; - tmp1 = (a >> i) & 0x0f; - for (size_t j = 0; j < 16; ++j) { - tmp2 = tmp1 - j; - g ^= (u[j] & (uint64_t)(0 - (1 - ((uint64_t)(tmp2 | (0 - tmp2)) >> 63)))); - } - - l ^= g << i; - h ^= g >> (64 - i); - } - - // Step 3 - mask_tab [0] = 0 - ((b >> 60) & 1); - mask_tab [1] = 0 - ((b >> 61) & 1); - mask_tab [2] = 0 - ((b >> 62) & 1); - mask_tab [3] = 0 - ((b >> 63) & 1); - - l ^= ((a << 60) & mask_tab[0]); - h ^= ((a >> 4) & mask_tab[0]); - - l ^= ((a << 61) & mask_tab[1]); - h ^= ((a >> 3) & mask_tab[1]); - - l ^= ((a << 62) & mask_tab[2]); - h ^= ((a >> 2) & mask_tab[2]); - - l ^= ((a << 63) & mask_tab[3]); - h ^= ((a >> 1) & mask_tab[3]); - - c[0] = l; - c[1] = h; -} - -static void karatsuba_add1(uint64_t *alh, uint64_t *blh, const uint64_t *a, const uint64_t *b, size_t size_l, size_t size_h) { - for (size_t i = 0; i < size_h; ++i) { - alh[i] = a[i] ^ a[i + size_l]; - blh[i] = b[i] ^ b[i + size_l]; - } - - if (size_h < size_l) { - alh[size_h] = a[size_h]; - blh[size_h] = b[size_h]; - } -} - -static void karatsuba_add2(uint64_t *o, uint64_t *tmp1, const uint64_t *tmp2, size_t size_l, size_t size_h) { - for (size_t i = 0; i < (2 * size_l); ++i) { - tmp1[i] = tmp1[i] ^ o[i]; - } - - for (size_t i = 0; i < ( 2 * size_h); ++i) { - tmp1[i] = tmp1[i] ^ tmp2[i]; - } - - for (size_t i = 0; i < (2 * size_l); ++i) { - o[i + size_l] = o[i + size_l] ^ tmp1[i]; - } -} - -/** - * Karatsuba multiplication of a and b, Implementation inspired from the NTL library. - * - * @param[out] o Polynomial - * @param[in] a Polynomial - * @param[in] b Polynomial - * @param[in] size Length of polynomial - * @param[in] stack Length of polynomial - */ -static void karatsuba(uint64_t *o, const uint64_t *a, const uint64_t *b, size_t size, uint64_t *stack) { - size_t size_l, size_h; - const uint64_t *ah, *bh; - - if (size == 1) { - base_mul(o, a[0], b[0]); - return; - } - - size_h = size / 2; - size_l = (size + 1) / 2; - - uint64_t *alh = stack; - uint64_t *blh = alh + size_l; - uint64_t *tmp1 = blh + size_l; - uint64_t *tmp2 = o + 2 * size_l; - - stack += 4 * size_l; - - ah = a + size_l; - bh = b + size_l; - - karatsuba(o, a, b, size_l, stack); - - karatsuba(tmp2, ah, bh, size_h, stack); - - karatsuba_add1(alh, blh, a, b, size_l, size_h); - - karatsuba(tmp1, alh, blh, size_l, stack); - - karatsuba_add2(o, tmp1, tmp2, size_l, size_h); -} - -/** - * @brief Compute o(x) = a(x) mod \f$ X^n - 1\f$ - * - * This function computes the modular reduction of the polynomial a(x) - * - * @param[in] a Pointer to the polynomial a(x) - * @param[out] o Pointer to the result - */ -static void reduce(uint64_t *o, const uint64_t *a) { - uint64_t r; - uint64_t carry; - - for (size_t i = 0; i < VEC_N_SIZE_64; ++i) { - r = a[i + VEC_N_SIZE_64 - 1] >> (PARAM_N & 0x3F); - carry = a[i + VEC_N_SIZE_64] << (64 - (PARAM_N & 0x3F)); - o[i] = a[i] ^ r ^ carry; - } - - o[VEC_N_SIZE_64 - 1] &= RED_MASK; -} - -/** - * @brief Multiply two polynomials modulo \f$ X^n - 1\f$. - * - * This functions multiplies polynomials v1 and v2. - * The multiplication is done modulo \f$ X^n - 1\f$. - * - * @param[out] o Product of v1 and v2 - * @param[in] v1 Pointer to the first polynomial - * @param[in] v2 Pointer to the second polynomial - */ -void PQCLEAN_HQC192_CLEAN_vect_mul(uint64_t *o, const uint64_t *v1, const uint64_t *v2) { - uint64_t stack[VEC_N_SIZE_64 << 3] = {0}; - uint64_t o_karat[VEC_N_SIZE_64 << 1] = {0}; - - karatsuba(o_karat, v1, v2, VEC_N_SIZE_64, stack); - reduce(o, o_karat); -} diff --git a/src/kem/hqc/pqclean_hqc-192_clean/gf2x.h b/src/kem/hqc/pqclean_hqc-192_clean/gf2x.h deleted file mode 100644 index a7569d3f52..0000000000 --- a/src/kem/hqc/pqclean_hqc-192_clean/gf2x.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef GF2X_H -#define GF2X_H -/** - * @file gf2x.h - * @brief Header file for gf2x.c - */ - -#include - -void PQCLEAN_HQC192_CLEAN_vect_mul(uint64_t *o, const uint64_t *v1, const uint64_t *v2); - - -#endif diff --git a/src/kem/hqc/pqclean_hqc-192_clean/hqc.c b/src/kem/hqc/pqclean_hqc-192_clean/hqc.c deleted file mode 100644 index 7ef8d6ab4b..0000000000 --- a/src/kem/hqc/pqclean_hqc-192_clean/hqc.c +++ /dev/null @@ -1,146 +0,0 @@ -#include "code.h" -#include "gf2x.h" -#include "hqc.h" -#include "parameters.h" -#include "parsing.h" -#include "randombytes.h" -#include "shake_prng.h" -#include "vector.h" -#include -/** - * @file hqc.c - * @brief Implementation of hqc.h - */ - - - -/** - * @brief Keygen of the HQC_PKE IND_CPA scheme - * - * The public key is composed of the syndrome s as well as the seed used to generate the vector h. - * - * The secret key is composed of the seed used to generate vectors x and y. - * As a technicality, the public key is appended to the secret key in order to respect NIST API. - * - * @param[out] pk String containing the public key - * @param[out] sk String containing the secret key - */ -void PQCLEAN_HQC192_CLEAN_hqc_pke_keygen(uint8_t *pk, uint8_t *sk) { - seedexpander_state sk_seedexpander; - seedexpander_state pk_seedexpander; - uint8_t sk_seed[SEED_BYTES] = {0}; - uint8_t sigma[VEC_K_SIZE_BYTES] = {0}; - uint8_t pk_seed[SEED_BYTES] = {0}; - uint64_t x[VEC_N_SIZE_64] = {0}; - uint64_t y[VEC_N_SIZE_64] = {0}; - uint64_t h[VEC_N_SIZE_64] = {0}; - uint64_t s[VEC_N_SIZE_64] = {0}; - - // Create seed_expanders for public key and secret key - randombytes(sk_seed, SEED_BYTES); - randombytes(sigma, VEC_K_SIZE_BYTES); - PQCLEAN_HQC192_CLEAN_seedexpander_init(&sk_seedexpander, sk_seed, SEED_BYTES); - - randombytes(pk_seed, SEED_BYTES); - PQCLEAN_HQC192_CLEAN_seedexpander_init(&pk_seedexpander, pk_seed, SEED_BYTES); - - // Compute secret key - PQCLEAN_HQC192_CLEAN_vect_set_random_fixed_weight(&sk_seedexpander, x, PARAM_OMEGA); - PQCLEAN_HQC192_CLEAN_vect_set_random_fixed_weight(&sk_seedexpander, y, PARAM_OMEGA); - - // Compute public key - PQCLEAN_HQC192_CLEAN_vect_set_random(&pk_seedexpander, h); - PQCLEAN_HQC192_CLEAN_vect_mul(s, y, h); - PQCLEAN_HQC192_CLEAN_vect_add(s, x, s, VEC_N_SIZE_64); - - // Parse keys to string - PQCLEAN_HQC192_CLEAN_hqc_public_key_to_string(pk, pk_seed, s); - PQCLEAN_HQC192_CLEAN_hqc_secret_key_to_string(sk, sk_seed, sigma, pk); - - PQCLEAN_HQC192_CLEAN_seedexpander_release(&pk_seedexpander); - PQCLEAN_HQC192_CLEAN_seedexpander_release(&sk_seedexpander); -} - - - -/** - * @brief Encryption of the HQC_PKE IND_CPA scheme - * - * The cihertext is composed of vectors u and v. - * - * @param[out] u Vector u (first part of the ciphertext) - * @param[out] v Vector v (second part of the ciphertext) - * @param[in] m Vector representing the message to encrypt - * @param[in] theta Seed used to derive randomness required for encryption - * @param[in] pk String containing the public key - */ -void PQCLEAN_HQC192_CLEAN_hqc_pke_encrypt(uint64_t *u, uint64_t *v, uint8_t *m, uint8_t *theta, const uint8_t *pk) { - seedexpander_state vec_seedexpander; - uint64_t h[VEC_N_SIZE_64] = {0}; - uint64_t s[VEC_N_SIZE_64] = {0}; - uint64_t r1[VEC_N_SIZE_64] = {0}; - uint64_t r2[VEC_N_SIZE_64] = {0}; - uint64_t e[VEC_N_SIZE_64] = {0}; - uint64_t tmp1[VEC_N_SIZE_64] = {0}; - uint64_t tmp2[VEC_N_SIZE_64] = {0}; - - // Create seed_expander from theta - PQCLEAN_HQC192_CLEAN_seedexpander_init(&vec_seedexpander, theta, SEED_BYTES); - - // Retrieve h and s from public key - PQCLEAN_HQC192_CLEAN_hqc_public_key_from_string(h, s, pk); - - // Generate r1, r2 and e - PQCLEAN_HQC192_CLEAN_vect_set_random_fixed_weight(&vec_seedexpander, r1, PARAM_OMEGA_R); - PQCLEAN_HQC192_CLEAN_vect_set_random_fixed_weight(&vec_seedexpander, r2, PARAM_OMEGA_R); - PQCLEAN_HQC192_CLEAN_vect_set_random_fixed_weight(&vec_seedexpander, e, PARAM_OMEGA_E); - - // Compute u = r1 + r2.h - PQCLEAN_HQC192_CLEAN_vect_mul(u, r2, h); - PQCLEAN_HQC192_CLEAN_vect_add(u, r1, u, VEC_N_SIZE_64); - - // Compute v = m.G by encoding the message - PQCLEAN_HQC192_CLEAN_code_encode(v, m); - PQCLEAN_HQC192_CLEAN_vect_resize(tmp1, PARAM_N, v, PARAM_N1N2); - - // Compute v = m.G + s.r2 + e - PQCLEAN_HQC192_CLEAN_vect_mul(tmp2, r2, s); - PQCLEAN_HQC192_CLEAN_vect_add(tmp2, e, tmp2, VEC_N_SIZE_64); - PQCLEAN_HQC192_CLEAN_vect_add(tmp2, tmp1, tmp2, VEC_N_SIZE_64); - PQCLEAN_HQC192_CLEAN_vect_resize(v, PARAM_N1N2, tmp2, PARAM_N); - - PQCLEAN_HQC192_CLEAN_seedexpander_release(&vec_seedexpander); -} - - - -/** - * @brief Decryption of the HQC_PKE IND_CPA scheme - * - * @param[out] m Vector representing the decrypted message - * @param[in] u Vector u (first part of the ciphertext) - * @param[in] v Vector v (second part of the ciphertext) - * @param[in] sk String containing the secret key - * @returns 0 - */ -uint8_t PQCLEAN_HQC192_CLEAN_hqc_pke_decrypt(uint8_t *m, uint8_t *sigma, const uint64_t *u, const uint64_t *v, const uint8_t *sk) { - uint64_t x[VEC_N_SIZE_64] = {0}; - uint64_t y[VEC_N_SIZE_64] = {0}; - uint8_t pk[PUBLIC_KEY_BYTES] = {0}; - uint64_t tmp1[VEC_N_SIZE_64] = {0}; - uint64_t tmp2[VEC_N_SIZE_64] = {0}; - - // Retrieve x, y, pk from secret key - PQCLEAN_HQC192_CLEAN_hqc_secret_key_from_string(x, y, sigma, pk, sk); - - // Compute v - u.y - PQCLEAN_HQC192_CLEAN_vect_resize(tmp1, PARAM_N, v, PARAM_N1N2); - PQCLEAN_HQC192_CLEAN_vect_mul(tmp2, y, u); - PQCLEAN_HQC192_CLEAN_vect_add(tmp2, tmp1, tmp2, VEC_N_SIZE_64); - - - // Compute m by decoding v - u.y - PQCLEAN_HQC192_CLEAN_code_decode(m, tmp2); - - return 0; -} diff --git a/src/kem/hqc/pqclean_hqc-192_clean/hqc.h b/src/kem/hqc/pqclean_hqc-192_clean/hqc.h deleted file mode 100644 index 05cf6e80b8..0000000000 --- a/src/kem/hqc/pqclean_hqc-192_clean/hqc.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef HQC_H -#define HQC_H - - -/** - * @file hqc.h - * @brief Functions of the HQC_PKE IND_CPA scheme - */ - -#include - -void PQCLEAN_HQC192_CLEAN_hqc_pke_keygen(uint8_t *pk, uint8_t *sk); - -void PQCLEAN_HQC192_CLEAN_hqc_pke_encrypt(uint64_t *u, uint64_t *v, uint8_t *m, unsigned char *theta, const unsigned char *pk); - -uint8_t PQCLEAN_HQC192_CLEAN_hqc_pke_decrypt(uint8_t *m, uint8_t *sigma, const uint64_t *u, const uint64_t *v, const unsigned char *sk); - - -#endif diff --git a/src/kem/hqc/pqclean_hqc-192_clean/kem.c b/src/kem/hqc/pqclean_hqc-192_clean/kem.c deleted file mode 100644 index 56be311491..0000000000 --- a/src/kem/hqc/pqclean_hqc-192_clean/kem.c +++ /dev/null @@ -1,138 +0,0 @@ -#include "api.h" -#include "domains.h" -#include "fips202.h" -#include "hqc.h" -#include "parameters.h" -#include "parsing.h" -#include "randombytes.h" -#include "shake_ds.h" -#include "vector.h" -#include -#include -/** - * @file kem.c - * @brief Implementation of api.h - */ - - - -/** - * @brief Keygen of the HQC_KEM IND_CAA2 scheme - * - * The public key is composed of the syndrome s as well as the seed used to generate the vector h. - * - * The secret key is composed of the seed used to generate vectors x and y. - * As a technicality, the public key is appended to the secret key in order to respect NIST API. - * - * @param[out] pk String containing the public key - * @param[out] sk String containing the secret key - * @returns 0 if keygen is successful - */ -int PQCLEAN_HQC192_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk) { - - PQCLEAN_HQC192_CLEAN_hqc_pke_keygen(pk, sk); - return 0; -} - - - -/** - * @brief Encapsulation of the HQC_KEM IND_CAA2 scheme - * - * @param[out] ct String containing the ciphertext - * @param[out] ss String containing the shared secret - * @param[in] pk String containing the public key - * @returns 0 if encapsulation is successful - */ -int PQCLEAN_HQC192_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk) { - - uint8_t theta[SHAKE256_512_BYTES] = {0}; - uint64_t u[VEC_N_SIZE_64] = {0}; - uint64_t v[VEC_N1N2_SIZE_64] = {0}; - uint8_t mc[VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES] = {0}; - uint8_t tmp[VEC_K_SIZE_BYTES + PUBLIC_KEY_BYTES + SALT_SIZE_BYTES] = {0}; - uint8_t *m = tmp; - uint8_t *salt = tmp + VEC_K_SIZE_BYTES + PUBLIC_KEY_BYTES; - shake256incctx shake256state; - - // Computing m - randombytes(m, VEC_K_SIZE_BYTES); - - // Computing theta - randombytes(salt, SALT_SIZE_BYTES); - memcpy(tmp + VEC_K_SIZE_BYTES, pk, PUBLIC_KEY_BYTES); - PQCLEAN_HQC192_CLEAN_shake256_512_ds(&shake256state, theta, tmp, VEC_K_SIZE_BYTES + PUBLIC_KEY_BYTES + SALT_SIZE_BYTES, G_FCT_DOMAIN); - - // Encrypting m - PQCLEAN_HQC192_CLEAN_hqc_pke_encrypt(u, v, m, theta, pk); - - // Computing shared secret - memcpy(mc, m, VEC_K_SIZE_BYTES); - PQCLEAN_HQC192_CLEAN_store8_arr(mc + VEC_K_SIZE_BYTES, VEC_N_SIZE_BYTES, u, VEC_N_SIZE_64); - PQCLEAN_HQC192_CLEAN_store8_arr(mc + VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES, VEC_N1N2_SIZE_BYTES, v, VEC_N1N2_SIZE_64); - PQCLEAN_HQC192_CLEAN_shake256_512_ds(&shake256state, ss, mc, VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES, K_FCT_DOMAIN); - - // Computing ciphertext - PQCLEAN_HQC192_CLEAN_hqc_ciphertext_to_string(ct, u, v, salt); - - - return 0; -} - - - -/** - * @brief Decapsulation of the HQC_KEM IND_CAA2 scheme - * - * @param[out] ss String containing the shared secret - * @param[in] ct String containing the cipĥertext - * @param[in] sk String containing the secret key - * @returns 0 if decapsulation is successful, -1 otherwise - */ -int PQCLEAN_HQC192_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) { - - uint8_t result; - uint64_t u[VEC_N_SIZE_64] = {0}; - uint64_t v[VEC_N1N2_SIZE_64] = {0}; - const uint8_t *pk = sk + SEED_BYTES + VEC_K_SIZE_BYTES; - uint8_t sigma[VEC_K_SIZE_BYTES] = {0}; - uint8_t theta[SHAKE256_512_BYTES] = {0}; - uint64_t u2[VEC_N_SIZE_64] = {0}; - uint64_t v2[VEC_N1N2_SIZE_64] = {0}; - uint8_t mc[VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES] = {0}; - uint8_t tmp[VEC_K_SIZE_BYTES + PUBLIC_KEY_BYTES + SALT_SIZE_BYTES] = {0}; - uint8_t *m = tmp; - uint8_t *salt = tmp + VEC_K_SIZE_BYTES + PUBLIC_KEY_BYTES; - shake256incctx shake256state; - - // Retrieving u, v and d from ciphertext - PQCLEAN_HQC192_CLEAN_hqc_ciphertext_from_string(u, v, salt, ct); - - // Decrypting - result = PQCLEAN_HQC192_CLEAN_hqc_pke_decrypt(m, sigma, u, v, sk); - - // Computing theta - memcpy(tmp + VEC_K_SIZE_BYTES, pk, PUBLIC_KEY_BYTES); - PQCLEAN_HQC192_CLEAN_shake256_512_ds(&shake256state, theta, tmp, VEC_K_SIZE_BYTES + PUBLIC_KEY_BYTES + SALT_SIZE_BYTES, G_FCT_DOMAIN); - - // Encrypting m' - PQCLEAN_HQC192_CLEAN_hqc_pke_encrypt(u2, v2, m, theta, pk); - - // Check if c != c' - result |= PQCLEAN_HQC192_CLEAN_vect_compare((uint8_t *)u, (uint8_t *)u2, VEC_N_SIZE_BYTES); - result |= PQCLEAN_HQC192_CLEAN_vect_compare((uint8_t *)v, (uint8_t *)v2, VEC_N1N2_SIZE_BYTES); - - result -= 1; - - for (size_t i = 0; i < VEC_K_SIZE_BYTES; ++i) { - mc[i] = (m[i] & result) ^ (sigma[i] & ~result); - } - - // Computing shared secret - PQCLEAN_HQC192_CLEAN_store8_arr(mc + VEC_K_SIZE_BYTES, VEC_N_SIZE_BYTES, u, VEC_N_SIZE_64); - PQCLEAN_HQC192_CLEAN_store8_arr(mc + VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES, VEC_N1N2_SIZE_BYTES, v, VEC_N1N2_SIZE_64); - PQCLEAN_HQC192_CLEAN_shake256_512_ds(&shake256state, ss, mc, VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES, K_FCT_DOMAIN); - - - return (result & 1) - 1; -} diff --git a/src/kem/hqc/pqclean_hqc-192_clean/parameters.h b/src/kem/hqc/pqclean_hqc-192_clean/parameters.h deleted file mode 100644 index 136e3d99d8..0000000000 --- a/src/kem/hqc/pqclean_hqc-192_clean/parameters.h +++ /dev/null @@ -1,96 +0,0 @@ -#ifndef HQC_PARAMETERS_H -#define HQC_PARAMETERS_H - - -/** - * @file parameters.h - * @brief Parameters of the HQC_KEM IND-CCA2 scheme - */ -#include "api.h" - - -#define CEIL_DIVIDE(a, b) (((a)+(b)-1)/(b)) /*!< Divide a by b and ceil the result*/ - -/* - #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 -*/ - -#define PARAM_N 35851 -#define PARAM_N1 56 -#define PARAM_N2 640 -#define PARAM_N1N2 35840 -#define PARAM_OMEGA 100 -#define PARAM_OMEGA_E 114 -#define PARAM_OMEGA_R 114 - -#define SECRET_KEY_BYTES PQCLEAN_HQC192_CLEAN_CRYPTO_SECRETKEYBYTES -#define PUBLIC_KEY_BYTES PQCLEAN_HQC192_CLEAN_CRYPTO_PUBLICKEYBYTES -#define SHARED_SECRET_BYTES PQCLEAN_HQC192_CLEAN_CRYPTO_BYTES -#define CIPHERTEXT_BYTES PQCLEAN_HQC192_CLEAN_CRYPTO_CIPHERTEXTBYTES - -#define VEC_N_SIZE_BYTES CEIL_DIVIDE(PARAM_N, 8) -#define VEC_K_SIZE_BYTES PARAM_K -#define VEC_N1_SIZE_BYTES PARAM_N1 -#define VEC_N1N2_SIZE_BYTES CEIL_DIVIDE(PARAM_N1N2, 8) - -#define VEC_N_SIZE_64 CEIL_DIVIDE(PARAM_N, 64) -#define VEC_K_SIZE_64 CEIL_DIVIDE(PARAM_K, 8) -#define VEC_N1_SIZE_64 CEIL_DIVIDE(PARAM_N1, 8) -#define VEC_N1N2_SIZE_64 CEIL_DIVIDE(PARAM_N1N2, 64) - -#define PARAM_DELTA 16 -#define PARAM_M 8 -#define PARAM_GF_POLY 0x11D -#define PARAM_GF_POLY_WT 5 -#define PARAM_GF_POLY_M2 4 -#define PARAM_GF_MUL_ORDER 255 -#define PARAM_K 24 -#define PARAM_G 33 -#define PARAM_FFT 5 -#define 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 RED_MASK 0x7ff -#define SHAKE256_512_BYTES 64 -#define SEED_BYTES 40 -#define SALT_SIZE_BYTES 16 - -#endif diff --git a/src/kem/hqc/pqclean_hqc-192_clean/parsing.c b/src/kem/hqc/pqclean_hqc-192_clean/parsing.c deleted file mode 100644 index f3ef0064b4..0000000000 --- a/src/kem/hqc/pqclean_hqc-192_clean/parsing.c +++ /dev/null @@ -1,173 +0,0 @@ -#include "parameters.h" -#include "parsing.h" -#include "vector.h" -#include -#include -/** - * @file parsing.c - * @brief Functions to parse secret key, public key and ciphertext of the HQC scheme - */ - - -static uint64_t load8(const uint8_t *in) { - uint64_t ret = in[7]; - - for (int8_t i = 6; i >= 0; --i) { - ret <<= 8; - ret |= in[i]; - } - - return ret; -} - -void PQCLEAN_HQC192_CLEAN_load8_arr(uint64_t *out64, size_t outlen, const uint8_t *in8, size_t inlen) { - size_t index_in = 0; - size_t index_out = 0; - - // first copy by 8 bytes - if (inlen >= 8 && outlen >= 1) { - while (index_out < outlen && index_in + 8 <= inlen) { - out64[index_out] = load8(in8 + index_in); - - index_in += 8; - index_out += 1; - } - } - - // we now need to do the last 7 bytes if necessary - if (index_in >= inlen || index_out >= outlen) { - return; - } - out64[index_out] = in8[inlen - 1]; - for (int8_t i = (int8_t)(inlen - index_in) - 2; i >= 0; --i) { - out64[index_out] <<= 8; - out64[index_out] |= in8[index_in + i]; - } -} - -void PQCLEAN_HQC192_CLEAN_store8_arr(uint8_t *out8, size_t outlen, const uint64_t *in64, size_t inlen) { - for (size_t index_out = 0, index_in = 0; index_out < outlen && index_in < inlen;) { - out8[index_out] = (in64[index_in] >> ((index_out % 8) * 8)) & 0xFF; - ++index_out; - if (index_out % 8 == 0) { - ++index_in; - } - } -} - -/** - * @brief Parse a secret key into a string - * - * The secret key is composed of the seed used to generate vectors x and y. - * As technicality, the public key is appended to the secret key in order to respect NIST API. - * - * @param[out] sk String containing the secret key - * @param[in] sk_seed Seed used to generate the secret key - * @param[in] sigma String used in HHK transform - * @param[in] pk String containing the public key - */ -void PQCLEAN_HQC192_CLEAN_hqc_secret_key_to_string(uint8_t *sk, const uint8_t *sk_seed, const uint8_t *sigma, const uint8_t *pk) { - memcpy(sk, sk_seed, SEED_BYTES); - memcpy(sk + SEED_BYTES, sigma, VEC_K_SIZE_BYTES); - memcpy(sk + SEED_BYTES + VEC_K_SIZE_BYTES, pk, PUBLIC_KEY_BYTES); -} - - - -/** - * @brief Parse a secret key from a string - * - * The secret key is composed of the seed used to generate vectors x and y. - * As technicality, the public key is appended to the secret key in order to respect NIST API. - * - * @param[out] x uint64_t representation of vector x - * @param[out] y uint64_t representation of vector y - * @param[out] pk String containing the public key - * @param[in] sk String containing the secret key - */ -void PQCLEAN_HQC192_CLEAN_hqc_secret_key_from_string(uint64_t *x, uint64_t *y, uint8_t *sigma, uint8_t *pk, const uint8_t *sk) { - seedexpander_state sk_seedexpander; - - memcpy(sigma, sk + SEED_BYTES, VEC_K_SIZE_BYTES); - PQCLEAN_HQC192_CLEAN_seedexpander_init(&sk_seedexpander, sk, SEED_BYTES); - - PQCLEAN_HQC192_CLEAN_vect_set_random_fixed_weight(&sk_seedexpander, x, PARAM_OMEGA); - PQCLEAN_HQC192_CLEAN_vect_set_random_fixed_weight(&sk_seedexpander, y, PARAM_OMEGA); - memcpy(pk, sk + SEED_BYTES + VEC_K_SIZE_BYTES, PUBLIC_KEY_BYTES); - - PQCLEAN_HQC192_CLEAN_seedexpander_release(&sk_seedexpander); -} - - - -/** - * @brief Parse a public key into a string - * - * The public key is composed of the syndrome s as well as the seed used to generate the vector h - * - * @param[out] pk String containing the public key - * @param[in] pk_seed Seed used to generate the public key - * @param[in] s uint64_t representation of vector s - */ -void PQCLEAN_HQC192_CLEAN_hqc_public_key_to_string(uint8_t *pk, const uint8_t *pk_seed, const uint64_t *s) { - memcpy(pk, pk_seed, SEED_BYTES); - PQCLEAN_HQC192_CLEAN_store8_arr(pk + SEED_BYTES, VEC_N_SIZE_BYTES, s, VEC_N_SIZE_64); -} - - - -/** - * @brief Parse a public key from a string - * - * The public key is composed of the syndrome s as well as the seed used to generate the vector h - * - * @param[out] h uint64_t representation of vector h - * @param[out] s uint64_t representation of vector s - * @param[in] pk String containing the public key - */ -void PQCLEAN_HQC192_CLEAN_hqc_public_key_from_string(uint64_t *h, uint64_t *s, const uint8_t *pk) { - seedexpander_state pk_seedexpander; - - PQCLEAN_HQC192_CLEAN_seedexpander_init(&pk_seedexpander, pk, SEED_BYTES); - PQCLEAN_HQC192_CLEAN_vect_set_random(&pk_seedexpander, h); - - PQCLEAN_HQC192_CLEAN_load8_arr(s, VEC_N_SIZE_64, pk + SEED_BYTES, VEC_N_SIZE_BYTES); - - PQCLEAN_HQC192_CLEAN_seedexpander_release(&pk_seedexpander); -} - - - -/** - * @brief Parse a ciphertext into a string - * - * The ciphertext is composed of vectors u, v and salt. - * - * @param[out] ct String containing the ciphertext - * @param[in] u uint64_t representation of vector u - * @param[in] v uint64_t representation of vector v - * @param[in] salt String containing a salt - */ -void PQCLEAN_HQC192_CLEAN_hqc_ciphertext_to_string(uint8_t *ct, const uint64_t *u, const uint64_t *v, const uint8_t *salt) { - PQCLEAN_HQC192_CLEAN_store8_arr(ct, VEC_N_SIZE_BYTES, u, VEC_N_SIZE_64); - PQCLEAN_HQC192_CLEAN_store8_arr(ct + VEC_N_SIZE_BYTES, VEC_N1N2_SIZE_BYTES, v, VEC_N1N2_SIZE_64); - memcpy(ct + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES, salt, SALT_SIZE_BYTES); -} - - - -/** - * @brief Parse a ciphertext from a string - * - * The ciphertext is composed of vectors u, v and salt. - * - * @param[out] u uint64_t representation of vector u - * @param[out] v uint64_t representation of vector v - * @param[out] d String containing the hash d - * @param[in] ct String containing the ciphertext - */ -void PQCLEAN_HQC192_CLEAN_hqc_ciphertext_from_string(uint64_t *u, uint64_t *v, uint8_t *salt, const uint8_t *ct) { - PQCLEAN_HQC192_CLEAN_load8_arr(u, VEC_N_SIZE_64, ct, VEC_N_SIZE_BYTES); - PQCLEAN_HQC192_CLEAN_load8_arr(v, VEC_N1N2_SIZE_64, ct + VEC_N_SIZE_BYTES, VEC_N1N2_SIZE_BYTES); - memcpy(salt, ct + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES, SALT_SIZE_BYTES); -} diff --git a/src/kem/hqc/pqclean_hqc-192_clean/parsing.h b/src/kem/hqc/pqclean_hqc-192_clean/parsing.h deleted file mode 100644 index f3e6c726fb..0000000000 --- a/src/kem/hqc/pqclean_hqc-192_clean/parsing.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef PARSING_H -#define PARSING_H - - -/** - * @file parsing.h - * @brief Header file for parsing.c - */ - -#include -#include - -void PQCLEAN_HQC192_CLEAN_load8_arr(uint64_t *out64, size_t outlen, const uint8_t *in8, size_t inlen); - -void PQCLEAN_HQC192_CLEAN_store8_arr(uint8_t *out8, size_t outlen, const uint64_t *in64, size_t inlen); - - -void PQCLEAN_HQC192_CLEAN_hqc_secret_key_to_string(uint8_t *sk, const uint8_t *sk_seed, const uint8_t *sigma, const uint8_t *pk); - -void PQCLEAN_HQC192_CLEAN_hqc_secret_key_from_string(uint64_t *x, uint64_t *y, uint8_t *sigma, uint8_t *pk, const uint8_t *sk); - - -void PQCLEAN_HQC192_CLEAN_hqc_public_key_to_string(uint8_t *pk, const uint8_t *pk_seed, const uint64_t *s); - -void PQCLEAN_HQC192_CLEAN_hqc_public_key_from_string(uint64_t *h, uint64_t *s, const uint8_t *pk); - - -void PQCLEAN_HQC192_CLEAN_hqc_ciphertext_to_string(uint8_t *ct, const uint64_t *u, const uint64_t *v, const uint8_t *salt); - -void PQCLEAN_HQC192_CLEAN_hqc_ciphertext_from_string(uint64_t *u, uint64_t *v, uint8_t *salt, const uint8_t *ct); - - -#endif diff --git a/src/kem/hqc/pqclean_hqc-192_clean/reed_muller.c b/src/kem/hqc/pqclean_hqc-192_clean/reed_muller.c deleted file mode 100644 index a23994a542..0000000000 --- a/src/kem/hqc/pqclean_hqc-192_clean/reed_muller.c +++ /dev/null @@ -1,193 +0,0 @@ -#include "parameters.h" -#include "reed_muller.h" -#include -#include -/** - * @file reed_muller.c - * @brief Constant time implementation of Reed-Muller code RM(1,7) - */ - - -// number of repeated code words -#define MULTIPLICITY CEIL_DIVIDE(PARAM_N2, 128) - -// copy bit 0 into all bits of a 32 bit value -#define BIT0MASK(x) (uint32_t)(-((x) & 1)) - -/** - * @brief Encode a single byte into a single codeword using RM(1,7) - * - * Encoding matrix of this code: - * bit pattern (note that bits are numbered big endian) - * 0 aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa - * 1 cccccccc cccccccc cccccccc cccccccc - * 2 f0f0f0f0 f0f0f0f0 f0f0f0f0 f0f0f0f0 - * 3 ff00ff00 ff00ff00 ff00ff00 ff00ff00 - * 4 ffff0000 ffff0000 ffff0000 ffff0000 - * 5 ffffffff 00000000 ffffffff 00000000 - * 6 ffffffff ffffffff 00000000 00000000 - * 7 ffffffff ffffffff ffffffff ffffffff - * - * @param[out] word An RM(1,7) codeword - * @param[in] message A message - */ -static void encode(uint64_t *cword, uint8_t message) { - uint32_t first_word; - // bit 7 flips all the bits, do that first to save work - first_word = BIT0MASK(message >> 7); - // bits 0, 1, 2, 3, 4 are the same for all four longs - // (Warning: in the bit matrix above, low bits are at the left!) - first_word ^= BIT0MASK(message >> 0) & 0xaaaaaaaa; - first_word ^= BIT0MASK(message >> 1) & 0xcccccccc; - first_word ^= BIT0MASK(message >> 2) & 0xf0f0f0f0; - first_word ^= BIT0MASK(message >> 3) & 0xff00ff00; - first_word ^= BIT0MASK(message >> 4) & 0xffff0000; - // we can store this in the first quarter - cword[0] = first_word; - // bit 5 flips entries 1 and 3; bit 6 flips 2 and 3 - first_word ^= BIT0MASK(message >> 5); - cword[0] |= (uint64_t)first_word << 32; - first_word ^= BIT0MASK(message >> 6); - cword[1] = (uint64_t)first_word << 32; - first_word ^= BIT0MASK(message >> 5); - cword[1] |= first_word; -} - - - -/** - * @brief Hadamard transform - * - * Perform hadamard transform of src and store result in dst - * src is overwritten - * - * @param[out] src Structure that contain the expanded codeword - * @param[out] dst Structure that contain the expanded codeword - */ -static void hadamard(uint16_t src[128], uint16_t dst[128]) { - // the passes move data: - // src -> dst -> src -> dst -> src -> dst -> src -> dst - // using p1 and p2 alternately - uint16_t *p1 = src; - uint16_t *p2 = dst; - uint16_t *p3; - for (size_t pass = 0; pass < 7; ++pass) { - for (size_t i = 0; i < 64; ++i) { - p2[i] = p1[2 * i] + p1[2 * i + 1]; - p2[i + 64] = p1[2 * i] - p1[2 * i + 1]; - } - // swap p1, p2 for next round - p3 = p1; - p1 = p2; - p2 = p3; - } -} - - - -/** - * @brief Add multiple codewords into expanded codeword - * - * Accesses memory in order - * Note: this does not write the codewords as -1 or +1 as the green machine does - * instead, just 0 and 1 is used. - * The resulting hadamard transform has: - * all values are halved - * the first entry is 64 too high - * - * @param[out] dest Structure that contain the expanded codeword - * @param[in] src Structure that contain the codeword - */ -static void expand_and_sum(uint16_t dest[128], const uint64_t src[2 * MULTIPLICITY]) { - // start with the first copy - for (size_t part = 0; part < 2; ++part) { - for (size_t bit = 0; bit < 64; ++bit) { - dest[part * 64 + bit] = ((src[part] >> bit) & 1); - } - } - // sum the rest of the copies - for (size_t copy = 1; copy < MULTIPLICITY; ++copy) { - for (size_t part = 0; part < 2; ++part) { - for (size_t bit = 0; bit < 64; ++bit) { - dest[part * 64 + bit] += (uint16_t) ((src[2 * copy + part] >> bit) & 1); - } - } - } -} - - - -/** - * @brief Finding the location of the highest value - * - * This is the final step of the green machine: find the location of the highest value, - * and add 128 if the peak is positive - * if there are two identical peaks, the peak with smallest value - * in the lowest 7 bits it taken - * @param[in] transform Structure that contain the expanded codeword - */ -static uint8_t find_peaks(const uint16_t transform[128]) { - uint16_t peak_abs = 0; - uint16_t peak = 0; - uint16_t pos = 0; - uint16_t t, abs, mask; - for (uint16_t i = 0; i < 128; ++i) { - t = transform[i]; - abs = t ^ ((uint16_t)(-(t >> 15)) & (t ^ -t)); // t = abs(t) - mask = -(((uint16_t)(peak_abs - abs)) >> 15); - peak ^= mask & (peak ^ t); - pos ^= mask & (pos ^ i); - peak_abs ^= mask & (peak_abs ^ abs); - } - // set bit 7 - pos |= 128 & (uint16_t)((peak >> 15) - 1); - return (uint8_t) pos; -} - - - -/** - * @brief Encodes the received word - * - * The message consists of N1 bytes each byte is encoded into PARAM_N2 bits, - * or MULTIPLICITY repeats of 128 bits - * - * @param[out] cdw Array of size VEC_N1N2_SIZE_64 receiving the encoded message - * @param[in] msg Array of size VEC_N1_SIZE_64 storing the message - */ -void PQCLEAN_HQC192_CLEAN_reed_muller_encode(uint64_t *cdw, const uint8_t *msg) { - for (size_t i = 0; i < VEC_N1_SIZE_BYTES; ++i) { - // encode first word - encode(&cdw[2 * i * MULTIPLICITY], msg[i]); - // copy to other identical codewords - for (size_t copy = 1; copy < MULTIPLICITY; ++copy) { - memcpy(&cdw[2 * i * MULTIPLICITY + 2 * copy], &cdw[2 * i * MULTIPLICITY], 16); - } - } -} - - - -/** - * @brief Decodes the received word - * - * Decoding uses fast hadamard transform, for a more complete picture on Reed-Muller decoding, see MacWilliams, Florence Jessie, and Neil James Alexander Sloane. - * The theory of error-correcting codes codes @cite macwilliams1977theory - * - * @param[out] msg Array of size VEC_N1_SIZE_64 receiving the decoded message - * @param[in] cdw Array of size VEC_N1N2_SIZE_64 storing the received word - */ -void PQCLEAN_HQC192_CLEAN_reed_muller_decode(uint8_t *msg, const uint64_t *cdw) { - uint16_t expanded[128]; - uint16_t transform[128]; - for (size_t i = 0; i < VEC_N1_SIZE_BYTES; ++i) { - // collect the codewords - expand_and_sum(expanded, &cdw[2 * i * MULTIPLICITY]); - // apply hadamard transform - hadamard(expanded, transform); - // fix the first entry to get the half Hadamard transform - transform[0] -= 64 * MULTIPLICITY; - // finish the decoding - msg[i] = find_peaks(transform); - } -} diff --git a/src/kem/hqc/pqclean_hqc-192_clean/reed_muller.h b/src/kem/hqc/pqclean_hqc-192_clean/reed_muller.h deleted file mode 100644 index b7ea4ecafc..0000000000 --- a/src/kem/hqc/pqclean_hqc-192_clean/reed_muller.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef REED_MULLER_H -#define REED_MULLER_H - - -/** - * @file reed_muller.h - * @brief Header file of reed_muller.c - */ - -#include - -void PQCLEAN_HQC192_CLEAN_reed_muller_encode(uint64_t *cdw, const uint8_t *msg); - -void PQCLEAN_HQC192_CLEAN_reed_muller_decode(uint8_t *msg, const uint64_t *cdw); - - -#endif diff --git a/src/kem/hqc/pqclean_hqc-192_clean/reed_solomon.c b/src/kem/hqc/pqclean_hqc-192_clean/reed_solomon.c deleted file mode 100644 index ce12752304..0000000000 --- a/src/kem/hqc/pqclean_hqc-192_clean/reed_solomon.c +++ /dev/null @@ -1,335 +0,0 @@ -#include "fft.h" -#include "gf.h" -#include "parameters.h" -#include "reed_solomon.h" -#include -#include -/** - * @file reed_solomon.c - * @brief Constant time implementation of Reed-Solomon codes - */ - - -/** - * @brief Encodes a message message of PARAM_K bits to a Reed-Solomon codeword codeword of PARAM_N1 bytes - * - * Following @cite lin1983error (Chapter 4 - Cyclic Codes), - * We perform a systematic encoding using a linear (PARAM_N1 - PARAM_K)-stage shift register - * with feedback connections based on the generator polynomial PARAM_RS_POLY of the Reed-Solomon code. - * - * @param[out] cdw Array of size VEC_N1_SIZE_64 receiving the encoded message - * @param[in] msg Array of size VEC_K_SIZE_64 storing the message - */ -void PQCLEAN_HQC192_CLEAN_reed_solomon_encode(uint8_t *cdw, const uint8_t *msg) { - uint8_t gate_value = 0; - - uint16_t tmp[PARAM_G] = {0}; - uint16_t PARAM_RS_POLY [] = {RS_POLY_COEFS}; - - memset(cdw, 0, PARAM_N1); - - for (size_t i = 0; i < PARAM_K; ++i) { - gate_value = msg[PARAM_K - 1 - i] ^ cdw[PARAM_N1 - PARAM_K - 1]; - - for (size_t j = 0; j < PARAM_G; ++j) { - tmp[j] = PQCLEAN_HQC192_CLEAN_gf_mul(gate_value, PARAM_RS_POLY[j]); - } - - for (size_t k = PARAM_N1 - PARAM_K - 1; k; --k) { - cdw[k] = (uint8_t)(cdw[k - 1] ^ tmp[k]); - } - - cdw[0] = (uint8_t)tmp[0]; - } - - memcpy(cdw + PARAM_N1 - PARAM_K, msg, PARAM_K); -} - - - -/** - * @brief Computes 2 * PARAM_DELTA syndromes - * - * @param[out] syndromes Array of size 2 * PARAM_DELTA receiving the computed syndromes - * @param[in] cdw Array of size PARAM_N1 storing the received vector - */ -static void compute_syndromes(uint16_t *syndromes, uint8_t *cdw) { - for (size_t i = 0; i < 2 * PARAM_DELTA; ++i) { - for (size_t j = 1; j < PARAM_N1; ++j) { - syndromes[i] ^= PQCLEAN_HQC192_CLEAN_gf_mul(cdw[j], alpha_ij_pow[i][j - 1]); - } - syndromes[i] ^= cdw[0]; - } -} - - - -/** - * @brief Computes the error locator polynomial (ELP) sigma - * - * This is a constant time implementation of Berlekamp's simplified algorithm (see @cite lin1983error (Chapter 6 - BCH Codes).
- * We use the letter p for rho which is initialized at -1.
- * The array X_sigma_p represents the polynomial X^(mu-rho)*sigma_p(X).
- * Instead of maintaining a list of sigmas, we update in place both sigma and X_sigma_p.
- * sigma_copy serves as a temporary save of sigma in case X_sigma_p needs to be updated.
- * We can properly correct only if the degree of sigma does not exceed PARAM_DELTA. - * This means only the first PARAM_DELTA + 1 coefficients of sigma are of value - * and we only need to save its first PARAM_DELTA - 1 coefficients. - * - * @returns the degree of the ELP sigma - * @param[out] sigma Array of size (at least) PARAM_DELTA receiving the ELP - * @param[in] syndromes Array of size (at least) 2*PARAM_DELTA storing the syndromes - */ -static uint16_t compute_elp(uint16_t *sigma, const uint16_t *syndromes) { - uint16_t deg_sigma = 0; - uint16_t deg_sigma_p = 0; - uint16_t deg_sigma_copy = 0; - uint16_t sigma_copy[PARAM_DELTA + 1] = {0}; - uint16_t X_sigma_p[PARAM_DELTA + 1] = {0, 1}; - uint16_t pp = (uint16_t) -1; // 2*rho - uint16_t d_p = 1; - uint16_t d = syndromes[0]; - - uint16_t mask1, mask2, mask12; - uint16_t deg_X, deg_X_sigma_p; - uint16_t dd; - uint16_t mu; - - uint16_t i; - - sigma[0] = 1; - for (mu = 0; (mu < (2 * PARAM_DELTA)); ++mu) { - // Save sigma in case we need it to update X_sigma_p - memcpy(sigma_copy, sigma, 2 * (PARAM_DELTA)); - deg_sigma_copy = deg_sigma; - - dd = PQCLEAN_HQC192_CLEAN_gf_mul(d, PQCLEAN_HQC192_CLEAN_gf_inverse(d_p)); - - for (i = 1; (i <= mu + 1) && (i <= PARAM_DELTA); ++i) { - sigma[i] ^= PQCLEAN_HQC192_CLEAN_gf_mul(dd, X_sigma_p[i]); - } - - deg_X = mu - pp; - deg_X_sigma_p = deg_X + deg_sigma_p; - - // mask1 = 0xffff if(d != 0) and 0 otherwise - mask1 = -((uint16_t) - d >> 15); - - // mask2 = 0xffff if(deg_X_sigma_p > deg_sigma) and 0 otherwise - mask2 = -((uint16_t) (deg_sigma - deg_X_sigma_p) >> 15); - - // mask12 = 0xffff if the deg_sigma increased and 0 otherwise - mask12 = mask1 & mask2; - deg_sigma ^= mask12 & (deg_X_sigma_p ^ deg_sigma); - - if (mu == (2 * PARAM_DELTA - 1)) { - break; - } - - pp ^= mask12 & (mu ^ pp); - d_p ^= mask12 & (d ^ d_p); - for (i = PARAM_DELTA; i; --i) { - X_sigma_p[i] = (mask12 & sigma_copy[i - 1]) ^ (~mask12 & X_sigma_p[i - 1]); - } - - deg_sigma_p ^= mask12 & (deg_sigma_copy ^ deg_sigma_p); - d = syndromes[mu + 1]; - - for (i = 1; (i <= mu + 1) && (i <= PARAM_DELTA); ++i) { - d ^= PQCLEAN_HQC192_CLEAN_gf_mul(sigma[i], syndromes[mu + 1 - i]); - } - } - - return deg_sigma; -} - - - -/** - * @brief Computes the error polynomial error from the error locator polynomial sigma - * - * See function PQCLEAN_HQC192_CLEAN_fft for more details. - * - * @param[out] error Array of 2^PARAM_M elements receiving the error polynomial - * @param[out] error_compact Array of PARAM_DELTA + PARAM_N1 elements receiving a compact representation of the vector error - * @param[in] sigma Array of 2^PARAM_FFT elements storing the error locator polynomial - */ -static void compute_roots(uint8_t *error, uint16_t *sigma) { - uint16_t w[1 << PARAM_M] = {0}; - - PQCLEAN_HQC192_CLEAN_fft(w, sigma, PARAM_DELTA + 1); - PQCLEAN_HQC192_CLEAN_fft_retrieve_error_poly(error, w); -} - - - -/** - * @brief Computes the polynomial z(x) - * - * See @cite lin1983error (Chapter 6 - BCH Codes) for more details. - * - * @param[out] z Array of PARAM_DELTA + 1 elements receiving the polynomial z(x) - * @param[in] sigma Array of 2^PARAM_FFT elements storing the error locator polynomial - * @param[in] degree Integer that is the degree of polynomial sigma - * @param[in] syndromes Array of 2 * PARAM_DELTA storing the syndromes - */ -static void compute_z_poly(uint16_t *z, const uint16_t *sigma, uint16_t degree, const uint16_t *syndromes) { - size_t i, j; - uint16_t mask; - - z[0] = 1; - - for (i = 1; i < PARAM_DELTA + 1; ++i) { - mask = -((uint16_t) (i - degree - 1) >> 15); - z[i] = mask & sigma[i]; - } - - z[1] ^= syndromes[0]; - - for (i = 2; i <= PARAM_DELTA; ++i) { - mask = -((uint16_t) (i - degree - 1) >> 15); - z[i] ^= mask & syndromes[i - 1]; - - for (j = 1; j < i; ++j) { - z[i] ^= mask & PQCLEAN_HQC192_CLEAN_gf_mul(sigma[j], syndromes[i - j - 1]); - } - } -} - - - -/** - * @brief Computes the error values - * - * See @cite lin1983error (Chapter 6 - BCH Codes) for more details. - * - * @param[out] error_values Array of PARAM_DELTA elements receiving the error values - * @param[in] z Array of PARAM_DELTA + 1 elements storing the polynomial z(x) - * @param[in] z_degree Integer that is the degree of polynomial z(x) - * @param[in] error_compact Array of PARAM_DELTA + PARAM_N1 storing compact representation of the error - */ -static void compute_error_values(uint16_t *error_values, const uint16_t *z, const uint8_t *error) { - uint16_t beta_j[PARAM_DELTA] = {0}; - uint16_t e_j[PARAM_DELTA] = {0}; - - uint16_t delta_counter; - uint16_t delta_real_value; - uint16_t found; - uint16_t mask1; - uint16_t mask2; - uint16_t tmp1; - uint16_t tmp2; - uint16_t inverse; - uint16_t inverse_power_j; - - // Compute the beta_{j_i} page 31 of the documentation - delta_counter = 0; - for (size_t i = 0; i < PARAM_N1; i++) { - found = 0; - mask1 = (uint16_t) (-((int32_t)error[i]) >> 31); // error[i] != 0 - for (size_t j = 0; j < PARAM_DELTA; j++) { - mask2 = ~((uint16_t) (-((int32_t) j ^ delta_counter) >> 31)); // j == delta_counter - beta_j[j] += mask1 & mask2 & gf_exp[i]; - found += mask1 & mask2 & 1; - } - delta_counter += found; - } - delta_real_value = delta_counter; - - // Compute the e_{j_i} page 31 of the documentation - for (size_t i = 0; i < PARAM_DELTA; ++i) { - tmp1 = 1; - tmp2 = 1; - inverse = PQCLEAN_HQC192_CLEAN_gf_inverse(beta_j[i]); - inverse_power_j = 1; - - for (size_t j = 1; j <= PARAM_DELTA; ++j) { - inverse_power_j = PQCLEAN_HQC192_CLEAN_gf_mul(inverse_power_j, inverse); - tmp1 ^= PQCLEAN_HQC192_CLEAN_gf_mul(inverse_power_j, z[j]); - } - for (size_t k = 1; k < PARAM_DELTA; ++k) { - tmp2 = PQCLEAN_HQC192_CLEAN_gf_mul(tmp2, (1 ^ PQCLEAN_HQC192_CLEAN_gf_mul(inverse, beta_j[(i + k) % PARAM_DELTA]))); - } - mask1 = (uint16_t) (((int16_t) i - delta_real_value) >> 15); // i < delta_real_value - e_j[i] = mask1 & PQCLEAN_HQC192_CLEAN_gf_mul(tmp1, PQCLEAN_HQC192_CLEAN_gf_inverse(tmp2)); - } - - // Place the delta e_{j_i} values at the right coordinates of the output vector - delta_counter = 0; - for (size_t i = 0; i < PARAM_N1; ++i) { - found = 0; - mask1 = (uint16_t) (-((int32_t)error[i]) >> 31); // error[i] != 0 - for (size_t j = 0; j < PARAM_DELTA; j++) { - mask2 = ~((uint16_t) (-((int32_t) j ^ delta_counter) >> 31)); // j == delta_counter - error_values[i] += mask1 & mask2 & e_j[j]; - found += mask1 & mask2 & 1; - } - delta_counter += found; - } -} - - - -/** - * @brief Correct the errors - * - * @param[out] cdw Array of PARAM_N1 elements receiving the corrected vector - * @param[in] error Array of the error vector - * @param[in] error_values Array of PARAM_DELTA elements storing the error values - */ -static void correct_errors(uint8_t *cdw, const uint16_t *error_values) { - for (size_t i = 0; i < PARAM_N1; ++i) { - cdw[i] ^= error_values[i]; - } -} - - - -/** - * @brief Decodes the received word - * - * This function relies on six steps: - *
    - *
  1. The first step, is the computation of the 2*PARAM_DELTA syndromes. - *
  2. The second step is the computation of the error-locator polynomial sigma. - *
  3. The third step, done by additive FFT, is finding the error-locator numbers by calculating the roots of the polynomial sigma and takings their inverses. - *
  4. The fourth step, is the polynomial z(x). - *
  5. The fifth step, is the computation of the error values. - *
  6. The sixth step is the correction of the errors in the received polynomial. - *
- * For a more complete picture on Reed-Solomon decoding, see Shu. Lin and Daniel J. Costello in Error Control Coding: Fundamentals and Applications @cite lin1983error - * - * @param[out] msg Array of size VEC_K_SIZE_64 receiving the decoded message - * @param[in] cdw Array of size VEC_N1_SIZE_64 storing the received word - */ -void PQCLEAN_HQC192_CLEAN_reed_solomon_decode(uint8_t *msg, uint8_t *cdw) { - uint16_t syndromes[2 * PARAM_DELTA] = {0}; - uint16_t sigma[1 << PARAM_FFT] = {0}; - uint8_t error[1 << PARAM_M] = {0}; - uint16_t z[PARAM_N1] = {0}; - uint16_t error_values[PARAM_N1] = {0}; - uint16_t deg; - - // Calculate the 2*PARAM_DELTA syndromes - compute_syndromes(syndromes, cdw); - - // Compute the error locator polynomial sigma - // Sigma's degree is at most PARAM_DELTA but the FFT requires the extra room - deg = compute_elp(sigma, syndromes); - - // Compute the error polynomial error - compute_roots(error, sigma); - - // Compute the polynomial z(x) - compute_z_poly(z, sigma, deg, syndromes); - - // Compute the error values - compute_error_values(error_values, z, error); - - // Correct the errors - correct_errors(cdw, error_values); - - // Retrieve the message from the decoded codeword - memcpy(msg, cdw + (PARAM_G - 1), PARAM_K); - -} diff --git a/src/kem/hqc/pqclean_hqc-192_clean/reed_solomon.h b/src/kem/hqc/pqclean_hqc-192_clean/reed_solomon.h deleted file mode 100644 index aae6421216..0000000000 --- a/src/kem/hqc/pqclean_hqc-192_clean/reed_solomon.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef REED_SOLOMON_H -#define REED_SOLOMON_H - - -/** - * @file reed_solomon.h - * @brief Header file of reed_solomon.c - */ - -#include - -static const uint16_t alpha_ij_pow [32][55] = {{2, 4, 8, 16, 32, 64, 128, 29, 58, 116, 232, 205, 135, 19, 38, 76, 152, 45, 90, 180, 117, 234, 201, 143, 3, 6, 12, 24, 48, 96, 192, 157, 39, 78, 156, 37, 74, 148, 53, 106, 212, 181, 119, 238, 193, 159, 35, 70, 140, 5, 10, 20, 40, 80, 160}, {4, 16, 64, 29, 116, 205, 19, 76, 45, 180, 234, 143, 6, 24, 96, 157, 78, 37, 148, 106, 181, 238, 159, 70, 5, 20, 80, 93, 105, 185, 222, 95, 97, 153, 94, 101, 137, 30, 120, 253, 211, 107, 177, 254, 223, 91, 113, 217, 67, 17, 68, 13, 52, 208, 103}, {8, 64, 58, 205, 38, 45, 117, 143, 12, 96, 39, 37, 53, 181, 193, 70, 10, 80, 186, 185, 161, 97, 47, 101, 15, 120, 231, 107, 127, 223, 182, 217, 134, 68, 26, 208, 206, 62, 237, 59, 197, 102, 23, 184, 169, 33, 21, 168, 41, 85, 146, 228, 115, 191, 145}, {16, 29, 205, 76, 180, 143, 24, 157, 37, 106, 238, 70, 20, 93, 185, 95, 153, 101, 30, 253, 107, 254, 91, 217, 17, 13, 208, 129, 248, 59, 151, 133, 184, 79, 132, 168, 82, 73, 228, 230, 198, 252, 123, 227, 150, 149, 165, 130, 200, 28, 221, 81, 121, 195, 172}, {32, 116, 38, 180, 3, 96, 156, 106, 193, 5, 160, 185, 190, 94, 15, 253, 214, 223, 226, 17, 26, 103, 124, 59, 51, 46, 169, 132, 77, 85, 114, 230, 145, 215, 255, 150, 55, 174, 100, 28, 167, 89, 239, 172, 36, 244, 235, 44, 233, 108, 1, 32, 116, 38, 180}, {64, 205, 45, 143, 96, 37, 181, 70, 80, 185, 97, 101, 120, 107, 223, 217, 68, 208, 62, 59, 102, 184, 33, 168, 85, 228, 191, 252, 241, 150, 110, 130, 7, 221, 89, 195, 138, 61, 251, 44, 207, 173, 8, 58, 38, 117, 12, 39, 53, 193, 10, 186, 161, 47, 15}, {128, 19, 117, 24, 156, 181, 140, 93, 161, 94, 60, 107, 163, 67, 26, 129, 147, 102, 109, 132, 41, 57, 209, 252, 255, 98, 87, 200, 224, 89, 155, 18, 245, 11, 233, 173, 16, 232, 45, 3, 157, 53, 159, 40, 185, 194, 137, 231, 254, 226, 68, 189, 248, 197, 46}, {29, 76, 143, 157, 106, 70, 93, 95, 101, 253, 254, 217, 13, 129, 59, 133, 79, 168, 73, 230, 252, 227, 149, 130, 28, 81, 195, 18, 247, 44, 27, 2, 58, 152, 3, 39, 212, 140, 186, 190, 202, 231, 225, 175, 26, 31, 118, 23, 158, 77, 146, 209, 229, 219, 55}, {58, 45, 12, 37, 193, 80, 161, 101, 231, 223, 134, 208, 237, 102, 169, 168, 146, 191, 179, 150, 87, 7, 166, 195, 36, 251, 125, 173, 64, 38, 143, 39, 181, 10, 185, 47, 120, 127, 217, 26, 62, 197, 184, 21, 85, 115, 252, 219, 110, 100, 221, 242, 138, 245, 44}, {116, 180, 96, 106, 5, 185, 94, 253, 223, 17, 103, 59, 46, 132, 85, 230, 215, 150, 174, 28, 89, 172, 244, 44, 108, 32, 38, 3, 156, 193, 160, 190, 15, 214, 226, 26, 124, 51, 169, 77, 114, 145, 255, 55, 100, 167, 239, 36, 235, 233, 1, 116, 180, 96, 106}, {232, 234, 39, 238, 160, 97, 60, 254, 134, 103, 118, 184, 84, 57, 145, 227, 220, 7, 162, 172, 245, 176, 71, 58, 180, 192, 181, 40, 95, 15, 177, 175, 208, 147, 46, 21, 73, 99, 241, 55, 200, 166, 43, 122, 44, 216, 128, 45, 48, 106, 10, 222, 202, 107, 226}, {205, 143, 37, 70, 185, 101, 107, 217, 208, 59, 184, 168, 228, 252, 150, 130, 221, 195, 61, 44, 173, 58, 117, 39, 193, 186, 47, 231, 182, 26, 237, 23, 21, 146, 145, 219, 87, 56, 242, 36, 139, 54, 64, 45, 96, 181, 80, 97, 120, 223, 68, 62, 102, 33, 85}, {135, 6, 53, 20, 190, 120, 163, 13, 237, 46, 84, 228, 229, 98, 100, 81, 69, 251, 131, 32, 45, 192, 238, 186, 94, 187, 217, 189, 236, 169, 82, 209, 241, 220, 28, 242, 72, 22, 173, 116, 201, 37, 140, 222, 15, 254, 34, 62, 204, 132, 146, 63, 75, 130, 167}, {19, 24, 181, 93, 94, 107, 67, 129, 102, 132, 57, 252, 98, 200, 89, 18, 11, 173, 232, 3, 53, 40, 194, 231, 226, 189, 197, 158, 170, 145, 75, 25, 166, 69, 235, 54, 29, 234, 37, 5, 95, 120, 91, 52, 59, 218, 82, 191, 227, 174, 221, 43, 247, 207, 32}, {38, 96, 193, 185, 15, 223, 26, 59, 169, 85, 145, 150, 100, 89, 36, 44, 1, 38, 96, 193, 185, 15, 223, 26, 59, 169, 85, 145, 150, 100, 89, 36, 44, 1, 38, 96, 193, 185, 15, 223, 26, 59, 169, 85, 145, 150, 100, 89, 36, 44, 1, 38, 96, 193, 185}, {76, 157, 70, 95, 253, 217, 129, 133, 168, 230, 227, 130, 81, 18, 44, 2, 152, 39, 140, 190, 231, 175, 31, 23, 77, 209, 219, 25, 162, 36, 88, 4, 45, 78, 5, 97, 211, 67, 62, 46, 154, 191, 171, 50, 89, 72, 176, 8, 90, 156, 10, 194, 187, 134, 124}, {152, 78, 10, 153, 214, 68, 147, 79, 146, 215, 220, 221, 69, 11, 1, 152, 78, 10, 153, 214, 68, 147, 79, 146, 215, 220, 221, 69, 11, 1, 152, 78, 10, 153, 214, 68, 147, 79, 146, 215, 220, 221, 69, 11, 1, 152, 78, 10, 153, 214, 68, 147, 79, 146, 215}, {45, 37, 80, 101, 223, 208, 102, 168, 191, 150, 7, 195, 251, 173, 38, 39, 10, 47, 127, 26, 197, 21, 115, 219, 100, 242, 245, 54, 205, 96, 70, 97, 107, 68, 59, 33, 228, 241, 130, 89, 61, 207, 58, 12, 193, 161, 231, 134, 237, 169, 146, 179, 87, 166, 36}, {90, 148, 186, 30, 226, 62, 109, 73, 179, 174, 162, 61, 131, 232, 96, 140, 153, 127, 52, 51, 168, 99, 98, 56, 172, 22, 8, 234, 212, 185, 240, 67, 237, 79, 114, 241, 25, 121, 245, 108, 19, 39, 20, 188, 223, 189, 133, 41, 63, 55, 221, 9, 176, 64, 3}, {180, 106, 185, 253, 17, 59, 132, 230, 150, 28, 172, 44, 32, 3, 193, 190, 214, 26, 51, 77, 145, 55, 167, 36, 233, 116, 96, 5, 94, 223, 103, 46, 85, 215, 174, 89, 244, 108, 38, 156, 160, 15, 226, 124, 169, 114, 255, 100, 239, 235, 1, 180, 106, 185, 253}, {117, 181, 161, 107, 26, 102, 41, 252, 87, 89, 245, 173, 45, 53, 185, 231, 68, 197, 168, 145, 110, 166, 61, 54, 38, 37, 186, 120, 134, 59, 21, 191, 196, 221, 36, 207, 205, 39, 80, 15, 217, 237, 33, 115, 150, 56, 138, 125, 58, 96, 10, 101, 182, 62, 169}, {234, 238, 97, 254, 103, 184, 57, 227, 7, 172, 176, 58, 192, 40, 15, 175, 147, 21, 99, 55, 166, 122, 216, 45, 106, 222, 107, 52, 133, 85, 123, 50, 195, 11, 32, 12, 140, 188, 182, 124, 158, 115, 49, 224, 36, 131, 19, 37, 105, 253, 68, 151, 154, 252, 174}, {201, 159, 47, 91, 124, 33, 209, 149, 166, 244, 71, 117, 238, 194, 223, 31, 79, 115, 98, 167, 61, 216, 90, 181, 190, 254, 206, 218, 213, 150, 224, 72, 54, 152, 106, 161, 177, 189, 184, 114, 171, 56, 18, 131, 38, 148, 111, 107, 104, 46, 146, 227, 14, 138, 233}, {143, 70, 101, 217, 59, 168, 252, 130, 195, 44, 58, 39, 186, 231, 26, 23, 146, 219, 56, 36, 54, 45, 181, 97, 223, 62, 33, 191, 110, 89, 251, 8, 12, 10, 15, 134, 197, 41, 179, 100, 86, 125, 205, 37, 185, 107, 208, 184, 228, 150, 221, 61, 173, 117, 193}, {3, 5, 15, 17, 51, 85, 255, 28, 36, 108, 180, 193, 94, 226, 59, 77, 215, 100, 172, 233, 38, 106, 190, 223, 124, 132, 145, 174, 239, 44, 116, 156, 185, 214, 103, 169, 230, 55, 89, 235, 32, 96, 160, 253, 26, 46, 114, 150, 167, 244, 1, 3, 5, 15, 17}, {6, 20, 120, 13, 46, 228, 98, 81, 251, 32, 192, 186, 187, 189, 169, 209, 220, 242, 22, 116, 37, 222, 254, 62, 132, 63, 130, 43, 250, 38, 212, 194, 182, 147, 77, 179, 141, 9, 54, 180, 159, 101, 67, 151, 85, 227, 112, 61, 142, 3, 10, 60, 136, 23, 114}, {12, 80, 231, 208, 169, 191, 87, 195, 125, 38, 181, 47, 217, 197, 85, 219, 221, 245, 8, 96, 186, 107, 206, 33, 145, 130, 86, 207, 45, 193, 101, 134, 102, 146, 150, 166, 251, 64, 39, 185, 127, 62, 21, 252, 100, 138, 54, 117, 70, 15, 68, 23, 228, 196, 89}, {24, 93, 107, 129, 132, 252, 200, 18, 173, 3, 40, 231, 189, 158, 145, 25, 69, 54, 234, 5, 120, 52, 218, 191, 174, 43, 207, 90, 35, 15, 136, 92, 115, 220, 239, 125, 76, 238, 101, 17, 133, 228, 149, 121, 44, 135, 212, 47, 175, 51, 146, 49, 162, 139, 116}, {48, 105, 127, 248, 77, 241, 224, 247, 64, 156, 95, 182, 236, 170, 150, 162, 11, 205, 212, 94, 134, 133, 213, 110, 239, 250, 45, 35, 30, 26, 218, 99, 130, 69, 108, 143, 40, 211, 206, 132, 229, 7, 144, 2, 96, 210, 254, 237, 154, 255, 221, 243, 128, 37, 190}, {96, 185, 223, 59, 85, 150, 89, 44, 38, 193, 15, 26, 169, 145, 100, 36, 1, 96, 185, 223, 59, 85, 150, 89, 44, 38, 193, 15, 26, 169, 145, 100, 36, 1, 96, 185, 223, 59, 85, 150, 89, 44, 38, 193, 15, 26, 169, 145, 100, 36, 1, 96, 185, 223, 59}, {192, 222, 182, 151, 114, 110, 155, 27, 143, 160, 177, 237, 82, 75, 89, 88, 152, 70, 240, 103, 21, 123, 224, 251, 116, 212, 101, 136, 218, 145, 200, 144, 8, 78, 190, 217, 204, 183, 87, 172, 216, 12, 105, 225, 59, 170, 98, 242, 250, 180, 10, 211, 31, 168, 255}, {157, 95, 217, 133, 230, 130, 18, 2, 39, 190, 175, 23, 209, 25, 36, 4, 78, 97, 67, 46, 191, 50, 72, 8, 156, 194, 134, 92, 99, 100, 144, 16, 37, 153, 17, 184, 198, 200, 61, 32, 74, 47, 34, 109, 145, 141, 122, 64, 148, 94, 68, 218, 63, 7, 244}}; - -void PQCLEAN_HQC192_CLEAN_reed_solomon_encode(uint8_t *cdw, const uint8_t *msg); - -void PQCLEAN_HQC192_CLEAN_reed_solomon_decode(uint8_t *msg, uint8_t *cdw); - - -#endif diff --git a/src/kem/hqc/pqclean_hqc-192_clean/shake_ds.c b/src/kem/hqc/pqclean_hqc-192_clean/shake_ds.c deleted file mode 100644 index f85d7c740b..0000000000 --- a/src/kem/hqc/pqclean_hqc-192_clean/shake_ds.c +++ /dev/null @@ -1,40 +0,0 @@ -#include "shake_ds.h" - - -/** - * @file shake_ds.c - * @brief Implementation SHAKE-256 with incremental API and domain separation - */ - - - -/** - * @brief SHAKE-256 with incremental API and domain separation - * - * Derived from function SHAKE_256 in fips202.c - * - * @param[out] state Internal state of SHAKE - * @param[in] output Pointer to output - * @param[in] input Pointer to input - * @param[in] inlen length of input in bytes - * @param[in] domain byte for domain separation - */ -void PQCLEAN_HQC192_CLEAN_shake256_512_ds(shake256incctx *state, uint8_t *output, const uint8_t *input, size_t inlen, uint8_t domain) { - /* Init state */ - shake256_inc_init(state); - - /* Absorb input */ - shake256_inc_absorb(state, input, inlen); - - /* Absorb domain separation byte */ - shake256_inc_absorb(state, &domain, 1); - - /* Finalize */ - shake256_inc_finalize(state); - - /* Squeeze output */ - shake256_inc_squeeze(output, 512 / 8, state); - - /* Release ctx */ - shake256_inc_ctx_release(state); -} diff --git a/src/kem/hqc/pqclean_hqc-192_clean/shake_ds.h b/src/kem/hqc/pqclean_hqc-192_clean/shake_ds.h deleted file mode 100644 index 1adff58c40..0000000000 --- a/src/kem/hqc/pqclean_hqc-192_clean/shake_ds.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef SHAKE_DS_H -#define SHAKE_DS_H - - -/** - * @file shake_ds.h - * @brief Header file of shake_ds.c - */ -#include "fips202.h" -#include -#include - -void PQCLEAN_HQC192_CLEAN_shake256_512_ds(shake256incctx *state, uint8_t *output, const uint8_t *input, size_t inlen, uint8_t domain); - - -#endif diff --git a/src/kem/hqc/pqclean_hqc-192_clean/shake_prng.c b/src/kem/hqc/pqclean_hqc-192_clean/shake_prng.c deleted file mode 100644 index 13d7776bcc..0000000000 --- a/src/kem/hqc/pqclean_hqc-192_clean/shake_prng.c +++ /dev/null @@ -1,60 +0,0 @@ -#include "domains.h" -#include "fips202.h" -#include "shake_prng.h" - -/** - * @file shake_prng.c - * @brief Implementation of SHAKE-256 based seed expander - */ - - -/** - * @brief Initialise a SHAKE-256 based seed expander - * - * Derived from function SHAKE_256 in fips202.c - * - * @param[out] state Keccak internal state and a counter - * @param[in] seed A seed - * @param[in] seedlen The seed bytes length - */ -void PQCLEAN_HQC192_CLEAN_seedexpander_init(seedexpander_state *state, const uint8_t *seed, size_t seedlen) { - uint8_t domain = SEEDEXPANDER_DOMAIN; - shake256_inc_init(state); - shake256_inc_absorb(state, seed, seedlen); - shake256_inc_absorb(state, &domain, 1); - shake256_inc_finalize(state); -} - - - -/** - * @brief A SHAKE-256 based seed expander - * - * Derived from function SHAKE_256 in fips202.c - * Squeezes Keccak state by 64-bit blocks (hardware version compatibility) - * - * @param[out] state Internal state of SHAKE - * @param[out] output The XOF data - * @param[in] outlen Number of bytes to return - */ -void PQCLEAN_HQC192_CLEAN_seedexpander(seedexpander_state *state, uint8_t *output, size_t outlen) { - const size_t bsize = sizeof(uint64_t); - const size_t remainder = outlen % bsize; - uint8_t tmp[sizeof(uint64_t)]; - shake256_inc_squeeze(output, outlen - remainder, state); - if (remainder != 0) { - shake256_inc_squeeze(tmp, bsize, state); - output += outlen - remainder; - for (size_t i = 0; i < remainder; ++i) { - output[i] = tmp[i]; - } - } -} - -/** - * @brief Release the seed expander context - * @param[in] state Internal state of the seed expander - */ -void PQCLEAN_HQC192_CLEAN_seedexpander_release(seedexpander_state *state) { - shake256_inc_ctx_release(state); -} diff --git a/src/kem/hqc/pqclean_hqc-192_clean/shake_prng.h b/src/kem/hqc/pqclean_hqc-192_clean/shake_prng.h deleted file mode 100644 index ac535e32a2..0000000000 --- a/src/kem/hqc/pqclean_hqc-192_clean/shake_prng.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef SHAKE_PRNG_H -#define SHAKE_PRNG_H - - -/** - * @file shake_prng.h - * @brief Header file of shake_prng.c - */ -#include "fips202.h" -#include -#include - -typedef shake256incctx seedexpander_state; - -void PQCLEAN_HQC192_CLEAN_seedexpander_init(seedexpander_state *state, const uint8_t *seed, size_t seedlen); - -void PQCLEAN_HQC192_CLEAN_seedexpander(seedexpander_state *state, uint8_t *output, size_t outlen); - -void PQCLEAN_HQC192_CLEAN_seedexpander_release(seedexpander_state *state); - - -#endif diff --git a/src/kem/hqc/pqclean_hqc-192_clean/vector.c b/src/kem/hqc/pqclean_hqc-192_clean/vector.c deleted file mode 100644 index aa27d8ecb3..0000000000 --- a/src/kem/hqc/pqclean_hqc-192_clean/vector.c +++ /dev/null @@ -1,197 +0,0 @@ -#include "parameters.h" -#include "parsing.h" -#include "randombytes.h" -#include "vector.h" -#include -#include -/** - * @file vector.c - * @brief Implementation of vectors sampling and some utilities for the HQC scheme - */ - - -static uint32_t m_val[114] = { 119800, 119803, 119807, 119810, 119813, 119817, 119820, 119823, 119827, 119830, 119833, 119837, 119840, 119843, 119847, 119850, 119853, 119857, 119860, 119864, 119867, 119870, 119874, 119877, 119880, 119884, 119887, 119890, 119894, 119897, 119900, 119904, 119907, 119910, 119914, 119917, 119920, 119924, 119927, 119930, 119934, 119937, 119941, 119944, 119947, 119951, 119954, 119957, 119961, 119964, 119967, 119971, 119974, 119977, 119981, 119984, 119987, 119991, 119994, 119997, 120001, 120004, 120008, 120011, 120014, 120018, 120021, 120024, 120028, 120031, 120034, 120038, 120041, 120044, 120048, 120051, 120054, 120058, 120061, 120065, 120068, 120071, 120075, 120078, 120081, 120085, 120088, 120091, 120095, 120098, 120101, 120105, 120108, 120112, 120115, 120118, 120122, 120125, 120128, 120132, 120135, 120138, 120142, 120145, 120149, 120152, 120155, 120159, 120162, 120165, 120169, 120172, 120175, 120179 }; - -/** - * @brief Constant-time comparison of two integers v1 and v2 - * - * Returns 1 if v1 is equal to v2 and 0 otherwise - * https://gist.github.com/sneves/10845247 - * - * @param[in] v1 - * @param[in] v2 - */ -static inline uint32_t compare_u32(uint32_t v1, uint32_t v2) { - return 1 ^ ((uint32_t)((v1 - v2) | (v2 - v1)) >> 31); -} - -static uint64_t single_bit_mask(uint32_t pos) { - uint64_t ret = 0; - uint64_t mask = 1; - uint64_t tmp; - - for (size_t i = 0; i < 64; ++i) { - tmp = pos - i; - tmp = 0 - (1 - ((uint64_t)(tmp | (0 - tmp)) >> 63)); - ret |= mask & tmp; - mask <<= 1; - } - - return ret; -} - -static inline uint32_t cond_sub(uint32_t r, uint32_t n) { - uint32_t mask; - r -= n; - mask = 0 - (r >> 31); - return r + (n & mask); -} - -static inline uint32_t reduce(uint32_t a, size_t i) { - uint32_t q, n, r; - q = ((uint64_t) a * m_val[i]) >> 32; - n = (uint32_t)(PARAM_N - i); - r = a - q * n; - return cond_sub(r, n); -} - -/** - * @brief Generates a vector of a given Hamming weight - * - * Implementation of Algorithm 5 in https://eprint.iacr.org/2021/1631.pdf - * - * @param[in] ctx Pointer to the context of the seed expander - * @param[in] v Pointer to an array - * @param[in] weight Integer that is the Hamming weight - */ -void PQCLEAN_HQC192_CLEAN_vect_set_random_fixed_weight(seedexpander_state *ctx, uint64_t *v, uint16_t weight) { - uint8_t rand_bytes[4 * PARAM_OMEGA_R] = {0}; // to be interpreted as PARAM_OMEGA_R 32-bit unsigned ints - uint32_t support[PARAM_OMEGA_R] = {0}; - uint32_t index_tab [PARAM_OMEGA_R] = {0}; - uint64_t bit_tab [PARAM_OMEGA_R] = {0}; - uint32_t pos, found, mask32, tmp; - uint64_t mask64, val; - - PQCLEAN_HQC192_CLEAN_seedexpander(ctx, rand_bytes, 4 * weight); - - for (size_t i = 0; i < weight; ++i) { - support[i] = rand_bytes[4 * i]; - support[i] |= rand_bytes[4 * i + 1] << 8; - support[i] |= (uint32_t)rand_bytes[4 * i + 2] << 16; - support[i] |= (uint32_t)rand_bytes[4 * i + 3] << 24; - support[i] = (uint32_t)(i + reduce(support[i], i)); // use constant-tme reduction - } - - for (size_t i = (weight - 1); i-- > 0;) { - found = 0; - - for (size_t j = i + 1; j < weight; ++j) { - found |= compare_u32(support[j], support[i]); - } - - mask32 = 0 - found; - support[i] = (mask32 & i) ^ (~mask32 & support[i]); - } - - for (size_t i = 0; i < weight; ++i) { - index_tab[i] = support[i] >> 6; - pos = support[i] & 0x3f; - bit_tab[i] = single_bit_mask(pos); // avoid secret shift - } - - for (size_t i = 0; i < VEC_N_SIZE_64; ++i) { - val = 0; - for (size_t j = 0; j < weight; ++j) { - tmp = (uint32_t)(i - index_tab[j]); - tmp = 1 ^ ((uint32_t)(tmp | (0 - tmp)) >> 31); - mask64 = 0 - (uint64_t)tmp; - val |= (bit_tab[j] & mask64); - } - v[i] |= val; - } -} - - - -/** - * @brief Generates a random vector of dimension PARAM_N - * - * This function generates a random binary vector of dimension PARAM_N. It generates a random - * array of bytes using the PQCLEAN_HQC192_CLEAN_seedexpander function, and drop the extra bits using a mask. - * - * @param[in] v Pointer to an array - * @param[in] ctx Pointer to the context of the seed expander - */ -void PQCLEAN_HQC192_CLEAN_vect_set_random(seedexpander_state *ctx, uint64_t *v) { - uint8_t rand_bytes[VEC_N_SIZE_BYTES] = {0}; - - PQCLEAN_HQC192_CLEAN_seedexpander(ctx, rand_bytes, VEC_N_SIZE_BYTES); - - PQCLEAN_HQC192_CLEAN_load8_arr(v, VEC_N_SIZE_64, rand_bytes, VEC_N_SIZE_BYTES); - v[VEC_N_SIZE_64 - 1] &= RED_MASK; -} - - - -/** - * @brief Adds two vectors - * - * @param[out] o Pointer to an array that is the result - * @param[in] v1 Pointer to an array that is the first vector - * @param[in] v2 Pointer to an array that is the second vector - * @param[in] size Integer that is the size of the vectors - */ -void PQCLEAN_HQC192_CLEAN_vect_add(uint64_t *o, const uint64_t *v1, const uint64_t *v2, size_t size) { - for (size_t i = 0; i < size; ++i) { - o[i] = v1[i] ^ v2[i]; - } -} - - - -/** - * @brief Compares two vectors - * - * @param[in] v1 Pointer to an array that is first vector - * @param[in] v2 Pointer to an array that is second vector - * @param[in] size Integer that is the size of the vectors - * @returns 0 if the vectors are equal and 1 otherwise - */ -uint8_t PQCLEAN_HQC192_CLEAN_vect_compare(const uint8_t *v1, const uint8_t *v2, size_t size) { - uint16_t r = 0x0100; - - for (size_t i = 0; i < size; i++) { - r |= v1[i] ^ v2[i]; - } - - return (r - 1) >> 8; -} - - - -/** - * @brief Resize a vector so that it contains size_o bits - * - * @param[out] o Pointer to the output vector - * @param[in] size_o Integer that is the size of the output vector in bits - * @param[in] v Pointer to the input vector - * @param[in] size_v Integer that is the size of the input vector in bits - */ -void PQCLEAN_HQC192_CLEAN_vect_resize(uint64_t *o, uint32_t size_o, const uint64_t *v, uint32_t size_v) { - uint64_t mask = 0x7FFFFFFFFFFFFFFF; - size_t val = 0; - if (size_o < size_v) { - - if (size_o % 64) { - val = 64 - (size_o % 64); - } - - memcpy(o, v, VEC_N1N2_SIZE_BYTES); - - for (size_t i = 0; i < val; ++i) { - o[VEC_N1N2_SIZE_64 - 1] &= (mask >> i); - } - } else { - memcpy(o, v, 8 * CEIL_DIVIDE(size_v, 64)); - } -} diff --git a/src/kem/hqc/pqclean_hqc-192_clean/vector.h b/src/kem/hqc/pqclean_hqc-192_clean/vector.h deleted file mode 100644 index 6a5107c39c..0000000000 --- a/src/kem/hqc/pqclean_hqc-192_clean/vector.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef VECTOR_H -#define VECTOR_H - - -/** - * @file vector.h - * @brief Header file for vector.c - */ -#include "shake_prng.h" -#include -#include - -void PQCLEAN_HQC192_CLEAN_vect_set_random_fixed_weight(seedexpander_state *ctx, uint64_t *v, uint16_t weight); - -void PQCLEAN_HQC192_CLEAN_vect_set_random(seedexpander_state *ctx, uint64_t *v); - - -void PQCLEAN_HQC192_CLEAN_vect_add(uint64_t *o, const uint64_t *v1, const uint64_t *v2, size_t size); - -uint8_t PQCLEAN_HQC192_CLEAN_vect_compare(const uint8_t *v1, const uint8_t *v2, size_t size); - -void PQCLEAN_HQC192_CLEAN_vect_resize(uint64_t *o, uint32_t size_o, const uint64_t *v, uint32_t size_v); - - -#endif diff --git a/src/kem/hqc/pqclean_hqc-256_clean/LICENSE b/src/kem/hqc/pqclean_hqc-256_clean/LICENSE deleted file mode 100644 index d5d21fff6d..0000000000 --- a/src/kem/hqc/pqclean_hqc-256_clean/LICENSE +++ /dev/null @@ -1 +0,0 @@ -Public Domain diff --git a/src/kem/hqc/pqclean_hqc-256_clean/api.h b/src/kem/hqc/pqclean_hqc-256_clean/api.h deleted file mode 100644 index ec63b50c27..0000000000 --- a/src/kem/hqc/pqclean_hqc-256_clean/api.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef PQCLEAN_HQC256_CLEAN_API_H -#define PQCLEAN_HQC256_CLEAN_API_H -/** - * @file api.h - * @brief NIST KEM API used by the HQC_KEM IND-CCA2 scheme - */ - -#include - -#define PQCLEAN_HQC256_CLEAN_CRYPTO_ALGNAME "HQC-256" - -#define PQCLEAN_HQC256_CLEAN_CRYPTO_SECRETKEYBYTES 7317 -#define PQCLEAN_HQC256_CLEAN_CRYPTO_PUBLICKEYBYTES 7245 -#define PQCLEAN_HQC256_CLEAN_CRYPTO_BYTES 64 -#define PQCLEAN_HQC256_CLEAN_CRYPTO_CIPHERTEXTBYTES 14421 - -// As a technicality, the public key is appended to the secret key in order to respect the NIST API. -// Without this constraint, PQCLEAN_HQC256_CLEAN_CRYPTO_SECRETKEYBYTES would be defined as 32 - -int PQCLEAN_HQC256_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk); - -int PQCLEAN_HQC256_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk); - -int PQCLEAN_HQC256_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk); - - -#endif diff --git a/src/kem/hqc/pqclean_hqc-256_clean/code.c b/src/kem/hqc/pqclean_hqc-256_clean/code.c deleted file mode 100644 index 0bb4e697a6..0000000000 --- a/src/kem/hqc/pqclean_hqc-256_clean/code.c +++ /dev/null @@ -1,46 +0,0 @@ -#include "code.h" -#include "parameters.h" -#include "reed_muller.h" -#include "reed_solomon.h" -#include -/** - * @file code.c - * @brief Implementation of concatenated code - */ - - - -/** - * - * @brief Encoding the message m to a code word em using the concatenated code - * - * First we encode the message using the Reed-Solomon code, then with the duplicated Reed-Muller code we obtain - * a concatenated code word. - * - * @param[out] em Pointer to an array that is the tensor code word - * @param[in] m Pointer to an array that is the message - */ -void PQCLEAN_HQC256_CLEAN_code_encode(uint64_t *em, const uint8_t *m) { - uint8_t tmp[VEC_N1_SIZE_BYTES] = {0}; - - PQCLEAN_HQC256_CLEAN_reed_solomon_encode(tmp, m); - PQCLEAN_HQC256_CLEAN_reed_muller_encode(em, tmp); - -} - - - -/** - * @brief Decoding the code word em to a message m using the concatenated code - * - * @param[out] m Pointer to an array that is the message - * @param[in] em Pointer to an array that is the code word - */ -void PQCLEAN_HQC256_CLEAN_code_decode(uint8_t *m, const uint64_t *em) { - uint8_t tmp[VEC_N1_SIZE_BYTES] = {0}; - - PQCLEAN_HQC256_CLEAN_reed_muller_decode(tmp, em); - PQCLEAN_HQC256_CLEAN_reed_solomon_decode(m, tmp); - - -} diff --git a/src/kem/hqc/pqclean_hqc-256_clean/code.h b/src/kem/hqc/pqclean_hqc-256_clean/code.h deleted file mode 100644 index 6c3f238aa0..0000000000 --- a/src/kem/hqc/pqclean_hqc-256_clean/code.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef CODE_H -#define CODE_H - - -/** - * @file code.h - * @brief Header file of code.c - */ - -#include - -void PQCLEAN_HQC256_CLEAN_code_encode(uint64_t *em, const uint8_t *message); - -void PQCLEAN_HQC256_CLEAN_code_decode(uint8_t *m, const uint64_t *em); - - -#endif diff --git a/src/kem/hqc/pqclean_hqc-256_clean/domains.h b/src/kem/hqc/pqclean_hqc-256_clean/domains.h deleted file mode 100644 index 20c782ccae..0000000000 --- a/src/kem/hqc/pqclean_hqc-256_clean/domains.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef DOMAINS_H -#define DOMAINS_H - - -/** - * @file domains.h - * @brief SHAKE-256 domains separation header grouping all domains to avoid collisions - */ - - -#define PRNG_DOMAIN 1 -#define SEEDEXPANDER_DOMAIN 2 -#define G_FCT_DOMAIN 3 -#define K_FCT_DOMAIN 4 - -#endif diff --git a/src/kem/hqc/pqclean_hqc-256_clean/fft.c b/src/kem/hqc/pqclean_hqc-256_clean/fft.c deleted file mode 100644 index dae2209521..0000000000 --- a/src/kem/hqc/pqclean_hqc-256_clean/fft.c +++ /dev/null @@ -1,346 +0,0 @@ -#include "fft.h" -#include "gf.h" -#include "parameters.h" -#include -#include -/** - * @file fft.c - * @brief Implementation of the additive FFT and its transpose. - * This implementation is based on the paper from Gao and Mateer:
- * Shuhong Gao and Todd Mateer, Additive Fast Fourier Transforms over Finite Fields, - * IEEE Transactions on Information Theory 56 (2010), 6265--6272. - * http://www.math.clemson.edu/~sgao/papers/GM10.pdf
- * and includes improvements proposed by Bernstein, Chou and Schwabe here: - * https://binary.cr.yp.to/mcbits-20130616.pdf - */ - - -static void radix_big(uint16_t *f0, uint16_t *f1, const uint16_t *f, uint32_t m_f); - -/** - * @brief Computes the basis of betas (omitting 1) used in the additive FFT and its transpose - * - * @param[out] betas Array of size PARAM_M-1 - */ -static void compute_fft_betas(uint16_t *betas) { - size_t i; - for (i = 0; i < PARAM_M - 1; ++i) { - betas[i] = 1 << (PARAM_M - 1 - i); - } -} - - - -/** - * @brief Computes the subset sums of the given set - * - * The array subset_sums is such that its ith element is - * the subset sum of the set elements given by the binary form of i. - * - * @param[out] subset_sums Array of size 2^set_size receiving the subset sums - * @param[in] set Array of set_size elements - * @param[in] set_size Size of the array set - */ -static void compute_subset_sums(uint16_t *subset_sums, const uint16_t *set, uint16_t set_size) { - uint16_t i, j; - subset_sums[0] = 0; - - for (i = 0; i < set_size; ++i) { - for (j = 0; j < (1 << i); ++j) { - subset_sums[(1 << i) + j] = set[i] ^ subset_sums[j]; - } - } -} - - - -/** - * @brief Computes the radix conversion of a polynomial f in GF(2^m)[x] - * - * Computes f0 and f1 such that f(x) = f0(x^2-x) + x.f1(x^2-x) - * as proposed by Bernstein, Chou and Schwabe: - * https://binary.cr.yp.to/mcbits-20130616.pdf - * - * @param[out] f0 Array half the size of f - * @param[out] f1 Array half the size of f - * @param[in] f Array of size a power of 2 - * @param[in] m_f 2^{m_f} is the smallest power of 2 greater or equal to the number of coefficients of f - */ -static void radix(uint16_t *f0, uint16_t *f1, const uint16_t *f, uint32_t m_f) { - switch (m_f) { - case 4: - f0[4] = f[8] ^ f[12]; - f0[6] = f[12] ^ f[14]; - f0[7] = f[14] ^ f[15]; - f1[5] = f[11] ^ f[13]; - f1[6] = f[13] ^ f[14]; - f1[7] = f[15]; - f0[5] = f[10] ^ f[12] ^ f1[5]; - f1[4] = f[9] ^ f[13] ^ f0[5]; - - f0[0] = f[0]; - f1[3] = f[7] ^ f[11] ^ f[15]; - f0[3] = f[6] ^ f[10] ^ f[14] ^ f1[3]; - f0[2] = f[4] ^ f0[4] ^ f0[3] ^ f1[3]; - f1[1] = f[3] ^ f[5] ^ f[9] ^ f[13] ^ f1[3]; - f1[2] = f[3] ^ f1[1] ^ f0[3]; - f0[1] = f[2] ^ f0[2] ^ f1[1]; - f1[0] = f[1] ^ f0[1]; - break; - - case 3: - f0[0] = f[0]; - f0[2] = f[4] ^ f[6]; - f0[3] = f[6] ^ f[7]; - f1[1] = f[3] ^ f[5] ^ f[7]; - f1[2] = f[5] ^ f[6]; - f1[3] = f[7]; - f0[1] = f[2] ^ f0[2] ^ f1[1]; - f1[0] = f[1] ^ f0[1]; - break; - - case 2: - f0[0] = f[0]; - f0[1] = f[2] ^ f[3]; - f1[0] = f[1] ^ f0[1]; - f1[1] = f[3]; - break; - - case 1: - f0[0] = f[0]; - f1[0] = f[1]; - break; - - default: - radix_big(f0, f1, f, m_f); - break; - } -} - -static void radix_big(uint16_t *f0, uint16_t *f1, const uint16_t *f, uint32_t m_f) { - uint16_t Q[2 * (1 << (PARAM_FFT - 2)) + 1] = {0}; - uint16_t R[2 * (1 << (PARAM_FFT - 2)) + 1] = {0}; - - uint16_t Q0[1 << (PARAM_FFT - 2)] = {0}; - uint16_t Q1[1 << (PARAM_FFT - 2)] = {0}; - uint16_t R0[1 << (PARAM_FFT - 2)] = {0}; - uint16_t R1[1 << (PARAM_FFT - 2)] = {0}; - - size_t i, n; - - n = 1; - n <<= (m_f - 2); - memcpy(Q, f + 3 * n, 2 * n); - memcpy(Q + n, f + 3 * n, 2 * n); - memcpy(R, f, 4 * n); - - for (i = 0; i < n; ++i) { - Q[i] ^= f[2 * n + i]; - R[n + i] ^= Q[i]; - } - - radix(Q0, Q1, Q, m_f - 1); - radix(R0, R1, R, m_f - 1); - - memcpy(f0, R0, 2 * n); - memcpy(f0 + n, Q0, 2 * n); - memcpy(f1, R1, 2 * n); - memcpy(f1 + n, Q1, 2 * n); -} - - - -/** - * @brief Evaluates f at all subset sums of a given set - * - * This function is a subroutine of the function PQCLEAN_HQC256_CLEAN_fft. - * - * @param[out] w Array - * @param[in] f Array - * @param[in] f_coeffs Number of coefficients of f - * @param[in] m Number of betas - * @param[in] m_f Number of coefficients of f (one more than its degree) - * @param[in] betas FFT constants - */ -static void fft_rec(uint16_t *w, uint16_t *f, size_t f_coeffs, uint8_t m, uint32_t m_f, const uint16_t *betas) { - uint16_t f0[1 << (PARAM_FFT - 2)] = {0}; - uint16_t f1[1 << (PARAM_FFT - 2)] = {0}; - uint16_t gammas[PARAM_M - 2] = {0}; - uint16_t deltas[PARAM_M - 2] = {0}; - uint16_t gammas_sums[1 << (PARAM_M - 2)] = {0}; - uint16_t u[1 << (PARAM_M - 2)] = {0}; - uint16_t v[1 << (PARAM_M - 2)] = {0}; - uint16_t tmp[PARAM_M - (PARAM_FFT - 1)] = {0}; - - uint16_t beta_m_pow; - size_t i, j, k; - size_t x; - - // Step 1 - if (m_f == 1) { - for (i = 0; i < m; ++i) { - tmp[i] = PQCLEAN_HQC256_CLEAN_gf_mul(betas[i], f[1]); - } - - w[0] = f[0]; - x = 1; - for (j = 0; j < m; ++j) { - for (k = 0; k < x; ++k) { - w[x + k] = w[k] ^ tmp[j]; - } - x <<= 1; - } - - return; - } - - // Step 2: compute g - if (betas[m - 1] != 1) { - beta_m_pow = 1; - x = 1; - x <<= m_f; - for (i = 1; i < x; ++i) { - beta_m_pow = PQCLEAN_HQC256_CLEAN_gf_mul(beta_m_pow, betas[m - 1]); - f[i] = PQCLEAN_HQC256_CLEAN_gf_mul(beta_m_pow, f[i]); - } - } - - // Step 3 - radix(f0, f1, f, m_f); - - // Step 4: compute gammas and deltas - for (i = 0; i + 1 < m; ++i) { - gammas[i] = PQCLEAN_HQC256_CLEAN_gf_mul(betas[i], PQCLEAN_HQC256_CLEAN_gf_inverse(betas[m - 1])); - deltas[i] = PQCLEAN_HQC256_CLEAN_gf_square(gammas[i]) ^ gammas[i]; - } - - // Compute gammas sums - compute_subset_sums(gammas_sums, gammas, m - 1); - - // Step 5 - fft_rec(u, f0, (f_coeffs + 1) / 2, m - 1, m_f - 1, deltas); - - k = 1; - k <<= ((m - 1) & 0xf); // &0xf is to let the compiler know that m-1 is small. - if (f_coeffs <= 3) { // 3-coefficient polynomial f case: f1 is constant - w[0] = u[0]; - w[k] = u[0] ^ f1[0]; - for (i = 1; i < k; ++i) { - w[i] = u[i] ^ PQCLEAN_HQC256_CLEAN_gf_mul(gammas_sums[i], f1[0]); - w[k + i] = w[i] ^ f1[0]; - } - } else { - fft_rec(v, f1, f_coeffs / 2, m - 1, m_f - 1, deltas); - - // Step 6 - memcpy(w + k, v, 2 * k); - w[0] = u[0]; - w[k] ^= u[0]; - for (i = 1; i < k; ++i) { - w[i] = u[i] ^ PQCLEAN_HQC256_CLEAN_gf_mul(gammas_sums[i], v[i]); - w[k + i] ^= w[i]; - } - } -} - - - -/** - * @brief Evaluates f on all fields elements using an additive FFT algorithm - * - * f_coeffs is the number of coefficients of f (one less than its degree).
- * The FFT proceeds recursively to evaluate f at all subset sums of a basis B.
- * This implementation is based on the paper from Gao and Mateer:
- * Shuhong Gao and Todd Mateer, Additive Fast Fourier Transforms over Finite Fields, - * IEEE Transactions on Information Theory 56 (2010), 6265--6272. - * http://www.math.clemson.edu/~sgao/papers/GM10.pdf
- * and includes improvements proposed by Bernstein, Chou and Schwabe here: - * https://binary.cr.yp.to/mcbits-20130616.pdf
- * Note that on this first call (as opposed to the recursive calls to fft_rec), gammas are equal to betas, - * meaning the first gammas subset sums are actually the subset sums of betas (except 1).
- * Also note that f is altered during computation (twisted at each level). - * - * @param[out] w Array - * @param[in] f Array of 2^PARAM_FFT elements - * @param[in] f_coeffs Number coefficients of f (i.e. deg(f)+1) - */ -void PQCLEAN_HQC256_CLEAN_fft(uint16_t *w, const uint16_t *f, size_t f_coeffs) { - uint16_t betas[PARAM_M - 1] = {0}; - uint16_t betas_sums[1 << (PARAM_M - 1)] = {0}; - uint16_t f0[1 << (PARAM_FFT - 1)] = {0}; - uint16_t f1[1 << (PARAM_FFT - 1)] = {0}; - uint16_t deltas[PARAM_M - 1] = {0}; - uint16_t u[1 << (PARAM_M - 1)] = {0}; - uint16_t v[1 << (PARAM_M - 1)] = {0}; - - size_t i, k; - - // Follows Gao and Mateer algorithm - compute_fft_betas(betas); - - // Step 1: PARAM_FFT > 1, nothing to do - - // Compute gammas sums - compute_subset_sums(betas_sums, betas, PARAM_M - 1); - - // Step 2: beta_m = 1, nothing to do - - // Step 3 - radix(f0, f1, f, PARAM_FFT); - - // Step 4: Compute deltas - for (i = 0; i < PARAM_M - 1; ++i) { - deltas[i] = PQCLEAN_HQC256_CLEAN_gf_square(betas[i]) ^ betas[i]; - } - - // Step 5 - fft_rec(u, f0, (f_coeffs + 1) / 2, PARAM_M - 1, PARAM_FFT - 1, deltas); - fft_rec(v, f1, f_coeffs / 2, PARAM_M - 1, PARAM_FFT - 1, deltas); - - k = 1 << (PARAM_M - 1); - // Step 6, 7 and error polynomial computation - memcpy(w + k, v, 2 * k); - - // Check if 0 is root - w[0] = u[0]; - - // Check if 1 is root - w[k] ^= u[0]; - - // Find other roots - for (i = 1; i < k; ++i) { - w[i] = u[i] ^ PQCLEAN_HQC256_CLEAN_gf_mul(betas_sums[i], v[i]); - w[k + i] ^= w[i]; - } -} - - - -/** - * @brief Retrieves the error polynomial error from the evaluations w of the ELP (Error Locator Polynomial) on all field elements. - * - * @param[out] error Array with the error - * @param[out] error_compact Array with the error in a compact form - * @param[in] w Array of size 2^PARAM_M - */ -void PQCLEAN_HQC256_CLEAN_fft_retrieve_error_poly(uint8_t *error, const uint16_t *w) { - uint16_t gammas[PARAM_M - 1] = {0}; - uint16_t gammas_sums[1 << (PARAM_M - 1)] = {0}; - uint16_t k; - size_t i, index; - - compute_fft_betas(gammas); - compute_subset_sums(gammas_sums, gammas, PARAM_M - 1); - - k = 1 << (PARAM_M - 1); - error[0] ^= 1 ^ ((uint16_t) - w[0] >> 15); - error[0] ^= 1 ^ ((uint16_t) - w[k] >> 15); - - for (i = 1; i < k; ++i) { - index = PARAM_GF_MUL_ORDER - gf_log[gammas_sums[i]]; - error[index] ^= 1 ^ ((uint16_t) - w[i] >> 15); - - index = PARAM_GF_MUL_ORDER - gf_log[gammas_sums[i] ^ 1]; - error[index] ^= 1 ^ ((uint16_t) - w[k + i] >> 15); - } -} diff --git a/src/kem/hqc/pqclean_hqc-256_clean/fft.h b/src/kem/hqc/pqclean_hqc-256_clean/fft.h deleted file mode 100644 index 723203aba2..0000000000 --- a/src/kem/hqc/pqclean_hqc-256_clean/fft.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef FFT_H -#define FFT_H - - -/** - * @file fft.h - * @brief Header file of fft.c - */ - -#include -#include - -void PQCLEAN_HQC256_CLEAN_fft(uint16_t *w, const uint16_t *f, size_t f_coeffs); - -void PQCLEAN_HQC256_CLEAN_fft_retrieve_error_poly(uint8_t *error, const uint16_t *w); - - -#endif diff --git a/src/kem/hqc/pqclean_hqc-256_clean/gf.c b/src/kem/hqc/pqclean_hqc-256_clean/gf.c deleted file mode 100644 index 0c4eb67503..0000000000 --- a/src/kem/hqc/pqclean_hqc-256_clean/gf.c +++ /dev/null @@ -1,170 +0,0 @@ -#include "gf.h" -#include "parameters.h" -#include -#include -/** - * @file gf.c - * @brief Galois field implementation - */ - - -/** - * @brief Computes the number of trailing zero bits. - * - * @returns The number of trailing zero bits in a. - * @param[in] a An operand - */ -static uint16_t trailing_zero_bits_count(uint16_t a) { - uint16_t tmp = 0; - uint16_t mask = 0xFFFF; - for (size_t i = 0; i < 14; ++i) { - tmp += ((1 - ((a >> i) & 0x0001)) & mask); - mask &= - (1 - ((a >> i) & 0x0001)); - } - return tmp; -} - - - -/** - * Reduces polynomial x modulo primitive polynomial GF_POLY. - * @returns x mod GF_POLY - * @param[in] x Polynomial of degree less than 64 - * @param[in] deg_x The degree of polynomial x - */ -static uint16_t gf_reduce(uint64_t x, size_t deg_x) { - uint16_t z1, z2, rmdr, dist; - uint64_t mod; - - // Deduce the number of steps of reduction - size_t steps = CEIL_DIVIDE(deg_x - (PARAM_M - 1), PARAM_GF_POLY_M2); - - // Reduce - for (size_t i = 0; i < steps; ++i) { - mod = x >> PARAM_M; - x &= (1 << PARAM_M) - 1; - x ^= mod; - - z1 = 0; - rmdr = PARAM_GF_POLY ^ 1; - for (size_t j = PARAM_GF_POLY_WT - 2; j; --j) { - z2 = trailing_zero_bits_count(rmdr); - dist = z2 - z1; - mod <<= dist; - x ^= mod; - rmdr ^= 1 << z2; - z1 = z2; - } - } - - return (uint16_t)x; -} - - - -/** - * Carryless multiplication of two polynomials a and b. - * - * Implementation of the algorithm mul1 in https://hal.inria.fr/inria-00188261v4/document - * with s = 2 and w = 8 - * - * @param[out] The polynomial c = a * b - * @param[in] a The first polynomial - * @param[in] b The second polynomial - */ -static void gf_carryless_mul(uint8_t c[2], uint8_t a, uint8_t b) { - uint16_t h = 0, l = 0, g = 0, u[4]; - uint32_t tmp1, tmp2; - uint16_t mask; - u[0] = 0; - u[1] = b & 0x7F; - u[2] = u[1] << 1; - u[3] = u[2] ^ u[1]; - tmp1 = a & 3; - - for (size_t i = 0; i < 4; i++) { - tmp2 = (uint32_t)(tmp1 - i); - g ^= (u[i] & (uint32_t)(0 - (1 - ((uint32_t)(tmp2 | (0 - tmp2)) >> 31)))); - } - - l = g; - h = 0; - - for (size_t i = 2; i < 8; i += 2) { - g = 0; - tmp1 = (a >> i) & 3; - for (size_t j = 0; j < 4; ++j) { - tmp2 = (uint32_t)(tmp1 - j); - g ^= (u[j] & (uint32_t)(0 - (1 - ((uint32_t)(tmp2 | (0 - tmp2)) >> 31)))); - } - - l ^= g << i; - h ^= g >> (8 - i); - } - - mask = (-((b >> 7) & 1)); - l ^= ((a << 7) & mask); - h ^= ((a >> 1) & mask); - - c[0] = (uint8_t)l; - c[1] = (uint8_t)h; -} - - - -/** - * Multiplies two elements of GF(2^GF_M). - * @returns the product a*b - * @param[in] a Element of GF(2^GF_M) - * @param[in] b Element of GF(2^GF_M) - */ -uint16_t PQCLEAN_HQC256_CLEAN_gf_mul(uint16_t a, uint16_t b) { - uint8_t c[2] = {0}; - gf_carryless_mul(c, (uint8_t) a, (uint8_t) b); - uint16_t tmp = c[0] ^ (c[1] << 8); - return gf_reduce(tmp, 2 * (PARAM_M - 1)); -} - - - -/** - * @brief Squares an element of GF(2^PARAM_M). - * @returns a^2 - * @param[in] a Element of GF(2^PARAM_M) - */ -uint16_t PQCLEAN_HQC256_CLEAN_gf_square(uint16_t a) { - uint32_t b = a; - uint32_t s = b & 1; - for (size_t i = 1; i < PARAM_M; ++i) { - b <<= 1; - s ^= b & (1 << 2 * i); - } - - return gf_reduce(s, 2 * (PARAM_M - 1)); -} - - - -/** - * @brief Computes the inverse of an element of GF(2^PARAM_M), - * using the addition chain 1 2 3 4 7 11 15 30 60 120 127 254 - * @returns the inverse of a if a != 0 or 0 if a = 0 - * @param[in] a Element of GF(2^PARAM_M) - */ -uint16_t PQCLEAN_HQC256_CLEAN_gf_inverse(uint16_t a) { - uint16_t inv = a; - uint16_t tmp1, tmp2; - - inv = PQCLEAN_HQC256_CLEAN_gf_square(a); /* a^2 */ - tmp1 = PQCLEAN_HQC256_CLEAN_gf_mul(inv, a); /* a^3 */ - inv = PQCLEAN_HQC256_CLEAN_gf_square(inv); /* a^4 */ - tmp2 = PQCLEAN_HQC256_CLEAN_gf_mul(inv, tmp1); /* a^7 */ - tmp1 = PQCLEAN_HQC256_CLEAN_gf_mul(inv, tmp2); /* a^11 */ - inv = PQCLEAN_HQC256_CLEAN_gf_mul(tmp1, inv); /* a^15 */ - inv = PQCLEAN_HQC256_CLEAN_gf_square(inv); /* a^30 */ - inv = PQCLEAN_HQC256_CLEAN_gf_square(inv); /* a^60 */ - inv = PQCLEAN_HQC256_CLEAN_gf_square(inv); /* a^120 */ - inv = PQCLEAN_HQC256_CLEAN_gf_mul(inv, tmp2); /* a^127 */ - inv = PQCLEAN_HQC256_CLEAN_gf_square(inv); /* a^254 */ - return inv; -} diff --git a/src/kem/hqc/pqclean_hqc-256_clean/gf.h b/src/kem/hqc/pqclean_hqc-256_clean/gf.h deleted file mode 100644 index 06c55a2462..0000000000 --- a/src/kem/hqc/pqclean_hqc-256_clean/gf.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef GF_H -#define GF_H - - -/** - * @file gf.h - * @brief Header file of gf.c - */ - -#include - - -/** - * Powers of the root alpha of 1 + x^2 + x^3 + x^4 + x^8. - * The last two elements are needed by the PQCLEAN_HQC256_CLEAN_gf_mul function - * (for example if both elements to multiply are zero). - */ -static const uint16_t gf_exp [258] = { 1, 2, 4, 8, 16, 32, 64, 128, 29, 58, 116, 232, 205, 135, 19, 38, 76, 152, 45, 90, 180, 117, 234, 201, 143, 3, 6, 12, 24, 48, 96, 192, 157, 39, 78, 156, 37, 74, 148, 53, 106, 212, 181, 119, 238, 193, 159, 35, 70, 140, 5, 10, 20, 40, 80, 160, 93, 186, 105, 210, 185, 111, 222, 161, 95, 190, 97, 194, 153, 47, 94, 188, 101, 202, 137, 15, 30, 60, 120, 240, 253, 231, 211, 187, 107, 214, 177, 127, 254, 225, 223, 163, 91, 182, 113, 226, 217, 175, 67, 134, 17, 34, 68, 136, 13, 26, 52, 104, 208, 189, 103, 206, 129, 31, 62, 124, 248, 237, 199, 147, 59, 118, 236, 197, 151, 51, 102, 204, 133, 23, 46, 92, 184, 109, 218, 169, 79, 158, 33, 66, 132, 21, 42, 84, 168, 77, 154, 41, 82, 164, 85, 170, 73, 146, 57, 114, 228, 213, 183, 115, 230, 209, 191, 99, 198, 145, 63, 126, 252, 229, 215, 179, 123, 246, 241, 255, 227, 219, 171, 75, 150, 49, 98, 196, 149, 55, 110, 220, 165, 87, 174, 65, 130, 25, 50, 100, 200, 141, 7, 14, 28, 56, 112, 224, 221, 167, 83, 166, 81, 162, 89, 178, 121, 242, 249, 239, 195, 155, 43, 86, 172, 69, 138, 9, 18, 36, 72, 144, 61, 122, 244, 245, 247, 243, 251, 235, 203, 139, 11, 22, 44, 88, 176, 125, 250, 233, 207, 131, 27, 54, 108, 216, 173, 71, 142, 1, 2, 4 }; - - - -/** - * Logarithm of elements of GF(2^8) to the base alpha (root of 1 + x^2 + x^3 + x^4 + x^8). - * The logarithm of 0 is set to 0 by convention. - */ -static const uint16_t gf_log [256] = { 0, 0, 1, 25, 2, 50, 26, 198, 3, 223, 51, 238, 27, 104, 199, 75, 4, 100, 224, 14, 52, 141, 239, 129, 28, 193, 105, 248, 200, 8, 76, 113, 5, 138, 101, 47, 225, 36, 15, 33, 53, 147, 142, 218, 240, 18, 130, 69, 29, 181, 194, 125, 106, 39, 249, 185, 201, 154, 9, 120, 77, 228, 114, 166, 6, 191, 139, 98, 102, 221, 48, 253, 226, 152, 37, 179, 16, 145, 34, 136, 54, 208, 148, 206, 143, 150, 219, 189, 241, 210, 19, 92, 131, 56, 70, 64, 30, 66, 182, 163, 195, 72, 126, 110, 107, 58, 40, 84, 250, 133, 186, 61, 202, 94, 155, 159, 10, 21, 121, 43, 78, 212, 229, 172, 115, 243, 167, 87, 7, 112, 192, 247, 140, 128, 99, 13, 103, 74, 222, 237, 49, 197, 254, 24, 227, 165, 153, 119, 38, 184, 180, 124, 17, 68, 146, 217, 35, 32, 137, 46, 55, 63, 209, 91, 149, 188, 207, 205, 144, 135, 151, 178, 220, 252, 190, 97, 242, 86, 211, 171, 20, 42, 93, 158, 132, 60, 57, 83, 71, 109, 65, 162, 31, 45, 67, 216, 183, 123, 164, 118, 196, 23, 73, 236, 127, 12, 111, 246, 108, 161, 59, 82, 41, 157, 85, 170, 251, 96, 134, 177, 187, 204, 62, 90, 203, 89, 95, 176, 156, 169, 160, 81, 11, 245, 22, 235, 122, 117, 44, 215, 79, 174, 213, 233, 230, 231, 173, 232, 116, 214, 244, 234, 168, 80, 88, 175 }; - - - -uint16_t PQCLEAN_HQC256_CLEAN_gf_mul(uint16_t a, uint16_t b); - -uint16_t PQCLEAN_HQC256_CLEAN_gf_square(uint16_t a); - -uint16_t PQCLEAN_HQC256_CLEAN_gf_inverse(uint16_t a); - - -#endif diff --git a/src/kem/hqc/pqclean_hqc-256_clean/gf2x.c b/src/kem/hqc/pqclean_hqc-256_clean/gf2x.c deleted file mode 100644 index 713f276b61..0000000000 --- a/src/kem/hqc/pqclean_hqc-256_clean/gf2x.c +++ /dev/null @@ -1,198 +0,0 @@ -#include "gf2x.h" -#include "parameters.h" -#include -#include -/** - * @file gf2x.c - * @brief Implementation of multiplication of two polynomials - */ - - -/** - * @brief Caryless multiplication of two words of 64 bits - * - * Implemntation of the algorithm mul1 in https://hal.inria.fr/inria-00188261v4/document. - * With w = 64 and s = 4 - * - * @param[out] c The result c = a * b - * @param[in] a The first value a - * @param[in] b The second value b - */ -static void base_mul(uint64_t *c, uint64_t a, uint64_t b) { - uint64_t h = 0; - uint64_t l = 0; - uint64_t g; - uint64_t u[16] = {0}; - uint64_t mask_tab[4] = {0}; - uint64_t tmp1, tmp2; - - // Step 1 - u[0] = 0; - u[1] = b & (((uint64_t)1 << (64 - 4)) - 1); - u[2] = u[1] << 1; - u[3] = u[2] ^ u[1]; - u[4] = u[2] << 1; - u[5] = u[4] ^ u[1]; - u[6] = u[3] << 1; - u[7] = u[6] ^ u[1]; - u[8] = u[4] << 1; - u[9] = u[8] ^ u[1]; - u[10] = u[5] << 1; - u[11] = u[10] ^ u[1]; - u[12] = u[6] << 1; - u[13] = u[12] ^ u[1]; - u[14] = u[7] << 1; - u[15] = u[14] ^ u[1]; - - g = 0; - tmp1 = a & 0x0f; - - for (size_t i = 0; i < 16; ++i) { - tmp2 = tmp1 - i; - g ^= (u[i] & (uint64_t)(0 - (1 - ((uint64_t)(tmp2 | (0 - tmp2)) >> 63)))); - } - - l = g; - h = 0; - - // Step 2 - for (size_t i = 4; i < 64; i += 4) { - g = 0; - tmp1 = (a >> i) & 0x0f; - for (size_t j = 0; j < 16; ++j) { - tmp2 = tmp1 - j; - g ^= (u[j] & (uint64_t)(0 - (1 - ((uint64_t)(tmp2 | (0 - tmp2)) >> 63)))); - } - - l ^= g << i; - h ^= g >> (64 - i); - } - - // Step 3 - mask_tab [0] = 0 - ((b >> 60) & 1); - mask_tab [1] = 0 - ((b >> 61) & 1); - mask_tab [2] = 0 - ((b >> 62) & 1); - mask_tab [3] = 0 - ((b >> 63) & 1); - - l ^= ((a << 60) & mask_tab[0]); - h ^= ((a >> 4) & mask_tab[0]); - - l ^= ((a << 61) & mask_tab[1]); - h ^= ((a >> 3) & mask_tab[1]); - - l ^= ((a << 62) & mask_tab[2]); - h ^= ((a >> 2) & mask_tab[2]); - - l ^= ((a << 63) & mask_tab[3]); - h ^= ((a >> 1) & mask_tab[3]); - - c[0] = l; - c[1] = h; -} - -static void karatsuba_add1(uint64_t *alh, uint64_t *blh, const uint64_t *a, const uint64_t *b, size_t size_l, size_t size_h) { - for (size_t i = 0; i < size_h; ++i) { - alh[i] = a[i] ^ a[i + size_l]; - blh[i] = b[i] ^ b[i + size_l]; - } - - if (size_h < size_l) { - alh[size_h] = a[size_h]; - blh[size_h] = b[size_h]; - } -} - -static void karatsuba_add2(uint64_t *o, uint64_t *tmp1, const uint64_t *tmp2, size_t size_l, size_t size_h) { - for (size_t i = 0; i < (2 * size_l); ++i) { - tmp1[i] = tmp1[i] ^ o[i]; - } - - for (size_t i = 0; i < ( 2 * size_h); ++i) { - tmp1[i] = tmp1[i] ^ tmp2[i]; - } - - for (size_t i = 0; i < (2 * size_l); ++i) { - o[i + size_l] = o[i + size_l] ^ tmp1[i]; - } -} - -/** - * Karatsuba multiplication of a and b, Implementation inspired from the NTL library. - * - * @param[out] o Polynomial - * @param[in] a Polynomial - * @param[in] b Polynomial - * @param[in] size Length of polynomial - * @param[in] stack Length of polynomial - */ -static void karatsuba(uint64_t *o, const uint64_t *a, const uint64_t *b, size_t size, uint64_t *stack) { - size_t size_l, size_h; - const uint64_t *ah, *bh; - - if (size == 1) { - base_mul(o, a[0], b[0]); - return; - } - - size_h = size / 2; - size_l = (size + 1) / 2; - - uint64_t *alh = stack; - uint64_t *blh = alh + size_l; - uint64_t *tmp1 = blh + size_l; - uint64_t *tmp2 = o + 2 * size_l; - - stack += 4 * size_l; - - ah = a + size_l; - bh = b + size_l; - - karatsuba(o, a, b, size_l, stack); - - karatsuba(tmp2, ah, bh, size_h, stack); - - karatsuba_add1(alh, blh, a, b, size_l, size_h); - - karatsuba(tmp1, alh, blh, size_l, stack); - - karatsuba_add2(o, tmp1, tmp2, size_l, size_h); -} - -/** - * @brief Compute o(x) = a(x) mod \f$ X^n - 1\f$ - * - * This function computes the modular reduction of the polynomial a(x) - * - * @param[in] a Pointer to the polynomial a(x) - * @param[out] o Pointer to the result - */ -static void reduce(uint64_t *o, const uint64_t *a) { - uint64_t r; - uint64_t carry; - - for (size_t i = 0; i < VEC_N_SIZE_64; ++i) { - r = a[i + VEC_N_SIZE_64 - 1] >> (PARAM_N & 0x3F); - carry = a[i + VEC_N_SIZE_64] << (64 - (PARAM_N & 0x3F)); - o[i] = a[i] ^ r ^ carry; - } - - o[VEC_N_SIZE_64 - 1] &= RED_MASK; -} - -/** - * @brief Multiply two polynomials modulo \f$ X^n - 1\f$. - * - * This functions multiplies polynomials v1 and v2. - * The multiplication is done modulo \f$ X^n - 1\f$. - * - * @param[out] o Product of v1 and v2 - * @param[in] v1 Pointer to the first polynomial - * @param[in] v2 Pointer to the second polynomial - */ -void PQCLEAN_HQC256_CLEAN_vect_mul(uint64_t *o, const uint64_t *v1, const uint64_t *v2) { - uint64_t stack[VEC_N_SIZE_64 << 3] = {0}; - uint64_t o_karat[VEC_N_SIZE_64 << 1] = {0}; - - karatsuba(o_karat, v1, v2, VEC_N_SIZE_64, stack); - reduce(o, o_karat); -} diff --git a/src/kem/hqc/pqclean_hqc-256_clean/gf2x.h b/src/kem/hqc/pqclean_hqc-256_clean/gf2x.h deleted file mode 100644 index 0088672fde..0000000000 --- a/src/kem/hqc/pqclean_hqc-256_clean/gf2x.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef GF2X_H -#define GF2X_H -/** - * @file gf2x.h - * @brief Header file for gf2x.c - */ - -#include - -void PQCLEAN_HQC256_CLEAN_vect_mul(uint64_t *o, const uint64_t *v1, const uint64_t *v2); - - -#endif diff --git a/src/kem/hqc/pqclean_hqc-256_clean/hqc.c b/src/kem/hqc/pqclean_hqc-256_clean/hqc.c deleted file mode 100644 index dfa4787dea..0000000000 --- a/src/kem/hqc/pqclean_hqc-256_clean/hqc.c +++ /dev/null @@ -1,146 +0,0 @@ -#include "code.h" -#include "gf2x.h" -#include "hqc.h" -#include "parameters.h" -#include "parsing.h" -#include "randombytes.h" -#include "shake_prng.h" -#include "vector.h" -#include -/** - * @file hqc.c - * @brief Implementation of hqc.h - */ - - - -/** - * @brief Keygen of the HQC_PKE IND_CPA scheme - * - * The public key is composed of the syndrome s as well as the seed used to generate the vector h. - * - * The secret key is composed of the seed used to generate vectors x and y. - * As a technicality, the public key is appended to the secret key in order to respect NIST API. - * - * @param[out] pk String containing the public key - * @param[out] sk String containing the secret key - */ -void PQCLEAN_HQC256_CLEAN_hqc_pke_keygen(uint8_t *pk, uint8_t *sk) { - seedexpander_state sk_seedexpander; - seedexpander_state pk_seedexpander; - uint8_t sk_seed[SEED_BYTES] = {0}; - uint8_t sigma[VEC_K_SIZE_BYTES] = {0}; - uint8_t pk_seed[SEED_BYTES] = {0}; - uint64_t x[VEC_N_SIZE_64] = {0}; - uint64_t y[VEC_N_SIZE_64] = {0}; - uint64_t h[VEC_N_SIZE_64] = {0}; - uint64_t s[VEC_N_SIZE_64] = {0}; - - // Create seed_expanders for public key and secret key - randombytes(sk_seed, SEED_BYTES); - randombytes(sigma, VEC_K_SIZE_BYTES); - PQCLEAN_HQC256_CLEAN_seedexpander_init(&sk_seedexpander, sk_seed, SEED_BYTES); - - randombytes(pk_seed, SEED_BYTES); - PQCLEAN_HQC256_CLEAN_seedexpander_init(&pk_seedexpander, pk_seed, SEED_BYTES); - - // Compute secret key - PQCLEAN_HQC256_CLEAN_vect_set_random_fixed_weight(&sk_seedexpander, x, PARAM_OMEGA); - PQCLEAN_HQC256_CLEAN_vect_set_random_fixed_weight(&sk_seedexpander, y, PARAM_OMEGA); - - // Compute public key - PQCLEAN_HQC256_CLEAN_vect_set_random(&pk_seedexpander, h); - PQCLEAN_HQC256_CLEAN_vect_mul(s, y, h); - PQCLEAN_HQC256_CLEAN_vect_add(s, x, s, VEC_N_SIZE_64); - - // Parse keys to string - PQCLEAN_HQC256_CLEAN_hqc_public_key_to_string(pk, pk_seed, s); - PQCLEAN_HQC256_CLEAN_hqc_secret_key_to_string(sk, sk_seed, sigma, pk); - - PQCLEAN_HQC256_CLEAN_seedexpander_release(&pk_seedexpander); - PQCLEAN_HQC256_CLEAN_seedexpander_release(&sk_seedexpander); -} - - - -/** - * @brief Encryption of the HQC_PKE IND_CPA scheme - * - * The cihertext is composed of vectors u and v. - * - * @param[out] u Vector u (first part of the ciphertext) - * @param[out] v Vector v (second part of the ciphertext) - * @param[in] m Vector representing the message to encrypt - * @param[in] theta Seed used to derive randomness required for encryption - * @param[in] pk String containing the public key - */ -void PQCLEAN_HQC256_CLEAN_hqc_pke_encrypt(uint64_t *u, uint64_t *v, uint8_t *m, uint8_t *theta, const uint8_t *pk) { - seedexpander_state vec_seedexpander; - uint64_t h[VEC_N_SIZE_64] = {0}; - uint64_t s[VEC_N_SIZE_64] = {0}; - uint64_t r1[VEC_N_SIZE_64] = {0}; - uint64_t r2[VEC_N_SIZE_64] = {0}; - uint64_t e[VEC_N_SIZE_64] = {0}; - uint64_t tmp1[VEC_N_SIZE_64] = {0}; - uint64_t tmp2[VEC_N_SIZE_64] = {0}; - - // Create seed_expander from theta - PQCLEAN_HQC256_CLEAN_seedexpander_init(&vec_seedexpander, theta, SEED_BYTES); - - // Retrieve h and s from public key - PQCLEAN_HQC256_CLEAN_hqc_public_key_from_string(h, s, pk); - - // Generate r1, r2 and e - PQCLEAN_HQC256_CLEAN_vect_set_random_fixed_weight(&vec_seedexpander, r1, PARAM_OMEGA_R); - PQCLEAN_HQC256_CLEAN_vect_set_random_fixed_weight(&vec_seedexpander, r2, PARAM_OMEGA_R); - PQCLEAN_HQC256_CLEAN_vect_set_random_fixed_weight(&vec_seedexpander, e, PARAM_OMEGA_E); - - // Compute u = r1 + r2.h - PQCLEAN_HQC256_CLEAN_vect_mul(u, r2, h); - PQCLEAN_HQC256_CLEAN_vect_add(u, r1, u, VEC_N_SIZE_64); - - // Compute v = m.G by encoding the message - PQCLEAN_HQC256_CLEAN_code_encode(v, m); - PQCLEAN_HQC256_CLEAN_vect_resize(tmp1, PARAM_N, v, PARAM_N1N2); - - // Compute v = m.G + s.r2 + e - PQCLEAN_HQC256_CLEAN_vect_mul(tmp2, r2, s); - PQCLEAN_HQC256_CLEAN_vect_add(tmp2, e, tmp2, VEC_N_SIZE_64); - PQCLEAN_HQC256_CLEAN_vect_add(tmp2, tmp1, tmp2, VEC_N_SIZE_64); - PQCLEAN_HQC256_CLEAN_vect_resize(v, PARAM_N1N2, tmp2, PARAM_N); - - PQCLEAN_HQC256_CLEAN_seedexpander_release(&vec_seedexpander); -} - - - -/** - * @brief Decryption of the HQC_PKE IND_CPA scheme - * - * @param[out] m Vector representing the decrypted message - * @param[in] u Vector u (first part of the ciphertext) - * @param[in] v Vector v (second part of the ciphertext) - * @param[in] sk String containing the secret key - * @returns 0 - */ -uint8_t PQCLEAN_HQC256_CLEAN_hqc_pke_decrypt(uint8_t *m, uint8_t *sigma, const uint64_t *u, const uint64_t *v, const uint8_t *sk) { - uint64_t x[VEC_N_SIZE_64] = {0}; - uint64_t y[VEC_N_SIZE_64] = {0}; - uint8_t pk[PUBLIC_KEY_BYTES] = {0}; - uint64_t tmp1[VEC_N_SIZE_64] = {0}; - uint64_t tmp2[VEC_N_SIZE_64] = {0}; - - // Retrieve x, y, pk from secret key - PQCLEAN_HQC256_CLEAN_hqc_secret_key_from_string(x, y, sigma, pk, sk); - - // Compute v - u.y - PQCLEAN_HQC256_CLEAN_vect_resize(tmp1, PARAM_N, v, PARAM_N1N2); - PQCLEAN_HQC256_CLEAN_vect_mul(tmp2, y, u); - PQCLEAN_HQC256_CLEAN_vect_add(tmp2, tmp1, tmp2, VEC_N_SIZE_64); - - - // Compute m by decoding v - u.y - PQCLEAN_HQC256_CLEAN_code_decode(m, tmp2); - - return 0; -} diff --git a/src/kem/hqc/pqclean_hqc-256_clean/hqc.h b/src/kem/hqc/pqclean_hqc-256_clean/hqc.h deleted file mode 100644 index 34dd4cfadd..0000000000 --- a/src/kem/hqc/pqclean_hqc-256_clean/hqc.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef HQC_H -#define HQC_H - - -/** - * @file hqc.h - * @brief Functions of the HQC_PKE IND_CPA scheme - */ - -#include - -void PQCLEAN_HQC256_CLEAN_hqc_pke_keygen(uint8_t *pk, uint8_t *sk); - -void PQCLEAN_HQC256_CLEAN_hqc_pke_encrypt(uint64_t *u, uint64_t *v, uint8_t *m, unsigned char *theta, const unsigned char *pk); - -uint8_t PQCLEAN_HQC256_CLEAN_hqc_pke_decrypt(uint8_t *m, uint8_t *sigma, const uint64_t *u, const uint64_t *v, const unsigned char *sk); - - -#endif diff --git a/src/kem/hqc/pqclean_hqc-256_clean/kem.c b/src/kem/hqc/pqclean_hqc-256_clean/kem.c deleted file mode 100644 index 2929ba08e0..0000000000 --- a/src/kem/hqc/pqclean_hqc-256_clean/kem.c +++ /dev/null @@ -1,138 +0,0 @@ -#include "api.h" -#include "domains.h" -#include "fips202.h" -#include "hqc.h" -#include "parameters.h" -#include "parsing.h" -#include "randombytes.h" -#include "shake_ds.h" -#include "vector.h" -#include -#include -/** - * @file kem.c - * @brief Implementation of api.h - */ - - - -/** - * @brief Keygen of the HQC_KEM IND_CAA2 scheme - * - * The public key is composed of the syndrome s as well as the seed used to generate the vector h. - * - * The secret key is composed of the seed used to generate vectors x and y. - * As a technicality, the public key is appended to the secret key in order to respect NIST API. - * - * @param[out] pk String containing the public key - * @param[out] sk String containing the secret key - * @returns 0 if keygen is successful - */ -int PQCLEAN_HQC256_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk) { - - PQCLEAN_HQC256_CLEAN_hqc_pke_keygen(pk, sk); - return 0; -} - - - -/** - * @brief Encapsulation of the HQC_KEM IND_CAA2 scheme - * - * @param[out] ct String containing the ciphertext - * @param[out] ss String containing the shared secret - * @param[in] pk String containing the public key - * @returns 0 if encapsulation is successful - */ -int PQCLEAN_HQC256_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk) { - - uint8_t theta[SHAKE256_512_BYTES] = {0}; - uint64_t u[VEC_N_SIZE_64] = {0}; - uint64_t v[VEC_N1N2_SIZE_64] = {0}; - uint8_t mc[VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES] = {0}; - uint8_t tmp[VEC_K_SIZE_BYTES + PUBLIC_KEY_BYTES + SALT_SIZE_BYTES] = {0}; - uint8_t *m = tmp; - uint8_t *salt = tmp + VEC_K_SIZE_BYTES + PUBLIC_KEY_BYTES; - shake256incctx shake256state; - - // Computing m - randombytes(m, VEC_K_SIZE_BYTES); - - // Computing theta - randombytes(salt, SALT_SIZE_BYTES); - memcpy(tmp + VEC_K_SIZE_BYTES, pk, PUBLIC_KEY_BYTES); - PQCLEAN_HQC256_CLEAN_shake256_512_ds(&shake256state, theta, tmp, VEC_K_SIZE_BYTES + PUBLIC_KEY_BYTES + SALT_SIZE_BYTES, G_FCT_DOMAIN); - - // Encrypting m - PQCLEAN_HQC256_CLEAN_hqc_pke_encrypt(u, v, m, theta, pk); - - // Computing shared secret - memcpy(mc, m, VEC_K_SIZE_BYTES); - PQCLEAN_HQC256_CLEAN_store8_arr(mc + VEC_K_SIZE_BYTES, VEC_N_SIZE_BYTES, u, VEC_N_SIZE_64); - PQCLEAN_HQC256_CLEAN_store8_arr(mc + VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES, VEC_N1N2_SIZE_BYTES, v, VEC_N1N2_SIZE_64); - PQCLEAN_HQC256_CLEAN_shake256_512_ds(&shake256state, ss, mc, VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES, K_FCT_DOMAIN); - - // Computing ciphertext - PQCLEAN_HQC256_CLEAN_hqc_ciphertext_to_string(ct, u, v, salt); - - - return 0; -} - - - -/** - * @brief Decapsulation of the HQC_KEM IND_CAA2 scheme - * - * @param[out] ss String containing the shared secret - * @param[in] ct String containing the cipĥertext - * @param[in] sk String containing the secret key - * @returns 0 if decapsulation is successful, -1 otherwise - */ -int PQCLEAN_HQC256_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) { - - uint8_t result; - uint64_t u[VEC_N_SIZE_64] = {0}; - uint64_t v[VEC_N1N2_SIZE_64] = {0}; - const uint8_t *pk = sk + SEED_BYTES + VEC_K_SIZE_BYTES; - uint8_t sigma[VEC_K_SIZE_BYTES] = {0}; - uint8_t theta[SHAKE256_512_BYTES] = {0}; - uint64_t u2[VEC_N_SIZE_64] = {0}; - uint64_t v2[VEC_N1N2_SIZE_64] = {0}; - uint8_t mc[VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES] = {0}; - uint8_t tmp[VEC_K_SIZE_BYTES + PUBLIC_KEY_BYTES + SALT_SIZE_BYTES] = {0}; - uint8_t *m = tmp; - uint8_t *salt = tmp + VEC_K_SIZE_BYTES + PUBLIC_KEY_BYTES; - shake256incctx shake256state; - - // Retrieving u, v and d from ciphertext - PQCLEAN_HQC256_CLEAN_hqc_ciphertext_from_string(u, v, salt, ct); - - // Decrypting - result = PQCLEAN_HQC256_CLEAN_hqc_pke_decrypt(m, sigma, u, v, sk); - - // Computing theta - memcpy(tmp + VEC_K_SIZE_BYTES, pk, PUBLIC_KEY_BYTES); - PQCLEAN_HQC256_CLEAN_shake256_512_ds(&shake256state, theta, tmp, VEC_K_SIZE_BYTES + PUBLIC_KEY_BYTES + SALT_SIZE_BYTES, G_FCT_DOMAIN); - - // Encrypting m' - PQCLEAN_HQC256_CLEAN_hqc_pke_encrypt(u2, v2, m, theta, pk); - - // Check if c != c' - result |= PQCLEAN_HQC256_CLEAN_vect_compare((uint8_t *)u, (uint8_t *)u2, VEC_N_SIZE_BYTES); - result |= PQCLEAN_HQC256_CLEAN_vect_compare((uint8_t *)v, (uint8_t *)v2, VEC_N1N2_SIZE_BYTES); - - result -= 1; - - for (size_t i = 0; i < VEC_K_SIZE_BYTES; ++i) { - mc[i] = (m[i] & result) ^ (sigma[i] & ~result); - } - - // Computing shared secret - PQCLEAN_HQC256_CLEAN_store8_arr(mc + VEC_K_SIZE_BYTES, VEC_N_SIZE_BYTES, u, VEC_N_SIZE_64); - PQCLEAN_HQC256_CLEAN_store8_arr(mc + VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES, VEC_N1N2_SIZE_BYTES, v, VEC_N1N2_SIZE_64); - PQCLEAN_HQC256_CLEAN_shake256_512_ds(&shake256state, ss, mc, VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES, K_FCT_DOMAIN); - - - return (result & 1) - 1; -} diff --git a/src/kem/hqc/pqclean_hqc-256_clean/parameters.h b/src/kem/hqc/pqclean_hqc-256_clean/parameters.h deleted file mode 100644 index 725ff3758c..0000000000 --- a/src/kem/hqc/pqclean_hqc-256_clean/parameters.h +++ /dev/null @@ -1,96 +0,0 @@ -#ifndef HQC_PARAMETERS_H -#define HQC_PARAMETERS_H - - -/** - * @file parameters.h - * @brief Parameters of the HQC_KEM IND-CCA2 scheme - */ -#include "api.h" - - -#define CEIL_DIVIDE(a, b) (((a)+(b)-1)/(b)) /*!< Divide a by b and ceil the result*/ - -/* - #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_N1Y_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 -*/ - -#define PARAM_N 57637 -#define PARAM_N1 90 -#define PARAM_N2 640 -#define PARAM_N1N2 57600 -#define PARAM_OMEGA 131 -#define PARAM_OMEGA_E 149 -#define PARAM_OMEGA_R 149 - -#define SECRET_KEY_BYTES PQCLEAN_HQC256_CLEAN_CRYPTO_SECRETKEYBYTES -#define PUBLIC_KEY_BYTES PQCLEAN_HQC256_CLEAN_CRYPTO_PUBLICKEYBYTES -#define SHARED_SECRET_BYTES PQCLEAN_HQC256_CLEAN_CRYPTO_BYTES -#define CIPHERTEXT_BYTES PQCLEAN_HQC256_CLEAN_CRYPTO_CIPHERTEXTBYTES - -#define VEC_N_SIZE_BYTES CEIL_DIVIDE(PARAM_N, 8) -#define VEC_K_SIZE_BYTES PARAM_K -#define VEC_N1_SIZE_BYTES PARAM_N1 -#define VEC_N1N2_SIZE_BYTES CEIL_DIVIDE(PARAM_N1N2, 8) - -#define VEC_N_SIZE_64 CEIL_DIVIDE(PARAM_N, 64) -#define VEC_K_SIZE_64 CEIL_DIVIDE(PARAM_K, 8) -#define VEC_N1_SIZE_64 CEIL_DIVIDE(PARAM_N1, 8) -#define VEC_N1N2_SIZE_64 CEIL_DIVIDE(PARAM_N1N2, 64) - -#define PARAM_DELTA 29 -#define PARAM_M 8 -#define PARAM_GF_POLY 0x11D -#define PARAM_GF_POLY_WT 5 -#define PARAM_GF_POLY_M2 4 -#define PARAM_GF_MUL_ORDER 255 -#define PARAM_K 32 -#define PARAM_G 59 -#define PARAM_FFT 5 -#define 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 RED_MASK 0x1fffffffff -#define SHAKE256_512_BYTES 64 -#define SEED_BYTES 40 -#define SALT_SIZE_BYTES 16 - -#endif diff --git a/src/kem/hqc/pqclean_hqc-256_clean/parsing.c b/src/kem/hqc/pqclean_hqc-256_clean/parsing.c deleted file mode 100644 index fb34da7aba..0000000000 --- a/src/kem/hqc/pqclean_hqc-256_clean/parsing.c +++ /dev/null @@ -1,173 +0,0 @@ -#include "parameters.h" -#include "parsing.h" -#include "vector.h" -#include -#include -/** - * @file parsing.c - * @brief Functions to parse secret key, public key and ciphertext of the HQC scheme - */ - - -static uint64_t load8(const uint8_t *in) { - uint64_t ret = in[7]; - - for (int8_t i = 6; i >= 0; --i) { - ret <<= 8; - ret |= in[i]; - } - - return ret; -} - -void PQCLEAN_HQC256_CLEAN_load8_arr(uint64_t *out64, size_t outlen, const uint8_t *in8, size_t inlen) { - size_t index_in = 0; - size_t index_out = 0; - - // first copy by 8 bytes - if (inlen >= 8 && outlen >= 1) { - while (index_out < outlen && index_in + 8 <= inlen) { - out64[index_out] = load8(in8 + index_in); - - index_in += 8; - index_out += 1; - } - } - - // we now need to do the last 7 bytes if necessary - if (index_in >= inlen || index_out >= outlen) { - return; - } - out64[index_out] = in8[inlen - 1]; - for (int8_t i = (int8_t)(inlen - index_in) - 2; i >= 0; --i) { - out64[index_out] <<= 8; - out64[index_out] |= in8[index_in + i]; - } -} - -void PQCLEAN_HQC256_CLEAN_store8_arr(uint8_t *out8, size_t outlen, const uint64_t *in64, size_t inlen) { - for (size_t index_out = 0, index_in = 0; index_out < outlen && index_in < inlen;) { - out8[index_out] = (in64[index_in] >> ((index_out % 8) * 8)) & 0xFF; - ++index_out; - if (index_out % 8 == 0) { - ++index_in; - } - } -} - -/** - * @brief Parse a secret key into a string - * - * The secret key is composed of the seed used to generate vectors x and y. - * As technicality, the public key is appended to the secret key in order to respect NIST API. - * - * @param[out] sk String containing the secret key - * @param[in] sk_seed Seed used to generate the secret key - * @param[in] sigma String used in HHK transform - * @param[in] pk String containing the public key - */ -void PQCLEAN_HQC256_CLEAN_hqc_secret_key_to_string(uint8_t *sk, const uint8_t *sk_seed, const uint8_t *sigma, const uint8_t *pk) { - memcpy(sk, sk_seed, SEED_BYTES); - memcpy(sk + SEED_BYTES, sigma, VEC_K_SIZE_BYTES); - memcpy(sk + SEED_BYTES + VEC_K_SIZE_BYTES, pk, PUBLIC_KEY_BYTES); -} - - - -/** - * @brief Parse a secret key from a string - * - * The secret key is composed of the seed used to generate vectors x and y. - * As technicality, the public key is appended to the secret key in order to respect NIST API. - * - * @param[out] x uint64_t representation of vector x - * @param[out] y uint64_t representation of vector y - * @param[out] pk String containing the public key - * @param[in] sk String containing the secret key - */ -void PQCLEAN_HQC256_CLEAN_hqc_secret_key_from_string(uint64_t *x, uint64_t *y, uint8_t *sigma, uint8_t *pk, const uint8_t *sk) { - seedexpander_state sk_seedexpander; - - memcpy(sigma, sk + SEED_BYTES, VEC_K_SIZE_BYTES); - PQCLEAN_HQC256_CLEAN_seedexpander_init(&sk_seedexpander, sk, SEED_BYTES); - - PQCLEAN_HQC256_CLEAN_vect_set_random_fixed_weight(&sk_seedexpander, x, PARAM_OMEGA); - PQCLEAN_HQC256_CLEAN_vect_set_random_fixed_weight(&sk_seedexpander, y, PARAM_OMEGA); - memcpy(pk, sk + SEED_BYTES + VEC_K_SIZE_BYTES, PUBLIC_KEY_BYTES); - - PQCLEAN_HQC256_CLEAN_seedexpander_release(&sk_seedexpander); -} - - - -/** - * @brief Parse a public key into a string - * - * The public key is composed of the syndrome s as well as the seed used to generate the vector h - * - * @param[out] pk String containing the public key - * @param[in] pk_seed Seed used to generate the public key - * @param[in] s uint64_t representation of vector s - */ -void PQCLEAN_HQC256_CLEAN_hqc_public_key_to_string(uint8_t *pk, const uint8_t *pk_seed, const uint64_t *s) { - memcpy(pk, pk_seed, SEED_BYTES); - PQCLEAN_HQC256_CLEAN_store8_arr(pk + SEED_BYTES, VEC_N_SIZE_BYTES, s, VEC_N_SIZE_64); -} - - - -/** - * @brief Parse a public key from a string - * - * The public key is composed of the syndrome s as well as the seed used to generate the vector h - * - * @param[out] h uint64_t representation of vector h - * @param[out] s uint64_t representation of vector s - * @param[in] pk String containing the public key - */ -void PQCLEAN_HQC256_CLEAN_hqc_public_key_from_string(uint64_t *h, uint64_t *s, const uint8_t *pk) { - seedexpander_state pk_seedexpander; - - PQCLEAN_HQC256_CLEAN_seedexpander_init(&pk_seedexpander, pk, SEED_BYTES); - PQCLEAN_HQC256_CLEAN_vect_set_random(&pk_seedexpander, h); - - PQCLEAN_HQC256_CLEAN_load8_arr(s, VEC_N_SIZE_64, pk + SEED_BYTES, VEC_N_SIZE_BYTES); - - PQCLEAN_HQC256_CLEAN_seedexpander_release(&pk_seedexpander); -} - - - -/** - * @brief Parse a ciphertext into a string - * - * The ciphertext is composed of vectors u, v and salt. - * - * @param[out] ct String containing the ciphertext - * @param[in] u uint64_t representation of vector u - * @param[in] v uint64_t representation of vector v - * @param[in] salt String containing a salt - */ -void PQCLEAN_HQC256_CLEAN_hqc_ciphertext_to_string(uint8_t *ct, const uint64_t *u, const uint64_t *v, const uint8_t *salt) { - PQCLEAN_HQC256_CLEAN_store8_arr(ct, VEC_N_SIZE_BYTES, u, VEC_N_SIZE_64); - PQCLEAN_HQC256_CLEAN_store8_arr(ct + VEC_N_SIZE_BYTES, VEC_N1N2_SIZE_BYTES, v, VEC_N1N2_SIZE_64); - memcpy(ct + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES, salt, SALT_SIZE_BYTES); -} - - - -/** - * @brief Parse a ciphertext from a string - * - * The ciphertext is composed of vectors u, v and salt. - * - * @param[out] u uint64_t representation of vector u - * @param[out] v uint64_t representation of vector v - * @param[out] d String containing the hash d - * @param[in] ct String containing the ciphertext - */ -void PQCLEAN_HQC256_CLEAN_hqc_ciphertext_from_string(uint64_t *u, uint64_t *v, uint8_t *salt, const uint8_t *ct) { - PQCLEAN_HQC256_CLEAN_load8_arr(u, VEC_N_SIZE_64, ct, VEC_N_SIZE_BYTES); - PQCLEAN_HQC256_CLEAN_load8_arr(v, VEC_N1N2_SIZE_64, ct + VEC_N_SIZE_BYTES, VEC_N1N2_SIZE_BYTES); - memcpy(salt, ct + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES, SALT_SIZE_BYTES); -} diff --git a/src/kem/hqc/pqclean_hqc-256_clean/parsing.h b/src/kem/hqc/pqclean_hqc-256_clean/parsing.h deleted file mode 100644 index b00abe4fab..0000000000 --- a/src/kem/hqc/pqclean_hqc-256_clean/parsing.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef PARSING_H -#define PARSING_H - - -/** - * @file parsing.h - * @brief Header file for parsing.c - */ - -#include -#include - -void PQCLEAN_HQC256_CLEAN_load8_arr(uint64_t *out64, size_t outlen, const uint8_t *in8, size_t inlen); - -void PQCLEAN_HQC256_CLEAN_store8_arr(uint8_t *out8, size_t outlen, const uint64_t *in64, size_t inlen); - - -void PQCLEAN_HQC256_CLEAN_hqc_secret_key_to_string(uint8_t *sk, const uint8_t *sk_seed, const uint8_t *sigma, const uint8_t *pk); - -void PQCLEAN_HQC256_CLEAN_hqc_secret_key_from_string(uint64_t *x, uint64_t *y, uint8_t *sigma, uint8_t *pk, const uint8_t *sk); - - -void PQCLEAN_HQC256_CLEAN_hqc_public_key_to_string(uint8_t *pk, const uint8_t *pk_seed, const uint64_t *s); - -void PQCLEAN_HQC256_CLEAN_hqc_public_key_from_string(uint64_t *h, uint64_t *s, const uint8_t *pk); - - -void PQCLEAN_HQC256_CLEAN_hqc_ciphertext_to_string(uint8_t *ct, const uint64_t *u, const uint64_t *v, const uint8_t *salt); - -void PQCLEAN_HQC256_CLEAN_hqc_ciphertext_from_string(uint64_t *u, uint64_t *v, uint8_t *salt, const uint8_t *ct); - - -#endif diff --git a/src/kem/hqc/pqclean_hqc-256_clean/reed_muller.c b/src/kem/hqc/pqclean_hqc-256_clean/reed_muller.c deleted file mode 100644 index 9e8101cd12..0000000000 --- a/src/kem/hqc/pqclean_hqc-256_clean/reed_muller.c +++ /dev/null @@ -1,193 +0,0 @@ -#include "parameters.h" -#include "reed_muller.h" -#include -#include -/** - * @file reed_muller.c - * @brief Constant time implementation of Reed-Muller code RM(1,7) - */ - - -// number of repeated code words -#define MULTIPLICITY CEIL_DIVIDE(PARAM_N2, 128) - -// copy bit 0 into all bits of a 32 bit value -#define BIT0MASK(x) (uint32_t)(-((x) & 1)) - -/** - * @brief Encode a single byte into a single codeword using RM(1,7) - * - * Encoding matrix of this code: - * bit pattern (note that bits are numbered big endian) - * 0 aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa - * 1 cccccccc cccccccc cccccccc cccccccc - * 2 f0f0f0f0 f0f0f0f0 f0f0f0f0 f0f0f0f0 - * 3 ff00ff00 ff00ff00 ff00ff00 ff00ff00 - * 4 ffff0000 ffff0000 ffff0000 ffff0000 - * 5 ffffffff 00000000 ffffffff 00000000 - * 6 ffffffff ffffffff 00000000 00000000 - * 7 ffffffff ffffffff ffffffff ffffffff - * - * @param[out] word An RM(1,7) codeword - * @param[in] message A message - */ -static void encode(uint64_t *cword, uint8_t message) { - uint32_t first_word; - // bit 7 flips all the bits, do that first to save work - first_word = BIT0MASK(message >> 7); - // bits 0, 1, 2, 3, 4 are the same for all four longs - // (Warning: in the bit matrix above, low bits are at the left!) - first_word ^= BIT0MASK(message >> 0) & 0xaaaaaaaa; - first_word ^= BIT0MASK(message >> 1) & 0xcccccccc; - first_word ^= BIT0MASK(message >> 2) & 0xf0f0f0f0; - first_word ^= BIT0MASK(message >> 3) & 0xff00ff00; - first_word ^= BIT0MASK(message >> 4) & 0xffff0000; - // we can store this in the first quarter - cword[0] = first_word; - // bit 5 flips entries 1 and 3; bit 6 flips 2 and 3 - first_word ^= BIT0MASK(message >> 5); - cword[0] |= (uint64_t)first_word << 32; - first_word ^= BIT0MASK(message >> 6); - cword[1] = (uint64_t)first_word << 32; - first_word ^= BIT0MASK(message >> 5); - cword[1] |= first_word; -} - - - -/** - * @brief Hadamard transform - * - * Perform hadamard transform of src and store result in dst - * src is overwritten - * - * @param[out] src Structure that contain the expanded codeword - * @param[out] dst Structure that contain the expanded codeword - */ -static void hadamard(uint16_t src[128], uint16_t dst[128]) { - // the passes move data: - // src -> dst -> src -> dst -> src -> dst -> src -> dst - // using p1 and p2 alternately - uint16_t *p1 = src; - uint16_t *p2 = dst; - uint16_t *p3; - for (size_t pass = 0; pass < 7; ++pass) { - for (size_t i = 0; i < 64; ++i) { - p2[i] = p1[2 * i] + p1[2 * i + 1]; - p2[i + 64] = p1[2 * i] - p1[2 * i + 1]; - } - // swap p1, p2 for next round - p3 = p1; - p1 = p2; - p2 = p3; - } -} - - - -/** - * @brief Add multiple codewords into expanded codeword - * - * Accesses memory in order - * Note: this does not write the codewords as -1 or +1 as the green machine does - * instead, just 0 and 1 is used. - * The resulting hadamard transform has: - * all values are halved - * the first entry is 64 too high - * - * @param[out] dest Structure that contain the expanded codeword - * @param[in] src Structure that contain the codeword - */ -static void expand_and_sum(uint16_t dest[128], const uint64_t src[2 * MULTIPLICITY]) { - // start with the first copy - for (size_t part = 0; part < 2; ++part) { - for (size_t bit = 0; bit < 64; ++bit) { - dest[part * 64 + bit] = ((src[part] >> bit) & 1); - } - } - // sum the rest of the copies - for (size_t copy = 1; copy < MULTIPLICITY; ++copy) { - for (size_t part = 0; part < 2; ++part) { - for (size_t bit = 0; bit < 64; ++bit) { - dest[part * 64 + bit] += (uint16_t) ((src[2 * copy + part] >> bit) & 1); - } - } - } -} - - - -/** - * @brief Finding the location of the highest value - * - * This is the final step of the green machine: find the location of the highest value, - * and add 128 if the peak is positive - * if there are two identical peaks, the peak with smallest value - * in the lowest 7 bits it taken - * @param[in] transform Structure that contain the expanded codeword - */ -static uint8_t find_peaks(const uint16_t transform[128]) { - uint16_t peak_abs = 0; - uint16_t peak = 0; - uint16_t pos = 0; - uint16_t t, abs, mask; - for (uint16_t i = 0; i < 128; ++i) { - t = transform[i]; - abs = t ^ ((uint16_t)(-(t >> 15)) & (t ^ -t)); // t = abs(t) - mask = -(((uint16_t)(peak_abs - abs)) >> 15); - peak ^= mask & (peak ^ t); - pos ^= mask & (pos ^ i); - peak_abs ^= mask & (peak_abs ^ abs); - } - // set bit 7 - pos |= 128 & (uint16_t)((peak >> 15) - 1); - return (uint8_t) pos; -} - - - -/** - * @brief Encodes the received word - * - * The message consists of N1 bytes each byte is encoded into PARAM_N2 bits, - * or MULTIPLICITY repeats of 128 bits - * - * @param[out] cdw Array of size VEC_N1N2_SIZE_64 receiving the encoded message - * @param[in] msg Array of size VEC_N1_SIZE_64 storing the message - */ -void PQCLEAN_HQC256_CLEAN_reed_muller_encode(uint64_t *cdw, const uint8_t *msg) { - for (size_t i = 0; i < VEC_N1_SIZE_BYTES; ++i) { - // encode first word - encode(&cdw[2 * i * MULTIPLICITY], msg[i]); - // copy to other identical codewords - for (size_t copy = 1; copy < MULTIPLICITY; ++copy) { - memcpy(&cdw[2 * i * MULTIPLICITY + 2 * copy], &cdw[2 * i * MULTIPLICITY], 16); - } - } -} - - - -/** - * @brief Decodes the received word - * - * Decoding uses fast hadamard transform, for a more complete picture on Reed-Muller decoding, see MacWilliams, Florence Jessie, and Neil James Alexander Sloane. - * The theory of error-correcting codes codes @cite macwilliams1977theory - * - * @param[out] msg Array of size VEC_N1_SIZE_64 receiving the decoded message - * @param[in] cdw Array of size VEC_N1N2_SIZE_64 storing the received word - */ -void PQCLEAN_HQC256_CLEAN_reed_muller_decode(uint8_t *msg, const uint64_t *cdw) { - uint16_t expanded[128]; - uint16_t transform[128]; - for (size_t i = 0; i < VEC_N1_SIZE_BYTES; ++i) { - // collect the codewords - expand_and_sum(expanded, &cdw[2 * i * MULTIPLICITY]); - // apply hadamard transform - hadamard(expanded, transform); - // fix the first entry to get the half Hadamard transform - transform[0] -= 64 * MULTIPLICITY; - // finish the decoding - msg[i] = find_peaks(transform); - } -} diff --git a/src/kem/hqc/pqclean_hqc-256_clean/reed_muller.h b/src/kem/hqc/pqclean_hqc-256_clean/reed_muller.h deleted file mode 100644 index 00b83b0669..0000000000 --- a/src/kem/hqc/pqclean_hqc-256_clean/reed_muller.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef REED_MULLER_H -#define REED_MULLER_H - - -/** - * @file reed_muller.h - * @brief Header file of reed_muller.c - */ - -#include - -void PQCLEAN_HQC256_CLEAN_reed_muller_encode(uint64_t *cdw, const uint8_t *msg); - -void PQCLEAN_HQC256_CLEAN_reed_muller_decode(uint8_t *msg, const uint64_t *cdw); - - -#endif diff --git a/src/kem/hqc/pqclean_hqc-256_clean/reed_solomon.c b/src/kem/hqc/pqclean_hqc-256_clean/reed_solomon.c deleted file mode 100644 index 7d742dee73..0000000000 --- a/src/kem/hqc/pqclean_hqc-256_clean/reed_solomon.c +++ /dev/null @@ -1,335 +0,0 @@ -#include "fft.h" -#include "gf.h" -#include "parameters.h" -#include "reed_solomon.h" -#include -#include -/** - * @file reed_solomon.c - * @brief Constant time implementation of Reed-Solomon codes - */ - - -/** - * @brief Encodes a message message of PARAM_K bits to a Reed-Solomon codeword codeword of PARAM_N1 bytes - * - * Following @cite lin1983error (Chapter 4 - Cyclic Codes), - * We perform a systematic encoding using a linear (PARAM_N1 - PARAM_K)-stage shift register - * with feedback connections based on the generator polynomial PARAM_RS_POLY of the Reed-Solomon code. - * - * @param[out] cdw Array of size VEC_N1_SIZE_64 receiving the encoded message - * @param[in] msg Array of size VEC_K_SIZE_64 storing the message - */ -void PQCLEAN_HQC256_CLEAN_reed_solomon_encode(uint8_t *cdw, const uint8_t *msg) { - uint8_t gate_value = 0; - - uint16_t tmp[PARAM_G] = {0}; - uint16_t PARAM_RS_POLY [] = {RS_POLY_COEFS}; - - memset(cdw, 0, PARAM_N1); - - for (size_t i = 0; i < PARAM_K; ++i) { - gate_value = msg[PARAM_K - 1 - i] ^ cdw[PARAM_N1 - PARAM_K - 1]; - - for (size_t j = 0; j < PARAM_G; ++j) { - tmp[j] = PQCLEAN_HQC256_CLEAN_gf_mul(gate_value, PARAM_RS_POLY[j]); - } - - for (size_t k = PARAM_N1 - PARAM_K - 1; k; --k) { - cdw[k] = (uint8_t)(cdw[k - 1] ^ tmp[k]); - } - - cdw[0] = (uint8_t)tmp[0]; - } - - memcpy(cdw + PARAM_N1 - PARAM_K, msg, PARAM_K); -} - - - -/** - * @brief Computes 2 * PARAM_DELTA syndromes - * - * @param[out] syndromes Array of size 2 * PARAM_DELTA receiving the computed syndromes - * @param[in] cdw Array of size PARAM_N1 storing the received vector - */ -static void compute_syndromes(uint16_t *syndromes, uint8_t *cdw) { - for (size_t i = 0; i < 2 * PARAM_DELTA; ++i) { - for (size_t j = 1; j < PARAM_N1; ++j) { - syndromes[i] ^= PQCLEAN_HQC256_CLEAN_gf_mul(cdw[j], alpha_ij_pow[i][j - 1]); - } - syndromes[i] ^= cdw[0]; - } -} - - - -/** - * @brief Computes the error locator polynomial (ELP) sigma - * - * This is a constant time implementation of Berlekamp's simplified algorithm (see @cite lin1983error (Chapter 6 - BCH Codes).
- * We use the letter p for rho which is initialized at -1.
- * The array X_sigma_p represents the polynomial X^(mu-rho)*sigma_p(X).
- * Instead of maintaining a list of sigmas, we update in place both sigma and X_sigma_p.
- * sigma_copy serves as a temporary save of sigma in case X_sigma_p needs to be updated.
- * We can properly correct only if the degree of sigma does not exceed PARAM_DELTA. - * This means only the first PARAM_DELTA + 1 coefficients of sigma are of value - * and we only need to save its first PARAM_DELTA - 1 coefficients. - * - * @returns the degree of the ELP sigma - * @param[out] sigma Array of size (at least) PARAM_DELTA receiving the ELP - * @param[in] syndromes Array of size (at least) 2*PARAM_DELTA storing the syndromes - */ -static uint16_t compute_elp(uint16_t *sigma, const uint16_t *syndromes) { - uint16_t deg_sigma = 0; - uint16_t deg_sigma_p = 0; - uint16_t deg_sigma_copy = 0; - uint16_t sigma_copy[PARAM_DELTA + 1] = {0}; - uint16_t X_sigma_p[PARAM_DELTA + 1] = {0, 1}; - uint16_t pp = (uint16_t) -1; // 2*rho - uint16_t d_p = 1; - uint16_t d = syndromes[0]; - - uint16_t mask1, mask2, mask12; - uint16_t deg_X, deg_X_sigma_p; - uint16_t dd; - uint16_t mu; - - uint16_t i; - - sigma[0] = 1; - for (mu = 0; (mu < (2 * PARAM_DELTA)); ++mu) { - // Save sigma in case we need it to update X_sigma_p - memcpy(sigma_copy, sigma, 2 * (PARAM_DELTA)); - deg_sigma_copy = deg_sigma; - - dd = PQCLEAN_HQC256_CLEAN_gf_mul(d, PQCLEAN_HQC256_CLEAN_gf_inverse(d_p)); - - for (i = 1; (i <= mu + 1) && (i <= PARAM_DELTA); ++i) { - sigma[i] ^= PQCLEAN_HQC256_CLEAN_gf_mul(dd, X_sigma_p[i]); - } - - deg_X = mu - pp; - deg_X_sigma_p = deg_X + deg_sigma_p; - - // mask1 = 0xffff if(d != 0) and 0 otherwise - mask1 = -((uint16_t) - d >> 15); - - // mask2 = 0xffff if(deg_X_sigma_p > deg_sigma) and 0 otherwise - mask2 = -((uint16_t) (deg_sigma - deg_X_sigma_p) >> 15); - - // mask12 = 0xffff if the deg_sigma increased and 0 otherwise - mask12 = mask1 & mask2; - deg_sigma ^= mask12 & (deg_X_sigma_p ^ deg_sigma); - - if (mu == (2 * PARAM_DELTA - 1)) { - break; - } - - pp ^= mask12 & (mu ^ pp); - d_p ^= mask12 & (d ^ d_p); - for (i = PARAM_DELTA; i; --i) { - X_sigma_p[i] = (mask12 & sigma_copy[i - 1]) ^ (~mask12 & X_sigma_p[i - 1]); - } - - deg_sigma_p ^= mask12 & (deg_sigma_copy ^ deg_sigma_p); - d = syndromes[mu + 1]; - - for (i = 1; (i <= mu + 1) && (i <= PARAM_DELTA); ++i) { - d ^= PQCLEAN_HQC256_CLEAN_gf_mul(sigma[i], syndromes[mu + 1 - i]); - } - } - - return deg_sigma; -} - - - -/** - * @brief Computes the error polynomial error from the error locator polynomial sigma - * - * See function PQCLEAN_HQC256_CLEAN_fft for more details. - * - * @param[out] error Array of 2^PARAM_M elements receiving the error polynomial - * @param[out] error_compact Array of PARAM_DELTA + PARAM_N1 elements receiving a compact representation of the vector error - * @param[in] sigma Array of 2^PARAM_FFT elements storing the error locator polynomial - */ -static void compute_roots(uint8_t *error, uint16_t *sigma) { - uint16_t w[1 << PARAM_M] = {0}; - - PQCLEAN_HQC256_CLEAN_fft(w, sigma, PARAM_DELTA + 1); - PQCLEAN_HQC256_CLEAN_fft_retrieve_error_poly(error, w); -} - - - -/** - * @brief Computes the polynomial z(x) - * - * See @cite lin1983error (Chapter 6 - BCH Codes) for more details. - * - * @param[out] z Array of PARAM_DELTA + 1 elements receiving the polynomial z(x) - * @param[in] sigma Array of 2^PARAM_FFT elements storing the error locator polynomial - * @param[in] degree Integer that is the degree of polynomial sigma - * @param[in] syndromes Array of 2 * PARAM_DELTA storing the syndromes - */ -static void compute_z_poly(uint16_t *z, const uint16_t *sigma, uint16_t degree, const uint16_t *syndromes) { - size_t i, j; - uint16_t mask; - - z[0] = 1; - - for (i = 1; i < PARAM_DELTA + 1; ++i) { - mask = -((uint16_t) (i - degree - 1) >> 15); - z[i] = mask & sigma[i]; - } - - z[1] ^= syndromes[0]; - - for (i = 2; i <= PARAM_DELTA; ++i) { - mask = -((uint16_t) (i - degree - 1) >> 15); - z[i] ^= mask & syndromes[i - 1]; - - for (j = 1; j < i; ++j) { - z[i] ^= mask & PQCLEAN_HQC256_CLEAN_gf_mul(sigma[j], syndromes[i - j - 1]); - } - } -} - - - -/** - * @brief Computes the error values - * - * See @cite lin1983error (Chapter 6 - BCH Codes) for more details. - * - * @param[out] error_values Array of PARAM_DELTA elements receiving the error values - * @param[in] z Array of PARAM_DELTA + 1 elements storing the polynomial z(x) - * @param[in] z_degree Integer that is the degree of polynomial z(x) - * @param[in] error_compact Array of PARAM_DELTA + PARAM_N1 storing compact representation of the error - */ -static void compute_error_values(uint16_t *error_values, const uint16_t *z, const uint8_t *error) { - uint16_t beta_j[PARAM_DELTA] = {0}; - uint16_t e_j[PARAM_DELTA] = {0}; - - uint16_t delta_counter; - uint16_t delta_real_value; - uint16_t found; - uint16_t mask1; - uint16_t mask2; - uint16_t tmp1; - uint16_t tmp2; - uint16_t inverse; - uint16_t inverse_power_j; - - // Compute the beta_{j_i} page 31 of the documentation - delta_counter = 0; - for (size_t i = 0; i < PARAM_N1; i++) { - found = 0; - mask1 = (uint16_t) (-((int32_t)error[i]) >> 31); // error[i] != 0 - for (size_t j = 0; j < PARAM_DELTA; j++) { - mask2 = ~((uint16_t) (-((int32_t) j ^ delta_counter) >> 31)); // j == delta_counter - beta_j[j] += mask1 & mask2 & gf_exp[i]; - found += mask1 & mask2 & 1; - } - delta_counter += found; - } - delta_real_value = delta_counter; - - // Compute the e_{j_i} page 31 of the documentation - for (size_t i = 0; i < PARAM_DELTA; ++i) { - tmp1 = 1; - tmp2 = 1; - inverse = PQCLEAN_HQC256_CLEAN_gf_inverse(beta_j[i]); - inverse_power_j = 1; - - for (size_t j = 1; j <= PARAM_DELTA; ++j) { - inverse_power_j = PQCLEAN_HQC256_CLEAN_gf_mul(inverse_power_j, inverse); - tmp1 ^= PQCLEAN_HQC256_CLEAN_gf_mul(inverse_power_j, z[j]); - } - for (size_t k = 1; k < PARAM_DELTA; ++k) { - tmp2 = PQCLEAN_HQC256_CLEAN_gf_mul(tmp2, (1 ^ PQCLEAN_HQC256_CLEAN_gf_mul(inverse, beta_j[(i + k) % PARAM_DELTA]))); - } - mask1 = (uint16_t) (((int16_t) i - delta_real_value) >> 15); // i < delta_real_value - e_j[i] = mask1 & PQCLEAN_HQC256_CLEAN_gf_mul(tmp1, PQCLEAN_HQC256_CLEAN_gf_inverse(tmp2)); - } - - // Place the delta e_{j_i} values at the right coordinates of the output vector - delta_counter = 0; - for (size_t i = 0; i < PARAM_N1; ++i) { - found = 0; - mask1 = (uint16_t) (-((int32_t)error[i]) >> 31); // error[i] != 0 - for (size_t j = 0; j < PARAM_DELTA; j++) { - mask2 = ~((uint16_t) (-((int32_t) j ^ delta_counter) >> 31)); // j == delta_counter - error_values[i] += mask1 & mask2 & e_j[j]; - found += mask1 & mask2 & 1; - } - delta_counter += found; - } -} - - - -/** - * @brief Correct the errors - * - * @param[out] cdw Array of PARAM_N1 elements receiving the corrected vector - * @param[in] error Array of the error vector - * @param[in] error_values Array of PARAM_DELTA elements storing the error values - */ -static void correct_errors(uint8_t *cdw, const uint16_t *error_values) { - for (size_t i = 0; i < PARAM_N1; ++i) { - cdw[i] ^= error_values[i]; - } -} - - - -/** - * @brief Decodes the received word - * - * This function relies on six steps: - *
    - *
  1. The first step, is the computation of the 2*PARAM_DELTA syndromes. - *
  2. The second step is the computation of the error-locator polynomial sigma. - *
  3. The third step, done by additive FFT, is finding the error-locator numbers by calculating the roots of the polynomial sigma and takings their inverses. - *
  4. The fourth step, is the polynomial z(x). - *
  5. The fifth step, is the computation of the error values. - *
  6. The sixth step is the correction of the errors in the received polynomial. - *
- * For a more complete picture on Reed-Solomon decoding, see Shu. Lin and Daniel J. Costello in Error Control Coding: Fundamentals and Applications @cite lin1983error - * - * @param[out] msg Array of size VEC_K_SIZE_64 receiving the decoded message - * @param[in] cdw Array of size VEC_N1_SIZE_64 storing the received word - */ -void PQCLEAN_HQC256_CLEAN_reed_solomon_decode(uint8_t *msg, uint8_t *cdw) { - uint16_t syndromes[2 * PARAM_DELTA] = {0}; - uint16_t sigma[1 << PARAM_FFT] = {0}; - uint8_t error[1 << PARAM_M] = {0}; - uint16_t z[PARAM_N1] = {0}; - uint16_t error_values[PARAM_N1] = {0}; - uint16_t deg; - - // Calculate the 2*PARAM_DELTA syndromes - compute_syndromes(syndromes, cdw); - - // Compute the error locator polynomial sigma - // Sigma's degree is at most PARAM_DELTA but the FFT requires the extra room - deg = compute_elp(sigma, syndromes); - - // Compute the error polynomial error - compute_roots(error, sigma); - - // Compute the polynomial z(x) - compute_z_poly(z, sigma, deg, syndromes); - - // Compute the error values - compute_error_values(error_values, z, error); - - // Correct the errors - correct_errors(cdw, error_values); - - // Retrieve the message from the decoded codeword - memcpy(msg, cdw + (PARAM_G - 1), PARAM_K); - -} diff --git a/src/kem/hqc/pqclean_hqc-256_clean/reed_solomon.h b/src/kem/hqc/pqclean_hqc-256_clean/reed_solomon.h deleted file mode 100644 index 522a98c52b..0000000000 --- a/src/kem/hqc/pqclean_hqc-256_clean/reed_solomon.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef REED_SOLOMON_H -#define REED_SOLOMON_H - - -/** - * @file reed_solomon.h - * @brief Header file of reed_solomon.c - */ - -#include - -static const uint16_t alpha_ij_pow [58][89] = {{2, 4, 8, 16, 32, 64, 128, 29, 58, 116, 232, 205, 135, 19, 38, 76, 152, 45, 90, 180, 117, 234, 201, 143, 3, 6, 12, 24, 48, 96, 192, 157, 39, 78, 156, 37, 74, 148, 53, 106, 212, 181, 119, 238, 193, 159, 35, 70, 140, 5, 10, 20, 40, 80, 160, 93, 186, 105, 210, 185, 111, 222, 161, 95, 190, 97, 194, 153, 47, 94, 188, 101, 202, 137, 15, 30, 60, 120, 240, 253, 231, 211, 187, 107, 214, 177, 127, 254, 225}, {4, 16, 64, 29, 116, 205, 19, 76, 45, 180, 234, 143, 6, 24, 96, 157, 78, 37, 148, 106, 181, 238, 159, 70, 5, 20, 80, 93, 105, 185, 222, 95, 97, 153, 94, 101, 137, 30, 120, 253, 211, 107, 177, 254, 223, 91, 113, 217, 67, 17, 68, 13, 52, 208, 103, 129, 62, 248, 199, 59, 236, 151, 102, 133, 46, 184, 218, 79, 33, 132, 42, 168, 154, 82, 85, 73, 57, 228, 183, 230, 191, 198, 63, 252, 215, 123, 241, 227, 171}, {8, 64, 58, 205, 38, 45, 117, 143, 12, 96, 39, 37, 53, 181, 193, 70, 10, 80, 186, 185, 161, 97, 47, 101, 15, 120, 231, 107, 127, 223, 182, 217, 134, 68, 26, 208, 206, 62, 237, 59, 197, 102, 23, 184, 169, 33, 21, 168, 41, 85, 146, 228, 115, 191, 145, 252, 179, 241, 219, 150, 196, 110, 87, 130, 100, 7, 56, 221, 166, 89, 242, 195, 86, 138, 36, 61, 245, 251, 139, 44, 125, 207, 54, 173, 1, 8, 64, 58, 205}, {16, 29, 205, 76, 180, 143, 24, 157, 37, 106, 238, 70, 20, 93, 185, 95, 153, 101, 30, 253, 107, 254, 91, 217, 17, 13, 208, 129, 248, 59, 151, 133, 184, 79, 132, 168, 82, 73, 228, 230, 198, 252, 123, 227, 150, 149, 165, 130, 200, 28, 221, 81, 121, 195, 172, 18, 61, 247, 203, 44, 250, 27, 173, 2, 32, 58, 135, 152, 117, 3, 48, 39, 74, 212, 193, 140, 40, 186, 111, 190, 47, 202, 60, 231, 214, 225, 182, 175, 34}, {32, 116, 38, 180, 3, 96, 156, 106, 193, 5, 160, 185, 190, 94, 15, 253, 214, 223, 226, 17, 26, 103, 124, 59, 51, 46, 169, 132, 77, 85, 114, 230, 145, 215, 255, 150, 55, 174, 100, 28, 167, 89, 239, 172, 36, 244, 235, 44, 233, 108, 1, 32, 116, 38, 180, 3, 96, 156, 106, 193, 5, 160, 185, 190, 94, 15, 253, 214, 223, 226, 17, 26, 103, 124, 59, 51, 46, 169, 132, 77, 85, 114, 230, 145, 215, 255, 150, 55, 174}, {64, 205, 45, 143, 96, 37, 181, 70, 80, 185, 97, 101, 120, 107, 223, 217, 68, 208, 62, 59, 102, 184, 33, 168, 85, 228, 191, 252, 241, 150, 110, 130, 7, 221, 89, 195, 138, 61, 251, 44, 207, 173, 8, 58, 38, 117, 12, 39, 53, 193, 10, 186, 161, 47, 15, 231, 127, 182, 134, 26, 206, 237, 197, 23, 169, 21, 41, 146, 115, 145, 179, 219, 196, 87, 100, 56, 166, 242, 86, 36, 245, 139, 125, 54, 1, 64, 205, 45, 143}, {128, 19, 117, 24, 156, 181, 140, 93, 161, 94, 60, 107, 163, 67, 26, 129, 147, 102, 109, 132, 41, 57, 209, 252, 255, 98, 87, 200, 224, 89, 155, 18, 245, 11, 233, 173, 16, 232, 45, 3, 157, 53, 159, 40, 185, 194, 137, 231, 254, 226, 68, 189, 248, 197, 46, 158, 168, 170, 183, 145, 123, 75, 110, 25, 28, 166, 249, 69, 61, 235, 176, 54, 2, 29, 38, 234, 48, 37, 119, 5, 186, 95, 188, 120, 214, 91, 134, 52, 31}, {29, 76, 143, 157, 106, 70, 93, 95, 101, 253, 254, 217, 13, 129, 59, 133, 79, 168, 73, 230, 252, 227, 149, 130, 28, 81, 195, 18, 247, 44, 27, 2, 58, 152, 3, 39, 212, 140, 186, 190, 202, 231, 225, 175, 26, 31, 118, 23, 158, 77, 146, 209, 229, 219, 55, 25, 56, 162, 155, 36, 243, 88, 54, 4, 116, 45, 6, 78, 181, 5, 105, 97, 137, 211, 223, 67, 52, 62, 236, 46, 33, 154, 57, 191, 215, 171, 110, 50, 112}, {58, 45, 12, 37, 193, 80, 161, 101, 231, 223, 134, 208, 237, 102, 169, 168, 146, 191, 179, 150, 87, 7, 166, 195, 36, 251, 125, 173, 64, 38, 143, 39, 181, 10, 185, 47, 120, 127, 217, 26, 62, 197, 184, 21, 85, 115, 252, 219, 110, 100, 221, 242, 138, 245, 44, 54, 8, 205, 117, 96, 53, 70, 186, 97, 15, 107, 182, 68, 206, 59, 23, 33, 41, 228, 145, 241, 196, 130, 56, 89, 86, 61, 139, 207, 1, 58, 45, 12, 37}, {116, 180, 96, 106, 5, 185, 94, 253, 223, 17, 103, 59, 46, 132, 85, 230, 215, 150, 174, 28, 89, 172, 244, 44, 108, 32, 38, 3, 156, 193, 160, 190, 15, 214, 226, 26, 124, 51, 169, 77, 114, 145, 255, 55, 100, 167, 239, 36, 235, 233, 1, 116, 180, 96, 106, 5, 185, 94, 253, 223, 17, 103, 59, 46, 132, 85, 230, 215, 150, 174, 28, 89, 172, 244, 44, 108, 32, 38, 3, 156, 193, 160, 190, 15, 214, 226, 26, 124, 51}, {232, 234, 39, 238, 160, 97, 60, 254, 134, 103, 118, 184, 84, 57, 145, 227, 220, 7, 162, 172, 245, 176, 71, 58, 180, 192, 181, 40, 95, 15, 177, 175, 208, 147, 46, 21, 73, 99, 241, 55, 200, 166, 43, 122, 44, 216, 128, 45, 48, 106, 10, 222, 202, 107, 226, 52, 237, 133, 66, 85, 209, 123, 196, 50, 167, 195, 144, 11, 54, 32, 76, 12, 148, 140, 185, 188, 211, 182, 13, 124, 102, 158, 82, 115, 215, 49, 130, 224, 249}, {205, 143, 37, 70, 185, 101, 107, 217, 208, 59, 184, 168, 228, 252, 150, 130, 221, 195, 61, 44, 173, 58, 117, 39, 193, 186, 47, 231, 182, 26, 237, 23, 21, 146, 145, 219, 87, 56, 242, 36, 139, 54, 64, 45, 96, 181, 80, 97, 120, 223, 68, 62, 102, 33, 85, 191, 241, 110, 7, 89, 138, 251, 207, 8, 38, 12, 53, 10, 161, 15, 127, 134, 206, 197, 169, 41, 115, 179, 196, 100, 166, 86, 245, 125, 1, 205, 143, 37, 70}, {135, 6, 53, 20, 190, 120, 163, 13, 237, 46, 84, 228, 229, 98, 100, 81, 69, 251, 131, 32, 45, 192, 238, 186, 94, 187, 217, 189, 236, 169, 82, 209, 241, 220, 28, 242, 72, 22, 173, 116, 201, 37, 140, 222, 15, 254, 34, 62, 204, 132, 146, 63, 75, 130, 167, 43, 245, 250, 4, 38, 24, 212, 80, 194, 253, 182, 52, 147, 184, 77, 183, 179, 149, 141, 89, 9, 203, 54, 128, 180, 39, 159, 210, 101, 214, 67, 206, 151, 158}, {19, 24, 181, 93, 94, 107, 67, 129, 102, 132, 57, 252, 98, 200, 89, 18, 11, 173, 232, 3, 53, 40, 194, 231, 226, 189, 197, 158, 170, 145, 75, 25, 166, 69, 235, 54, 29, 234, 37, 5, 95, 120, 91, 52, 59, 218, 82, 191, 227, 174, 221, 43, 247, 207, 32, 90, 39, 35, 111, 15, 225, 136, 237, 92, 77, 115, 246, 220, 56, 239, 122, 125, 4, 76, 96, 238, 105, 101, 177, 17, 62, 133, 42, 228, 215, 149, 7, 121, 72}, {38, 96, 193, 185, 15, 223, 26, 59, 169, 85, 145, 150, 100, 89, 36, 44, 1, 38, 96, 193, 185, 15, 223, 26, 59, 169, 85, 145, 150, 100, 89, 36, 44, 1, 38, 96, 193, 185, 15, 223, 26, 59, 169, 85, 145, 150, 100, 89, 36, 44, 1, 38, 96, 193, 185, 15, 223, 26, 59, 169, 85, 145, 150, 100, 89, 36, 44, 1, 38, 96, 193, 185, 15, 223, 26, 59, 169, 85, 145, 150, 100, 89, 36, 44, 1, 38, 96, 193, 185}, {76, 157, 70, 95, 253, 217, 129, 133, 168, 230, 227, 130, 81, 18, 44, 2, 152, 39, 140, 190, 231, 175, 31, 23, 77, 209, 219, 25, 162, 36, 88, 4, 45, 78, 5, 97, 211, 67, 62, 46, 154, 191, 171, 50, 89, 72, 176, 8, 90, 156, 10, 194, 187, 134, 124, 92, 41, 99, 75, 100, 178, 144, 125, 16, 180, 37, 20, 153, 107, 17, 248, 184, 82, 198, 150, 200, 121, 61, 250, 32, 117, 74, 40, 47, 214, 34, 237, 109, 164}, {152, 78, 10, 153, 214, 68, 147, 79, 146, 215, 220, 221, 69, 11, 1, 152, 78, 10, 153, 214, 68, 147, 79, 146, 215, 220, 221, 69, 11, 1, 152, 78, 10, 153, 214, 68, 147, 79, 146, 215, 220, 221, 69, 11, 1, 152, 78, 10, 153, 214, 68, 147, 79, 146, 215, 220, 221, 69, 11, 1, 152, 78, 10, 153, 214, 68, 147, 79, 146, 215, 220, 221, 69, 11, 1, 152, 78, 10, 153, 214, 68, 147, 79, 146, 215, 220, 221, 69, 11}, {45, 37, 80, 101, 223, 208, 102, 168, 191, 150, 7, 195, 251, 173, 38, 39, 10, 47, 127, 26, 197, 21, 115, 219, 100, 242, 245, 54, 205, 96, 70, 97, 107, 68, 59, 33, 228, 241, 130, 89, 61, 207, 58, 12, 193, 161, 231, 134, 237, 169, 146, 179, 87, 166, 36, 125, 64, 143, 181, 185, 120, 217, 62, 184, 85, 252, 110, 221, 138, 44, 8, 117, 53, 186, 15, 182, 206, 23, 41, 145, 196, 56, 86, 139, 1, 45, 37, 80, 101}, {90, 148, 186, 30, 226, 62, 109, 73, 179, 174, 162, 61, 131, 232, 96, 140, 153, 127, 52, 51, 168, 99, 98, 56, 172, 22, 8, 234, 212, 185, 240, 67, 237, 79, 114, 241, 25, 121, 245, 108, 19, 39, 20, 188, 223, 189, 133, 41, 63, 55, 221, 9, 176, 64, 3, 238, 161, 211, 34, 59, 66, 183, 219, 200, 239, 251, 71, 152, 37, 160, 137, 182, 129, 92, 85, 229, 165, 166, 72, 233, 58, 24, 35, 97, 214, 13, 197, 42, 209}, {180, 106, 185, 253, 17, 59, 132, 230, 150, 28, 172, 44, 32, 3, 193, 190, 214, 26, 51, 77, 145, 55, 167, 36, 233, 116, 96, 5, 94, 223, 103, 46, 85, 215, 174, 89, 244, 108, 38, 156, 160, 15, 226, 124, 169, 114, 255, 100, 239, 235, 1, 180, 106, 185, 253, 17, 59, 132, 230, 150, 28, 172, 44, 32, 3, 193, 190, 214, 26, 51, 77, 145, 55, 167, 36, 233, 116, 96, 5, 94, 223, 103, 46, 85, 215, 174, 89, 244, 108}, {117, 181, 161, 107, 26, 102, 41, 252, 87, 89, 245, 173, 45, 53, 185, 231, 68, 197, 168, 145, 110, 166, 61, 54, 38, 37, 186, 120, 134, 59, 21, 191, 196, 221, 36, 207, 205, 39, 80, 15, 217, 237, 33, 115, 150, 56, 138, 125, 58, 96, 10, 101, 182, 62, 169, 228, 219, 7, 86, 44, 64, 12, 70, 47, 223, 206, 184, 146, 241, 100, 195, 139, 8, 143, 193, 97, 127, 208, 23, 85, 179, 130, 242, 251, 1, 117, 181, 161, 107}, {234, 238, 97, 254, 103, 184, 57, 227, 7, 172, 176, 58, 192, 40, 15, 175, 147, 21, 99, 55, 166, 122, 216, 45, 106, 222, 107, 52, 133, 85, 123, 50, 195, 11, 32, 12, 140, 188, 182, 124, 158, 115, 49, 224, 36, 131, 19, 37, 105, 253, 68, 151, 154, 252, 174, 121, 251, 2, 201, 193, 194, 225, 206, 109, 114, 219, 14, 69, 125, 116, 157, 80, 30, 67, 59, 42, 198, 110, 81, 244, 173, 90, 212, 161, 214, 104, 23, 170, 246}, {201, 159, 47, 91, 124, 33, 209, 149, 166, 244, 71, 117, 238, 194, 223, 31, 79, 115, 98, 167, 61, 216, 90, 181, 190, 254, 206, 218, 213, 150, 224, 72, 54, 152, 106, 161, 177, 189, 184, 114, 171, 56, 18, 131, 38, 148, 111, 107, 104, 46, 146, 227, 14, 138, 233, 135, 37, 210, 211, 26, 133, 170, 241, 141, 172, 125, 232, 78, 186, 253, 136, 102, 164, 123, 100, 43, 88, 58, 157, 160, 120, 34, 151, 41, 215, 25, 195, 22, 128}, {143, 70, 101, 217, 59, 168, 252, 130, 195, 44, 58, 39, 186, 231, 26, 23, 146, 219, 56, 36, 54, 45, 181, 97, 223, 62, 33, 191, 110, 89, 251, 8, 12, 10, 15, 134, 197, 41, 179, 100, 86, 125, 205, 37, 185, 107, 208, 184, 228, 150, 221, 61, 173, 117, 193, 47, 182, 237, 21, 145, 87, 242, 139, 64, 96, 80, 120, 68, 102, 85, 241, 7, 138, 207, 38, 53, 161, 127, 206, 169, 115, 196, 166, 245, 1, 143, 70, 101, 217}, {3, 5, 15, 17, 51, 85, 255, 28, 36, 108, 180, 193, 94, 226, 59, 77, 215, 100, 172, 233, 38, 106, 190, 223, 124, 132, 145, 174, 239, 44, 116, 156, 185, 214, 103, 169, 230, 55, 89, 235, 32, 96, 160, 253, 26, 46, 114, 150, 167, 244, 1, 3, 5, 15, 17, 51, 85, 255, 28, 36, 108, 180, 193, 94, 226, 59, 77, 215, 100, 172, 233, 38, 106, 190, 223, 124, 132, 145, 174, 239, 44, 116, 156, 185, 214, 103, 169, 230, 55}, {6, 20, 120, 13, 46, 228, 98, 81, 251, 32, 192, 186, 187, 189, 169, 209, 220, 242, 22, 116, 37, 222, 254, 62, 132, 63, 130, 43, 250, 38, 212, 194, 182, 147, 77, 179, 141, 9, 54, 180, 159, 101, 67, 151, 85, 227, 112, 61, 142, 3, 10, 60, 136, 23, 114, 49, 166, 243, 16, 96, 93, 211, 208, 218, 230, 110, 121, 11, 58, 156, 111, 127, 31, 66, 145, 65, 155, 125, 19, 106, 97, 91, 199, 168, 215, 200, 138, 27, 90}, {12, 80, 231, 208, 169, 191, 87, 195, 125, 38, 181, 47, 217, 197, 85, 219, 221, 245, 8, 96, 186, 107, 206, 33, 145, 130, 86, 207, 45, 193, 101, 134, 102, 146, 150, 166, 251, 64, 39, 185, 127, 62, 21, 252, 100, 138, 54, 117, 70, 15, 68, 23, 228, 196, 89, 139, 58, 37, 161, 223, 237, 168, 179, 7, 36, 173, 143, 10, 120, 26, 184, 115, 110, 242, 44, 205, 53, 97, 182, 59, 41, 241, 56, 61, 1, 12, 80, 231, 208}, {24, 93, 107, 129, 132, 252, 200, 18, 173, 3, 40, 231, 189, 158, 145, 25, 69, 54, 234, 5, 120, 52, 218, 191, 174, 43, 207, 90, 35, 15, 136, 92, 115, 220, 239, 125, 76, 238, 101, 17, 133, 228, 149, 121, 44, 135, 212, 47, 175, 51, 146, 49, 162, 139, 116, 148, 97, 113, 236, 85, 171, 83, 251, 128, 156, 161, 163, 147, 41, 255, 224, 245, 16, 157, 185, 254, 248, 168, 123, 28, 61, 2, 48, 186, 214, 31, 21, 229, 141}, {48, 105, 127, 248, 77, 241, 224, 247, 64, 156, 95, 182, 236, 170, 150, 162, 11, 205, 212, 94, 134, 133, 213, 110, 239, 250, 45, 35, 30, 26, 218, 99, 130, 69, 108, 143, 40, 211, 206, 132, 229, 7, 144, 2, 96, 210, 254, 237, 154, 255, 221, 243, 128, 37, 190, 113, 197, 73, 49, 89, 22, 135, 181, 188, 17, 23, 183, 220, 195, 233, 90, 70, 60, 52, 169, 198, 25, 138, 216, 3, 80, 187, 129, 21, 215, 14, 61, 4, 192}, {96, 185, 223, 59, 85, 150, 89, 44, 38, 193, 15, 26, 169, 145, 100, 36, 1, 96, 185, 223, 59, 85, 150, 89, 44, 38, 193, 15, 26, 169, 145, 100, 36, 1, 96, 185, 223, 59, 85, 150, 89, 44, 38, 193, 15, 26, 169, 145, 100, 36, 1, 96, 185, 223, 59, 85, 150, 89, 44, 38, 193, 15, 26, 169, 145, 100, 36, 1, 96, 185, 223, 59, 85, 150, 89, 44, 38, 193, 15, 26, 169, 145, 100, 36, 1, 96, 185, 223, 59}, {192, 222, 182, 151, 114, 110, 155, 27, 143, 160, 177, 237, 82, 75, 89, 88, 152, 70, 240, 103, 21, 123, 224, 251, 116, 212, 101, 136, 218, 145, 200, 144, 8, 78, 190, 217, 204, 183, 87, 172, 216, 12, 105, 225, 59, 170, 98, 242, 250, 180, 10, 211, 31, 168, 255, 83, 139, 135, 238, 15, 52, 158, 252, 14, 244, 64, 74, 153, 134, 46, 209, 130, 9, 142, 96, 111, 91, 197, 57, 55, 195, 131, 201, 80, 214, 248, 41, 171, 162}, {157, 95, 217, 133, 230, 130, 18, 2, 39, 190, 175, 23, 209, 25, 36, 4, 78, 97, 67, 46, 191, 50, 72, 8, 156, 194, 134, 92, 99, 100, 144, 16, 37, 153, 17, 184, 198, 200, 61, 32, 74, 47, 34, 109, 145, 141, 122, 64, 148, 94, 68, 218, 63, 7, 244, 128, 53, 188, 136, 169, 126, 14, 245, 29, 106, 101, 13, 79, 252, 28, 247, 58, 212, 202, 26, 158, 229, 56, 243, 116, 181, 137, 52, 33, 215, 112, 251, 232, 119}, {39, 97, 134, 184, 145, 7, 245, 58, 181, 15, 208, 21, 241, 166, 44, 45, 10, 107, 237, 85, 196, 195, 54, 12, 185, 182, 102, 115, 130, 36, 8, 37, 47, 68, 169, 252, 56, 251, 205, 193, 120, 206, 168, 219, 89, 125, 117, 80, 127, 59, 146, 110, 86, 173, 96, 161, 217, 23, 191, 100, 61, 64, 53, 101, 26, 33, 179, 221, 139, 38, 70, 231, 62, 41, 150, 242, 207, 143, 186, 223, 197, 228, 87, 138, 1, 39, 97, 134, 184}, {78, 153, 68, 79, 215, 221, 11, 152, 10, 214, 147, 146, 220, 69, 1, 78, 153, 68, 79, 215, 221, 11, 152, 10, 214, 147, 146, 220, 69, 1, 78, 153, 68, 79, 215, 221, 11, 152, 10, 214, 147, 146, 220, 69, 1, 78, 153, 68, 79, 215, 221, 11, 152, 10, 214, 147, 146, 220, 69, 1, 78, 153, 68, 79, 215, 221, 11, 152, 10, 214, 147, 146, 220, 69, 1, 78, 153, 68, 79, 215, 221, 11, 152, 10, 214, 147, 146, 220, 69}, {156, 94, 26, 132, 255, 89, 233, 3, 185, 226, 46, 145, 28, 235, 38, 5, 214, 59, 114, 174, 36, 32, 106, 15, 103, 77, 150, 239, 108, 96, 190, 17, 169, 215, 167, 44, 180, 160, 223, 51, 230, 100, 244, 116, 193, 253, 124, 85, 55, 172, 1, 156, 94, 26, 132, 255, 89, 233, 3, 185, 226, 46, 145, 28, 235, 38, 5, 214, 59, 114, 174, 36, 32, 106, 15, 103, 77, 150, 239, 108, 96, 190, 17, 169, 215, 167, 44, 180, 160}, {37, 101, 208, 168, 150, 195, 173, 39, 47, 26, 21, 219, 242, 54, 96, 97, 68, 33, 241, 89, 207, 12, 161, 134, 169, 179, 166, 125, 143, 185, 217, 184, 252, 221, 44, 117, 186, 182, 23, 145, 56, 139, 45, 80, 223, 102, 191, 7, 251, 38, 10, 127, 197, 115, 100, 245, 205, 70, 107, 59, 228, 130, 61, 58, 193, 231, 237, 146, 87, 36, 64, 181, 120, 62, 85, 110, 138, 8, 53, 15, 206, 41, 196, 86, 1, 37, 101, 208, 168}, {74, 137, 206, 82, 55, 138, 16, 212, 120, 124, 73, 87, 72, 29, 193, 211, 147, 228, 25, 244, 205, 140, 177, 197, 230, 141, 251, 76, 40, 223, 204, 198, 56, 11, 180, 186, 113, 92, 252, 167, 176, 143, 111, 67, 169, 123, 162, 207, 24, 190, 68, 66, 227, 242, 108, 157, 47, 52, 84, 150, 155, 142, 37, 202, 103, 41, 149, 69, 8, 106, 60, 62, 170, 165, 36, 128, 238, 231, 199, 114, 130, 122, 232, 70, 214, 236, 115, 200, 243}, {148, 30, 62, 73, 174, 61, 232, 140, 127, 51, 99, 56, 22, 234, 185, 67, 79, 241, 121, 108, 39, 188, 189, 41, 55, 9, 64, 238, 211, 59, 183, 200, 251, 152, 160, 182, 92, 229, 166, 233, 24, 97, 13, 42, 150, 43, 2, 53, 60, 124, 146, 65, 122, 205, 5, 254, 102, 198, 112, 44, 201, 111, 134, 158, 255, 242, 216, 78, 101, 103, 82, 110, 18, 128, 193, 187, 118, 115, 141, 235, 45, 93, 113, 184, 215, 81, 207, 48, 194}, {53, 120, 237, 228, 100, 251, 45, 186, 217, 169, 241, 242, 173, 37, 15, 62, 146, 130, 245, 38, 80, 182, 184, 179, 89, 54, 39, 101, 206, 85, 87, 61, 205, 10, 223, 23, 252, 166, 207, 96, 47, 208, 41, 110, 36, 58, 70, 127, 102, 145, 221, 125, 12, 97, 26, 168, 196, 138, 64, 193, 107, 197, 191, 56, 44, 143, 161, 68, 21, 150, 86, 8, 181, 231, 59, 115, 7, 139, 117, 185, 134, 33, 219, 195, 1, 53, 120, 237, 228}, {106, 253, 59, 230, 28, 44, 3, 190, 26, 77, 55, 36, 116, 5, 223, 46, 215, 89, 108, 156, 15, 124, 114, 100, 235, 180, 185, 17, 132, 150, 172, 32, 193, 214, 51, 145, 167, 233, 96, 94, 103, 85, 174, 244, 38, 160, 226, 169, 255, 239, 1, 106, 253, 59, 230, 28, 44, 3, 190, 26, 77, 55, 36, 116, 5, 223, 46, 215, 89, 108, 156, 15, 124, 114, 100, 235, 180, 185, 17, 132, 150, 172, 32, 193, 214, 51, 145, 167, 233}, {212, 211, 197, 198, 167, 207, 157, 202, 62, 114, 200, 139, 201, 95, 26, 154, 220, 61, 19, 160, 217, 158, 171, 86, 32, 159, 127, 133, 229, 89, 216, 74, 120, 147, 230, 56, 176, 24, 47, 103, 170, 130, 243, 90, 185, 34, 42, 196, 18, 116, 10, 91, 109, 241, 239, 2, 181, 187, 151, 145, 83, 131, 39, 137, 124, 228, 141, 11, 143, 190, 52, 41, 165, 122, 38, 93, 175, 33, 75, 172, 64, 35, 254, 23, 215, 178, 173, 148, 240}, {181, 107, 102, 252, 89, 173, 53, 231, 197, 145, 166, 54, 37, 120, 59, 191, 221, 207, 39, 15, 237, 115, 56, 125, 96, 101, 62, 228, 7, 44, 12, 47, 206, 146, 100, 139, 143, 97, 208, 85, 130, 251, 117, 161, 26, 41, 87, 245, 45, 185, 68, 168, 110, 61, 38, 186, 134, 21, 196, 36, 205, 80, 217, 33, 150, 138, 58, 10, 182, 169, 219, 86, 64, 70, 223, 184, 241, 195, 8, 193, 127, 23, 179, 242, 1, 181, 107, 102, 252}, {119, 177, 23, 123, 239, 8, 159, 225, 184, 255, 43, 64, 140, 91, 169, 171, 69, 58, 20, 226, 33, 49, 18, 205, 160, 67, 21, 149, 144, 38, 105, 34, 168, 220, 244, 45, 111, 13, 41, 174, 243, 117, 95, 104, 85, 25, 203, 143, 194, 103, 146, 200, 22, 12, 94, 31, 228, 14, 176, 96, 202, 248, 115, 112, 233, 39, 30, 147, 191, 167, 27, 37, 240, 236, 145, 81, 216, 53, 211, 51, 252, 178, 142, 181, 214, 133, 179, 249, 4}, {238, 254, 184, 227, 172, 58, 40, 175, 21, 55, 122, 45, 222, 52, 85, 50, 11, 12, 188, 124, 115, 224, 131, 37, 253, 151, 252, 121, 2, 193, 225, 109, 219, 69, 116, 80, 67, 42, 110, 244, 90, 161, 104, 170, 100, 22, 24, 101, 248, 230, 221, 27, 74, 231, 51, 229, 242, 4, 159, 223, 218, 171, 138, 232, 160, 134, 84, 220, 245, 180, 95, 208, 73, 200, 44, 48, 202, 237, 209, 167, 54, 148, 211, 102, 215, 249, 8, 35, 163}, {193, 223, 169, 150, 36, 38, 185, 26, 85, 100, 44, 96, 15, 59, 145, 89, 1, 193, 223, 169, 150, 36, 38, 185, 26, 85, 100, 44, 96, 15, 59, 145, 89, 1, 193, 223, 169, 150, 36, 38, 185, 26, 85, 100, 44, 96, 15, 59, 145, 89, 1, 193, 223, 169, 150, 36, 38, 185, 26, 85, 100, 44, 96, 15, 59, 145, 89, 1, 193, 223, 169, 150, 36, 38, 185, 26, 85, 100, 44, 96, 15, 59, 145, 89, 1, 193, 223, 169, 150}, {159, 91, 33, 149, 244, 117, 194, 31, 115, 167, 216, 181, 254, 218, 150, 72, 152, 161, 189, 114, 56, 131, 148, 107, 46, 227, 138, 135, 210, 26, 170, 141, 125, 78, 253, 102, 123, 43, 58, 160, 34, 41, 25, 22, 96, 30, 236, 252, 249, 32, 10, 175, 84, 87, 235, 6, 101, 199, 198, 89, 2, 35, 182, 66, 55, 245, 234, 153, 62, 230, 83, 173, 119, 225, 169, 49, 144, 45, 95, 103, 228, 112, 27, 53, 214, 92, 219, 9, 19}, {35, 113, 21, 165, 235, 12, 137, 118, 252, 239, 128, 80, 34, 82, 100, 176, 78, 231, 133, 255, 138, 19, 111, 208, 114, 112, 54, 212, 254, 169, 98, 122, 117, 153, 124, 191, 162, 2, 70, 226, 42, 87, 203, 24, 15, 236, 229, 195, 29, 160, 68, 164, 200, 125, 156, 211, 23, 227, 9, 38, 222, 189, 228, 224, 108, 181, 225, 79, 196, 244, 234, 47, 248, 99, 89, 4, 140, 217, 84, 174, 139, 48, 30, 197, 215, 155, 58, 93, 136}, {70, 217, 168, 130, 44, 39, 231, 23, 219, 36, 45, 97, 62, 191, 89, 8, 10, 134, 41, 100, 125, 37, 107, 184, 150, 61, 117, 47, 237, 145, 242, 64, 80, 68, 85, 7, 207, 53, 127, 169, 196, 245, 143, 101, 59, 252, 195, 58, 186, 26, 146, 56, 54, 181, 223, 33, 110, 251, 12, 15, 197, 179, 86, 205, 185, 208, 228, 221, 173, 193, 182, 21, 87, 139, 96, 120, 102, 241, 138, 38, 161, 206, 115, 166, 1, 70, 217, 168, 130}, {140, 67, 41, 200, 233, 53, 254, 158, 110, 235, 48, 120, 204, 227, 36, 90, 153, 237, 63, 239, 58, 105, 104, 228, 167, 142, 70, 175, 154, 100, 250, 148, 127, 79, 55, 251, 24, 60, 102, 255, 18, 45, 194, 248, 145, 249, 29, 186, 52, 114, 221, 71, 35, 217, 77, 50, 125, 74, 177, 169, 149, 243, 12, 30, 51, 241, 9, 152, 97, 124, 198, 242, 128, 93, 26, 57, 224, 173, 159, 226, 168, 25, 176, 37, 214, 218, 196, 247, 6}, {5, 17, 85, 28, 108, 193, 226, 77, 100, 233, 106, 223, 132, 174, 44, 156, 214, 169, 55, 235, 96, 253, 46, 150, 244, 3, 15, 51, 255, 36, 180, 94, 59, 215, 172, 38, 190, 124, 145, 239, 116, 185, 103, 230, 89, 32, 160, 26, 114, 167, 1, 5, 17, 85, 28, 108, 193, 226, 77, 100, 233, 106, 223, 132, 174, 44, 156, 214, 169, 55, 235, 96, 253, 46, 150, 244, 3, 15, 51, 255, 36, 180, 94, 59, 215, 172, 38, 190, 124}, {10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221}, {20, 13, 228, 81, 32, 186, 189, 209, 242, 116, 222, 62, 63, 43, 38, 194, 147, 179, 9, 180, 101, 151, 227, 61, 3, 60, 23, 49, 243, 96, 211, 218, 110, 11, 156, 127, 66, 65, 125, 106, 91, 168, 200, 27, 193, 175, 164, 56, 71, 5, 68, 57, 83, 8, 160, 104, 115, 178, 29, 185, 129, 198, 195, 135, 190, 237, 229, 69, 45, 94, 236, 241, 72, 201, 15, 204, 75, 245, 24, 253, 184, 149, 203, 39, 214, 158, 87, 88, 148}, {40, 52, 115, 121, 116, 161, 248, 229, 138, 180, 202, 102, 75, 247, 96, 187, 79, 87, 176, 106, 182, 154, 14, 173, 5, 136, 228, 162, 128, 185, 31, 63, 86, 152, 94, 197, 227, 122, 12, 253, 109, 110, 22, 74, 223, 84, 200, 54, 35, 17, 146, 83, 16, 186, 103, 99, 195, 19, 194, 59, 246, 72, 143, 60, 46, 196, 203, 78, 127, 132, 25, 207, 238, 175, 85, 224, 2, 80, 104, 230, 242, 232, 95, 237, 215, 9, 117, 137, 204}, {80, 208, 191, 195, 38, 47, 197, 219, 245, 96, 107, 33, 130, 207, 193, 134, 146, 166, 64, 185, 62, 252, 138, 117, 15, 23, 196, 139, 37, 223, 168, 7, 173, 10, 26, 115, 242, 205, 97, 59, 241, 61, 12, 231, 169, 87, 125, 181, 217, 85, 221, 8, 186, 206, 145, 86, 45, 101, 102, 150, 251, 39, 127, 21, 100, 54, 70, 68, 228, 89, 58, 161, 237, 179, 36, 143, 120, 184, 110, 44, 53, 182, 41, 56, 1, 80, 208, 191, 195}, {160, 103, 145, 172, 180, 15, 46, 55, 44, 106, 226, 85, 167, 32, 185, 124, 215, 36, 3, 253, 169, 174, 233, 193, 17, 114, 89, 116, 190, 59, 255, 244, 96, 214, 132, 100, 108, 5, 26, 230, 239, 38, 94, 51, 150, 235, 156, 223, 77, 28, 1, 160, 103, 145, 172, 180, 15, 46, 55, 44, 106, 226, 85, 167, 32, 185, 124, 215, 36, 3, 253, 169, 174, 233, 193, 17, 114, 89, 116, 190, 59, 255, 244, 96, 214, 132, 100, 108, 5}, {93, 129, 252, 18, 3, 231, 158, 25, 54, 5, 52, 191, 43, 90, 15, 92, 220, 125, 238, 17, 228, 121, 135, 47, 51, 49, 139, 148, 113, 85, 83, 128, 161, 147, 255, 245, 157, 254, 168, 28, 2, 186, 31, 229, 36, 6, 211, 33, 50, 108, 10, 104, 99, 86, 180, 30, 184, 165, 250, 193, 34, 213, 242, 19, 94, 102, 98, 11, 53, 226, 170, 166, 29, 95, 59, 227, 247, 39, 225, 77, 56, 4, 105, 62, 215, 72, 12, 187, 66}, {186, 62, 179, 61, 96, 127, 168, 56, 8, 185, 237, 241, 245, 39, 223, 41, 221, 64, 161, 59, 219, 251, 37, 182, 85, 166, 58, 97, 197, 150, 139, 53, 217, 146, 89, 205, 47, 102, 196, 44, 181, 134, 228, 242, 38, 101, 23, 110, 125, 193, 68, 115, 195, 45, 15, 184, 87, 207, 70, 26, 191, 86, 117, 120, 169, 130, 54, 10, 208, 145, 138, 143, 231, 33, 100, 173, 80, 206, 252, 36, 12, 107, 21, 7, 1, 186, 62, 179, 61}, {105, 248, 241, 247, 156, 182, 170, 162, 205, 94, 133, 110, 250, 35, 26, 99, 69, 143, 211, 132, 7, 2, 210, 237, 255, 243, 37, 113, 73, 89, 135, 188, 23, 220, 233, 70, 52, 198, 138, 3, 187, 21, 14, 4, 185, 199, 227, 251, 74, 226, 146, 178, 19, 101, 46, 165, 207, 140, 104, 145, 9, 6, 107, 42, 28, 8, 111, 147, 219, 235, 148, 217, 57, 121, 38, 202, 92, 87, 131, 5, 208, 63, 18, 12, 214, 84, 56, 16, 222}}; - -void PQCLEAN_HQC256_CLEAN_reed_solomon_encode(uint8_t *cdw, const uint8_t *msg); - -void PQCLEAN_HQC256_CLEAN_reed_solomon_decode(uint8_t *msg, uint8_t *cdw); - - -#endif diff --git a/src/kem/hqc/pqclean_hqc-256_clean/shake_ds.c b/src/kem/hqc/pqclean_hqc-256_clean/shake_ds.c deleted file mode 100644 index 3b80cc74e7..0000000000 --- a/src/kem/hqc/pqclean_hqc-256_clean/shake_ds.c +++ /dev/null @@ -1,40 +0,0 @@ -#include "shake_ds.h" - - -/** - * @file shake_ds.c - * @brief Implementation SHAKE-256 with incremental API and domain separation - */ - - - -/** - * @brief SHAKE-256 with incremental API and domain separation - * - * Derived from function SHAKE_256 in fips202.c - * - * @param[out] state Internal state of SHAKE - * @param[in] output Pointer to output - * @param[in] input Pointer to input - * @param[in] inlen length of input in bytes - * @param[in] domain byte for domain separation - */ -void PQCLEAN_HQC256_CLEAN_shake256_512_ds(shake256incctx *state, uint8_t *output, const uint8_t *input, size_t inlen, uint8_t domain) { - /* Init state */ - shake256_inc_init(state); - - /* Absorb input */ - shake256_inc_absorb(state, input, inlen); - - /* Absorb domain separation byte */ - shake256_inc_absorb(state, &domain, 1); - - /* Finalize */ - shake256_inc_finalize(state); - - /* Squeeze output */ - shake256_inc_squeeze(output, 512 / 8, state); - - /* Release ctx */ - shake256_inc_ctx_release(state); -} diff --git a/src/kem/hqc/pqclean_hqc-256_clean/shake_ds.h b/src/kem/hqc/pqclean_hqc-256_clean/shake_ds.h deleted file mode 100644 index eac52bfe29..0000000000 --- a/src/kem/hqc/pqclean_hqc-256_clean/shake_ds.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef SHAKE_DS_H -#define SHAKE_DS_H - - -/** - * @file shake_ds.h - * @brief Header file of shake_ds.c - */ -#include "fips202.h" -#include -#include - -void PQCLEAN_HQC256_CLEAN_shake256_512_ds(shake256incctx *state, uint8_t *output, const uint8_t *input, size_t inlen, uint8_t domain); - - -#endif diff --git a/src/kem/hqc/pqclean_hqc-256_clean/shake_prng.c b/src/kem/hqc/pqclean_hqc-256_clean/shake_prng.c deleted file mode 100644 index 10ee0900a4..0000000000 --- a/src/kem/hqc/pqclean_hqc-256_clean/shake_prng.c +++ /dev/null @@ -1,60 +0,0 @@ -#include "domains.h" -#include "fips202.h" -#include "shake_prng.h" - -/** - * @file shake_prng.c - * @brief Implementation of SHAKE-256 based seed expander - */ - - -/** - * @brief Initialise a SHAKE-256 based seed expander - * - * Derived from function SHAKE_256 in fips202.c - * - * @param[out] state Keccak internal state and a counter - * @param[in] seed A seed - * @param[in] seedlen The seed bytes length - */ -void PQCLEAN_HQC256_CLEAN_seedexpander_init(seedexpander_state *state, const uint8_t *seed, size_t seedlen) { - uint8_t domain = SEEDEXPANDER_DOMAIN; - shake256_inc_init(state); - shake256_inc_absorb(state, seed, seedlen); - shake256_inc_absorb(state, &domain, 1); - shake256_inc_finalize(state); -} - - - -/** - * @brief A SHAKE-256 based seed expander - * - * Derived from function SHAKE_256 in fips202.c - * Squeezes Keccak state by 64-bit blocks (hardware version compatibility) - * - * @param[out] state Internal state of SHAKE - * @param[out] output The XOF data - * @param[in] outlen Number of bytes to return - */ -void PQCLEAN_HQC256_CLEAN_seedexpander(seedexpander_state *state, uint8_t *output, size_t outlen) { - const size_t bsize = sizeof(uint64_t); - const size_t remainder = outlen % bsize; - uint8_t tmp[sizeof(uint64_t)]; - shake256_inc_squeeze(output, outlen - remainder, state); - if (remainder != 0) { - shake256_inc_squeeze(tmp, bsize, state); - output += outlen - remainder; - for (uint8_t i = 0; i < remainder; i++) { - output[i] = tmp[i]; - } - } -} - -/** - * @brief Release the seed expander context - * @param[in] state Internal state of the seed expander - */ -void PQCLEAN_HQC256_CLEAN_seedexpander_release(seedexpander_state *state) { - shake256_inc_ctx_release(state); -} diff --git a/src/kem/hqc/pqclean_hqc-256_clean/shake_prng.h b/src/kem/hqc/pqclean_hqc-256_clean/shake_prng.h deleted file mode 100644 index f07fed6fb7..0000000000 --- a/src/kem/hqc/pqclean_hqc-256_clean/shake_prng.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef SHAKE_PRNG_H -#define SHAKE_PRNG_H - - -/** - * @file shake_prng.h - * @brief Header file of shake_prng.c - */ -#include "fips202.h" -#include -#include - -typedef shake256incctx seedexpander_state; - -void PQCLEAN_HQC256_CLEAN_seedexpander_init(seedexpander_state *state, const uint8_t *seed, size_t seedlen); - -void PQCLEAN_HQC256_CLEAN_seedexpander(seedexpander_state *state, uint8_t *output, size_t outlen); - -void PQCLEAN_HQC256_CLEAN_seedexpander_release(seedexpander_state *state); - - -#endif diff --git a/src/kem/hqc/pqclean_hqc-256_clean/vector.c b/src/kem/hqc/pqclean_hqc-256_clean/vector.c deleted file mode 100644 index 08a78ffec3..0000000000 --- a/src/kem/hqc/pqclean_hqc-256_clean/vector.c +++ /dev/null @@ -1,197 +0,0 @@ -#include "parameters.h" -#include "parsing.h" -#include "randombytes.h" -#include "vector.h" -#include -#include -/** - * @file vector.c - * @brief Implementation of vectors sampling and some utilities for the HQC scheme - */ - - -static uint32_t m_val[149] = { 74517, 74518, 74520, 74521, 74522, 74524, 74525, 74526, 74527, 74529, 74530, 74531, 74533, 74534, 74535, 74536, 74538, 74539, 74540, 74542, 74543, 74544, 74545, 74547, 74548, 74549, 74551, 74552, 74553, 74555, 74556, 74557, 74558, 74560, 74561, 74562, 74564, 74565, 74566, 74567, 74569, 74570, 74571, 74573, 74574, 74575, 74577, 74578, 74579, 74580, 74582, 74583, 74584, 74586, 74587, 74588, 74590, 74591, 74592, 74593, 74595, 74596, 74597, 74599, 74600, 74601, 74602, 74604, 74605, 74606, 74608, 74609, 74610, 74612, 74613, 74614, 74615, 74617, 74618, 74619, 74621, 74622, 74623, 74625, 74626, 74627, 74628, 74630, 74631, 74632, 74634, 74635, 74636, 74637, 74639, 74640, 74641, 74643, 74644, 74645, 74647, 74648, 74649, 74650, 74652, 74653, 74654, 74656, 74657, 74658, 74660, 74661, 74662, 74663, 74665, 74666, 74667, 74669, 74670, 74671, 74673, 74674, 74675, 74676, 74678, 74679, 74680, 74682, 74683, 74684, 74685, 74687, 74688, 74689, 74691, 74692, 74693, 74695, 74696, 74697, 74698, 74700, 74701, 74702, 74704, 74705, 74706, 74708, 74709 }; - -/** - * @brief Constant-time comparison of two integers v1 and v2 - * - * Returns 1 if v1 is equal to v2 and 0 otherwise - * https://gist.github.com/sneves/10845247 - * - * @param[in] v1 - * @param[in] v2 - */ -static inline uint32_t compare_u32(uint32_t v1, uint32_t v2) { - return 1 ^ ((uint32_t)((v1 - v2) | (v2 - v1)) >> 31); -} - -static uint64_t single_bit_mask(uint32_t pos) { - uint64_t ret = 0; - uint64_t mask = 1; - uint64_t tmp; - - for (size_t i = 0; i < 64; ++i) { - tmp = pos - i; - tmp = 0 - (1 - ((uint64_t)(tmp | (0 - tmp)) >> 63)); - ret |= mask & tmp; - mask <<= 1; - } - - return ret; -} - -static inline uint32_t cond_sub(uint32_t r, uint32_t n) { - uint32_t mask; - r -= n; - mask = 0 - (r >> 31); - return r + (n & mask); -} - -static inline uint32_t reduce(uint32_t a, size_t i) { - uint32_t q, n, r; - q = ((uint64_t) a * m_val[i]) >> 32; - n = (uint32_t)(PARAM_N - i); - r = a - q * n; - return cond_sub(r, n); -} - -/** - * @brief Generates a vector of a given Hamming weight - * - * Implementation of Algorithm 5 in https://eprint.iacr.org/2021/1631.pdf - * - * @param[in] ctx Pointer to the context of the seed expander - * @param[in] v Pointer to an array - * @param[in] weight Integer that is the Hamming weight - */ -void PQCLEAN_HQC256_CLEAN_vect_set_random_fixed_weight(seedexpander_state *ctx, uint64_t *v, uint16_t weight) { - uint8_t rand_bytes[4 * PARAM_OMEGA_R] = {0}; // to be interpreted as PARAM_OMEGA_R 32-bit unsigned ints - uint32_t support[PARAM_OMEGA_R] = {0}; - uint32_t index_tab [PARAM_OMEGA_R] = {0}; - uint64_t bit_tab [PARAM_OMEGA_R] = {0}; - uint32_t pos, found, mask32, tmp; - uint64_t mask64, val; - - PQCLEAN_HQC256_CLEAN_seedexpander(ctx, rand_bytes, 4 * weight); - - for (size_t i = 0; i < weight; ++i) { - support[i] = rand_bytes[4 * i]; - support[i] |= rand_bytes[4 * i + 1] << 8; - support[i] |= (uint32_t)rand_bytes[4 * i + 2] << 16; - support[i] |= (uint32_t)rand_bytes[4 * i + 3] << 24; - support[i] = (uint32_t)(i + reduce(support[i], i)); // use constant-tme reduction - } - - for (size_t i = (weight - 1); i-- > 0;) { - found = 0; - - for (size_t j = i + 1; j < weight; ++j) { - found |= compare_u32(support[j], support[i]); - } - - mask32 = 0 - found; - support[i] = (mask32 & i) ^ (~mask32 & support[i]); - } - - for (size_t i = 0; i < weight; ++i) { - index_tab[i] = support[i] >> 6; - pos = support[i] & 0x3f; - bit_tab[i] = single_bit_mask(pos); // avoid secret shift - } - - for (size_t i = 0; i < VEC_N_SIZE_64; ++i) { - val = 0; - for (size_t j = 0; j < weight; ++j) { - tmp = (uint32_t)(i - index_tab[j]); - tmp = 1 ^ ((uint32_t)(tmp | (0 - tmp)) >> 31); - mask64 = 0 - (uint64_t)tmp; - val |= (bit_tab[j] & mask64); - } - v[i] |= val; - } -} - - - -/** - * @brief Generates a random vector of dimension PARAM_N - * - * This function generates a random binary vector of dimension PARAM_N. It generates a random - * array of bytes using the PQCLEAN_HQC256_CLEAN_seedexpander function, and drop the extra bits using a mask. - * - * @param[in] v Pointer to an array - * @param[in] ctx Pointer to the context of the seed expander - */ -void PQCLEAN_HQC256_CLEAN_vect_set_random(seedexpander_state *ctx, uint64_t *v) { - uint8_t rand_bytes[VEC_N_SIZE_BYTES] = {0}; - - PQCLEAN_HQC256_CLEAN_seedexpander(ctx, rand_bytes, VEC_N_SIZE_BYTES); - - PQCLEAN_HQC256_CLEAN_load8_arr(v, VEC_N_SIZE_64, rand_bytes, VEC_N_SIZE_BYTES); - v[VEC_N_SIZE_64 - 1] &= RED_MASK; -} - - - -/** - * @brief Adds two vectors - * - * @param[out] o Pointer to an array that is the result - * @param[in] v1 Pointer to an array that is the first vector - * @param[in] v2 Pointer to an array that is the second vector - * @param[in] size Integer that is the size of the vectors - */ -void PQCLEAN_HQC256_CLEAN_vect_add(uint64_t *o, const uint64_t *v1, const uint64_t *v2, size_t size) { - for (size_t i = 0; i < size; ++i) { - o[i] = v1[i] ^ v2[i]; - } -} - - - -/** - * @brief Compares two vectors - * - * @param[in] v1 Pointer to an array that is first vector - * @param[in] v2 Pointer to an array that is second vector - * @param[in] size Integer that is the size of the vectors - * @returns 0 if the vectors are equal and 1 otherwise - */ -uint8_t PQCLEAN_HQC256_CLEAN_vect_compare(const uint8_t *v1, const uint8_t *v2, size_t size) { - uint16_t r = 0x0100; - - for (size_t i = 0; i < size; i++) { - r |= v1[i] ^ v2[i]; - } - - return (r - 1) >> 8; -} - - - -/** - * @brief Resize a vector so that it contains size_o bits - * - * @param[out] o Pointer to the output vector - * @param[in] size_o Integer that is the size of the output vector in bits - * @param[in] v Pointer to the input vector - * @param[in] size_v Integer that is the size of the input vector in bits - */ -void PQCLEAN_HQC256_CLEAN_vect_resize(uint64_t *o, uint32_t size_o, const uint64_t *v, uint32_t size_v) { - uint64_t mask = 0x7FFFFFFFFFFFFFFF; - size_t val = 0; - if (size_o < size_v) { - - if (size_o % 64) { - val = 64 - (size_o % 64); - } - - memcpy(o, v, VEC_N1N2_SIZE_BYTES); - - for (size_t i = 0; i < val; ++i) { - o[VEC_N1N2_SIZE_64 - 1] &= (mask >> i); - } - } else { - memcpy(o, v, 8 * CEIL_DIVIDE(size_v, 64)); - } -} diff --git a/src/kem/hqc/pqclean_hqc-256_clean/vector.h b/src/kem/hqc/pqclean_hqc-256_clean/vector.h deleted file mode 100644 index 9067320d03..0000000000 --- a/src/kem/hqc/pqclean_hqc-256_clean/vector.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef VECTOR_H -#define VECTOR_H - - -/** - * @file vector.h - * @brief Header file for vector.c - */ -#include "shake_prng.h" -#include -#include - -void PQCLEAN_HQC256_CLEAN_vect_set_random_fixed_weight(seedexpander_state *ctx, uint64_t *v, uint16_t weight); - -void PQCLEAN_HQC256_CLEAN_vect_set_random(seedexpander_state *ctx, uint64_t *v); - - -void PQCLEAN_HQC256_CLEAN_vect_add(uint64_t *o, const uint64_t *v1, const uint64_t *v2, size_t size); - -uint8_t PQCLEAN_HQC256_CLEAN_vect_compare(const uint8_t *v1, const uint8_t *v2, size_t size); - -void PQCLEAN_HQC256_CLEAN_vect_resize(uint64_t *o, uint32_t size_o, const uint64_t *v, uint32_t size_v); - - -#endif