mirror of
https://github.com/luxfi/pqclean.git
synced 2026-11-03 09:57:54 +00:00
99 lines
4.2 KiB
C
99 lines
4.2 KiB
C
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
#include "context.h"
|
|
#include "thashx4.h"
|
|
|
|
#include "params.h"
|
|
#include "utils.h"
|
|
|
|
#include "fips202x4.h"
|
|
|
|
extern void KeccakP1600times4_PermuteAll_24rounds(__m256i *s);
|
|
|
|
/**
|
|
* 4-way parallel version of thash; takes 4x as much input and output
|
|
*/
|
|
void thashx4(unsigned char *out0,
|
|
unsigned char *out1,
|
|
unsigned char *out2,
|
|
unsigned char *out3,
|
|
const unsigned char *in0,
|
|
const unsigned char *in1,
|
|
const unsigned char *in2,
|
|
const unsigned char *in3, unsigned int inblocks,
|
|
const spx_ctx *ctx, uint32_t addrx4[4 * 8]) {
|
|
if (inblocks == 1 || inblocks == 2) {
|
|
/* As we write and read only a few quadwords, it is more efficient to
|
|
* build and extract from the fourway SHAKE256 state by hand. */
|
|
__m256i state[25];
|
|
for (int i = 0; i < SPX_N / 8; i++) {
|
|
state[i] = _mm256_set1_epi64x(((int64_t *)ctx->pub_seed)[i]);
|
|
}
|
|
for (int i = 0; i < 4; i++) {
|
|
state[(SPX_N / 8) + i] = _mm256_set_epi32(
|
|
(int)addrx4[(3 * 8) + 1 + (2 * i)],
|
|
(int)addrx4[(3 * 8) + (2 * i)],
|
|
(int)addrx4[(2 * 8) + 1 + (2 * i)],
|
|
(int)addrx4[(2 * 8) + (2 * i)],
|
|
(int)addrx4[8 + 1 + (2 * i)],
|
|
(int)addrx4[8 + (2 * i)],
|
|
(int)addrx4[1 + (2 * i)],
|
|
(int)addrx4[2 * i]
|
|
);
|
|
}
|
|
|
|
for (unsigned int i = 0; i < (SPX_N / 8) * inblocks; i++) {
|
|
state[(SPX_N / 8) + 4 + i] = _mm256_set_epi64x(
|
|
((int64_t *)in3)[i],
|
|
((int64_t *)in2)[i],
|
|
((int64_t *)in1)[i],
|
|
((int64_t *)in0)[i]
|
|
);
|
|
}
|
|
|
|
/* Domain separator and padding. */
|
|
for (size_t i = ((SPX_N / 8) * (1 + inblocks)) + 4; i < 16; i++) {
|
|
state[i] = _mm256_set1_epi64x(0);
|
|
}
|
|
state[16] = _mm256_set1_epi64x((long long)(0x80ULL << 56));
|
|
state[((SPX_N / 8) * (1 + inblocks)) + 4] = _mm256_xor_si256(
|
|
state[((SPX_N / 8) * (1 + inblocks)) + 4],
|
|
_mm256_set1_epi64x(0x1f)
|
|
);
|
|
for (int i = 17; i < 25; i++) {
|
|
state[i] = _mm256_set1_epi64x(0);
|
|
}
|
|
|
|
KeccakP1600times4_PermuteAll_24rounds(&state[0]);
|
|
|
|
for (int i = 0; i < SPX_N / 8; i++) {
|
|
((int64_t *)out0)[i] = _mm256_extract_epi64(state[i], 0);
|
|
((int64_t *)out1)[i] = _mm256_extract_epi64(state[i], 1);
|
|
((int64_t *)out2)[i] = _mm256_extract_epi64(state[i], 2);
|
|
((int64_t *)out3)[i] = _mm256_extract_epi64(state[i], 3);
|
|
}
|
|
} else {
|
|
PQCLEAN_VLA(unsigned char, buf0, SPX_N + SPX_ADDR_BYTES + (inblocks * SPX_N));
|
|
PQCLEAN_VLA(unsigned char, buf1, SPX_N + SPX_ADDR_BYTES + (inblocks * SPX_N));
|
|
PQCLEAN_VLA(unsigned char, buf2, SPX_N + SPX_ADDR_BYTES + (inblocks * SPX_N));
|
|
PQCLEAN_VLA(unsigned char, buf3, SPX_N + SPX_ADDR_BYTES + (inblocks * SPX_N));
|
|
|
|
memcpy(buf0, ctx->pub_seed, SPX_N);
|
|
memcpy(buf1, ctx->pub_seed, SPX_N);
|
|
memcpy(buf2, ctx->pub_seed, SPX_N);
|
|
memcpy(buf3, ctx->pub_seed, SPX_N);
|
|
memcpy(buf0 + SPX_N, addrx4 + (0 * 8), SPX_ADDR_BYTES);
|
|
memcpy(buf1 + SPX_N, addrx4 + (1 * 8), SPX_ADDR_BYTES);
|
|
memcpy(buf2 + SPX_N, addrx4 + (2 * 8), SPX_ADDR_BYTES);
|
|
memcpy(buf3 + SPX_N, addrx4 + (3 * 8), SPX_ADDR_BYTES);
|
|
memcpy(buf0 + SPX_N + SPX_ADDR_BYTES, in0, inblocks * SPX_N);
|
|
memcpy(buf1 + SPX_N + SPX_ADDR_BYTES, in1, inblocks * SPX_N);
|
|
memcpy(buf2 + SPX_N + SPX_ADDR_BYTES, in2, inblocks * SPX_N);
|
|
memcpy(buf3 + SPX_N + SPX_ADDR_BYTES, in3, inblocks * SPX_N);
|
|
|
|
shake256x4(out0, out1, out2, out3, SPX_N,
|
|
buf0, buf1, buf2, buf3, SPX_N + SPX_ADDR_BYTES + (inblocks * SPX_N));
|
|
}
|
|
}
|