pqc/crypto_kem/hqc-rmrs-192/clean/gf2x.c

155 lines
4.8 KiB
C
Raw Normal View History

2020-09-07 19:23:34 +01:00
#include "gf2x.h"
#include "nistseedexpander.h"
#include "parameters.h"
2020-09-12 14:59:40 +01:00
#include "parsing.h"
2020-09-07 19:23:34 +01:00
#include "randombytes.h"
#include <stdint.h>
/**
* \file gf2x.c
* \brief Implementation of multiplication of two polynomials
*/
static inline void swap(uint16_t *tab, uint16_t elt1, uint16_t elt2);
static void reduce(uint64_t *o, const uint64_t *a);
2020-09-12 14:59:40 +01:00
static void fast_convolution_mult(uint8_t *o, const uint32_t *a1, const uint64_t *a2, uint16_t weight, AES_XOF_struct *ctx);
2020-09-07 19:23:34 +01:00
/**
* @brief swap two elements in a table
*
* This function exchanges tab[elt1] with tab[elt2]
*
* @param[in] tab Pointer to the table
* @param[in] elt1 Index of the first element
* @param[in] elt2 Index of the second element
*/
static inline void swap(uint16_t *tab, uint16_t elt1, uint16_t elt2) {
uint16_t tmp = tab[elt1];
tab[elt1] = tab[elt2];
tab[elt2] = tmp;
}
/**
* @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) {
2020-09-11 21:53:23 +01:00
size_t i;
2020-09-07 19:23:34 +01:00
uint64_t r;
uint64_t carry;
2020-09-11 21:53:23 +01:00
for (i = 0; i < VEC_N_SIZE_64; i++) {
2020-09-07 19:23:34 +01:00
r = a[i + VEC_N_SIZE_64 - 1] >> (PARAM_N & 63);
carry = (uint64_t) (a[i + VEC_N_SIZE_64] << (64 - (PARAM_N & 63)));
o[i] = a[i] ^ r ^ carry;
}
o[VEC_N_SIZE_64 - 1] &= RED_MASK;
}
/**
* @brief computes product of the polynomial a1(x) with the sparse polynomial a2
*
* o(x) = a1(x)a2(x)
*
* @param[out] o Pointer to the result
* @param[in] a1 Pointer to the sparse polynomial a2 (list of degrees of the monomials which appear in a2)
* @param[in] a2 Pointer to the polynomial a1(x)
* @param[in] weight Hamming wifht of the sparse polynomial a2
* @param[in] ctx Pointer to a seed expander used to randomize the multiplication process
*/
2020-09-12 14:59:40 +01:00
static void fast_convolution_mult(uint8_t *o, const uint32_t *a1, const uint64_t *a2, uint16_t weight, AES_XOF_struct *ctx) {
2020-09-07 19:23:34 +01:00
//static uint32_t fast_convolution_mult(const uint64_t *A, const uint32_t *vB, uint64_t *C, const uint16_t w, AES_XOF_struct *ctx)
uint64_t carry;
uint32_t dec, s;
uint64_t table[16 * (VEC_N_SIZE_64 + 1)];
uint16_t permuted_table[16];
uint16_t permutation_table[16];
uint16_t permuted_sparse_vect[PARAM_OMEGA_E];
uint16_t permutation_sparse_vect[PARAM_OMEGA_E];
2020-09-12 14:59:40 +01:00
uint64_t tmp;
2020-09-07 19:23:34 +01:00
uint64_t *pt;
2020-09-12 14:59:40 +01:00
uint8_t *res;
2020-09-11 21:53:23 +01:00
size_t i, j;
2020-09-07 19:23:34 +01:00
2020-09-10 23:52:20 +01:00
for (i = 0; i < 16; i++) {
2020-09-11 23:19:10 +01:00
permuted_table[i] = (uint16_t) i;
2020-09-07 19:23:34 +01:00
}
seedexpander(ctx, (uint8_t *) permutation_table, 16 * sizeof(uint16_t));
2020-09-10 23:52:20 +01:00
for (i = 0; i < 15; i++) {
2020-09-07 19:23:34 +01:00
swap(permuted_table + i, 0, permutation_table[i] % (16 - i));
}
pt = table + (permuted_table[0] * (VEC_N_SIZE_64 + 1));
2020-09-10 23:52:20 +01:00
for (j = 0; j < VEC_N_SIZE_64; j++) {
2020-09-07 19:23:34 +01:00
pt[j] = a2[j];
}
pt[VEC_N_SIZE_64] = 0x0;
2020-09-10 23:52:20 +01:00
for (i = 1; i < 16; i++) {
2020-09-07 19:23:34 +01:00
carry = 0;
pt = table + (permuted_table[i] * (VEC_N_SIZE_64 + 1));
2020-09-10 23:52:20 +01:00
for (j = 0; j < VEC_N_SIZE_64; j++) {
2020-09-07 19:23:34 +01:00
pt[j] = (a2[j] << i) ^ carry;
carry = (a2[j] >> ((64 - i)));
}
pt[VEC_N_SIZE_64] = carry;
}
2020-09-10 23:52:20 +01:00
for (i = 0; i < weight; i++) {
2020-09-11 23:19:10 +01:00
permuted_sparse_vect[i] = (uint16_t) i;
2020-09-07 19:23:34 +01:00
}
seedexpander(ctx, (uint8_t *) permutation_sparse_vect, weight * sizeof(uint16_t));
2020-09-10 23:52:20 +01:00
for (i = 0; i + 1 < weight; i++) {
2020-09-11 21:53:23 +01:00
swap(permuted_sparse_vect + i, 0, (uint16_t) (permutation_sparse_vect[i] % (weight - i)));
2020-09-07 19:23:34 +01:00
}
2020-09-10 23:52:20 +01:00
for (i = 0; i < weight; i++) {
2020-09-07 19:23:34 +01:00
dec = a1[permuted_sparse_vect[i]] & 0xf;
s = a1[permuted_sparse_vect[i]] >> 4;
2020-09-12 14:59:40 +01:00
res = o + 2 * s;
2020-09-07 19:23:34 +01:00
pt = table + (permuted_table[dec] * (VEC_N_SIZE_64 + 1));
2020-09-10 23:52:20 +01:00
for (j = 0; j < VEC_N_SIZE_64 + 1; j++) {
2020-09-12 14:59:40 +01:00
tmp = PQCLEAN_HQCRMRS192_CLEAN_load8(res);
PQCLEAN_HQCRMRS192_CLEAN_store8(res, tmp ^ pt[j]);
res += 8;
2020-09-07 19:23:34 +01:00
}
}
}
/**
* @brief Multiply two polynomials modulo \f$ X^n - 1\f$.
*
* This functions multiplies a sparse polynomial <b>a1</b> (of Hamming weight equal to <b>weight</b>)
* and a dense polynomial <b>a2</b>. The multiplication is done modulo \f$ X^n - 1\f$.
*
* @param[out] o Pointer to the result
* @param[in] a1 Pointer to the sparse polynomial
* @param[in] a2 Pointer to the dense polynomial
* @param[in] weight Integer that is the weigt of the sparse polynomial
* @param[in] ctx Pointer to the randomness context
*/
void PQCLEAN_HQCRMRS192_CLEAN_vect_mul(uint64_t *o, const uint32_t *a1, const uint64_t *a2, uint16_t weight, AES_XOF_struct *ctx) {
2020-09-12 14:59:40 +01:00
uint64_t tmp[2 * VEC_N_SIZE_64 + 1] = {0};
2020-09-07 19:23:34 +01:00
2020-09-12 14:59:40 +01:00
fast_convolution_mult((uint8_t *) tmp, a1, a2, weight, ctx);
PQCLEAN_HQCRMRS192_CLEAN_load8_arr(tmp, 2 * VEC_N_SIZE_64 + 1, (uint8_t *) tmp, sizeof(tmp));
2020-09-07 19:23:34 +01:00
reduce(o, tmp);
}