#include "bch.h" #include "code.h" #include "gen_matrix.h" #include "parameters.h" #include "repetition.h" #include #include #include /** * @file code.c * @brief Implementation of tensor code */ static inline uint64_t mux(uint64_t a, uint64_t b, int64_t bit); static inline uint64_t mux(uint64_t a, uint64_t b, int64_t bit) { uint64_t ret = a ^ b; return (ret & (-bit >> 63)) ^ a; } /** * * @brief Encoding the message m to a code word em using the tensor code * * We encode the message using the BCH code. For each bit obtained, * we duplicate the bit PARAM_N2 times to apply repetition code. * BCH encoding is done using the classical mG operation, * columns of the matrix are stored in 256-bit registers * * @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_AVX2_code_encode(uint64_t *em, const uint64_t *m) { const uint64_t mask[2][2] = {{0x0UL, 0x0UL}, {0x7FFFFFFFUL, 0x3FFFFFFFUL}}; size_t i, pos_r; uint64_t bit; uint64_t idx_r; uint64_t select; __m256i *colonne, y, aux0; __m256i msg = _mm256_lddqu_si256((const __m256i *) m); colonne = ((__m256i *) gen_matrix); pos_r = 0; for (i = 0; i < PARAM_N1 - PARAM_K; i++) { // y is the and operation between m and ith column of G y = _mm256_and_si256(colonne[i], msg); // aux0 = (y2 y3 y0 y1) aux0 = _mm256_permute2x128_si256(y, y, 1); // y = (y0^y2 y1^y3 y2^y0 y3^y1) y = _mm256_xor_si256(y, aux0); // aux0 = (y1^y3 y0^y2 y1^y3 y0^y2) aux0 = _mm256_shuffle_epi32(y, 0x4e); // y = (y0^y1^y2^y3 repeated 4 times) y = _mm256_xor_si256(aux0, y); bit = _mm_popcnt_u64(_mm256_extract_epi64(y, 0)) & 1; idx_r = (pos_r & 0x3f); select = mux(mask[0][0], mask[1][0], bit); em[(pos_r >> 6) + 0] ^= select << idx_r; select = mux(mask[0][1], mask[1][1], bit); em[(pos_r >> 6) + 1] ^= select >> ((63 - idx_r)); pos_r += PARAM_N2; } /* now we add the message m */ /* systematic encoding */ pos_r = PARAM_N2 * (PARAM_N1 - PARAM_K); for (int32_t i = 0; i < 4; i++) { for (int32_t j = 0; j < 64; j++) { bit = (m[i] >> j) & 0x1; idx_r = (pos_r & 0x3f); select = mux(mask[0][0], mask[1][0], bit); em[(pos_r >> 6) + 0] ^= select << idx_r; select = mux(mask[0][1], mask[1][1], bit); em[(pos_r >> 6) + 1] ^= select >> ((63 - idx_r)); pos_r += PARAM_N2; } } } /** * @brief Decoding the code word em to a message m using the tensor 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_AVX2_code_decode(uint64_t *m, const uint64_t *em) { uint64_t tmp[VEC_N1_SIZE_64] = {0}; PQCLEAN_HQC128_AVX2_repetition_code_decode(tmp, em); PQCLEAN_HQC128_AVX2_bch_code_decode(m, tmp); }