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

115 lines
3.5 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_HQC256_AVX2_code_encode(uint64_t *em, const uint64_t *m) {
uint64_t res;
uint32_t i;
static const uint64_t mask[2][3] = {{0x0UL, 0x0UL, 0x0UL}, {0xFFFFFFFFFFFFFFFFUL, 0xFFFFFFFFFFFFFFFFUL, 0x3FFFFFUL}};
__m256i *colonne, y, aux0;
__m256i msg = _mm256_lddqu_si256((const __m256i *) m);
colonne = ((__m256i *) gen_matrix);
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);
res = _mm_popcnt_u64(_mm256_extract_epi64(y, 0)) & 1;
uint16_t pos_r = PARAM_N2 * i;
uint16_t idx_r = (pos_r & 0x3f);
uint64_t *p64 = em;
p64 += pos_r >> 6;
uint64_t select = mux(mask[0][0], mask[1][0], res);
*p64 ^= select << idx_r;
int64_t aux = (41 - idx_r);
uint64_t aux2 = (aux > 0);
uint64_t idx2 = aux * aux2;
select = mux(mask[0][1], mask[1][1], res);
*(p64 + 1) ^= select >> idx2;
select = mux(mask[0][2], mask[1][2], res);
*(p64 + 2) ^= select >> ((63 - idx_r));
}
/* now we add the message m */
/* systematic encoding */
for (int32_t i = 0; i < 4; i++) {
for (int32_t j = 0; j < 64; j++) {
uint8_t bit = (m[i] >> j) & 0x1;
uint32_t pos_r = PARAM_N2 * ((PARAM_N1 - PARAM_K) + ((i << 6) + j));
uint16_t idx_r = (pos_r & 0x3f);
uint64_t *p64 = em;
p64 += pos_r >> 6;
uint64_t select = mux(mask[0][0], mask[1][0], bit);
*p64 ^= select << idx_r;
int64_t aux = (41 - idx_r);
uint64_t aux2 = (aux > 0);
uint64_t idx2 = aux * aux2;
select = mux(mask[0][1], mask[1][1], bit);
*(p64 + 1) ^= select >> idx2;
select = mux(mask[0][2], mask[1][2], bit);
*(p64 + 2) ^= select >> ((63 - idx_r));
}
}
}
/**
* @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_HQC256_AVX2_code_decode(uint64_t *m, const uint64_t *em) {
uint64_t tmp[VEC_N1_SIZE_64] = {0};
PQCLEAN_HQC256_AVX2_repetition_code_decode(tmp, em);
PQCLEAN_HQC256_AVX2_bch_code_decode(m, tmp);
}