pqc/crypto_kem/hqc-192/avx2/code.c
2021-03-24 21:02:48 +00:00

106 lines
3.0 KiB
C

#include "bch.h"
#include "code.h"
#include "gen_matrix.h"
#include "parameters.h"
#include "repetition.h"
#include <immintrin.h>
#include <stdint.h>
#include <string.h>
/**
* @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_HQC192_AVX2_code_encode(uint64_t *em, const uint64_t *m) {
const uint64_t mask[2][2] = {{0x0UL, 0x0UL}, {0x7FFFFFFFFFFFFFFUL, 0x3FFFFFFFFFFFFFFUL}};
size_t i, j, pos_r;
uint64_t bit;
uint16_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 (i = 0; i < 4; i++) {
for (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_HQC192_AVX2_code_decode(uint64_t *m, const uint64_t *em) {
uint64_t tmp[VEC_N1_SIZE_64] = {0};
PQCLEAN_HQC192_AVX2_repetition_code_decode(tmp, em);
PQCLEAN_HQC192_AVX2_bch_code_decode(m, tmp);
}