158 lines
4.8 KiB
C
158 lines
4.8 KiB
C
#include "gf2x.h"
|
|
#include "nistseedexpander.h"
|
|
#include "parameters.h"
|
|
#include "randombytes.h"
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <string.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);
|
|
static void fast_convolution_mult(uint64_t *o, const uint32_t *a1, const uint64_t *a2, uint16_t weight, AES_XOF_struct *ctx);
|
|
|
|
/**
|
|
* @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) {
|
|
size_t i;
|
|
uint64_t r;
|
|
uint64_t carry;
|
|
|
|
for (i = 0; i < VEC_N_SIZE_64; i++) {
|
|
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
|
|
*/
|
|
static void fast_convolution_mult(uint64_t *o, const uint32_t *a1, const uint64_t *a2, uint16_t weight, AES_XOF_struct *ctx) {
|
|
//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];
|
|
uint64_t *pt;
|
|
uint16_t *res_16;
|
|
size_t i, j;
|
|
|
|
for (i = 0; i < 16; i++) {
|
|
permuted_table[i] = i;
|
|
}
|
|
|
|
seedexpander(ctx, (uint8_t *) permutation_table, 16 * sizeof(uint16_t));
|
|
|
|
for (i = 0; i < 15; i++) {
|
|
swap(permuted_table + i, 0, permutation_table[i] % (16 - i));
|
|
}
|
|
|
|
pt = table + (permuted_table[0] * (VEC_N_SIZE_64 + 1));
|
|
for (j = 0; j < VEC_N_SIZE_64; j++) {
|
|
pt[j] = a2[j];
|
|
}
|
|
pt[VEC_N_SIZE_64] = 0x0;
|
|
|
|
for (i = 1; i < 16; i++) {
|
|
carry = 0;
|
|
pt = table + (permuted_table[i] * (VEC_N_SIZE_64 + 1));
|
|
for (j = 0; j < VEC_N_SIZE_64; j++) {
|
|
pt[j] = (a2[j] << i) ^ carry;
|
|
carry = (a2[j] >> ((64 - i)));
|
|
}
|
|
pt[VEC_N_SIZE_64] = carry;
|
|
}
|
|
|
|
for (i = 0; i < weight; i++) {
|
|
permuted_sparse_vect[i] = i;
|
|
}
|
|
|
|
seedexpander(ctx, (uint8_t *) permutation_sparse_vect, weight * sizeof(uint16_t));
|
|
|
|
for (i = 0; i + 1 < weight; i++) {
|
|
swap(permuted_sparse_vect + i, 0, (uint16_t) (permutation_sparse_vect[i] % (weight - i)));
|
|
}
|
|
|
|
for (i = 0; i < weight; i++) {
|
|
dec = a1[permuted_sparse_vect[i]] & 0xf;
|
|
s = a1[permuted_sparse_vect[i]] >> 4;
|
|
res_16 = ((uint16_t *) o) + s;
|
|
pt = table + (permuted_table[dec] * (VEC_N_SIZE_64 + 1));
|
|
|
|
for (j = 0; j < VEC_N_SIZE_64 + 1; j++) {
|
|
*res_16++ ^= (uint16_t) pt[j];
|
|
*res_16++ ^= (uint16_t) (pt[j] >> 16);
|
|
*res_16++ ^= (uint16_t) (pt[j] >> 32);
|
|
*res_16++ ^= (uint16_t) (pt[j] >> 48);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* @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_HQCRMRS128_CLEAN_vect_mul(uint64_t *o, const uint32_t *a1, const uint64_t *a2, uint16_t weight, AES_XOF_struct *ctx) {
|
|
uint64_t tmp[2 * VEC_N_SIZE_64 + 1];
|
|
for (uint32_t j = 0; j < 2 * VEC_N_SIZE_64 + 1; j++) {
|
|
tmp[j] = 0;
|
|
}
|
|
|
|
fast_convolution_mult(tmp, a1, a2, weight, ctx);
|
|
reduce(o, tmp);
|
|
}
|