pqc/crypto_kem/frodokem640shake/clean/matrix_shake.c

80 lines
3.3 KiB
C
Raw Normal View History

/********************************************************************************************
* FrodoKEM: Learning with Errors Key Encapsulation
*
* Abstract: matrix arithmetic functions used by the KEM
*********************************************************************************************/
#include <stdint.h>
#include <string.h>
#include "fips202.h"
#include "api.h"
2019-04-01 02:44:36 +01:00
#include "common.h"
#include "params.h"
2019-03-22 03:27:16 +00:00
int PQCLEAN_FRODOKEM640SHAKE_CLEAN_mul_add_as_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A) {
// Generate-and-multiply: generate matrix A (N x N) row-wise, multiply by s on the right.
// Inputs: s, e (N x N_BAR)
// Output: out = A*s + e (N x N_BAR)
2019-04-01 02:52:35 +01:00
uint16_t i, j, k;
2019-03-22 03:27:16 +00:00
int16_t A[PARAMS_N * PARAMS_N] = {0};
uint8_t seed_A_separated[2 + BYTES_SEED_A];
2019-03-22 03:27:16 +00:00
uint16_t *seed_A_origin = (uint16_t *)&seed_A_separated;
memcpy(&seed_A_separated[2], seed_A, BYTES_SEED_A);
for (i = 0; i < PARAMS_N; i++) {
2019-04-01 02:44:36 +01:00
seed_A_origin[0] = PQCLEAN_FRODOKEM640SHAKE_CLEAN_UINT16_TO_LE(i);
2019-03-22 03:27:16 +00:00
shake128((unsigned char *)(A + i * PARAMS_N), (unsigned long long)(2 * PARAMS_N), seed_A_separated, 2 + BYTES_SEED_A);
}
2019-04-01 02:44:36 +01:00
for (i = 0; i < PARAMS_N * PARAMS_N; i++) {
A[i] = PQCLEAN_FRODOKEM640SHAKE_CLEAN_LE_TO_UINT16(A[i]);
}
2019-03-22 03:27:16 +00:00
memcpy(out, e, PARAMS_NBAR * PARAMS_N * sizeof(uint16_t));
for (i = 0; i < PARAMS_N; i++) { // Matrix multiplication-addition A*s + e
for (k = 0; k < PARAMS_NBAR; k++) {
uint16_t sum = 0;
2019-03-22 03:27:16 +00:00
for (j = 0; j < PARAMS_N; j++) {
sum += A[i * PARAMS_N + j] * s[k * PARAMS_N + j];
}
2019-03-22 03:27:16 +00:00
out[i * PARAMS_NBAR + k] += sum; // Adding e. No need to reduce modulo 2^15, extra bits are taken care of during packing later on.
}
}
2019-03-22 03:27:16 +00:00
return 1;
}
2019-03-22 03:27:16 +00:00
int PQCLEAN_FRODOKEM640SHAKE_CLEAN_mul_add_sa_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A) {
// Generate-and-multiply: generate matrix A (N x N) column-wise, multiply by s' on the left.
// Inputs: s', e' (N_BAR x N)
// Output: out = s'*A + e' (N_BAR x N)
2019-04-01 02:52:35 +01:00
uint16_t i, j, k;
2019-03-22 03:27:16 +00:00
int16_t A[PARAMS_N * PARAMS_N] = {0};
uint8_t seed_A_separated[2 + BYTES_SEED_A];
2019-03-22 03:27:16 +00:00
uint16_t *seed_A_origin = (uint16_t *)&seed_A_separated;
memcpy(&seed_A_separated[2], seed_A, BYTES_SEED_A);
for (i = 0; i < PARAMS_N; i++) {
2019-04-01 02:44:36 +01:00
seed_A_origin[0] = PQCLEAN_FRODOKEM640SHAKE_CLEAN_UINT16_TO_LE(i);
2019-03-22 03:27:16 +00:00
shake128((unsigned char *)(A + i * PARAMS_N), (unsigned long long)(2 * PARAMS_N), seed_A_separated, 2 + BYTES_SEED_A);
}
2019-04-01 02:44:36 +01:00
for (i = 0; i < PARAMS_N * PARAMS_N; i++) {
A[i] = PQCLEAN_FRODOKEM640SHAKE_CLEAN_LE_TO_UINT16(A[i]);
}
memcpy(out, e, PARAMS_NBAR * PARAMS_N * sizeof(uint16_t));
for (i = 0; i < PARAMS_N; i++) { // Matrix multiplication-addition A*s + e
for (k = 0; k < PARAMS_NBAR; k++) {
uint16_t sum = 0;
2019-03-22 03:27:16 +00:00
for (j = 0; j < PARAMS_N; j++) {
sum += A[j * PARAMS_N + i] * s[k * PARAMS_N + j];
}
2019-03-22 03:27:16 +00:00
out[k * PARAMS_N + i] += sum; // Adding e. No need to reduce modulo 2^15, extra bits are taken care of during packing later on.
}
}
2019-03-22 03:27:16 +00:00
return 1;
}