Update Saber and add AVX2 implementationmaster
@@ -14,4 +14,13 @@ principal-submitters: | |||
- Frederik Vercauteren | |||
implementations: | |||
- name: clean | |||
version: https://github.com/KULeuven-COSIC/SABER/commit/14ede83f1ff3bcc41f0464543542366c68b55871 | |||
version: https://github.com/KULeuven-COSIC/SABER/tree/509cc5ec3a7e12a751ccdd2ef5bd6e54e00bd350 via https://github.com/jschanck/package-pqclean/tree/1ae84c3c/saber | |||
- name: avx2 | |||
version: https://github.com/KULeuven-COSIC/SABER/tree/509cc5ec3a7e12a751ccdd2ef5bd6e54e00bd350 via https://github.com/jschanck/package-pqclean/tree/1ae84c3c/saber | |||
supported_platforms: | |||
- architecture: x86_64 | |||
operating_systems: | |||
- Linux | |||
- Darwin | |||
required_flags: | |||
- avx2 |
@@ -0,0 +1 @@ | |||
Public Domain |
@@ -0,0 +1,22 @@ | |||
# This Makefile can be used with GNU Make or BSD Make | |||
LIB=libfiresaber_avx2.a | |||
HEADERS=api.h cbd.h pack_unpack.h poly.h SABER_indcpa.h SABER_params.h verify.h | |||
OBJECTS=cbd.o kem.o pack_unpack.o poly.o poly_mul.o SABER_indcpa.o verify.o | |||
CFLAGS=-O3 -mavx2 -Wall -Wextra -Wpedantic -Wvla -Werror -Wredundant-decls -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) | |||
all: $(LIB) | |||
%.o: %.s $(HEADERS) | |||
$(AS) -o $@ $< | |||
%.o: %.c $(HEADERS) | |||
$(CC) $(CFLAGS) -c -o $@ $< | |||
$(LIB): $(OBJECTS) | |||
$(AR) -r $@ $(OBJECTS) | |||
clean: | |||
$(RM) $(OBJECTS) | |||
$(RM) $(LIB) |
@@ -0,0 +1,125 @@ | |||
#include "SABER_indcpa.h" | |||
#include "SABER_params.h" | |||
#include "fips202.h" | |||
#include "pack_unpack.h" | |||
#include "poly.h" | |||
#include "randombytes.h" | |||
#include <stdint.h> | |||
#include <string.h> | |||
#define h1 (1 << (SABER_EQ - SABER_EP - 1)) | |||
#define h2 ((1 << (SABER_EP - 2)) - (1 << (SABER_EP - SABER_ET - 1)) + (1 << (SABER_EQ - SABER_EP - 1))) | |||
void PQCLEAN_FIRESABER_AVX2_indcpa_kem_keypair(uint8_t pk[SABER_INDCPA_PUBLICKEYBYTES], uint8_t sk[SABER_INDCPA_SECRETKEYBYTES]) { | |||
size_t i, j; | |||
poly A[SABER_L][SABER_L]; | |||
poly *skpv1 = A[0]; // use first row of A to hold sk temporarily | |||
toom4_points skpv1_eval[SABER_L]; | |||
poly res[SABER_L]; | |||
uint8_t rand[SABER_NOISESEEDBYTES]; | |||
uint8_t *seed_A = pk + SABER_POLYVECCOMPRESSEDBYTES; | |||
randombytes(seed_A, SABER_SEEDBYTES); | |||
shake128(seed_A, SABER_SEEDBYTES, seed_A, SABER_SEEDBYTES); // for not revealing system RNG state | |||
randombytes(rand, SABER_NOISESEEDBYTES); | |||
PQCLEAN_FIRESABER_AVX2_GenSecret(skpv1, rand); | |||
PQCLEAN_FIRESABER_AVX2_POLVECq2BS(sk, skpv1); // pack secret key | |||
for (j = 0; j < SABER_L; j++) { | |||
PQCLEAN_FIRESABER_AVX2_toom4_eval(&skpv1_eval[j], &skpv1[j]); | |||
} | |||
PQCLEAN_FIRESABER_AVX2_GenMatrix(A, seed_A); // sample matrix A | |||
PQCLEAN_FIRESABER_AVX2_MatrixVectorMul(res, (const poly (*)[SABER_L])A, (const toom4_points *)skpv1_eval, 1); // Matrix in transposed order | |||
// rounding | |||
for (i = 0; i < SABER_L; i++) { | |||
for (j = 0; j < SABER_N; j++) { | |||
res[i].coeffs[j] += h1; | |||
res[i].coeffs[j] >>= SABER_EQ - SABER_EP; | |||
res[i].coeffs[j] &= SABER_Q - 1; | |||
} | |||
} | |||
PQCLEAN_FIRESABER_AVX2_POLVECp2BS(pk, res); // pack public key | |||
} | |||
void PQCLEAN_FIRESABER_AVX2_indcpa_kem_enc(uint8_t ciphertext[SABER_BYTES_CCA_DEC], const uint8_t m[SABER_KEYBYTES], const uint8_t noiseseed[SABER_NOISESEEDBYTES], const uint8_t pk[SABER_INDCPA_PUBLICKEYBYTES]) { | |||
size_t i, j; | |||
poly A[SABER_L][SABER_L]; | |||
poly res[SABER_L]; | |||
toom4_points skpv1_eval[SABER_L]; | |||
poly *temp = A[0]; // re-use stack space | |||
poly *vprime = &A[0][0]; | |||
poly *message = &A[0][1]; | |||
const uint8_t *seed_A = pk + SABER_POLYVECCOMPRESSEDBYTES; | |||
uint8_t *msk_c = ciphertext + SABER_POLYVECCOMPRESSEDBYTES; | |||
PQCLEAN_FIRESABER_AVX2_GenSecret(temp, noiseseed); | |||
for (j = 0; j < SABER_L; j++) { | |||
PQCLEAN_FIRESABER_AVX2_toom4_eval(&skpv1_eval[j], &temp[j]); | |||
} | |||
PQCLEAN_FIRESABER_AVX2_GenMatrix(A, seed_A); | |||
PQCLEAN_FIRESABER_AVX2_MatrixVectorMul(res, (const poly (*)[SABER_L])A, (const toom4_points *)skpv1_eval, 0); // 0 => not transposed | |||
// rounding | |||
for (i = 0; i < SABER_L; i++) { //shift right EQ-EP bits | |||
for (j = 0; j < SABER_N; j++) { | |||
res[i].coeffs[j] += h1; | |||
res[i].coeffs[j] >>= SABER_EQ - SABER_EP; | |||
res[i].coeffs[j] &= SABER_Q - 1; | |||
} | |||
} | |||
PQCLEAN_FIRESABER_AVX2_POLVECp2BS(ciphertext, res); | |||
// vector-vector scalar multiplication with mod p | |||
PQCLEAN_FIRESABER_AVX2_BS2POLVECp(temp, pk); | |||
PQCLEAN_FIRESABER_AVX2_InnerProd(vprime, temp, skpv1_eval); | |||
PQCLEAN_FIRESABER_AVX2_BS2POLmsg(message, m); | |||
for (i = 0; i < SABER_N; i++) { | |||
vprime->coeffs[i] += h1 - (message->coeffs[i] << (SABER_EP - 1)); | |||
vprime->coeffs[i] &= SABER_P - 1; | |||
vprime->coeffs[i] >>= SABER_EP - SABER_ET; | |||
} | |||
PQCLEAN_FIRESABER_AVX2_POLT2BS(msk_c, vprime); | |||
} | |||
void PQCLEAN_FIRESABER_AVX2_indcpa_kem_dec(uint8_t m[SABER_KEYBYTES], const uint8_t sk[SABER_INDCPA_SECRETKEYBYTES], const uint8_t ciphertext[SABER_BYTES_CCA_DEC]) { | |||
size_t i; | |||
poly temp[SABER_L]; | |||
toom4_points sksv_eval[SABER_L]; | |||
const uint8_t *packed_cm = ciphertext + SABER_POLYVECCOMPRESSEDBYTES; | |||
poly *v = &temp[0]; | |||
poly *cm = &temp[1]; | |||
PQCLEAN_FIRESABER_AVX2_BS2POLVECq(temp, sk); | |||
for (i = 0; i < SABER_L; i++) { | |||
PQCLEAN_FIRESABER_AVX2_toom4_eval(&sksv_eval[i], &temp[i]); | |||
} | |||
PQCLEAN_FIRESABER_AVX2_BS2POLVECp(temp, ciphertext); | |||
PQCLEAN_FIRESABER_AVX2_InnerProd(v, temp, sksv_eval); | |||
PQCLEAN_FIRESABER_AVX2_BS2POLT(cm, packed_cm); | |||
for (i = 0; i < SABER_N; i++) { | |||
v->coeffs[i] += h2 - (cm->coeffs[i] << (SABER_EP - SABER_ET)); | |||
v->coeffs[i] &= SABER_P - 1; | |||
v->coeffs[i] >>= SABER_EP - 1; | |||
} | |||
PQCLEAN_FIRESABER_AVX2_POLmsg2BS(m, v); | |||
} |
@@ -0,0 +1,13 @@ | |||
#ifndef INDCPA_H | |||
#define INDCPA_H | |||
#include "SABER_params.h" | |||
#include <stdint.h> | |||
void PQCLEAN_FIRESABER_AVX2_indcpa_kem_keypair(uint8_t pk[SABER_INDCPA_PUBLICKEYBYTES], uint8_t sk[SABER_INDCPA_SECRETKEYBYTES]); | |||
void PQCLEAN_FIRESABER_AVX2_indcpa_kem_enc(uint8_t ciphertext[SABER_BYTES_CCA_DEC], const uint8_t m[SABER_KEYBYTES], const uint8_t noiseseed[SABER_NOISESEEDBYTES], const uint8_t pk[SABER_INDCPA_PUBLICKEYBYTES]); | |||
void PQCLEAN_FIRESABER_AVX2_indcpa_kem_dec(uint8_t m[SABER_KEYBYTES], const uint8_t sk[SABER_INDCPA_SECRETKEYBYTES], const uint8_t ciphertext[SABER_BYTES_CCA_DEC]); | |||
#endif |
@@ -0,0 +1,41 @@ | |||
#ifndef PARAMS_H | |||
#define PARAMS_H | |||
/* Don't change anything below this line */ | |||
#define SABER_L 4 | |||
#define SABER_MU 6 | |||
#define SABER_ET 6 | |||
#define SABER_N 256 | |||
#define SABER_EP 10 | |||
#define SABER_P (1 << SABER_EP) | |||
#define SABER_EQ 13 | |||
#define SABER_Q (1 << SABER_EQ) | |||
#define SABER_SEEDBYTES 32 | |||
#define SABER_NOISESEEDBYTES 32 | |||
#define SABER_KEYBYTES 32 | |||
#define SABER_HASHBYTES 32 | |||
#define SABER_POLYCOINBYTES (SABER_MU * SABER_N / 8) | |||
#define SABER_POLYBYTES (SABER_EQ * SABER_N / 8) | |||
#define SABER_POLYVECBYTES (SABER_L * SABER_POLYBYTES) | |||
#define SABER_POLYCOMPRESSEDBYTES (SABER_EP * SABER_N / 8) | |||
#define SABER_POLYVECCOMPRESSEDBYTES (SABER_L * SABER_POLYCOMPRESSEDBYTES) | |||
#define SABER_SCALEBYTES_KEM (SABER_ET * SABER_N / 8) | |||
#define SABER_INDCPA_PUBLICKEYBYTES (SABER_POLYVECCOMPRESSEDBYTES + SABER_SEEDBYTES) | |||
#define SABER_INDCPA_SECRETKEYBYTES (SABER_POLYVECBYTES) | |||
#define SABER_PUBLICKEYBYTES (SABER_INDCPA_PUBLICKEYBYTES) | |||
#define SABER_SECRETKEYBYTES (SABER_INDCPA_SECRETKEYBYTES + SABER_INDCPA_PUBLICKEYBYTES + SABER_HASHBYTES + SABER_KEYBYTES) | |||
#define SABER_BYTES_CCA_DEC (SABER_POLYVECCOMPRESSEDBYTES + SABER_SCALEBYTES_KEM) | |||
#endif |
@@ -0,0 +1,18 @@ | |||
#ifndef PQCLEAN_FIRESABER_AVX2_API_H | |||
#define PQCLEAN_FIRESABER_AVX2_API_H | |||
#define PQCLEAN_FIRESABER_AVX2_CRYPTO_ALGNAME "FireSaber" | |||
#define PQCLEAN_FIRESABER_AVX2_CRYPTO_BYTES 32 | |||
#define PQCLEAN_FIRESABER_AVX2_CRYPTO_CIPHERTEXTBYTES 1472 | |||
#define PQCLEAN_FIRESABER_AVX2_CRYPTO_PUBLICKEYBYTES 1312 | |||
#define PQCLEAN_FIRESABER_AVX2_CRYPTO_SECRETKEYBYTES 3040 | |||
int PQCLEAN_FIRESABER_AVX2_crypto_kem_keypair(unsigned char *pk, unsigned char *sk); | |||
int PQCLEAN_FIRESABER_AVX2_crypto_kem_enc(unsigned char *ct, unsigned char *k, const unsigned char *pk); | |||
int PQCLEAN_FIRESABER_AVX2_crypto_kem_dec(unsigned char *k, const unsigned char *ct, const unsigned char *sk); | |||
#endif /* PQCLEAN_FIRESABER_AVX2_API_H */ |
@@ -0,0 +1,48 @@ | |||
#include "SABER_params.h" | |||
#include "api.h" | |||
#include "cbd.h" | |||
#include <stdint.h> | |||
/*--------------------------------------------------------------------- | |||
This file has been adapted from the implementation | |||
(available at, Public Domain https://github.com/pq-crystals/kyber) | |||
of "CRYSTALS – Kyber: a CCA-secure module-lattice-based KEM" | |||
by : Joppe Bos, Leo Ducas, Eike Kiltz, Tancrede Lepoint, | |||
Vadim Lyubashevsky, John M. Schanck, Peter Schwabe & Damien stehle | |||
----------------------------------------------------------------------*/ | |||
static uint64_t load_littleendian(const uint8_t *x, int bytes) { | |||
int i; | |||
uint64_t r = x[0]; | |||
for (i = 1; i < bytes; i++) { | |||
r |= (uint64_t)x[i] << (8 * i); | |||
} | |||
return r; | |||
} | |||
void PQCLEAN_FIRESABER_AVX2_cbd(uint16_t s[SABER_N], const uint8_t buf[SABER_POLYCOINBYTES]) { | |||
uint32_t t, d, a[4], b[4]; | |||
int i, j; | |||
for (i = 0; i < SABER_N / 4; i++) { | |||
t = (uint32_t) load_littleendian(buf + 3 * i, 3); | |||
d = 0; | |||
for (j = 0; j < 3; j++) { | |||
d += (t >> j) & 0x249249; | |||
} | |||
a[0] = d & 0x7; | |||
b[0] = (d >> 3) & 0x7; | |||
a[1] = (d >> 6) & 0x7; | |||
b[1] = (d >> 9) & 0x7; | |||
a[2] = (d >> 12) & 0x7; | |||
b[2] = (d >> 15) & 0x7; | |||
a[3] = (d >> 18) & 0x7; | |||
b[3] = (d >> 21); | |||
s[4 * i + 0] = (uint16_t)(a[0] - b[0]); | |||
s[4 * i + 1] = (uint16_t)(a[1] - b[1]); | |||
s[4 * i + 2] = (uint16_t)(a[2] - b[2]); | |||
s[4 * i + 3] = (uint16_t)(a[3] - b[3]); | |||
} | |||
} |
@@ -0,0 +1,16 @@ | |||
#ifndef CBD_H | |||
#define CBD_H | |||
/*--------------------------------------------------------------------- | |||
This file has been adapted from the implementation | |||
(available at, Public Domain https://github.com/pq-crystals/kyber) | |||
of "CRYSTALS – Kyber: a CCA-secure module-lattice-based KEM" | |||
by : Joppe Bos, Leo Ducas, Eike Kiltz, Tancrede Lepoint, | |||
Vadim Lyubashevsky, John M. Schanck, Peter Schwabe & Damien stehle | |||
----------------------------------------------------------------------*/ | |||
#include "SABER_params.h" | |||
#include <stdint.h> | |||
void PQCLEAN_FIRESABER_AVX2_cbd(uint16_t s[SABER_N], const uint8_t buf[SABER_POLYCOINBYTES]); | |||
#endif |
@@ -0,0 +1,77 @@ | |||
#include "SABER_indcpa.h" | |||
#include "SABER_params.h" | |||
#include "api.h" | |||
#include "fips202.h" | |||
#include "randombytes.h" | |||
#include "verify.h" | |||
#include <stddef.h> | |||
#include <stdint.h> | |||
int PQCLEAN_FIRESABER_AVX2_crypto_kem_keypair(uint8_t *pk, uint8_t *sk) { | |||
size_t i; | |||
PQCLEAN_FIRESABER_AVX2_indcpa_kem_keypair(pk, sk); // sk[0:SABER_INDCPA_SECRETKEYBYTES-1] <-- sk | |||
for (i = 0; i < SABER_INDCPA_PUBLICKEYBYTES; i++) { | |||
sk[i + SABER_INDCPA_SECRETKEYBYTES] = pk[i]; // sk[SABER_INDCPA_SECRETKEYBYTES:SABER_INDCPA_SECRETKEYBYTES+SABER_INDCPA_SECRETKEYBYTES-1] <-- pk | |||
} | |||
sha3_256(sk + SABER_SECRETKEYBYTES - 64, pk, SABER_INDCPA_PUBLICKEYBYTES); // Then hash(pk) is appended. | |||
randombytes(sk + SABER_SECRETKEYBYTES - SABER_KEYBYTES, SABER_KEYBYTES); // Remaining part of sk contains a pseudo-random number. | |||
// This is output when check in PQCLEAN_FIRESABER_AVX2_crypto_kem_dec() fails. | |||
return (0); | |||
} | |||
int PQCLEAN_FIRESABER_AVX2_crypto_kem_enc(uint8_t *c, uint8_t *k, const uint8_t *pk) { | |||
uint8_t kr[64]; // Will contain key, coins | |||
uint8_t buf[64]; | |||
randombytes(buf, 32); | |||
sha3_256(buf, buf, 32); // BUF[0:31] <-- random message (will be used as the key for client) Note: hash doesnot release system RNG output | |||
sha3_256(buf + 32, pk, SABER_INDCPA_PUBLICKEYBYTES); // BUF[32:63] <-- Hash(public key); Multitarget countermeasure for coins + contributory KEM | |||
sha3_512(kr, buf, 64); // kr[0:63] <-- Hash(buf[0:63]); | |||
// K^ <-- kr[0:31] | |||
// noiseseed (r) <-- kr[32:63]; | |||
PQCLEAN_FIRESABER_AVX2_indcpa_kem_enc(c, buf, kr + 32, pk); // buf[0:31] contains message; kr[32:63] contains randomness r; | |||
sha3_256(kr + 32, c, SABER_BYTES_CCA_DEC); | |||
sha3_256(k, kr, 64); // hash concatenation of pre-k and h(c) to k | |||
return (0); | |||
} | |||
int PQCLEAN_FIRESABER_AVX2_crypto_kem_dec(uint8_t *k, const uint8_t *c, const uint8_t *sk) { | |||
size_t i; | |||
uint8_t fail; | |||
uint8_t cmp[SABER_BYTES_CCA_DEC]; | |||
uint8_t buf[64]; | |||
uint8_t kr[64]; // Will contain key, coins | |||
const uint8_t *pk = sk + SABER_INDCPA_SECRETKEYBYTES; | |||
PQCLEAN_FIRESABER_AVX2_indcpa_kem_dec(buf, sk, c); // buf[0:31] <-- message | |||
// Multitarget countermeasure for coins + contributory KEM | |||
for (i = 0; i < 32; i++) { // Save hash by storing h(pk) in sk | |||
buf[32 + i] = sk[SABER_SECRETKEYBYTES - 64 + i]; | |||
} | |||
sha3_512(kr, buf, 64); | |||
PQCLEAN_FIRESABER_AVX2_indcpa_kem_enc(cmp, buf, kr + 32, pk); | |||
fail = PQCLEAN_FIRESABER_AVX2_verify(c, cmp, SABER_BYTES_CCA_DEC); | |||
sha3_256(kr + 32, c, SABER_BYTES_CCA_DEC); // overwrite coins in kr with h(c) | |||
PQCLEAN_FIRESABER_AVX2_cmov(kr, sk + SABER_SECRETKEYBYTES - SABER_KEYBYTES, SABER_KEYBYTES, fail); | |||
sha3_256(k, kr, 64); // hash concatenation of pre-k and h(c) to k | |||
return (0); | |||
} |
@@ -0,0 +1,151 @@ | |||
#include "SABER_params.h" | |||
#include "pack_unpack.h" | |||
#include "poly.h" | |||
#include <string.h> | |||
void PQCLEAN_FIRESABER_AVX2_POLT2BS(uint8_t bytes[SABER_SCALEBYTES_KEM], const poly *data) { | |||
size_t j; | |||
const uint16_t *in = data->coeffs; | |||
uint8_t *out = bytes; | |||
for (j = 0; j < SABER_N / 4; j++) { | |||
out[0] = (uint8_t) ((in[0] & 0x3f) | (in[1] << 6)); | |||
out[1] = (uint8_t) (((in[1] >> 2) & 0x0f) | (in[2] << 4)); | |||
out[2] = (uint8_t) (((in[2] >> 4) & 0x03) | (in[3] << 2)); | |||
in += 4; | |||
out += 3; | |||
} | |||
} | |||
void PQCLEAN_FIRESABER_AVX2_BS2POLT(poly *data, const uint8_t bytes[SABER_SCALEBYTES_KEM]) { | |||
/* This function does not reduce its output mod T */ | |||
size_t j; | |||
const uint8_t *in = bytes; | |||
uint16_t *out = data->coeffs; | |||
for (j = 0; j < SABER_N / 4; j++) { | |||
out[0] = in[0]; | |||
out[1] = (in[0] >> 6) | (in[1] << 2); | |||
out[2] = (in[1] >> 4) | (in[2] << 4); | |||
out[3] = (in[2] >> 2); | |||
in += 3; | |||
out += 4; | |||
} | |||
} | |||
static void POLq2BS(uint8_t bytes[SABER_POLYBYTES], const poly *data) { | |||
size_t j; | |||
const uint16_t *in = data->coeffs; | |||
uint8_t *out = bytes; | |||
for (j = 0; j < SABER_N / 8; j++) { | |||
out[0] = (uint8_t) (in[0]); | |||
out[1] = (uint8_t) (((in[0] >> 8) & 0x1f) | (in[1] << 5)); | |||
out[2] = (uint8_t) (in[1] >> 3); | |||
out[3] = (uint8_t) (((in[1] >> 11) & 0x03) | (in[2] << 2)); | |||
out[4] = (uint8_t) (((in[2] >> 6) & 0x7f) | (in[3] << 7)); | |||
out[5] = (uint8_t) (in[3] >> 1); | |||
out[6] = (uint8_t) (((in[3] >> 9) & 0x0f) | (in[4] << 4)); | |||
out[7] = (uint8_t) (in[4] >> 4); | |||
out[8] = (uint8_t) (((in[4] >> 12) & 0x01) | (in[5] << 1)); | |||
out[9] = (uint8_t) (((in[5] >> 7) & 0x3f) | (in[6] << 6)); | |||
out[10] = (uint8_t) (in[6] >> 2); | |||
out[11] = (uint8_t) (((in[6] >> 10) & 0x07) | (in[7] << 3)); | |||
out[12] = (uint8_t) (in[7] >> 5); | |||
in += 8; | |||
out += 13; | |||
} | |||
} | |||
static void BS2POLq(poly *data, const uint8_t bytes[SABER_POLYBYTES]) { | |||
/* This function does not reduce its output mod Q */ | |||
size_t j; | |||
const uint8_t *in = bytes; | |||
uint16_t *out = data->coeffs; | |||
for (j = 0; j < SABER_N / 8; j++) { | |||
out[0] = (in[0]) | (in[1] << 8); | |||
out[1] = (in[1] >> 5) | (in[2] << 3) | (in[3] << 11); | |||
out[2] = (in[3] >> 2) | (in[4] << 6); | |||
out[3] = (in[4] >> 7) | (in[5] << 1) | (in[6] << 9); | |||
out[4] = (in[6] >> 4) | (in[7] << 4) | (in[8] << 12); | |||
out[5] = (in[8] >> 1) | (in[9] << 7); | |||
out[6] = (in[9] >> 6) | (in[10] << 2) | (in[11] << 10); | |||
out[7] = (in[11] >> 3) | (in[12] << 5); | |||
in += 13; | |||
out += 8; | |||
} | |||
} | |||
static void POLp2BS(uint8_t bytes[SABER_POLYCOMPRESSEDBYTES], const poly *data) { | |||
size_t j; | |||
const uint16_t *in = data->coeffs; | |||
uint8_t *out = bytes; | |||
for (j = 0; j < SABER_N / 4; j++) { | |||
out[0] = (uint8_t) (in[0]); | |||
out[1] = (uint8_t) (((in[0] >> 8) & 0x03) | (in[1] << 2)); | |||
out[2] = (uint8_t) (((in[1] >> 6) & 0x0f) | (in[2] << 4)); | |||
out[3] = (uint8_t) (((in[2] >> 4) & 0x3f) | (in[3] << 6)); | |||
out[4] = (uint8_t) (in[3] >> 2); | |||
in += 4; | |||
out += 5; | |||
} | |||
} | |||
static void BS2POLp(poly *data, const uint8_t bytes[SABER_POLYCOMPRESSEDBYTES]) { | |||
size_t j; | |||
const uint8_t *in = bytes; | |||
uint16_t *out = data->coeffs; | |||
for (j = 0; j < SABER_N / 4; j++) { | |||
out[0] = in[0] | (in[1] << 8); | |||
out[1] = (in[1] >> 2) | (in[2] << 6); | |||
out[2] = (in[2] >> 4) | (in[3] << 4); | |||
out[3] = (in[3] >> 6) | (in[4] << 2); | |||
in += 5; | |||
out += 4; | |||
} | |||
} | |||
void PQCLEAN_FIRESABER_AVX2_POLVECq2BS(uint8_t bytes[SABER_POLYVECBYTES], const poly data[SABER_L]) { | |||
size_t i; | |||
for (i = 0; i < SABER_L; i++) { | |||
POLq2BS(bytes + i * SABER_POLYBYTES, &data[i]); | |||
} | |||
} | |||
void PQCLEAN_FIRESABER_AVX2_BS2POLVECq(poly data[SABER_L], const uint8_t bytes[SABER_POLYVECBYTES]) { | |||
size_t i; | |||
for (i = 0; i < SABER_L; i++) { | |||
BS2POLq(&data[i], bytes + i * SABER_POLYBYTES); | |||
} | |||
} | |||
void PQCLEAN_FIRESABER_AVX2_POLVECp2BS(uint8_t bytes[SABER_POLYVECCOMPRESSEDBYTES], const poly data[SABER_L]) { | |||
size_t i; | |||
for (i = 0; i < SABER_L; i++) { | |||
POLp2BS(bytes + i * SABER_POLYCOMPRESSEDBYTES, &data[i]); | |||
} | |||
} | |||
void PQCLEAN_FIRESABER_AVX2_BS2POLVECp(poly data[SABER_L], const uint8_t bytes[SABER_POLYVECCOMPRESSEDBYTES]) { | |||
size_t i; | |||
for (i = 0; i < SABER_L; i++) { | |||
BS2POLp(&data[i], bytes + i * SABER_POLYCOMPRESSEDBYTES); | |||
} | |||
} | |||
void PQCLEAN_FIRESABER_AVX2_BS2POLmsg(poly *data, const uint8_t bytes[SABER_KEYBYTES]) { | |||
size_t i, j; | |||
for (j = 0; j < SABER_KEYBYTES; j++) { | |||
for (i = 0; i < 8; i++) { | |||
data->coeffs[j * 8 + i] = ((bytes[j] >> i) & 0x01); | |||
} | |||
} | |||
} | |||
void PQCLEAN_FIRESABER_AVX2_POLmsg2BS(uint8_t bytes[SABER_KEYBYTES], const poly *data) { | |||
size_t i, j; | |||
memset(bytes, 0, SABER_KEYBYTES); | |||
for (j = 0; j < SABER_KEYBYTES; j++) { | |||
for (i = 0; i < 8; i++) { | |||
bytes[j] = bytes[j] | ((data->coeffs[j * 8 + i] & 0x01) << i); | |||
} | |||
} | |||
} |
@@ -0,0 +1,28 @@ | |||
#ifndef PACK_UNPACK_H | |||
#define PACK_UNPACK_H | |||
#include "SABER_params.h" | |||
#include "poly.h" | |||
#include <stdint.h> | |||
#include <stdio.h> | |||
void PQCLEAN_FIRESABER_AVX2_POLT2BS(uint8_t bytes[SABER_SCALEBYTES_KEM], const poly *data); | |||
void PQCLEAN_FIRESABER_AVX2_BS2POLT(poly *data, const uint8_t bytes[SABER_SCALEBYTES_KEM]); | |||
void PQCLEAN_FIRESABER_AVX2_POLVECq2BS(uint8_t bytes[SABER_POLYVECBYTES], const poly data[SABER_L]); | |||
void PQCLEAN_FIRESABER_AVX2_POLVECp2BS(uint8_t bytes[SABER_POLYVECCOMPRESSEDBYTES], const poly data[SABER_L]); | |||
void PQCLEAN_FIRESABER_AVX2_BS2POLVECq(poly data[SABER_L], const uint8_t bytes[SABER_POLYVECBYTES]); | |||
void PQCLEAN_FIRESABER_AVX2_BS2POLVECp(poly data[SABER_L], const uint8_t bytes[SABER_POLYVECCOMPRESSEDBYTES]); | |||
void PQCLEAN_FIRESABER_AVX2_BS2POLmsg(poly *data, const uint8_t bytes[SABER_KEYBYTES]); | |||
void PQCLEAN_FIRESABER_AVX2_POLmsg2BS(uint8_t bytes[SABER_KEYBYTES], const poly *data); | |||
#endif |
@@ -0,0 +1,62 @@ | |||
#include "cbd.h" | |||
#include "fips202.h" | |||
#include "pack_unpack.h" | |||
#include "poly.h" | |||
void PQCLEAN_FIRESABER_AVX2_MatrixVectorMul(poly c[SABER_L], const poly A[SABER_L][SABER_L], const toom4_points s_eval[SABER_L], int transpose) { | |||
size_t i, j; | |||
toom4_points_product c_eval; | |||
if (transpose) { | |||
for (i = 0; i < SABER_L; i++) { | |||
PQCLEAN_FIRESABER_AVX2_toom4_mul_A_by_B_eval(&c_eval, &A[0][i], &s_eval[0], 0); | |||
for (j = 1; j < SABER_L; j++) { | |||
PQCLEAN_FIRESABER_AVX2_toom4_mul_A_by_B_eval(&c_eval, &A[j][i], &s_eval[j], 1); | |||
} | |||
PQCLEAN_FIRESABER_AVX2_toom4_interp(&c[i], &c_eval); | |||
} | |||
} else { | |||
for (i = 0; i < SABER_L; i++) { | |||
PQCLEAN_FIRESABER_AVX2_toom4_mul_A_by_B_eval(&c_eval, &A[i][0], &s_eval[0], 0); | |||
for (j = 1; j < SABER_L; j++) { | |||
PQCLEAN_FIRESABER_AVX2_toom4_mul_A_by_B_eval(&c_eval, &A[i][j], &s_eval[j], 1); | |||
} | |||
PQCLEAN_FIRESABER_AVX2_toom4_interp(&c[i], &c_eval); | |||
} | |||
} | |||
} | |||
void PQCLEAN_FIRESABER_AVX2_InnerProd(poly *c, const poly b[SABER_L], const toom4_points s_eval[SABER_L]) { | |||
size_t i; | |||
toom4_points_product c_eval; //Holds results for 9 Karatsuba at a time | |||
PQCLEAN_FIRESABER_AVX2_toom4_mul_A_by_B_eval(&c_eval, &b[0], &s_eval[0], 0); | |||
for (i = 1; i < SABER_L; i++) { | |||
PQCLEAN_FIRESABER_AVX2_toom4_mul_A_by_B_eval(&c_eval, &b[i], &s_eval[i], 1); | |||
} | |||
PQCLEAN_FIRESABER_AVX2_toom4_interp(c, &c_eval); | |||
} | |||
void PQCLEAN_FIRESABER_AVX2_GenMatrix(poly A[SABER_L][SABER_L], const uint8_t seed[SABER_SEEDBYTES]) { | |||
size_t i; | |||
uint8_t buf[SABER_L * SABER_POLYVECBYTES]; | |||
shake128(buf, sizeof(buf), seed, SABER_SEEDBYTES); | |||
for (i = 0; i < SABER_L; i++) { | |||
PQCLEAN_FIRESABER_AVX2_BS2POLVECq(A[i], buf + i * SABER_POLYVECBYTES); | |||
} | |||
} | |||
void PQCLEAN_FIRESABER_AVX2_GenSecret(poly s[SABER_L], const uint8_t seed[SABER_NOISESEEDBYTES]) { | |||
size_t i; | |||
uint8_t buf[SABER_L * SABER_POLYCOINBYTES]; | |||
shake128(buf, sizeof(buf), seed, SABER_NOISESEEDBYTES); | |||
for (i = 0; i < SABER_L; i++) { | |||
PQCLEAN_FIRESABER_AVX2_cbd(s[i].coeffs, buf + i * SABER_POLYCOINBYTES); | |||
} | |||
} |
@@ -0,0 +1,38 @@ | |||
#ifndef POLY_H | |||
#define POLY_H | |||
#include "SABER_params.h" | |||
#include <immintrin.h> | |||
#include <stdint.h> | |||
typedef union { | |||
uint16_t coeffs[SABER_N]; | |||
__m256i dummy; | |||
} poly; | |||
typedef union { | |||
uint16_t coeffs[4 * SABER_N]; | |||
__m256i dummy; | |||
} toom4_points; | |||
typedef union { | |||
uint16_t coeffs[8 * SABER_N]; | |||
__m256i dummy; | |||
} toom4_points_product; | |||
void PQCLEAN_FIRESABER_AVX2_MatrixVectorMul(poly c[SABER_L], const poly A[SABER_L][SABER_L], const toom4_points s_eval[SABER_L], int transpose); | |||
void PQCLEAN_FIRESABER_AVX2_InnerProd(poly *c, const poly b[SABER_L], const toom4_points s_eval[SABER_L]); | |||
void PQCLEAN_FIRESABER_AVX2_GenMatrix(poly a[SABER_L][SABER_L], const uint8_t seed[SABER_SEEDBYTES]); | |||
void PQCLEAN_FIRESABER_AVX2_GenSecret(poly s[SABER_L], const uint8_t seed[SABER_NOISESEEDBYTES]); | |||
void PQCLEAN_FIRESABER_AVX2_toom4_interp(poly *res_avx, const toom4_points_product *c_eval); | |||
void PQCLEAN_FIRESABER_AVX2_toom4_eval(toom4_points *b_eval, const poly *b); | |||
void PQCLEAN_FIRESABER_AVX2_toom4_mul_A_by_B_eval(toom4_points_product *c_eval, const poly *a_avx, const toom4_points *b_eval, int accumulate); | |||
#endif |
@@ -0,0 +1,35 @@ | |||
#include "verify.h" | |||
/*------------------------------------------------- | |||
This file has been adapted from the implementation | |||
(available at https://github.com/pq-crystals/kyber) of | |||
"CRYSTALS – Kyber: a CCA-secure module-lattice-based KEM" | |||
by : Joppe Bos, Leo Ducas, Eike Kiltz, Tancrede Lepoint, | |||
Vadim Lyubashevsky, John M. Schanck, Peter Schwabe & Damien stehle | |||
----------------------------------------------------*/ | |||
/* returns 0 for equal strings, 1 for non-equal strings */ | |||
uint8_t PQCLEAN_FIRESABER_AVX2_verify(const uint8_t *a, const uint8_t *b, size_t len) { | |||
uint64_t r; | |||
size_t i; | |||
r = 0; | |||
for (i = 0; i < len; i++) { | |||
r |= a[i] ^ b[i]; | |||
} | |||
r = (~r + 1); // Two's complement | |||
r >>= 63; | |||
return (uint8_t) r; | |||
} | |||
/* b = 1 means mov, b = 0 means don't mov*/ | |||
void PQCLEAN_FIRESABER_AVX2_cmov(uint8_t *r, const uint8_t *x, size_t len, uint8_t b) { | |||
size_t i; | |||
b = -b; | |||
for (i = 0; i < len; i++) { | |||
r[i] ^= b & (x[i] ^ r[i]); | |||
} | |||
} |
@@ -0,0 +1,22 @@ | |||
#ifndef VERIFY_H | |||
#define VERIFY_H | |||
/*------------------------------------------------- | |||
This file has been adapted from the implementation | |||
(available at https://github.com/pq-crystals/kyber) of | |||
"CRYSTALS – Kyber: a CCA-secure module-lattice-based KEM" | |||
by : Joppe Bos, Leo Ducas, Eike Kiltz, Tancrede Lepoint, | |||
Vadim Lyubashevsky, John M. Schanck, Peter Schwabe & Damien stehle | |||
----------------------------------------------------*/ | |||
#include <stddef.h> | |||
#include <stdint.h> | |||
/* returns 0 for equal strings, 1 for non-equal strings */ | |||
uint8_t PQCLEAN_FIRESABER_AVX2_verify(const uint8_t *a, const uint8_t *b, size_t len); | |||
/* b = 1 means mov, b = 0 means don't mov*/ | |||
void PQCLEAN_FIRESABER_AVX2_cmov(uint8_t *r, const uint8_t *x, size_t len, uint8_t b); | |||
#endif |
@@ -1,8 +1 @@ | |||
SABER_v1.1 | |||
Public domain | |||
Authors: Jan-Pieter D'Anvers, Angshuman Karmakar, Sujoy Sinha Roy, | |||
Frederik Vercauteren | |||
Public Domain |
@@ -1,10 +1,10 @@ | |||
# This Makefile can be used with GNU Make or BSD Make | |||
LIB=libfiresaber_clean.a | |||
HEADERS=api.h cbd.h poly.h poly_mul.h SABER_indcpa.h SABER_params.h verify.h pack_unpack.h | |||
HEADERS=api.h cbd.h pack_unpack.h poly.h poly_mul.h SABER_indcpa.h SABER_params.h verify.h | |||
OBJECTS=cbd.o kem.o pack_unpack.o poly.o poly_mul.o SABER_indcpa.o verify.o | |||
CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) | |||
CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -Werror -Wredundant-decls -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) | |||
all: $(LIB) | |||
@@ -3,296 +3,111 @@ | |||
#include "fips202.h" | |||
#include "pack_unpack.h" | |||
#include "poly.h" | |||
#include "poly_mul.h" | |||
#include "randombytes.h" | |||
#include <stdint.h> | |||
#include <string.h> | |||
#define h1 (1 << (SABER_EQ - SABER_EP - 1)) | |||
#define h2 ((1 << (SABER_EP - 2)) - (1 << (SABER_EP - SABER_ET - 1)) + (1 << (SABER_EQ - SABER_EP - 1))) | |||
void PQCLEAN_FIRESABER_CLEAN_indcpa_kem_keypair(uint8_t pk[SABER_INDCPA_PUBLICKEYBYTES], uint8_t sk[SABER_INDCPA_SECRETKEYBYTES]) { | |||
size_t i, j; | |||
/*----------------------------------------------------------------------------------- | |||
This routine generates a=[Matrix K x K] of 256-coefficient polynomials | |||
poly A[SABER_L][SABER_L]; | |||
poly s[SABER_L]; | |||
poly res[SABER_L]; | |||
#define h1 4 //2^(EQ-EP-1) | |||
uint8_t rand[SABER_NOISESEEDBYTES]; | |||
uint8_t *seed_A = pk + SABER_POLYVECCOMPRESSEDBYTES; | |||
#define h2 ( (1<<(SABER_EP-2)) - (1<<(SABER_EP-SABER_ET-1)) + (1<<(SABER_EQ-SABER_EP-1)) ) | |||
randombytes(seed_A, SABER_SEEDBYTES); | |||
shake128(seed_A, SABER_SEEDBYTES, seed_A, SABER_SEEDBYTES); // for not revealing system RNG state | |||
static void InnerProd(uint16_t pkcl[SABER_K][SABER_N], uint16_t skpv[SABER_K][SABER_N], uint16_t mod, uint16_t res[SABER_N]); | |||
static void MatrixVectorMul(polyvec *a, uint16_t skpv[SABER_K][SABER_N], uint16_t res[SABER_K][SABER_N], uint16_t mod, int16_t transpose); | |||
randombytes(rand, SABER_NOISESEEDBYTES); | |||
PQCLEAN_FIRESABER_CLEAN_GenSecret(s, rand); | |||
PQCLEAN_FIRESABER_CLEAN_POLVECq2BS(sk, s); | |||
static void POL2MSG(const uint16_t *message_dec_unpacked, unsigned char *message_dec); | |||
PQCLEAN_FIRESABER_CLEAN_GenMatrix(A, seed_A); // sample matrix A | |||
PQCLEAN_FIRESABER_CLEAN_MatrixVectorMul(res, (const poly (*)[SABER_L])A, (const poly *)s, 1); // Matrix in transposed order | |||
static void GenMatrix(polyvec *a, const unsigned char *seed) { | |||
unsigned char buf[SABER_K * SABER_K * (13 * SABER_N / 8)]; | |||
uint16_t temp_ar[SABER_N]; | |||
int i, j, k; | |||
uint16_t mod = (SABER_Q - 1); | |||
shake128(buf, sizeof(buf), seed, SABER_SEEDBYTES); | |||
for (i = 0; i < SABER_K; i++) { | |||
for (j = 0; j < SABER_K; j++) { | |||
PQCLEAN_FIRESABER_CLEAN_BS2POL(buf + (i * SABER_K + j) * (13 * SABER_N / 8), temp_ar); | |||
for (k = 0; k < SABER_N; k++) { | |||
a[i].vec[j].coeffs[k] = (temp_ar[k])& mod ; | |||
} | |||
} | |||
} | |||
} | |||
void PQCLEAN_FIRESABER_CLEAN_indcpa_kem_keypair(unsigned char *pk, unsigned char *sk) { | |||
polyvec a[SABER_K]; | |||
uint16_t skpv[SABER_K][SABER_N]; | |||
unsigned char seed[SABER_SEEDBYTES]; | |||
unsigned char noiseseed[SABER_COINBYTES]; | |||
int32_t i, j; | |||
uint16_t mod_q = SABER_Q - 1; | |||
uint16_t res[SABER_K][SABER_N]; | |||
randombytes(seed, SABER_SEEDBYTES); | |||
// for not revealing system RNG state | |||
shake128(seed, SABER_SEEDBYTES, seed, SABER_SEEDBYTES); | |||
randombytes(noiseseed, SABER_COINBYTES); | |||
GenMatrix(a, seed); //sample matrix A | |||
// generate secret from constant-time binomial distribution | |||
PQCLEAN_FIRESABER_CLEAN_GenSecret(skpv, noiseseed); | |||
// do the matrix vector multiplication and rounding | |||
for (i = 0; i < SABER_K; i++) { | |||
for (j = 0; j < SABER_N; j++) { | |||
res[i][j] = 0; | |||
} | |||
} | |||
MatrixVectorMul(a, skpv, res, SABER_Q - 1, 1); | |||
// now rounding | |||
for (i = 0; i < SABER_K; i++) { | |||
// rounding | |||
for (i = 0; i < SABER_L; i++) { | |||
for (j = 0; j < SABER_N; j++) { | |||
// shift right 3 bits | |||
res[i][j] = (res[i][j] + h1) & (mod_q); | |||
res[i][j] = (res[i][j] >> (SABER_EQ - SABER_EP)); | |||
res[i].coeffs[j] += h1; | |||
res[i].coeffs[j] >>= SABER_EQ - SABER_EP; | |||
res[i].coeffs[j] &= SABER_Q - 1; | |||
} | |||
} | |||
// unload and pack sk=3 x (256 coefficients of 14 bits) | |||
PQCLEAN_FIRESABER_CLEAN_POLVEC2BS(sk, skpv, SABER_Q); | |||
// unload and pack pk=256 bits seed and 3 x (256 coefficients of 11 bits) | |||
// load the public-key coefficients | |||
PQCLEAN_FIRESABER_CLEAN_POLVEC2BS(pk, res, SABER_P); | |||
// now load the seedbytes in PK. Easy since seed bytes are kept in byte format. | |||
for (i = 0; i < SABER_SEEDBYTES; i++) { | |||
pk[SABER_POLYVECCOMPRESSEDBYTES + i] = seed[i]; | |||
} | |||
PQCLEAN_FIRESABER_CLEAN_POLVECp2BS(pk, res); // pack public key | |||
} | |||
void PQCLEAN_FIRESABER_CLEAN_indcpa_kem_enc(const unsigned char *message_received, unsigned char *noiseseed, const unsigned char *pk, unsigned char *ciphertext) { | |||
uint32_t i, j, k; | |||
polyvec a[SABER_K]; | |||
unsigned char seed[SABER_SEEDBYTES]; | |||
// public key of received by the client | |||
uint16_t pkcl[SABER_K][SABER_N]; | |||
uint16_t skpv1[SABER_K][SABER_N]; | |||
uint16_t message[SABER_KEYBYTES * 8]; | |||
uint16_t res[SABER_K][SABER_N]; | |||
uint16_t mod_p = SABER_P - 1; | |||
uint16_t mod_q = SABER_Q - 1; | |||
uint16_t vprime[SABER_N]; | |||
unsigned char msk_c[SABER_SCALEBYTES_KEM]; | |||
void PQCLEAN_FIRESABER_CLEAN_indcpa_kem_enc(uint8_t ciphertext[SABER_BYTES_CCA_DEC], const uint8_t m[SABER_KEYBYTES], const uint8_t noiseseed[SABER_NOISESEEDBYTES], const uint8_t pk[SABER_INDCPA_PUBLICKEYBYTES]) { | |||
size_t i, j; | |||
// extract the seedbytes from Public Key. | |||
for (i = 0; i < SABER_SEEDBYTES; i++) { | |||
seed[i] = pk[ SABER_POLYVECCOMPRESSEDBYTES + i]; | |||
} | |||
poly A[SABER_L][SABER_L]; | |||
poly res[SABER_L]; | |||
poly s[SABER_L]; | |||
poly *temp = A[0]; // re-use stack space | |||
poly *vprime = &A[0][0]; | |||
poly *message = &A[0][1]; | |||
GenMatrix(a, seed); | |||
const uint8_t *seed_A = pk + SABER_POLYVECCOMPRESSEDBYTES; | |||
uint8_t *msk_c = ciphertext + SABER_POLYVECCOMPRESSEDBYTES; | |||
// generate secret from constant-time binomial distribution | |||
PQCLEAN_FIRESABER_CLEAN_GenSecret(skpv1, noiseseed); | |||
PQCLEAN_FIRESABER_CLEAN_GenSecret(s, noiseseed); | |||
PQCLEAN_FIRESABER_CLEAN_GenMatrix(A, seed_A); | |||
PQCLEAN_FIRESABER_CLEAN_MatrixVectorMul(res, (const poly (*)[SABER_L])A, (const poly *)s, 0); // 0 => not transposed | |||
// matrix-vector multiplication and rounding | |||
for (i = 0; i < SABER_K; i++) { | |||
for (j = 0; j < SABER_N; j++) { | |||
res[i][j] = 0; | |||
} | |||
} | |||
MatrixVectorMul(a, skpv1, res, SABER_Q - 1, 0); | |||
// now rounding | |||
//shift right 3 bits | |||
for (i = 0; i < SABER_K; i++) { | |||
for (j = 0; j < SABER_N; j++) { | |||
res[i][j] = ( res[i][j] + h1 ) & mod_q; | |||
res[i][j] = (res[i][j] >> (SABER_EQ - SABER_EP) ); | |||
} | |||
} | |||
PQCLEAN_FIRESABER_CLEAN_POLVEC2BS(ciphertext, res, SABER_P); | |||
// ************client matrix-vector multiplication ends************ | |||
// now calculate the v' | |||
// unpack the public_key | |||
// pkcl is the b in the protocol | |||
PQCLEAN_FIRESABER_CLEAN_BS2POLVEC(pk, pkcl, SABER_P); | |||
for (i = 0; i < SABER_N; i++) { | |||
vprime[i] = 0; | |||
} | |||
for (i = 0; i < SABER_K; i++) { | |||
// rounding | |||
for (i = 0; i < SABER_L; i++) { //shift right EQ-EP bits | |||
for (j = 0; j < SABER_N; j++) { | |||
skpv1[i][j] = skpv1[i][j] & (mod_p); | |||
res[i].coeffs[j] += h1; | |||
res[i].coeffs[j] >>= SABER_EQ - SABER_EP; | |||
res[i].coeffs[j] &= SABER_Q - 1; | |||
} | |||
} | |||
PQCLEAN_FIRESABER_CLEAN_POLVECp2BS(ciphertext, res); | |||
// vector-vector scalar multiplication with mod p | |||
InnerProd(pkcl, skpv1, mod_p, vprime); | |||
PQCLEAN_FIRESABER_CLEAN_BS2POLVECp(temp, pk); | |||
PQCLEAN_FIRESABER_CLEAN_InnerProd(vprime, temp, s); | |||
PQCLEAN_FIRESABER_CLEAN_BS2POLmsg(message, m); | |||
// addition of h1 to vprime | |||
for (i = 0; i < SABER_N; i++) { | |||
vprime[i] = vprime[i] + h1; | |||
vprime->coeffs[i] += h1 - (message->coeffs[i] << (SABER_EP - 1)); | |||
vprime->coeffs[i] &= SABER_P - 1; | |||
vprime->coeffs[i] >>= SABER_EP - SABER_ET; | |||
} | |||
// unpack message_received; | |||
for (j = 0; j < SABER_KEYBYTES; j++) { | |||
for (i = 0; i < 8; i++) { | |||
message[8 * j + i] = ((message_received[j] >> i) & 0x01); | |||
} | |||
} | |||
// message encoding | |||
for (i = 0; i < SABER_N; i++) { | |||
message[i] = (message[i] << (SABER_EP - 1)); | |||
} | |||
for (k = 0; k < SABER_N; k++) { | |||
vprime[k] = ( (vprime[k] - message[k]) & (mod_p) ) >> (SABER_EP - SABER_ET); | |||
} | |||
PQCLEAN_FIRESABER_CLEAN_pack_6bit(msk_c, vprime); | |||
for (j = 0; j < SABER_SCALEBYTES_KEM; j++) { | |||
ciphertext[SABER_POLYVECCOMPRESSEDBYTES + j] = msk_c[j]; | |||
} | |||
PQCLEAN_FIRESABER_CLEAN_POLT2BS(msk_c, vprime); | |||
} | |||
void PQCLEAN_FIRESABER_CLEAN_indcpa_kem_dec(const unsigned char *sk, const unsigned char *ciphertext, unsigned char message_dec[]) { | |||
uint32_t i, j; | |||
// secret key of the server | |||
uint16_t sksv[SABER_K][SABER_N]; | |||
uint16_t pksv[SABER_K][SABER_N]; | |||
uint8_t scale_ar[SABER_SCALEBYTES_KEM]; | |||
uint16_t mod_p = SABER_P - 1; | |||
uint16_t v[SABER_N]; | |||
uint16_t op[SABER_N]; | |||
void PQCLEAN_FIRESABER_CLEAN_indcpa_kem_dec(uint8_t m[SABER_KEYBYTES], const uint8_t sk[SABER_INDCPA_SECRETKEYBYTES], const uint8_t ciphertext[SABER_BYTES_CCA_DEC]) { | |||
size_t i; | |||
// sksv is the secret-key | |||
PQCLEAN_FIRESABER_CLEAN_BS2POLVEC(sk, sksv, SABER_Q); | |||
// pksv is the ciphertext | |||
PQCLEAN_FIRESABER_CLEAN_BS2POLVEC(ciphertext, pksv, SABER_P); | |||
poly temp[SABER_L]; | |||
poly s[SABER_L]; | |||
// vector-vector scalar multiplication with mod p | |||
for (i = 0; i < SABER_N; i++) { | |||
v[i] = 0; | |||
} | |||
for (i = 0; i < SABER_K; i++) { | |||
for (j = 0; j < SABER_N; j++) { | |||
sksv[i][j] = sksv[i][j] & (mod_p); | |||
} | |||
} | |||
InnerProd(pksv, sksv, mod_p, v); | |||
const uint8_t *packed_cm = ciphertext + SABER_POLYVECCOMPRESSEDBYTES; | |||
poly *v = &temp[0]; | |||
poly *cm = &temp[1]; | |||
//Extraction | |||
for (i = 0; i < SABER_SCALEBYTES_KEM; i++) { | |||
scale_ar[i] = ciphertext[SABER_POLYVECCOMPRESSEDBYTES + i]; | |||
} | |||
PQCLEAN_FIRESABER_CLEAN_BS2POLVECq(s, sk); | |||
PQCLEAN_FIRESABER_CLEAN_BS2POLVECp(temp, ciphertext); | |||
PQCLEAN_FIRESABER_CLEAN_InnerProd(&temp[0], temp, s); | |||
PQCLEAN_FIRESABER_CLEAN_un_pack6bit(scale_ar, op); | |||
PQCLEAN_FIRESABER_CLEAN_BS2POLT(cm, packed_cm); | |||
//addition of h1 | |||
for (i = 0; i < SABER_N; i++) { | |||
v[i] = ( ( v[i] + h2 - (op[i] << (SABER_EP - SABER_ET)) ) & (mod_p) ) >> (SABER_EP - 1); | |||
v->coeffs[i] += h2 - (cm->coeffs[i] << (SABER_EP - SABER_ET)); | |||
v->coeffs[i] &= SABER_P - 1; | |||
v->coeffs[i] >>= SABER_EP - 1; | |||
} | |||
// pack decrypted message | |||
POL2MSG(v, message_dec); | |||
} | |||
static void MatrixVectorMul(polyvec *a, uint16_t skpv[SABER_K][SABER_N], uint16_t res[SABER_K][SABER_N], uint16_t mod, int16_t transpose) { | |||
uint16_t acc[SABER_N]; | |||
int32_t i, j, k; | |||
if (transpose == 1) { | |||
for (i = 0; i < SABER_K; i++) { | |||
for (j = 0; j < SABER_K; j++) { | |||
PQCLEAN_FIRESABER_CLEAN_pol_mul((uint16_t *)&a[j].vec[i], skpv[j], acc, SABER_Q, SABER_N); | |||
for (k = 0; k < SABER_N; k++) { | |||
res[i][k] = res[i][k] + acc[k]; | |||
//reduction mod p | |||
res[i][k] = (res[i][k] & mod); | |||
//clear the accumulator | |||
acc[k] = 0; | |||
} | |||
} | |||
} | |||
} else { | |||
for (i = 0; i < SABER_K; i++) { | |||
for (j = 0; j < SABER_K; j++) { | |||
PQCLEAN_FIRESABER_CLEAN_pol_mul((uint16_t *)&a[i].vec[j], skpv[j], acc, SABER_Q, SABER_N); | |||
for (k = 0; k < SABER_N; k++) { | |||
res[i][k] = res[i][k] + acc[k]; | |||
// reduction | |||
res[i][k] = res[i][k] & mod; | |||
// clear the accumulator | |||
acc[k] = 0; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
static void POL2MSG(const uint16_t *message_dec_unpacked, unsigned char *message_dec) { | |||
int32_t i, j; | |||
for (j = 0; j < SABER_KEYBYTES; j++) { | |||
message_dec[j] = 0; | |||
for (i = 0; i < 8; i++) { | |||
message_dec[j] = message_dec[j] | (uint8_t) (message_dec_unpacked[j * 8 + i] << i); | |||
} | |||
} | |||
} | |||
static void InnerProd(uint16_t pkcl[SABER_K][SABER_N], uint16_t skpv[SABER_K][SABER_N], uint16_t mod, uint16_t res[SABER_N]) { | |||
uint32_t j, k; | |||
uint16_t acc[SABER_N]; | |||
// vector-vector scalar multiplication with mod p | |||
for (j = 0; j < SABER_K; j++) { | |||
PQCLEAN_FIRESABER_CLEAN_pol_mul(pkcl[j], skpv[j], acc, SABER_P, SABER_N); | |||
for (k = 0; k < SABER_N; k++) { | |||
res[k] = res[k] + acc[k]; | |||
// reduction | |||
res[k] = res[k] & mod; | |||
// clear the accumulator | |||
acc[k] = 0; | |||
} | |||
} | |||
PQCLEAN_FIRESABER_CLEAN_POLmsg2BS(m, v); | |||
} |
@@ -1,9 +1,13 @@ | |||
#ifndef INDCPA_H | |||
#define INDCPA_H | |||
#include "SABER_params.h" | |||
#include <stdint.h> | |||
void PQCLEAN_FIRESABER_CLEAN_indcpa_kem_keypair(unsigned char *pk, unsigned char *sk); | |||
void PQCLEAN_FIRESABER_CLEAN_indcpa_kem_enc(const unsigned char *message, unsigned char *noiseseed, const unsigned char *pk, unsigned char *ciphertext); | |||
void PQCLEAN_FIRESABER_CLEAN_indcpa_kem_dec(const unsigned char *sk, const unsigned char *ciphertext, unsigned char *message_dec); | |||
void PQCLEAN_FIRESABER_CLEAN_indcpa_kem_keypair(uint8_t pk[SABER_INDCPA_PUBLICKEYBYTES], uint8_t sk[SABER_INDCPA_SECRETKEYBYTES]); | |||
#endif | |||
void PQCLEAN_FIRESABER_CLEAN_indcpa_kem_enc(uint8_t ciphertext[SABER_BYTES_CCA_DEC], const uint8_t m[SABER_KEYBYTES], const uint8_t noiseseed[SABER_NOISESEEDBYTES], const uint8_t pk[SABER_INDCPA_PUBLICKEYBYTES]); | |||
void PQCLEAN_FIRESABER_CLEAN_indcpa_kem_dec(uint8_t m[SABER_KEYBYTES], const uint8_t sk[SABER_INDCPA_SECRETKEYBYTES], const uint8_t ciphertext[SABER_BYTES_CCA_DEC]); | |||
#endif |
@@ -1,49 +1,41 @@ | |||
#ifndef PARAMS_H | |||
#define PARAMS_H | |||
#include "api.h" | |||
#define SABER_K 4 | |||
/* Don't change anything below this line */ | |||
#define SABER_L 4 | |||
#define SABER_MU 6 | |||
#define SABER_ET 6 | |||
#define SABER_EQ 13 | |||
#define SABER_EP 10 | |||
#define SABER_N 256 | |||
#define SABER_Q 8192 | |||
#define SABER_P 1024 | |||
#define SABER_SEEDBYTES 32 | |||
#define SABER_NOISESEEDBYTES 32 | |||
#define SABER_COINBYTES 32 | |||
#define SABER_KEYBYTES 32 | |||
#define SABER_HASHBYTES 32 | |||
#define SABER_EP 10 | |||
#define SABER_P (1 << SABER_EP) | |||
#define SABER_POLYBYTES 416 //13*256/8 | |||
#define SABER_EQ 13 | |||
#define SABER_Q (1 << SABER_EQ) | |||
#define SABER_POLYVECBYTES (SABER_K * SABER_POLYBYTES) | |||
#define SABER_SEEDBYTES 32 | |||
#define SABER_NOISESEEDBYTES 32 | |||
#define SABER_KEYBYTES 32 | |||
#define SABER_HASHBYTES 32 | |||
#define SABER_POLYVECCOMPRESSEDBYTES (SABER_K * 320) //10*256/8 NOTE : changed till here due to parameter adaptation | |||
#define SABER_POLYCOINBYTES (SABER_MU * SABER_N / 8) | |||
#define SABER_CIPHERTEXTBYTES (SABER_POLYVECCOMPRESSEDBYTES) | |||
#define SABER_POLYBYTES (SABER_EQ * SABER_N / 8) | |||
#define SABER_POLYVECBYTES (SABER_L * SABER_POLYBYTES) | |||
#define SABER_SCALEBYTES (SABER_DELTA*SABER_N/8) | |||
#define SABER_POLYCOMPRESSEDBYTES (SABER_EP * SABER_N / 8) | |||
#define SABER_POLYVECCOMPRESSEDBYTES (SABER_L * SABER_POLYCOMPRESSEDBYTES) | |||
#define SABER_SCALEBYTES_KEM ((SABER_ET)*SABER_N/8) | |||
#define SABER_SCALEBYTES_KEM (SABER_ET * SABER_N / 8) | |||
#define SABER_INDCPA_PUBLICKEYBYTES (SABER_POLYVECCOMPRESSEDBYTES + SABER_SEEDBYTES) | |||
#define SABER_INDCPA_SECRETKEYBYTES (SABER_POLYVECBYTES) | |||
#define SABER_PUBLICKEYBYTES (SABER_INDCPA_PUBLICKEYBYTES) | |||
#define SABER_SECRETKEYBYTES (SABER_INDCPA_SECRETKEYBYTES + SABER_INDCPA_PUBLICKEYBYTES + SABER_HASHBYTES + SABER_KEYBYTES) | |||
#define SABER_SECRETKEYBYTES (SABER_INDCPA_SECRETKEYBYTES + SABER_INDCPA_PUBLICKEYBYTES + SABER_HASHBYTES + SABER_KEYBYTES) | |||
#define SABER_BYTES_CCA_DEC (SABER_POLYVECCOMPRESSEDBYTES + SABER_SCALEBYTES_KEM) /* Second part is for Targhi-Unruh */ | |||
#define SABER_BYTES_CCA_DEC (SABER_POLYVECCOMPRESSEDBYTES + SABER_SCALEBYTES_KEM) | |||
#endif | |||
@@ -1,14 +1,18 @@ | |||
#ifndef PQCLEAN_FIRESABER_CLEAN_API_H | |||
#define PQCLEAN_FIRESABER_CLEAN_API_H | |||
#define PQCLEAN_FIRESABER_CLEAN_CRYPTO_ALGNAME "FireSaber" | |||
#define PQCLEAN_FIRESABER_CLEAN_CRYPTO_SECRETKEYBYTES 3040 | |||
#define PQCLEAN_FIRESABER_CLEAN_CRYPTO_PUBLICKEYBYTES (4*320+32) | |||
#define PQCLEAN_FIRESABER_CLEAN_CRYPTO_BYTES 32 | |||
#define PQCLEAN_FIRESABER_CLEAN_CRYPTO_CIPHERTEXTBYTES 1472 | |||
#define PQCLEAN_FIRESABER_CLEAN_CRYPTO_PUBLICKEYBYTES 1312 | |||
#define PQCLEAN_FIRESABER_CLEAN_CRYPTO_SECRETKEYBYTES 3040 | |||
int PQCLEAN_FIRESABER_CLEAN_crypto_kem_keypair(unsigned char *pk, unsigned char *sk); | |||
int PQCLEAN_FIRESABER_CLEAN_crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk); | |||
int PQCLEAN_FIRESABER_CLEAN_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk); | |||
#endif /* api_h */ | |||
int PQCLEAN_FIRESABER_CLEAN_crypto_kem_enc(unsigned char *ct, unsigned char *k, const unsigned char *pk); | |||
int PQCLEAN_FIRESABER_CLEAN_crypto_kem_dec(unsigned char *k, const unsigned char *ct, const unsigned char *sk); | |||
#endif /* PQCLEAN_FIRESABER_CLEAN_API_H */ |
@@ -1,3 +1,7 @@ | |||
#include "SABER_params.h" | |||
#include "api.h" | |||
#include "cbd.h" | |||
#include <stdint.h> | |||
/*--------------------------------------------------------------------- | |||
This file has been adapted from the implementation | |||
(available at, Public Domain https://github.com/pq-crystals/kyber) | |||
@@ -6,12 +10,8 @@ by : Joppe Bos, Leo Ducas, Eike Kiltz, Tancrede Lepoint, | |||
Vadim Lyubashevsky, John M. Schanck, Peter Schwabe & Damien stehle | |||
----------------------------------------------------------------------*/ | |||
#include "SABER_params.h" | |||
#include "api.h" | |||
#include "cbd.h" | |||
#include <stdint.h> | |||
static uint64_t load_littleendian(const unsigned char *x, int bytes) { | |||
static uint64_t load_littleendian(const uint8_t *x, int bytes) { | |||
int i; | |||
uint64_t r = x[0]; | |||
for (i = 1; i < bytes; i++) { | |||
@@ -20,10 +20,7 @@ static uint64_t load_littleendian(const unsigned char *x, int bytes) { | |||
return r; | |||
} | |||
void PQCLEAN_FIRESABER_CLEAN_cbd(uint16_t *r, const unsigned char *buf) { | |||
uint16_t Qmod_minus1 = SABER_Q - 1; | |||
void PQCLEAN_FIRESABER_CLEAN_cbd(uint16_t s[SABER_N], const uint8_t buf[SABER_POLYCOINBYTES]) { | |||
uint32_t t, d, a[4], b[4]; | |||
int i, j; | |||
@@ -34,19 +31,18 @@ void PQCLEAN_FIRESABER_CLEAN_cbd(uint16_t *r, const unsigned char *buf) { | |||
d += (t >> j) & 0x249249; | |||
} | |||
a[0] = d & 0x7; | |||
b[0] = (d >> 3) & 0x7; | |||
a[1] = (d >> 6) & 0x7; | |||
b[1] = (d >> 9) & 0x7; | |||
a[0] = d & 0x7; | |||
b[0] = (d >> 3) & 0x7; | |||
a[1] = (d >> 6) & 0x7; | |||
b[1] = (d >> 9) & 0x7; | |||
a[2] = (d >> 12) & 0x7; | |||
b[2] = (d >> 15) & 0x7; | |||
a[3] = (d >> 18) & 0x7; | |||
b[3] = (d >> 21); | |||
r[4 * i + 0] = (uint16_t)(a[0] - b[0]) & Qmod_minus1; | |||
r[4 * i + 1] = (uint16_t)(a[1] - b[1]) & Qmod_minus1; | |||
r[4 * i + 2] = (uint16_t)(a[2] - b[2]) & Qmod_minus1; | |||
r[4 * i + 3] = (uint16_t)(a[3] - b[3]) & Qmod_minus1; | |||
s[4 * i + 0] = (uint16_t)(a[0] - b[0]); | |||
s[4 * i + 1] = (uint16_t)(a[1] - b[1]); | |||
s[4 * i + 2] = (uint16_t)(a[2] - b[2]); | |||
s[4 * i + 3] = (uint16_t)(a[3] - b[3]); | |||
} | |||
} |
@@ -1,6 +1,5 @@ | |||
#ifndef CBD_H | |||
#define CBD_H | |||
/*--------------------------------------------------------------------- | |||
This file has been adapted from the implementation | |||
(available at, Public Domain https://github.com/pq-crystals/kyber) | |||
@@ -8,10 +7,10 @@ of "CRYSTALS – Kyber: a CCA-secure module-lattice-based KEM" | |||
by : Joppe Bos, Leo Ducas, Eike Kiltz, Tancrede Lepoint, | |||
Vadim Lyubashevsky, John M. Schanck, Peter Schwabe & Damien stehle | |||
----------------------------------------------------------------------*/ | |||
#include "poly.h" | |||
#include "SABER_params.h" | |||
#include <stdint.h> | |||
void PQCLEAN_FIRESABER_CLEAN_cbd(uint16_t *r, const unsigned char *buf); | |||
void PQCLEAN_FIRESABER_CLEAN_cbd(uint16_t s[SABER_N], const uint8_t buf[SABER_POLYCOINBYTES]); | |||
#endif |
@@ -1,96 +1,77 @@ | |||
#include "SABER_indcpa.h" | |||
#include "SABER_params.h" | |||
#include "api.h" | |||
#include "fips202.h" | |||
#include "randombytes.h" | |||
#include "verify.h" | |||
#include <stddef.h> | |||
#include <stdint.h> | |||
#include <stdio.h> | |||
#include <string.h> | |||
int PQCLEAN_FIRESABER_CLEAN_crypto_kem_keypair(unsigned char *pk, unsigned char *sk) { | |||
int i; | |||
// sk[0:SABER_INDCPA_SECRETKEYBYTES-1] <-- sk | |||
PQCLEAN_FIRESABER_CLEAN_indcpa_kem_keypair(pk, sk); | |||
int PQCLEAN_FIRESABER_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk) { | |||
size_t i; | |||
// sk[SABER_INDCPA_SECRETKEYBYTES:SABER_INDCPA_SECRETKEYBYTES+SABER_INDCPA_SECRETKEYBYTES-1] <-- pk | |||
PQCLEAN_FIRESABER_CLEAN_indcpa_kem_keypair(pk, sk); // sk[0:SABER_INDCPA_SECRETKEYBYTES-1] <-- sk | |||
for (i = 0; i < SABER_INDCPA_PUBLICKEYBYTES; i++) { | |||
sk[i + SABER_INDCPA_SECRETKEYBYTES] = pk[i]; | |||
sk[i + SABER_INDCPA_SECRETKEYBYTES] = pk[i]; // sk[SABER_INDCPA_SECRETKEYBYTES:SABER_INDCPA_SECRETKEYBYTES+SABER_INDCPA_SECRETKEYBYTES-1] <-- pk | |||
} | |||
// Then hash(pk) is appended. | |||
sha3_256(sk + SABER_SECRETKEYBYTES - 64, pk, SABER_INDCPA_PUBLICKEYBYTES); | |||
sha3_256(sk + SABER_SECRETKEYBYTES - 64, pk, SABER_INDCPA_PUBLICKEYBYTES); // Then hash(pk) is appended. | |||
// Remaining part of sk contains a pseudo-random number. | |||
// This is output when check in crypto_kem_dec() fails. | |||
randombytes(sk + SABER_SECRETKEYBYTES - SABER_KEYBYTES, SABER_KEYBYTES ); | |||
randombytes(sk + SABER_SECRETKEYBYTES - SABER_KEYBYTES, SABER_KEYBYTES); // Remaining part of sk contains a pseudo-random number. | |||
// This is output when check in PQCLEAN_FIRESABER_CLEAN_crypto_kem_dec() fails. | |||
return (0); | |||
} | |||
int PQCLEAN_FIRESABER_CLEAN_crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk) { | |||
// Will contain key, coins | |||
unsigned char kr[64]; | |||
unsigned char buf[64]; | |||
int PQCLEAN_FIRESABER_CLEAN_crypto_kem_enc(uint8_t *c, uint8_t *k, const uint8_t *pk) { | |||
randombytes(buf, 32); | |||
uint8_t kr[64]; // Will contain key, coins | |||
uint8_t buf[64]; | |||
// BUF[0:31] <-- random message (will be used as the key for client) Note: hash doesnot release system RNG output | |||
sha3_256(buf, buf, 32); | |||
randombytes(buf, 32); | |||
// BUF[32:63] <-- Hash(public key); Multitarget countermeasure for coins + contributory KEM | |||
sha3_256(buf + 32, pk, SABER_INDCPA_PUBLICKEYBYTES); | |||
sha3_256(buf, buf, 32); // BUF[0:31] <-- random message (will be used as the key for client) Note: hash doesnot release system RNG output | |||
// kr[0:63] <-- Hash(buf[0:63]); | |||
sha3_512(kr, buf, 64); | |||
sha3_256(buf + 32, pk, SABER_INDCPA_PUBLICKEYBYTES); // BUF[32:63] <-- Hash(public key); Multitarget countermeasure for coins + contributory KEM | |||
sha3_512(kr, buf, 64); // kr[0:63] <-- Hash(buf[0:63]); | |||
// K^ <-- kr[0:31] | |||
// noiseseed (r) <-- kr[32:63]; | |||
// buf[0:31] contains message; kr[32:63] contains randomness r; | |||
PQCLEAN_FIRESABER_CLEAN_indcpa_kem_enc(buf, kr + 32, pk, ct); | |||
PQCLEAN_FIRESABER_CLEAN_indcpa_kem_enc(c, buf, kr + 32, pk); // buf[0:31] contains message; kr[32:63] contains randomness r; | |||
sha3_256(kr + 32, ct, SABER_BYTES_CCA_DEC); | |||
sha3_256(kr + 32, c, SABER_BYTES_CCA_DEC); | |||
// hash concatenation of pre-k and h(c) to k | |||
sha3_256(ss, kr, 64); | |||
sha3_256(k, kr, 64); // hash concatenation of pre-k and h(c) to k | |||
return (0); | |||
} | |||
int PQCLEAN_FIRESABER_CLEAN_crypto_kem_dec(uint8_t *k, const uint8_t *c, const uint8_t *sk) { | |||
size_t i; | |||
uint8_t fail; | |||
uint8_t cmp[SABER_BYTES_CCA_DEC]; | |||
uint8_t buf[64]; | |||
uint8_t kr[64]; // Will contain key, coins | |||
const uint8_t *pk = sk + SABER_INDCPA_SECRETKEYBYTES; | |||
int PQCLEAN_FIRESABER_CLEAN_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk) { | |||
int i; | |||
unsigned char fail; | |||
unsigned char cmp[SABER_BYTES_CCA_DEC]; | |||
unsigned char buf[64]; | |||
// Will contain key, coins | |||
unsigned char kr[64]; | |||
const unsigned char *pk = sk + SABER_INDCPA_SECRETKEYBYTES; | |||
// buf[0:31] <-- message | |||
PQCLEAN_FIRESABER_CLEAN_indcpa_kem_dec(sk, ct, buf); | |||
PQCLEAN_FIRESABER_CLEAN_indcpa_kem_dec(buf, sk, c); // buf[0:31] <-- message | |||
// Multitarget countermeasure for coins + contributory KEM | |||
// Save hash by storing h(pk) in sk | |||
for (i = 0; i < 32; i++) { | |||
for (i = 0; i < 32; i++) { // Save hash by storing h(pk) in sk | |||
buf[32 + i] = sk[SABER_SECRETKEYBYTES - 64 + i]; | |||
} | |||
sha3_512(kr, buf, 64); | |||
PQCLEAN_FIRESABER_CLEAN_indcpa_kem_enc(buf, kr + 32, pk, cmp); | |||
PQCLEAN_FIRESABER_CLEAN_indcpa_kem_enc(cmp, buf, kr + 32, pk); | |||
fail = PQCLEAN_FIRESABER_CLEAN_verify(ct, cmp, SABER_BYTES_CCA_DEC); | |||
fail = PQCLEAN_FIRESABER_CLEAN_verify(c, cmp, SABER_BYTES_CCA_DEC); | |||
// overwrite coins in kr with h(c) | |||
sha3_256(kr + 32, ct, SABER_BYTES_CCA_DEC); | |||
sha3_256(kr + 32, c, SABER_BYTES_CCA_DEC); // overwrite coins in kr with h(c) | |||
PQCLEAN_FIRESABER_CLEAN_cmov(kr, sk + SABER_SECRETKEYBYTES - SABER_KEYBYTES, SABER_KEYBYTES, fail); | |||
// hash concatenation of pre-k and h(c) to k | |||
sha3_256(ss, kr, 64); | |||
sha3_256(k, kr, 64); // hash concatenation of pre-k and h(c) to k | |||
return (0); | |||
} |
@@ -1,254 +1,151 @@ | |||
#include "SABER_params.h" | |||
#include "pack_unpack.h" | |||
#include "poly.h" | |||
#include <string.h> | |||
void PQCLEAN_FIRESABER_CLEAN_pack_3bit(uint8_t *bytes, const uint16_t *data) { | |||
uint32_t j; | |||
uint32_t offset_data, offset_byte; | |||
for (j = 0; j < SABER_N / 8; j++) { | |||
offset_byte = 3 * j; | |||
offset_data = 8 * j; | |||
bytes[offset_byte + 0] = (data[offset_data + 0] & 0x7) | | |||
((data[offset_data + 1] & 0x7) << 3) | | |||
((data[offset_data + 2] & 0x3) << 6); | |||
bytes[offset_byte + 1] = ((data[offset_data + 2] >> 2 ) & 0x01) | | |||
((data[offset_data + 3] & 0x7) << 1) | | |||
((data[offset_data + 4] & 0x7) << 4) | | |||
(((data[offset_data + 5]) & 0x01) << 7); | |||
bytes[offset_byte + 2] = ((data[offset_data + 5] >> 1 ) & 0x03) | | |||
((data[offset_data + 6] & 0x7) << 2) | | |||
((data[offset_data + 7] & 0x7) << 5); | |||
void PQCLEAN_FIRESABER_CLEAN_POLT2BS(uint8_t bytes[SABER_SCALEBYTES_KEM], const poly *data) { | |||
size_t j; | |||
const uint16_t *in = data->coeffs; | |||
uint8_t *out = bytes; | |||
for (j = 0; j < SABER_N / 4; j++) { | |||
out[0] = (uint8_t) ((in[0] & 0x3f) | (in[1] << 6)); | |||
out[1] = (uint8_t) (((in[1] >> 2) & 0x0f) | (in[2] << 4)); | |||
out[2] = (uint8_t) (((in[2] >> 4) & 0x03) | (in[3] << 2)); | |||
in += 4; | |||
out += 3; | |||
} | |||
} | |||
void PQCLEAN_FIRESABER_CLEAN_un_pack3bit(const uint8_t *bytes, uint16_t *data) { | |||
uint32_t j; | |||
uint32_t offset_data, offset_byte; | |||
for (j = 0; j < SABER_N / 8; j++) { | |||
offset_byte = 3 * j; | |||
offset_data = 8 * j; | |||
data[offset_data + 0] = (bytes[offset_byte + 0]) & 0x07; | |||
data[offset_data + 1] = ((bytes[offset_byte + 0]) >> 3 ) & 0x07; | |||
data[offset_data + 2] = (((bytes[offset_byte + 0]) >> 6 ) & 0x03) | | |||
(((bytes[offset_byte + 1]) & 0x01) << 2); | |||
data[offset_data + 3] = ((bytes[offset_byte + 1]) >> 1 ) & 0x07; | |||
data[offset_data + 4] = ((bytes[offset_byte + 1]) >> 4 ) & 0x07; | |||
data[offset_data + 5] = (((bytes[offset_byte + 1]) >> 7 ) & 0x01) | | |||
(((bytes[offset_byte + 2]) & 0x03) << 1); | |||
data[offset_data + 6] = ((bytes[offset_byte + 2] >> 2) & 0x07); | |||
data[offset_data + 7] = ((bytes[offset_byte + 2] >> 5) & 0x07); | |||
void PQCLEAN_FIRESABER_CLEAN_BS2POLT(poly *data, const uint8_t bytes[SABER_SCALEBYTES_KEM]) { | |||
/* This function does not reduce its output mod T */ | |||
size_t j; | |||
const uint8_t *in = bytes; | |||
uint16_t *out = data->coeffs; | |||
for (j = 0; j < SABER_N / 4; j++) { | |||
out[0] = in[0]; | |||
out[1] = (in[0] >> 6) | (in[1] << 2); | |||
out[2] = (in[1] >> 4) | (in[2] << 4); | |||
out[3] = (in[2] >> 2); | |||
in += 3; | |||
out += 4; | |||
} | |||
} | |||
void PQCLEAN_FIRESABER_CLEAN_pack_4bit(uint8_t *bytes, const uint16_t *data) { | |||
uint32_t j; | |||
uint32_t offset_data; | |||
for (j = 0; j < SABER_N / 2; j++) { | |||
offset_data = 2 * j; | |||
bytes[j] = (data[offset_data] & 0x0f) | | |||
((data[offset_data + 1] & 0x0f) << 4); | |||
static void POLq2BS(uint8_t bytes[SABER_POLYBYTES], const poly *data) { | |||
size_t j; | |||
const uint16_t *in = data->coeffs; | |||
uint8_t *out = bytes; | |||
for (j = 0; j < SABER_N / 8; j++) { | |||
out[0] = (uint8_t) (in[0]); | |||
out[1] = (uint8_t) (((in[0] >> 8) & 0x1f) | (in[1] << 5)); | |||
out[2] = (uint8_t) (in[1] >> 3); | |||
out[3] = (uint8_t) (((in[1] >> 11) & 0x03) | (in[2] << 2)); | |||
out[4] = (uint8_t) (((in[2] >> 6) & 0x7f) | (in[3] << 7)); | |||
out[5] = (uint8_t) (in[3] >> 1); | |||
out[6] = (uint8_t) (((in[3] >> 9) & 0x0f) | (in[4] << 4)); | |||
out[7] = (uint8_t) (in[4] >> 4); | |||
out[8] = (uint8_t) (((in[4] >> 12) & 0x01) | (in[5] << 1)); | |||
out[9] = (uint8_t) (((in[5] >> 7) & 0x3f) | (in[6] << 6)); | |||
out[10] = (uint8_t) (in[6] >> 2); | |||
out[11] = (uint8_t) (((in[6] >> 10) & 0x07) | (in[7] << 3)); | |||
out[12] = (uint8_t) (in[7] >> 5); | |||
in += 8; | |||
out += 13; | |||
} | |||
} | |||
void PQCLEAN_FIRESABER_CLEAN_un_pack4bit(const unsigned char *bytes, uint16_t *ar) { | |||
uint32_t j; | |||
uint32_t offset_data; | |||
for (j = 0; j < SABER_N / 2; j++) { | |||
offset_data = 2 * j; | |||
ar[offset_data] = bytes[j] & 0x0f; | |||
ar[offset_data + 1] = (bytes[j] >> 4) & 0x0f; | |||
static void BS2POLq(poly *data, const uint8_t bytes[SABER_POLYBYTES]) { | |||
/* This function does not reduce its output mod Q */ | |||
size_t j; | |||
const uint8_t *in = bytes; | |||
uint16_t *out = data->coeffs; | |||
for (j = 0; j < SABER_N / 8; j++) { | |||
out[0] = (in[0]) | (in[1] << 8); | |||
out[1] = (in[1] >> 5) | (in[2] << 3) | (in[3] << 11); | |||
out[2] = (in[3] >> 2) | (in[4] << 6); | |||
out[3] = (in[4] >> 7) | (in[5] << 1) | (in[6] << 9); | |||
out[4] = (in[6] >> 4) | (in[7] << 4) | (in[8] << 12); | |||
out[5] = (in[8] >> 1) | (in[9] << 7); | |||
out[6] = (in[9] >> 6) | (in[10] << 2) | (in[11] << 10); | |||
out[7] = (in[11] >> 3) | (in[12] << 5); | |||
in += 13; | |||
out += 8; | |||
} | |||
} | |||
void PQCLEAN_FIRESABER_CLEAN_pack_6bit(uint8_t *bytes, const uint16_t *data) { | |||
uint32_t j; | |||
uint32_t offset_data, offset_byte; | |||
static void POLp2BS(uint8_t bytes[SABER_POLYCOMPRESSEDBYTES], const poly *data) { | |||
size_t j; | |||
const uint16_t *in = data->coeffs; | |||
uint8_t *out = bytes; | |||
for (j = 0; j < SABER_N / 4; j++) { | |||
offset_byte = 3 * j; | |||
offset_data = 4 * j; | |||
bytes[offset_byte + 0] = (data[offset_data + 0] & 0x3f) | | |||
((data[offset_data + 1] & 0x03) << 6); | |||
bytes[offset_byte + 1] = ((data[offset_data + 1] >> 2) & 0x0f) | | |||
((data[offset_data + 2] & 0x0f) << 4); | |||
bytes[offset_byte + 2] = ((data[offset_data + 2] >> 4) & 0x03) | | |||
((data[offset_data + 3] & 0x3f) << 2); | |||
out[0] = (uint8_t) (in[0]); | |||
out[1] = (uint8_t) (((in[0] >> 8) & 0x03) | (in[1] << 2)); | |||
out[2] = (uint8_t) (((in[1] >> 6) & 0x0f) | (in[2] << 4)); | |||
out[3] = (uint8_t) (((in[2] >> 4) & 0x3f) | (in[3] << 6)); | |||
out[4] = (uint8_t) (in[3] >> 2); | |||
in += 4; | |||
out += 5; | |||
} | |||
} | |||
void PQCLEAN_FIRESABER_CLEAN_un_pack6bit(const unsigned char *bytes, uint16_t *data) { | |||
uint32_t j; | |||
uint32_t offset_data, offset_byte; | |||
static void BS2POLp(poly *data, const uint8_t bytes[SABER_POLYCOMPRESSEDBYTES]) { | |||
size_t j; | |||
const uint8_t *in = bytes; | |||
uint16_t *out = data->coeffs; | |||
for (j = 0; j < SABER_N / 4; j++) { | |||
offset_byte = 3 * j; | |||
offset_data = 4 * j; | |||
data[offset_data + 0] = bytes[offset_byte + 0] & 0x3f; | |||
data[offset_data + 1] = ((bytes[offset_byte + 0] >> 6) & 0x03) | | |||
((bytes[offset_byte + 1] & 0x0f) << 2); | |||
data[offset_data + 2] = ((bytes[offset_byte + 1] & 0xff) >> 4) | | |||
((bytes[offset_byte + 2] & 0x03) << 4); | |||
data[offset_data + 3] = ((bytes[offset_byte + 2] & 0xff) >> 2); | |||
out[0] = in[0] | (in[1] << 8); | |||
out[1] = (in[1] >> 2) | (in[2] << 6); | |||
out[2] = (in[2] >> 4) | (in[3] << 4); | |||
out[3] = (in[3] >> 6) | (in[4] << 2); | |||
in += 5; | |||
out += 4; | |||
} | |||
} | |||
static void POLVECp2BS(uint8_t *bytes, uint16_t data[SABER_K][SABER_N]) { | |||
uint32_t i, j; | |||
uint32_t offset_data, offset_byte, offset_byte1; | |||
for (i = 0; i < SABER_K; i++) { | |||
offset_byte1 = i * (SABER_N * 10) / 8; | |||
for (j = 0; j < SABER_N / 4; j++) { | |||
offset_byte = offset_byte1 + 5 * j; | |||
offset_data = 4 * j; | |||
bytes[offset_byte + 0] = (data[i][offset_data + 0] & (0xff)); | |||
bytes[offset_byte + 1] = ((data[i][offset_data + 0] >> 8) & 0x03) | | |||
((data[i][offset_data + 1] & 0x3f) << 2); | |||
bytes[offset_byte + 2] = ((data[i][offset_data + 1] >> 6) & 0x0f) | | |||
((data[i][offset_data + 2] & 0x0f) << 4); | |||
bytes[offset_byte + 3] = ((data[i][offset_data + 2] >> 4) & 0x3f) | | |||
((data[i][offset_data + 3] & 0x03) << 6); | |||
bytes[offset_byte + 4] = ((data[i][offset_data + 3] >> 2) & 0xff); | |||
} | |||
void PQCLEAN_FIRESABER_CLEAN_POLVECq2BS(uint8_t bytes[SABER_POLYVECBYTES], const poly data[SABER_L]) { | |||
size_t i; | |||
for (i = 0; i < SABER_L; i++) { | |||
POLq2BS(bytes + i * SABER_POLYBYTES, &data[i]); | |||
} | |||
} | |||
static void BS2POLVECp(const unsigned char *bytes, uint16_t data[SABER_K][SABER_N]) { | |||
uint32_t i, j; | |||
uint32_t offset_data, offset_byte, offset_byte1; | |||
for (i = 0; i < SABER_K; i++) { | |||
offset_byte1 = i * (SABER_N * 10) / 8; | |||
for (j = 0; j < SABER_N / 4; j++) { | |||
offset_byte = offset_byte1 + 5 * j; | |||
offset_data = 4 * j; | |||
data[i][offset_data + 0] = (bytes[offset_byte + 0] & (0xff)) | | |||
((bytes[offset_byte + 1] & 0x03) << 8); | |||
data[i][offset_data + 1] = ((bytes[offset_byte + 1] >> 2) & (0x3f)) | | |||
((bytes[offset_byte + 2] & 0x0f) << 6); | |||
data[i][offset_data + 2] = ((bytes[offset_byte + 2] >> 4) & (0x0f)) | | |||
((bytes[offset_byte + 3] & 0x3f) << 4); | |||
data[i][offset_data + 3] = ((bytes[offset_byte + 3] >> 6) & (0x03)) | | |||
((bytes[offset_byte + 4] & 0xff) << 2); | |||
} | |||
void PQCLEAN_FIRESABER_CLEAN_BS2POLVECq(poly data[SABER_L], const uint8_t bytes[SABER_POLYVECBYTES]) { | |||
size_t i; | |||
for (i = 0; i < SABER_L; i++) { | |||
BS2POLq(&data[i], bytes + i * SABER_POLYBYTES); | |||
} | |||
} | |||
static void POLVECq2BS(uint8_t *bytes, uint16_t data[SABER_K][SABER_N]) { | |||
uint32_t i, j; | |||
uint32_t offset_data, offset_byte, offset_byte1; | |||
for (i = 0; i < SABER_K; i++) { | |||
offset_byte1 = i * (SABER_N * 13) / 8; | |||
for (j = 0; j < SABER_N / 8; j++) { | |||
offset_byte = offset_byte1 + 13 * j; | |||
offset_data = 8 * j; | |||
bytes[offset_byte + 0] = (data[i][offset_data + 0] & (0xff)); | |||
bytes[offset_byte + 1] = ((data[i][offset_data + 0] >> 8) & 0x1f) | | |||
((data[i][offset_data + 1] & 0x07) << 5); | |||
bytes[offset_byte + 2] = ((data[i][offset_data + 1] >> 3) & 0xff); | |||
bytes[offset_byte + 3] = ((data[i][offset_data + 1] >> 11) & 0x03) | | |||
((data[i][offset_data + 2] & 0x3f) << 2); | |||
bytes[offset_byte + 4] = ((data[i][offset_data + 2] >> 6) & 0x7f) | | |||
((data[i][offset_data + 3] & 0x01) << 7); | |||
bytes[offset_byte + 5] = ((data[i][offset_data + 3] >> 1) & 0xff); | |||
bytes[offset_byte + 6] = ((data[i][offset_data + 3] >> 9) & 0x0f) | | |||
((data[i][offset_data + 4] & 0x0f) << 4); | |||
bytes[offset_byte + 7] = ((data[i][offset_data + 4] >> 4) & 0xff); | |||
bytes[offset_byte + 8] = ((data[i][offset_data + 4] >> 12) & 0x01) | | |||
((data[i][offset_data + 5] & 0x7f) << 1); | |||
bytes[offset_byte + 9] = ((data[i][offset_data + 5] >> 7) & 0x3f) | | |||
((data[i][offset_data + 6] & 0x03) << 6); | |||
bytes[offset_byte + 10] = ((data[i][offset_data + 6] >> 2) & 0xff); | |||
bytes[offset_byte + 11] = ((data[i][offset_data + 6] >> 10) & 0x07) | | |||
((data[i][offset_data + 7] & 0x1f) << 3); | |||
bytes[offset_byte + 12] = ((data[i][offset_data + 7] >> 5) & 0xff); | |||
} | |||
void PQCLEAN_FIRESABER_CLEAN_POLVECp2BS(uint8_t bytes[SABER_POLYVECCOMPRESSEDBYTES], const poly data[SABER_L]) { | |||
size_t i; | |||
for (i = 0; i < SABER_L; i++) { | |||
POLp2BS(bytes + i * SABER_POLYCOMPRESSEDBYTES, &data[i]); | |||
} | |||
} | |||
static void BS2POLVECq(const unsigned char *bytes, uint16_t data[SABER_K][SABER_N]) { | |||
uint32_t i, j; | |||
uint32_t offset_data, offset_byte, offset_byte1; | |||
for (i = 0; i < SABER_K; i++) { | |||
offset_byte1 = i * (SABER_N * 13) / 8; | |||
for (j = 0; j < SABER_N / 8; j++) { | |||
offset_byte = offset_byte1 + 13 * j; | |||
offset_data = 8 * j; | |||
data[i][offset_data + 0] = (bytes[offset_byte + 0] & (0xff)) | | |||
((bytes[offset_byte + 1] & 0x1f) << 8); | |||
data[i][offset_data + 1] = (bytes[offset_byte + 1] >> 5 & (0x07)) | | |||
((bytes[offset_byte + 2] & 0xff) << 3) | | |||
((bytes[offset_byte + 3] & 0x03) << 11); | |||
data[i][offset_data + 2] = (bytes[offset_byte + 3] >> 2 & (0x3f)) | | |||
((bytes[offset_byte + 4] & 0x7f) << 6); | |||
data[i][offset_data + 3] = (bytes[offset_byte + 4] >> 7 & (0x01)) | | |||
((bytes[offset_byte + 5] & 0xff) << 1) | | |||
((bytes[offset_byte + 6] & 0x0f) << 9); | |||
data[i][offset_data + 4] = (bytes[offset_byte + 6] >> 4 & (0x0f)) | | |||
((bytes[offset_byte + 7] & 0xff) << 4) | | |||
((bytes[offset_byte + 8] & 0x01) << 12); | |||
data[i][offset_data + 5] = (bytes[offset_byte + 8] >> 1 & (0x7f)) | | |||
((bytes[offset_byte + 9] & 0x3f) << 7); | |||
data[i][offset_data + 6] = (bytes[offset_byte + 9] >> 6 & (0x03)) | | |||
((bytes[offset_byte + 10] & 0xff) << 2) | | |||
((bytes[offset_byte + 11] & 0x07) << 10); | |||
data[i][offset_data + 7] = (bytes[offset_byte + 11] >> 3 & (0x1f)) | | |||
((bytes[offset_byte + 12] & 0xff) << 5); | |||
} | |||
void PQCLEAN_FIRESABER_CLEAN_BS2POLVECp(poly data[SABER_L], const uint8_t bytes[SABER_POLYVECCOMPRESSEDBYTES]) { | |||
size_t i; | |||
for (i = 0; i < SABER_L; i++) { | |||
BS2POLp(&data[i], bytes + i * SABER_POLYCOMPRESSEDBYTES); | |||
} | |||
} | |||
//only BS2POLq no BS2POLp | |||
void PQCLEAN_FIRESABER_CLEAN_BS2POL(const unsigned char *bytes, uint16_t data[SABER_N]) { | |||
uint32_t j; | |||
uint32_t offset_data, offset_byte; | |||
for (j = 0; j < SABER_N / 8; j++) { | |||
offset_byte = 13 * j; | |||
offset_data = 8 * j; | |||
data[offset_data + 0] = (bytes[offset_byte + 0] & (0xff)) | | |||
((bytes[offset_byte + 1] & 0x1f) << 8); | |||
data[offset_data + 1] = (bytes[offset_byte + 1] >> 5 & (0x07)) | | |||
((bytes[offset_byte + 2] & 0xff) << 3) | | |||
((bytes[offset_byte + 3] & 0x03) << 11); | |||
data[offset_data + 2] = (bytes[offset_byte + 3] >> 2 & (0x3f)) | | |||
((bytes[offset_byte + 4] & 0x7f) << 6); | |||
data[offset_data + 3] = (bytes[offset_byte + 4] >> 7 & (0x01)) | | |||
((bytes[offset_byte + 5] & 0xff) << 1) | | |||
((bytes[offset_byte + 6] & 0x0f) << 9); | |||
data[offset_data + 4] = (bytes[offset_byte + 6] >> 4 & (0x0f)) | | |||
((bytes[offset_byte + 7] & 0xff) << 4) | | |||
((bytes[offset_byte + 8] & 0x01) << 12); | |||
data[offset_data + 5] = (bytes[offset_byte + 8] >> 1 & (0x7f)) | | |||
((bytes[offset_byte + 9] & 0x3f) << 7); | |||
data[offset_data + 6] = (bytes[offset_byte + 9] >> 6 & (0x03)) | | |||
((bytes[offset_byte + 10] & 0xff) << 2) | | |||
((bytes[offset_byte + 11] & 0x07) << 10); | |||
data[offset_data + 7] = (bytes[offset_byte + 11] >> 3 & (0x1f)) | | |||
((bytes[offset_byte + 12] & 0xff) << 5); | |||
void PQCLEAN_FIRESABER_CLEAN_BS2POLmsg(poly *data, const uint8_t bytes[SABER_KEYBYTES]) { | |||
size_t i, j; | |||
for (j = 0; j < SABER_KEYBYTES; j++) { | |||
for (i = 0; i < 8; i++) { | |||
data->coeffs[j * 8 + i] = ((bytes[j] >> i) & 0x01); | |||
} | |||
} | |||
} | |||
void PQCLEAN_FIRESABER_CLEAN_POLVEC2BS(uint8_t *bytes, uint16_t data[SABER_K][SABER_N], uint16_t modulus) { | |||
if (modulus == 1024) { | |||
POLVECp2BS(bytes, data); | |||
} else if (modulus == 8192) { | |||
POLVECq2BS(bytes, data); | |||
} | |||
} | |||
void PQCLEAN_FIRESABER_CLEAN_POLmsg2BS(uint8_t bytes[SABER_KEYBYTES], const poly *data) { | |||
size_t i, j; | |||
memset(bytes, 0, SABER_KEYBYTES); | |||
void PQCLEAN_FIRESABER_CLEAN_BS2POLVEC(const unsigned char *bytes, uint16_t data[SABER_K][SABER_N], uint16_t modulus) { | |||
if (modulus == 1024) { | |||
BS2POLVECp(bytes, data); | |||
} else if (modulus == 8192) { | |||
BS2POLVECq(bytes, data); | |||
for (j = 0; j < SABER_KEYBYTES; j++) { | |||
for (i = 0; i < 8; i++) { | |||
bytes[j] = bytes[j] | ((data->coeffs[j * 8 + i] & 0x01) << i); | |||
} | |||
} | |||
} |
@@ -1,28 +1,28 @@ | |||
#ifndef PACK_UNPACK_H | |||
#define PACK_UNPACK_H | |||
#include "SABER_params.h" | |||
#include "poly.h" | |||
#include <stdint.h> | |||
#include <stdio.h> | |||
void PQCLEAN_FIRESABER_CLEAN_POLT2BS(uint8_t bytes[SABER_SCALEBYTES_KEM], const poly *data); | |||
void PQCLEAN_FIRESABER_CLEAN_BS2POLT(poly *data, const uint8_t bytes[SABER_SCALEBYTES_KEM]); | |||
void PQCLEAN_FIRESABER_CLEAN_pack_3bit(uint8_t *bytes, const uint16_t *data); | |||
void PQCLEAN_FIRESABER_CLEAN_un_pack3bit(const uint8_t *bytes, uint16_t *data); | |||
void PQCLEAN_FIRESABER_CLEAN_POLVECq2BS(uint8_t bytes[SABER_POLYVECBYTES], const poly data[SABER_L]); | |||
void PQCLEAN_FIRESABER_CLEAN_pack_4bit(uint8_t *bytes, const uint16_t *data); | |||
void PQCLEAN_FIRESABER_CLEAN_POLVECp2BS(uint8_t bytes[SABER_POLYVECCOMPRESSEDBYTES], const poly data[SABER_L]); | |||
void PQCLEAN_FIRESABER_CLEAN_un_pack4bit(const unsigned char *bytes, uint16_t *ar); | |||
void PQCLEAN_FIRESABER_CLEAN_pack_6bit(uint8_t *bytes, const uint16_t *data); | |||
void PQCLEAN_FIRESABER_CLEAN_BS2POLVECq(poly data[SABER_L], const uint8_t bytes[SABER_POLYVECBYTES]); | |||
void PQCLEAN_FIRESABER_CLEAN_un_pack6bit(const unsigned char *bytes, uint16_t *data); | |||
void PQCLEAN_FIRESABER_CLEAN_BS2POLVECp(poly data[SABER_L], const uint8_t bytes[SABER_POLYVECCOMPRESSEDBYTES]); | |||
void PQCLEAN_FIRESABER_CLEAN_BS2POL(const unsigned char *bytes, uint16_t data[SABER_N]); | |||
void PQCLEAN_FIRESABER_CLEAN_BS2POLmsg(poly *data, const uint8_t bytes[SABER_KEYBYTES]); | |||
void PQCLEAN_FIRESABER_CLEAN_POLVEC2BS(uint8_t *bytes, uint16_t data[SABER_K][SABER_N], uint16_t modulus); | |||
void PQCLEAN_FIRESABER_CLEAN_POLmsg2BS(uint8_t bytes[SABER_KEYBYTES], const poly *data); | |||
void PQCLEAN_FIRESABER_CLEAN_BS2POLVEC(const unsigned char *bytes, uint16_t data[SABER_K][SABER_N], uint16_t modulus); | |||
#endif |
@@ -1,21 +1,57 @@ | |||
/*--------------------------------------------------------------------- | |||
This file has been adapted from the implementation | |||
(available at, Public Domain https://github.com/pq-crystals/kyber) | |||
of "CRYSTALS – Kyber: a CCA-secure module-lattice-based KEM" | |||
by : Joppe Bos, Leo Ducas, Eike Kiltz, Tancrede Lepoint, | |||
Vadim Lyubashevsky, John M. Schanck, Peter Schwabe & Damien stehle | |||
#include "SABER_params.h" | |||
#include "api.h" | |||
#include "cbd.h" | |||
#include "fips202.h" | |||
#include "pack_unpack.h" | |||
#include "poly.h" | |||
#include <stddef.h> | |||
void PQCLEAN_FIRESABER_CLEAN_GenSecret(uint16_t r[SABER_K][SABER_N], const unsigned char *seed) { | |||
uint8_t buf[SABER_MU * SABER_N * SABER_K / 8]; | |||
void PQCLEAN_FIRESABER_CLEAN_MatrixVectorMul(poly c[SABER_L], const poly A[SABER_L][SABER_L], const poly s[SABER_L], int16_t transpose) { | |||
size_t i, j; | |||
if (transpose) { | |||
for (i = 0; i < SABER_L; i++) { | |||
PQCLEAN_FIRESABER_CLEAN_poly_mul(&c[i], &A[0][i], &s[0], 0); | |||
for (j = 1; j < SABER_L; j++) { | |||
PQCLEAN_FIRESABER_CLEAN_poly_mul(&c[i], &A[j][i], &s[j], 1); | |||
} | |||
} | |||
} else { | |||
for (i = 0; i < SABER_L; i++) { | |||
PQCLEAN_FIRESABER_CLEAN_poly_mul(&c[i], &A[i][0], &s[0], 0); | |||
for (j = 1; j < SABER_L; j++) { | |||
PQCLEAN_FIRESABER_CLEAN_poly_mul(&c[i], &A[i][j], &s[j], 1); | |||
} | |||
} | |||
} | |||
} | |||
void PQCLEAN_FIRESABER_CLEAN_InnerProd(poly *c, const poly b[SABER_L], const poly s[SABER_L]) { | |||
size_t i; | |||
PQCLEAN_FIRESABER_CLEAN_poly_mul(c, &b[0], &s[0], 0); | |||
for (i = 1; i < SABER_L; i++) { | |||
PQCLEAN_FIRESABER_CLEAN_poly_mul(c, &b[i], &s[i], 1); | |||
} | |||
} | |||
void PQCLEAN_FIRESABER_CLEAN_GenMatrix(poly A[SABER_L][SABER_L], const uint8_t seed[SABER_SEEDBYTES]) { | |||
size_t i; | |||
uint8_t buf[SABER_L * SABER_POLYVECBYTES]; | |||
shake128(buf, sizeof(buf), seed, SABER_SEEDBYTES); | |||
for (i = 0; i < SABER_L; i++) { | |||
PQCLEAN_FIRESABER_CLEAN_BS2POLVECq(A[i], buf + i * SABER_POLYVECBYTES); | |||
} | |||
} | |||
void PQCLEAN_FIRESABER_CLEAN_GenSecret(poly s[SABER_L], const uint8_t seed[SABER_NOISESEEDBYTES]) { | |||
size_t i; | |||
uint8_t buf[SABER_L * SABER_POLYCOINBYTES]; | |||
shake128(buf, sizeof(buf), seed, SABER_NOISESEEDBYTES); | |||
for (size_t i = 0; i < SABER_K; i++) { | |||
PQCLEAN_FIRESABER_CLEAN_cbd(r[i], buf + i * SABER_MU * SABER_N / 8); | |||
for (i = 0; i < SABER_L; i++) { | |||
PQCLEAN_FIRESABER_CLEAN_cbd(s[i].coeffs, buf + i * SABER_POLYCOINBYTES); | |||
} | |||
} |
@@ -1,26 +1,23 @@ | |||
#ifndef POLY_H | |||
#define POLY_H | |||
/*--------------------------------------------------------------------- | |||
This file has been adapted from the implementation | |||
(available at, Public Domain https://github.com/pq-crystals/kyber) | |||
of "CRYSTALS – Kyber: a CCA-secure module-lattice-based KEM" | |||
by : Joppe Bos, Leo Ducas, Eike Kiltz, Tancrede Lepoint, | |||
Vadim Lyubashevsky, John M. Schanck, Peter Schwabe & Damien stehle | |||
#include "SABER_params.h" | |||
#include <stdint.h> | |||
typedef struct { | |||
typedef union { | |||
uint16_t coeffs[SABER_N]; | |||
} poly; | |||
typedef struct { | |||
poly vec[SABER_K]; | |||
} polyvec; | |||
void PQCLEAN_FIRESABER_CLEAN_GenSecret(uint16_t r[SABER_K][SABER_N], const unsigned char *seed); | |||
void PQCLEAN_FIRESABER_CLEAN_MatrixVectorMul(poly c[SABER_L], const poly A[SABER_L][SABER_L], const poly s[SABER_L], int16_t transpose); | |||
void PQCLEAN_FIRESABER_CLEAN_InnerProd(poly *c, const poly b[SABER_L], const poly s[SABER_L]); | |||
void PQCLEAN_FIRESABER_CLEAN_GenMatrix(poly A[SABER_L][SABER_L], const uint8_t seed[SABER_SEEDBYTES]); | |||
void PQCLEAN_FIRESABER_CLEAN_GenSecret(poly s[SABER_L], const uint8_t seed[SABER_NOISESEEDBYTES]); | |||
void PQCLEAN_FIRESABER_CLEAN_poly_mul(poly *c, const poly *a, const poly *b, int accumulate); | |||
#endif |
@@ -1,4 +1,4 @@ | |||
#include "poly_mul.h" | |||
#include "poly.h" | |||
#include <stdint.h> | |||
#include <string.h> | |||
@@ -11,13 +11,13 @@ | |||
#define OVERFLOWING_MUL(X, Y) ((uint16_t)((uint32_t)(X) * (uint32_t)(Y))) | |||
#define KARATSUBA_N 64 | |||
static void karatsuba_simple(const uint16_t *a_1, const uint16_t *b_1, uint16_t *result_final) { | |||
static void karatsuba_simple(uint16_t *result_final, const uint16_t *a_1, const uint16_t *b_1) { | |||
uint16_t d01[KARATSUBA_N / 2 - 1]; | |||
uint16_t d0123[KARATSUBA_N / 2 - 1]; | |||
uint16_t d23[KARATSUBA_N / 2 - 1]; | |||
uint16_t result_d01[KARATSUBA_N - 1]; | |||
int32_t i, j; | |||
size_t i, j; | |||
memset(result_d01, 0, (KARATSUBA_N - 1)*sizeof(uint16_t)); | |||
memset(d01, 0, (KARATSUBA_N / 2 - 1)*sizeof(uint16_t)); | |||
@@ -110,7 +110,7 @@ static void karatsuba_simple(const uint16_t *a_1, const uint16_t *b_1, uint16_t | |||
static void toom_cook_4way (const uint16_t *a1, const uint16_t *b1, uint16_t *result) { | |||
static void toom_cook_4way (uint16_t *result, const uint16_t *a1, const uint16_t *b1) { | |||
uint16_t inv3 = 43691, inv9 = 36409, inv15 = 61167; | |||
uint16_t aw1[N_SB], aw2[N_SB], aw3[N_SB], aw4[N_SB], aw5[N_SB], aw6[N_SB], aw7[N_SB]; | |||
@@ -181,13 +181,13 @@ static void toom_cook_4way (const uint16_t *a1, const uint16_t *b1, uint16_t *re | |||
// MULTIPLICATION | |||
karatsuba_simple(aw1, bw1, w1); | |||
karatsuba_simple(aw2, bw2, w2); | |||
karatsuba_simple(aw3, bw3, w3); | |||
karatsuba_simple(aw4, bw4, w4); | |||
karatsuba_simple(aw5, bw5, w5); | |||
karatsuba_simple(aw6, bw6, w6); | |||
karatsuba_simple(aw7, bw7, w7); | |||
karatsuba_simple(w1, aw1, bw1); | |||
karatsuba_simple(w2, aw2, bw2); | |||
karatsuba_simple(w3, aw3, bw3); | |||
karatsuba_simple(w4, aw4, bw4); | |||
karatsuba_simple(w5, aw5, bw5); | |||
karatsuba_simple(w6, aw6, bw6); | |||
karatsuba_simple(w7, aw7, bw7); | |||
// INTERPOLATION | |||
for (i = 0; i < N_SB_RES; ++i) { | |||
@@ -228,19 +228,21 @@ static void toom_cook_4way (const uint16_t *a1, const uint16_t *b1, uint16_t *re | |||
} | |||
} | |||
void PQCLEAN_FIRESABER_CLEAN_pol_mul(uint16_t *a, uint16_t *b, uint16_t *res, uint16_t p, uint32_t n) { | |||
uint32_t i; | |||
// normal multiplication | |||
uint16_t c[512]; | |||
/* res += a*b */ | |||
void PQCLEAN_FIRESABER_CLEAN_poly_mul(poly *c, const poly *a, const poly *b, const int accumulate) { | |||
uint16_t C[2 * SABER_N] = {0}; | |||
size_t i; | |||
for (i = 0; i < 512; i++) { | |||
c[i] = 0; | |||
} | |||
toom_cook_4way(a, b, c); | |||
toom_cook_4way(C, a->coeffs, b->coeffs); | |||
// reduction | |||
for (i = n; i < 2 * n; i++) { | |||
res[i - n] = (c[i - n] - c[i]) & (p - 1); | |||
/* reduction */ | |||
if (accumulate == 0) { | |||
for (i = SABER_N; i < 2 * SABER_N; i++) { | |||
c->coeffs[i - SABER_N] = (C[i - SABER_N] - C[i]); | |||
} | |||
} else { | |||
for (i = SABER_N; i < 2 * SABER_N; i++) { | |||
c->coeffs[i - SABER_N] += (C[i - SABER_N] - C[i]); | |||
} | |||
} | |||
} |
@@ -1,9 +1,3 @@ | |||
#ifndef POLYMUL_H | |||
#define POLYMUL_H | |||
#include "SABER_params.h" | |||
#include <stdint.h> | |||
void PQCLEAN_FIRESABER_CLEAN_pol_mul(uint16_t *a, uint16_t *b, uint16_t *res, uint16_t p, uint32_t n); | |||
#endif |
@@ -1,3 +1,5 @@ | |||
#include "verify.h" | |||
/*------------------------------------------------- | |||
This file has been adapted from the implementation | |||
(available at https://github.com/pq-crystals/kyber) of | |||
@@ -5,26 +7,25 @@ This file has been adapted from the implementation | |||
by : Joppe Bos, Leo Ducas, Eike Kiltz, Tancrede Lepoint, | |||
Vadim Lyubashevsky, John M. Schanck, Peter Schwabe & Damien stehle | |||
----------------------------------------------------*/ | |||
#include "verify.h" | |||
#include <stdint.h> | |||
/* returns 0 for equal strings, 1 for non-equal strings */ | |||
unsigned char PQCLEAN_FIRESABER_CLEAN_verify(const unsigned char *a, const unsigned char *b, size_t len) { | |||
uint8_t PQCLEAN_FIRESABER_CLEAN_verify(const uint8_t *a, const uint8_t *b, size_t len) { | |||
uint64_t r; | |||
size_t i; | |||
r = 0; | |||
for (i = 0; i < len; i++) { | |||
r |= a[i] ^ b[i]; | |||
} | |||
r = (~r + 1); // Two's complement | |||
r >>= 63; | |||
return (unsigned char)r; | |||
return (uint8_t) r; | |||
} | |||
/* b = 1 means mov, b = 0 means don't mov*/ | |||
void PQCLEAN_FIRESABER_CLEAN_cmov(unsigned char *r, const unsigned char *x, size_t len, unsigned char b) { | |||
void PQCLEAN_FIRESABER_CLEAN_cmov(uint8_t *r, const uint8_t *x, size_t len, uint8_t b) { | |||
size_t i; | |||
b = -b; | |||
@@ -1,6 +1,5 @@ | |||
#ifndef VERIFY_H | |||
#define VERIFY_H | |||
/*------------------------------------------------- | |||
This file has been adapted from the implementation | |||
(available at https://github.com/pq-crystals/kyber) of | |||
@@ -13,9 +12,11 @@ Vadim Lyubashevsky, John M. Schanck, Peter Schwabe & Damien stehle | |||
#include <stdint.h> | |||
/* returns 0 for equal strings, 1 for non-equal strings */ | |||
unsigned char PQCLEAN_FIRESABER_CLEAN_verify(const unsigned char *a, const unsigned char *b, size_t len); | |||
uint8_t PQCLEAN_FIRESABER_CLEAN_verify(const uint8_t *a, const uint8_t *b, size_t len); | |||
/* b = 1 means mov, b = 0 means don't mov*/ | |||
void PQCLEAN_FIRESABER_CLEAN_cmov(unsigned char *r, const unsigned char *x, size_t len, unsigned char b); | |||
void PQCLEAN_FIRESABER_CLEAN_cmov(uint8_t *r, const uint8_t *x, size_t len, uint8_t b); | |||
#endif |
@@ -14,4 +14,13 @@ principal-submitters: | |||
- Frederik Vercauteren | |||
implementations: | |||
- name: clean | |||
version: https://github.com/KULeuven-COSIC/SABER/commit/14ede83f1ff3bcc41f0464543542366c68b55871 | |||
version: https://github.com/KULeuven-COSIC/SABER/tree/509cc5ec3a7e12a751ccdd2ef5bd6e54e00bd350 via https://github.com/jschanck/package-pqclean/tree/1ae84c3c/saber | |||
- name: avx2 | |||
version: https://github.com/KULeuven-COSIC/SABER/tree/509cc5ec3a7e12a751ccdd2ef5bd6e54e00bd350 via https://github.com/jschanck/package-pqclean/tree/1ae84c3c/saber | |||
supported_platforms: | |||
- architecture: x86_64 | |||
operating_systems: | |||
- Linux | |||
- Darwin | |||
required_flags: | |||
- avx2 |
@@ -0,0 +1 @@ | |||
Public Domain |
@@ -0,0 +1,22 @@ | |||
# This Makefile can be used with GNU Make or BSD Make | |||
LIB=liblightsaber_avx2.a | |||
HEADERS=api.h cbd.h pack_unpack.h poly.h SABER_indcpa.h SABER_params.h verify.h | |||
OBJECTS=cbd.o kem.o pack_unpack.o poly.o poly_mul.o SABER_indcpa.o verify.o | |||
CFLAGS=-O3 -mavx2 -Wall -Wextra -Wpedantic -Wvla -Werror -Wredundant-decls -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) | |||
all: $(LIB) | |||
%.o: %.s $(HEADERS) | |||
$(AS) -o $@ $< | |||
%.o: %.c $(HEADERS) | |||
$(CC) $(CFLAGS) -c -o $@ $< | |||
$(LIB): $(OBJECTS) | |||
$(AR) -r $@ $(OBJECTS) | |||
clean: | |||
$(RM) $(OBJECTS) | |||
$(RM) $(LIB) |
@@ -0,0 +1,125 @@ | |||
#include "SABER_indcpa.h" | |||
#include "SABER_params.h" | |||
#include "fips202.h" | |||
#include "pack_unpack.h" | |||
#include "poly.h" | |||
#include "randombytes.h" | |||
#include <stdint.h> | |||
#include <string.h> | |||
#define h1 (1 << (SABER_EQ - SABER_EP - 1)) | |||
#define h2 ((1 << (SABER_EP - 2)) - (1 << (SABER_EP - SABER_ET - 1)) + (1 << (SABER_EQ - SABER_EP - 1))) | |||
void PQCLEAN_LIGHTSABER_AVX2_indcpa_kem_keypair(uint8_t pk[SABER_INDCPA_PUBLICKEYBYTES], uint8_t sk[SABER_INDCPA_SECRETKEYBYTES]) { | |||
size_t i, j; | |||
poly A[SABER_L][SABER_L]; | |||
poly *skpv1 = A[0]; // use first row of A to hold sk temporarily | |||
toom4_points skpv1_eval[SABER_L]; | |||
poly res[SABER_L]; | |||
uint8_t rand[SABER_NOISESEEDBYTES]; | |||
uint8_t *seed_A = pk + SABER_POLYVECCOMPRESSEDBYTES; | |||
randombytes(seed_A, SABER_SEEDBYTES); | |||
shake128(seed_A, SABER_SEEDBYTES, seed_A, SABER_SEEDBYTES); // for not revealing system RNG state | |||
randombytes(rand, SABER_NOISESEEDBYTES); | |||
PQCLEAN_LIGHTSABER_AVX2_GenSecret(skpv1, rand); | |||
PQCLEAN_LIGHTSABER_AVX2_POLVECq2BS(sk, skpv1); // pack secret key | |||
for (j = 0; j < SABER_L; j++) { | |||
PQCLEAN_LIGHTSABER_AVX2_toom4_eval(&skpv1_eval[j], &skpv1[j]); | |||
} | |||
PQCLEAN_LIGHTSABER_AVX2_GenMatrix(A, seed_A); // sample matrix A | |||
PQCLEAN_LIGHTSABER_AVX2_MatrixVectorMul(res, (const poly (*)[SABER_L])A, (const toom4_points *)skpv1_eval, 1); // Matrix in transposed order | |||
// rounding | |||
for (i = 0; i < SABER_L; i++) { | |||
for (j = 0; j < SABER_N; j++) { | |||
res[i].coeffs[j] += h1; | |||
res[i].coeffs[j] >>= SABER_EQ - SABER_EP; | |||
res[i].coeffs[j] &= SABER_Q - 1; | |||
} | |||
} | |||
PQCLEAN_LIGHTSABER_AVX2_POLVECp2BS(pk, res); // pack public key | |||
} | |||
void PQCLEAN_LIGHTSABER_AVX2_indcpa_kem_enc(uint8_t ciphertext[SABER_BYTES_CCA_DEC], const uint8_t m[SABER_KEYBYTES], const uint8_t noiseseed[SABER_NOISESEEDBYTES], const uint8_t pk[SABER_INDCPA_PUBLICKEYBYTES]) { | |||
size_t i, j; | |||
poly A[SABER_L][SABER_L]; | |||
poly res[SABER_L]; | |||
toom4_points skpv1_eval[SABER_L]; | |||
poly *temp = A[0]; // re-use stack space | |||
poly *vprime = &A[0][0]; | |||
poly *message = &A[0][1]; | |||
const uint8_t *seed_A = pk + SABER_POLYVECCOMPRESSEDBYTES; | |||
uint8_t *msk_c = ciphertext + SABER_POLYVECCOMPRESSEDBYTES; | |||
PQCLEAN_LIGHTSABER_AVX2_GenSecret(temp, noiseseed); | |||
for (j = 0; j < SABER_L; j++) { | |||
PQCLEAN_LIGHTSABER_AVX2_toom4_eval(&skpv1_eval[j], &temp[j]); | |||
} | |||
PQCLEAN_LIGHTSABER_AVX2_GenMatrix(A, seed_A); | |||
PQCLEAN_LIGHTSABER_AVX2_MatrixVectorMul(res, (const poly (*)[SABER_L])A, (const toom4_points *)skpv1_eval, 0); // 0 => not transposed | |||
// rounding | |||
for (i = 0; i < SABER_L; i++) { //shift right EQ-EP bits | |||
for (j = 0; j < SABER_N; j++) { | |||
res[i].coeffs[j] += h1; | |||
res[i].coeffs[j] >>= SABER_EQ - SABER_EP; | |||
res[i].coeffs[j] &= SABER_Q - 1; | |||
} | |||
} | |||
PQCLEAN_LIGHTSABER_AVX2_POLVECp2BS(ciphertext, res); | |||
// vector-vector scalar multiplication with mod p | |||
PQCLEAN_LIGHTSABER_AVX2_BS2POLVECp(temp, pk); | |||
PQCLEAN_LIGHTSABER_AVX2_InnerProd(vprime, temp, skpv1_eval); | |||
PQCLEAN_LIGHTSABER_AVX2_BS2POLmsg(message, m); | |||
for (i = 0; i < SABER_N; i++) { | |||
vprime->coeffs[i] += h1 - (message->coeffs[i] << (SABER_EP - 1)); | |||
vprime->coeffs[i] &= SABER_P - 1; | |||
vprime->coeffs[i] >>= SABER_EP - SABER_ET; | |||
} | |||
PQCLEAN_LIGHTSABER_AVX2_POLT2BS(msk_c, vprime); | |||
} | |||
void PQCLEAN_LIGHTSABER_AVX2_indcpa_kem_dec(uint8_t m[SABER_KEYBYTES], const uint8_t sk[SABER_INDCPA_SECRETKEYBYTES], const uint8_t ciphertext[SABER_BYTES_CCA_DEC]) { | |||
size_t i; | |||
poly temp[SABER_L]; | |||
toom4_points sksv_eval[SABER_L]; | |||
const uint8_t *packed_cm = ciphertext + SABER_POLYVECCOMPRESSEDBYTES; | |||
poly *v = &temp[0]; | |||
poly *cm = &temp[1]; | |||
PQCLEAN_LIGHTSABER_AVX2_BS2POLVECq(temp, sk); | |||
for (i = 0; i < SABER_L; i++) { | |||
PQCLEAN_LIGHTSABER_AVX2_toom4_eval(&sksv_eval[i], &temp[i]); | |||
} | |||
PQCLEAN_LIGHTSABER_AVX2_BS2POLVECp(temp, ciphertext); | |||
PQCLEAN_LIGHTSABER_AVX2_InnerProd(v, temp, sksv_eval); | |||
PQCLEAN_LIGHTSABER_AVX2_BS2POLT(cm, packed_cm); | |||
for (i = 0; i < SABER_N; i++) { | |||
v->coeffs[i] += h2 - (cm->coeffs[i] << (SABER_EP - SABER_ET)); | |||
v->coeffs[i] &= SABER_P - 1; | |||
v->coeffs[i] >>= SABER_EP - 1; | |||
} | |||
PQCLEAN_LIGHTSABER_AVX2_POLmsg2BS(m, v); | |||
} |
@@ -0,0 +1,13 @@ | |||
#ifndef INDCPA_H | |||
#define INDCPA_H | |||
#include "SABER_params.h" | |||
#include <stdint.h> | |||
void PQCLEAN_LIGHTSABER_AVX2_indcpa_kem_keypair(uint8_t pk[SABER_INDCPA_PUBLICKEYBYTES], uint8_t sk[SABER_INDCPA_SECRETKEYBYTES]); | |||
void PQCLEAN_LIGHTSABER_AVX2_indcpa_kem_enc(uint8_t ciphertext[SABER_BYTES_CCA_DEC], const uint8_t m[SABER_KEYBYTES], const uint8_t noiseseed[SABER_NOISESEEDBYTES], const uint8_t pk[SABER_INDCPA_PUBLICKEYBYTES]); | |||
void PQCLEAN_LIGHTSABER_AVX2_indcpa_kem_dec(uint8_t m[SABER_KEYBYTES], const uint8_t sk[SABER_INDCPA_SECRETKEYBYTES], const uint8_t ciphertext[SABER_BYTES_CCA_DEC]); | |||
#endif |
@@ -0,0 +1,41 @@ | |||
#ifndef PARAMS_H | |||
#define PARAMS_H | |||
/* Don't change anything below this line */ | |||
#define SABER_L 2 | |||
#define SABER_MU 10 | |||
#define SABER_ET 3 | |||
#define SABER_N 256 | |||
#define SABER_EP 10 | |||
#define SABER_P (1 << SABER_EP) | |||
#define SABER_EQ 13 | |||
#define SABER_Q (1 << SABER_EQ) | |||
#define SABER_SEEDBYTES 32 | |||
#define SABER_NOISESEEDBYTES 32 | |||
#define SABER_KEYBYTES 32 | |||
#define SABER_HASHBYTES 32 | |||
#define SABER_POLYCOINBYTES (SABER_MU * SABER_N / 8) | |||
#define SABER_POLYBYTES (SABER_EQ * SABER_N / 8) | |||
#define SABER_POLYVECBYTES (SABER_L * SABER_POLYBYTES) | |||
#define SABER_POLYCOMPRESSEDBYTES (SABER_EP * SABER_N / 8) | |||
#define SABER_POLYVECCOMPRESSEDBYTES (SABER_L * SABER_POLYCOMPRESSEDBYTES) | |||
#define SABER_SCALEBYTES_KEM (SABER_ET * SABER_N / 8) | |||
#define SABER_INDCPA_PUBLICKEYBYTES (SABER_POLYVECCOMPRESSEDBYTES + SABER_SEEDBYTES) | |||
#define SABER_INDCPA_SECRETKEYBYTES (SABER_POLYVECBYTES) | |||
#define SABER_PUBLICKEYBYTES (SABER_INDCPA_PUBLICKEYBYTES) | |||
#define SABER_SECRETKEYBYTES (SABER_INDCPA_SECRETKEYBYTES + SABER_INDCPA_PUBLICKEYBYTES + SABER_HASHBYTES + SABER_KEYBYTES) | |||
#define SABER_BYTES_CCA_DEC (SABER_POLYVECCOMPRESSEDBYTES + SABER_SCALEBYTES_KEM) | |||
#endif |
@@ -0,0 +1,18 @@ | |||
#ifndef PQCLEAN_LIGHTSABER_AVX2_API_H | |||
#define PQCLEAN_LIGHTSABER_AVX2_API_H | |||
#define PQCLEAN_LIGHTSABER_AVX2_CRYPTO_ALGNAME "LightSaber" | |||
#define PQCLEAN_LIGHTSABER_AVX2_CRYPTO_BYTES 32 | |||
#define PQCLEAN_LIGHTSABER_AVX2_CRYPTO_CIPHERTEXTBYTES 736 | |||
#define PQCLEAN_LIGHTSABER_AVX2_CRYPTO_PUBLICKEYBYTES 672 | |||
#define PQCLEAN_LIGHTSABER_AVX2_CRYPTO_SECRETKEYBYTES 1568 | |||
int PQCLEAN_LIGHTSABER_AVX2_crypto_kem_keypair(unsigned char *pk, unsigned char *sk); | |||
int PQCLEAN_LIGHTSABER_AVX2_crypto_kem_enc(unsigned char *ct, unsigned char *k, const unsigned char *pk); | |||
int PQCLEAN_LIGHTSABER_AVX2_crypto_kem_dec(unsigned char *k, const unsigned char *ct, const unsigned char *sk); | |||
#endif /* PQCLEAN_LIGHTSABER_AVX2_API_H */ |
@@ -0,0 +1,48 @@ | |||
#include "SABER_params.h" | |||
#include "api.h" | |||
#include "cbd.h" | |||
#include <stdint.h> | |||
/*--------------------------------------------------------------------- | |||
This file has been adapted from the implementation | |||
(available at, Public Domain https://github.com/pq-crystals/kyber) | |||
of "CRYSTALS – Kyber: a CCA-secure module-lattice-based KEM" | |||
by : Joppe Bos, Leo Ducas, Eike Kiltz, Tancrede Lepoint, | |||
Vadim Lyubashevsky, John M. Schanck, Peter Schwabe & Damien stehle | |||
----------------------------------------------------------------------*/ | |||
static uint64_t load_littleendian(const uint8_t *x, int bytes) { | |||
int i; | |||
uint64_t r = x[0]; | |||
for (i = 1; i < bytes; i++) { | |||
r |= (uint64_t)x[i] << (8 * i); | |||
} | |||
return r; | |||
} | |||
void PQCLEAN_LIGHTSABER_AVX2_cbd(uint16_t s[SABER_N], const uint8_t buf[SABER_POLYCOINBYTES]) { | |||
uint64_t t, d, a[4], b[4]; | |||
int i, j; | |||
for (i = 0; i < SABER_N / 4; i++) { | |||
t = load_littleendian(buf + 5 * i, 5); | |||
d = 0; | |||
for (j = 0; j < 5; j++) { | |||
d += (t >> j) & 0x0842108421UL; | |||
} | |||
a[0] = d & 0x1f; | |||
b[0] = (d >> 5) & 0x1f; | |||
a[1] = (d >> 10) & 0x1f; | |||
b[1] = (d >> 15) & 0x1f; | |||
a[2] = (d >> 20) & 0x1f; | |||
b[2] = (d >> 25) & 0x1f; | |||
a[3] = (d >> 30) & 0x1f; | |||
b[3] = (d >> 35); | |||
s[4 * i + 0] = (uint16_t)(a[0] - b[0]); | |||
s[4 * i + 1] = (uint16_t)(a[1] - b[1]); | |||
s[4 * i + 2] = (uint16_t)(a[2] - b[2]); | |||
s[4 * i + 3] = (uint16_t)(a[3] - b[3]); | |||
} | |||
} |
@@ -0,0 +1,16 @@ | |||
#ifndef CBD_H | |||
#define CBD_H | |||
/*--------------------------------------------------------------------- | |||
This file has been adapted from the implementation | |||
(available at, Public Domain https://github.com/pq-crystals/kyber) | |||
of "CRYSTALS – Kyber: a CCA-secure module-lattice-based KEM" | |||
by : Joppe Bos, Leo Ducas, Eike Kiltz, Tancrede Lepoint, | |||
Vadim Lyubashevsky, John M. Schanck, Peter Schwabe & Damien stehle | |||
----------------------------------------------------------------------*/ | |||
#include "SABER_params.h" | |||
#include <stdint.h> | |||
void PQCLEAN_LIGHTSABER_AVX2_cbd(uint16_t s[SABER_N], const uint8_t buf[SABER_POLYCOINBYTES]); | |||
#endif |
@@ -0,0 +1,77 @@ | |||
#include "SABER_indcpa.h" | |||
#include "SABER_params.h" | |||
#include "api.h" | |||
#include "fips202.h" | |||
#include "randombytes.h" | |||
#include "verify.h" | |||
#include <stddef.h> | |||
#include <stdint.h> | |||
int PQCLEAN_LIGHTSABER_AVX2_crypto_kem_keypair(uint8_t *pk, uint8_t *sk) { | |||
size_t i; | |||
PQCLEAN_LIGHTSABER_AVX2_indcpa_kem_keypair(pk, sk); // sk[0:SABER_INDCPA_SECRETKEYBYTES-1] <-- sk | |||
for (i = 0; i < SABER_INDCPA_PUBLICKEYBYTES; i++) { | |||
sk[i + SABER_INDCPA_SECRETKEYBYTES] = pk[i]; // sk[SABER_INDCPA_SECRETKEYBYTES:SABER_INDCPA_SECRETKEYBYTES+SABER_INDCPA_SECRETKEYBYTES-1] <-- pk | |||
} | |||
sha3_256(sk + SABER_SECRETKEYBYTES - 64, pk, SABER_INDCPA_PUBLICKEYBYTES); // Then hash(pk) is appended. | |||
randombytes(sk + SABER_SECRETKEYBYTES - SABER_KEYBYTES, SABER_KEYBYTES); // Remaining part of sk contains a pseudo-random number. | |||
// This is output when check in PQCLEAN_LIGHTSABER_AVX2_crypto_kem_dec() fails. | |||
return (0); | |||
} | |||
int PQCLEAN_LIGHTSABER_AVX2_crypto_kem_enc(uint8_t *c, uint8_t *k, const uint8_t *pk) { | |||
uint8_t kr[64]; // Will contain key, coins | |||
uint8_t buf[64]; | |||
randombytes(buf, 32); | |||
sha3_256(buf, buf, 32); // BUF[0:31] <-- random message (will be used as the key for client) Note: hash doesnot release system RNG output | |||
sha3_256(buf + 32, pk, SABER_INDCPA_PUBLICKEYBYTES); // BUF[32:63] <-- Hash(public key); Multitarget countermeasure for coins + contributory KEM | |||
sha3_512(kr, buf, 64); // kr[0:63] <-- Hash(buf[0:63]); | |||
// K^ <-- kr[0:31] | |||
// noiseseed (r) <-- kr[32:63]; | |||
PQCLEAN_LIGHTSABER_AVX2_indcpa_kem_enc(c, buf, kr + 32, pk); // buf[0:31] contains message; kr[32:63] contains randomness r; | |||
sha3_256(kr + 32, c, SABER_BYTES_CCA_DEC); | |||
sha3_256(k, kr, 64); // hash concatenation of pre-k and h(c) to k | |||
return (0); | |||
} | |||
int PQCLEAN_LIGHTSABER_AVX2_crypto_kem_dec(uint8_t *k, const uint8_t *c, const uint8_t *sk) { | |||
size_t i; | |||
uint8_t fail; | |||
uint8_t cmp[SABER_BYTES_CCA_DEC]; | |||
uint8_t buf[64]; | |||
uint8_t kr[64]; // Will contain key, coins | |||
const uint8_t *pk = sk + SABER_INDCPA_SECRETKEYBYTES; | |||
PQCLEAN_LIGHTSABER_AVX2_indcpa_kem_dec(buf, sk, c); // buf[0:31] <-- message | |||
// Multitarget countermeasure for coins + contributory KEM | |||
for (i = 0; i < 32; i++) { // Save hash by storing h(pk) in sk | |||
buf[32 + i] = sk[SABER_SECRETKEYBYTES - 64 + i]; | |||
} | |||
sha3_512(kr, buf, 64); | |||
PQCLEAN_LIGHTSABER_AVX2_indcpa_kem_enc(cmp, buf, kr + 32, pk); | |||
fail = PQCLEAN_LIGHTSABER_AVX2_verify(c, cmp, SABER_BYTES_CCA_DEC); | |||
sha3_256(kr + 32, c, SABER_BYTES_CCA_DEC); // overwrite coins in kr with h(c) | |||
PQCLEAN_LIGHTSABER_AVX2_cmov(kr, sk + SABER_SECRETKEYBYTES - SABER_KEYBYTES, SABER_KEYBYTES, fail); | |||
sha3_256(k, kr, 64); // hash concatenation of pre-k and h(c) to k | |||
return (0); | |||
} |
@@ -0,0 +1,155 @@ | |||
#include "SABER_params.h" | |||
#include "pack_unpack.h" | |||
#include "poly.h" | |||
#include <string.h> | |||
void PQCLEAN_LIGHTSABER_AVX2_POLT2BS(uint8_t bytes[SABER_SCALEBYTES_KEM], const poly *data) { | |||
size_t j; | |||
const uint16_t *in = data->coeffs; | |||
uint8_t *out = bytes; | |||
for (j = 0; j < SABER_N / 8; j++) { | |||
out[0] = (uint8_t) ((in[0] & 0x7) | ((in[1] & 0x7) << 3) | (in[2] << 6)); | |||
out[1] = (uint8_t) (((in[2] >> 2) & 0x01) | ((in[3] & 0x7) << 1) | ((in[4] & 0x7) << 4) | (in[5] << 7)); | |||
out[2] = (uint8_t) (((in[5] >> 1) & 0x03) | ((in[6] & 0x7) << 2) | (in[7] << 5)); | |||
in += 8; | |||
out += 3; | |||
} | |||
} | |||
void PQCLEAN_LIGHTSABER_AVX2_BS2POLT(poly *data, const uint8_t bytes[SABER_SCALEBYTES_KEM]) { | |||
/* This function does not reduce its output mod T */ | |||
size_t j; | |||
const uint8_t *in = bytes; | |||
uint16_t *out = data->coeffs; | |||
for (j = 0; j < SABER_N / 8; j++) { | |||
out[0] = in[0]; | |||
out[1] = in[0] >> 3; | |||
out[2] = (in[0] >> 6) | (in[1] << 2); | |||
out[3] = in[1] >> 1; | |||
out[4] = in[1] >> 4; | |||
out[5] = (in[1] >> 7) | (in[2] << 1); | |||
out[6] = in[2] >> 2; | |||
out[7] = in[2] >> 5; | |||
in += 3; | |||
out += 8; | |||
} | |||
} | |||
static void POLq2BS(uint8_t bytes[SABER_POLYBYTES], const poly *data) { | |||
size_t j; | |||
const uint16_t *in = data->coeffs; | |||
uint8_t *out = bytes; | |||
for (j = 0; j < SABER_N / 8; j++) { | |||
out[0] = (uint8_t) (in[0]); | |||
out[1] = (uint8_t) (((in[0] >> 8) & 0x1f) | (in[1] << 5)); | |||
out[2] = (uint8_t) (in[1] >> 3); | |||
out[3] = (uint8_t) (((in[1] >> 11) & 0x03) | (in[2] << 2)); | |||
out[4] = (uint8_t) (((in[2] >> 6) & 0x7f) | (in[3] << 7)); | |||
out[5] = (uint8_t) (in[3] >> 1); | |||
out[6] = (uint8_t) (((in[3] >> 9) & 0x0f) | (in[4] << 4)); | |||
out[7] = (uint8_t) (in[4] >> 4); | |||
out[8] = (uint8_t) (((in[4] >> 12) & 0x01) | (in[5] << 1)); | |||
out[9] = (uint8_t) (((in[5] >> 7) & 0x3f) | (in[6] << 6)); | |||
out[10] = (uint8_t) (in[6] >> 2); | |||
out[11] = (uint8_t) (((in[6] >> 10) & 0x07) | (in[7] << 3)); | |||
out[12] = (uint8_t) (in[7] >> 5); | |||
in += 8; | |||
out += 13; | |||
} | |||
} | |||
static void BS2POLq(poly *data, const uint8_t bytes[SABER_POLYBYTES]) { | |||
/* This function does not reduce its output mod Q */ | |||
size_t j; | |||
const uint8_t *in = bytes; | |||
uint16_t *out = data->coeffs; | |||
for (j = 0; j < SABER_N / 8; j++) { | |||
out[0] = (in[0]) | (in[1] << 8); | |||
out[1] = (in[1] >> 5) | (in[2] << 3) | (in[3] << 11); | |||
out[2] = (in[3] >> 2) | (in[4] << 6); | |||
out[3] = (in[4] >> 7) | (in[5] << 1) | (in[6] << 9); | |||
out[4] = (in[6] >> 4) | (in[7] << 4) | (in[8] << 12); | |||
out[5] = (in[8] >> 1) | (in[9] << 7); | |||
out[6] = (in[9] >> 6) | (in[10] << 2) | (in[11] << 10); | |||
out[7] = (in[11] >> 3) | (in[12] << 5); | |||
in += 13; | |||
out += 8; | |||
} | |||
} | |||
static void POLp2BS(uint8_t bytes[SABER_POLYCOMPRESSEDBYTES], const poly *data) { | |||
size_t j; | |||
const uint16_t *in = data->coeffs; | |||
uint8_t *out = bytes; | |||
for (j = 0; j < SABER_N / 4; j++) { | |||
out[0] = (uint8_t) (in[0]); | |||
out[1] = (uint8_t) (((in[0] >> 8) & 0x03) | (in[1] << 2)); | |||
out[2] = (uint8_t) (((in[1] >> 6) & 0x0f) | (in[2] << 4)); | |||
out[3] = (uint8_t) (((in[2] >> 4) & 0x3f) | (in[3] << 6)); | |||
out[4] = (uint8_t) (in[3] >> 2); | |||
in += 4; | |||
out += 5; | |||
} | |||
} | |||
static void BS2POLp(poly *data, const uint8_t bytes[SABER_POLYCOMPRESSEDBYTES]) { | |||
size_t j; | |||
const uint8_t *in = bytes; | |||
uint16_t *out = data->coeffs; | |||
for (j = 0; j < SABER_N / 4; j++) { | |||
out[0] = in[0] | (in[1] << 8); | |||
out[1] = (in[1] >> 2) | (in[2] << 6); | |||
out[2] = (in[2] >> 4) | (in[3] << 4); | |||
out[3] = (in[3] >> 6) | (in[4] << 2); | |||
in += 5; | |||
out += 4; | |||
} | |||
} | |||
void PQCLEAN_LIGHTSABER_AVX2_POLVECq2BS(uint8_t bytes[SABER_POLYVECBYTES], const poly data[SABER_L]) { | |||
size_t i; | |||
for (i = 0; i < SABER_L; i++) { | |||
POLq2BS(bytes + i * SABER_POLYBYTES, &data[i]); | |||
} | |||
} | |||
void PQCLEAN_LIGHTSABER_AVX2_BS2POLVECq(poly data[SABER_L], const uint8_t bytes[SABER_POLYVECBYTES]) { | |||
size_t i; | |||
for (i = 0; i < SABER_L; i++) { | |||
BS2POLq(&data[i], bytes + i * SABER_POLYBYTES); | |||
} | |||
} | |||
void PQCLEAN_LIGHTSABER_AVX2_POLVECp2BS(uint8_t bytes[SABER_POLYVECCOMPRESSEDBYTES], const poly data[SABER_L]) { | |||
size_t i; | |||
for (i = 0; i < SABER_L; i++) { | |||
POLp2BS(bytes + i * SABER_POLYCOMPRESSEDBYTES, &data[i]); | |||
} | |||
} | |||
void PQCLEAN_LIGHTSABER_AVX2_BS2POLVECp(poly data[SABER_L], const uint8_t bytes[SABER_POLYVECCOMPRESSEDBYTES]) { | |||
size_t i; | |||
for (i = 0; i < SABER_L; i++) { | |||
BS2POLp(&data[i], bytes + i * SABER_POLYCOMPRESSEDBYTES); | |||
} | |||
} | |||
void PQCLEAN_LIGHTSABER_AVX2_BS2POLmsg(poly *data, const uint8_t bytes[SABER_KEYBYTES]) { | |||
size_t i, j; | |||
for (j = 0; j < SABER_KEYBYTES; j++) { | |||
for (i = 0; i < 8; i++) { | |||
data->coeffs[j * 8 + i] = ((bytes[j] >> i) & 0x01); | |||
} | |||
} | |||
} | |||
void PQCLEAN_LIGHTSABER_AVX2_POLmsg2BS(uint8_t bytes[SABER_KEYBYTES], const poly *data) { | |||
size_t i, j; | |||
memset(bytes, 0, SABER_KEYBYTES); | |||
for (j = 0; j < SABER_KEYBYTES; j++) { | |||
for (i = 0; i < 8; i++) { | |||
bytes[j] = bytes[j] | ((data->coeffs[j * 8 + i] & 0x01) << i); | |||
} | |||
} | |||
} |
@@ -0,0 +1,28 @@ | |||
#ifndef PACK_UNPACK_H | |||
#define PACK_UNPACK_H | |||
#include "SABER_params.h" | |||
#include "poly.h" | |||
#include <stdint.h> | |||
#include <stdio.h> | |||
void PQCLEAN_LIGHTSABER_AVX2_POLT2BS(uint8_t bytes[SABER_SCALEBYTES_KEM], const poly *data); | |||
void PQCLEAN_LIGHTSABER_AVX2_BS2POLT(poly *data, const uint8_t bytes[SABER_SCALEBYTES_KEM]); | |||
void PQCLEAN_LIGHTSABER_AVX2_POLVECq2BS(uint8_t bytes[SABER_POLYVECBYTES], const poly data[SABER_L]); | |||
void PQCLEAN_LIGHTSABER_AVX2_POLVECp2BS(uint8_t bytes[SABER_POLYVECCOMPRESSEDBYTES], const poly data[SABER_L]); | |||
void PQCLEAN_LIGHTSABER_AVX2_BS2POLVECq(poly data[SABER_L], const uint8_t bytes[SABER_POLYVECBYTES]); | |||
void PQCLEAN_LIGHTSABER_AVX2_BS2POLVECp(poly data[SABER_L], const uint8_t bytes[SABER_POLYVECCOMPRESSEDBYTES]); | |||
void PQCLEAN_LIGHTSABER_AVX2_BS2POLmsg(poly *data, const uint8_t bytes[SABER_KEYBYTES]); | |||
void PQCLEAN_LIGHTSABER_AVX2_POLmsg2BS(uint8_t bytes[SABER_KEYBYTES], const poly *data); | |||
#endif |
@@ -0,0 +1,62 @@ | |||
#include "cbd.h" | |||
#include "fips202.h" | |||
#include "pack_unpack.h" | |||
#include "poly.h" | |||
void PQCLEAN_LIGHTSABER_AVX2_MatrixVectorMul(poly c[SABER_L], const poly A[SABER_L][SABER_L], const toom4_points s_eval[SABER_L], int transpose) { | |||
size_t i, j; | |||
toom4_points_product c_eval; | |||
if (transpose) { | |||
for (i = 0; i < SABER_L; i++) { | |||
PQCLEAN_LIGHTSABER_AVX2_toom4_mul_A_by_B_eval(&c_eval, &A[0][i], &s_eval[0], 0); | |||
for (j = 1; j < SABER_L; j++) { | |||
PQCLEAN_LIGHTSABER_AVX2_toom4_mul_A_by_B_eval(&c_eval, &A[j][i], &s_eval[j], 1); | |||
} | |||
PQCLEAN_LIGHTSABER_AVX2_toom4_interp(&c[i], &c_eval); | |||
} | |||
} else { | |||
for (i = 0; i < SABER_L; i++) { | |||
PQCLEAN_LIGHTSABER_AVX2_toom4_mul_A_by_B_eval(&c_eval, &A[i][0], &s_eval[0], 0); | |||
for (j = 1; j < SABER_L; j++) { | |||
PQCLEAN_LIGHTSABER_AVX2_toom4_mul_A_by_B_eval(&c_eval, &A[i][j], &s_eval[j], 1); | |||
} | |||
PQCLEAN_LIGHTSABER_AVX2_toom4_interp(&c[i], &c_eval); | |||
} | |||
} | |||
} | |||
void PQCLEAN_LIGHTSABER_AVX2_InnerProd(poly *c, const poly b[SABER_L], const toom4_points s_eval[SABER_L]) { | |||
size_t i; | |||
toom4_points_product c_eval; //Holds results for 9 Karatsuba at a time | |||
PQCLEAN_LIGHTSABER_AVX2_toom4_mul_A_by_B_eval(&c_eval, &b[0], &s_eval[0], 0); | |||
for (i = 1; i < SABER_L; i++) { | |||
PQCLEAN_LIGHTSABER_AVX2_toom4_mul_A_by_B_eval(&c_eval, &b[i], &s_eval[i], 1); | |||
} | |||
PQCLEAN_LIGHTSABER_AVX2_toom4_interp(c, &c_eval); | |||
} | |||
void PQCLEAN_LIGHTSABER_AVX2_GenMatrix(poly A[SABER_L][SABER_L], const uint8_t seed[SABER_SEEDBYTES]) { | |||
size_t i; | |||
uint8_t buf[SABER_L * SABER_POLYVECBYTES]; | |||
shake128(buf, sizeof(buf), seed, SABER_SEEDBYTES); | |||
for (i = 0; i < SABER_L; i++) { | |||
PQCLEAN_LIGHTSABER_AVX2_BS2POLVECq(A[i], buf + i * SABER_POLYVECBYTES); | |||
} | |||
} | |||
void PQCLEAN_LIGHTSABER_AVX2_GenSecret(poly s[SABER_L], const uint8_t seed[SABER_NOISESEEDBYTES]) { | |||
size_t i; | |||
uint8_t buf[SABER_L * SABER_POLYCOINBYTES]; | |||
shake128(buf, sizeof(buf), seed, SABER_NOISESEEDBYTES); | |||
for (i = 0; i < SABER_L; i++) { | |||
PQCLEAN_LIGHTSABER_AVX2_cbd(s[i].coeffs, buf + i * SABER_POLYCOINBYTES); | |||
} | |||
} |
@@ -0,0 +1,38 @@ | |||
#ifndef POLY_H | |||
#define POLY_H | |||
#include "SABER_params.h" | |||
#include <immintrin.h> | |||
#include <stdint.h> | |||
typedef union { | |||
uint16_t coeffs[SABER_N]; | |||
__m256i dummy; | |||
} poly; | |||
typedef union { | |||
uint16_t coeffs[4 * SABER_N]; | |||
__m256i dummy; | |||
} toom4_points; | |||
typedef union { | |||
uint16_t coeffs[8 * SABER_N]; | |||
__m256i dummy; | |||
} toom4_points_product; | |||
void PQCLEAN_LIGHTSABER_AVX2_MatrixVectorMul(poly c[SABER_L], const poly A[SABER_L][SABER_L], const toom4_points s_eval[SABER_L], int transpose); | |||
void PQCLEAN_LIGHTSABER_AVX2_InnerProd(poly *c, const poly b[SABER_L], const toom4_points s_eval[SABER_L]); | |||
void PQCLEAN_LIGHTSABER_AVX2_GenMatrix(poly a[SABER_L][SABER_L], const uint8_t seed[SABER_SEEDBYTES]); | |||
void PQCLEAN_LIGHTSABER_AVX2_GenSecret(poly s[SABER_L], const uint8_t seed[SABER_NOISESEEDBYTES]); | |||
void PQCLEAN_LIGHTSABER_AVX2_toom4_interp(poly *res_avx, const toom4_points_product *c_eval); | |||
void PQCLEAN_LIGHTSABER_AVX2_toom4_eval(toom4_points *b_eval, const poly *b); | |||
void PQCLEAN_LIGHTSABER_AVX2_toom4_mul_A_by_B_eval(toom4_points_product *c_eval, const poly *a_avx, const toom4_points *b_eval, int accumulate); | |||
#endif |
@@ -0,0 +1,35 @@ | |||
#include "verify.h" | |||
/*------------------------------------------------- | |||
This file has been adapted from the implementation | |||
(available at https://github.com/pq-crystals/kyber) of | |||
"CRYSTALS – Kyber: a CCA-secure module-lattice-based KEM" | |||
by : Joppe Bos, Leo Ducas, Eike Kiltz, Tancrede Lepoint, | |||
Vadim Lyubashevsky, John M. Schanck, Peter Schwabe & Damien stehle | |||
----------------------------------------------------*/ | |||
/* returns 0 for equal strings, 1 for non-equal strings */ | |||
uint8_t PQCLEAN_LIGHTSABER_AVX2_verify(const uint8_t *a, const uint8_t *b, size_t len) { | |||
uint64_t r; | |||
size_t i; | |||
r = 0; | |||
for (i = 0; i < len; i++) { | |||
r |= a[i] ^ b[i]; | |||
} | |||
r = (~r + 1); // Two's complement | |||
r >>= 63; | |||
return (uint8_t) r; | |||
} | |||
/* b = 1 means mov, b = 0 means don't mov*/ | |||
void PQCLEAN_LIGHTSABER_AVX2_cmov(uint8_t *r, const uint8_t *x, size_t len, uint8_t b) { | |||
size_t i; | |||
b = -b; | |||
for (i = 0; i < len; i++) { | |||
r[i] ^= b & (x[i] ^ r[i]); | |||
} | |||
} |
@@ -0,0 +1,22 @@ | |||
#ifndef VERIFY_H | |||
#define VERIFY_H | |||
/*------------------------------------------------- | |||
This file has been adapted from the implementation | |||
(available at https://github.com/pq-crystals/kyber) of | |||
"CRYSTALS – Kyber: a CCA-secure module-lattice-based KEM" | |||
by : Joppe Bos, Leo Ducas, Eike Kiltz, Tancrede Lepoint, | |||
Vadim Lyubashevsky, John M. Schanck, Peter Schwabe & Damien stehle | |||
----------------------------------------------------*/ | |||
#include <stddef.h> | |||
#include <stdint.h> | |||
/* returns 0 for equal strings, 1 for non-equal strings */ | |||
uint8_t PQCLEAN_LIGHTSABER_AVX2_verify(const uint8_t *a, const uint8_t *b, size_t len); | |||
/* b = 1 means mov, b = 0 means don't mov*/ | |||
void PQCLEAN_LIGHTSABER_AVX2_cmov(uint8_t *r, const uint8_t *x, size_t len, uint8_t b); | |||
#endif |
@@ -1,8 +1 @@ | |||
SABER_v1.1 | |||
Public domain | |||
Authors: Jan-Pieter D'Anvers, Angshuman Karmakar, Sujoy Sinha Roy, | |||
Frederik Vercauteren | |||
Public Domain |
@@ -1,10 +1,10 @@ | |||
# This Makefile can be used with GNU Make or BSD Make | |||
LIB=liblightsaber_clean.a | |||
HEADERS=api.h cbd.h poly.h poly_mul.h SABER_indcpa.h SABER_params.h verify.h pack_unpack.h | |||
HEADERS=api.h cbd.h pack_unpack.h poly.h poly_mul.h SABER_indcpa.h SABER_params.h verify.h | |||
OBJECTS=cbd.o kem.o pack_unpack.o poly.o poly_mul.o SABER_indcpa.o verify.o | |||
CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) | |||
CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -Werror -Wredundant-decls -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) | |||
all: $(LIB) | |||
@@ -3,296 +3,111 @@ | |||
#include "fips202.h" | |||
#include "pack_unpack.h" | |||
#include "poly.h" | |||
#include "poly_mul.h" | |||
#include "randombytes.h" | |||
#include <stdint.h> | |||
#include <string.h> | |||
#define h1 (1 << (SABER_EQ - SABER_EP - 1)) | |||
#define h2 ((1 << (SABER_EP - 2)) - (1 << (SABER_EP - SABER_ET - 1)) + (1 << (SABER_EQ - SABER_EP - 1))) | |||
void PQCLEAN_LIGHTSABER_CLEAN_indcpa_kem_keypair(uint8_t pk[SABER_INDCPA_PUBLICKEYBYTES], uint8_t sk[SABER_INDCPA_SECRETKEYBYTES]) { | |||
size_t i, j; | |||
/*----------------------------------------------------------------------------------- | |||
This routine generates a=[Matrix K x K] of 256-coefficient polynomials | |||
poly A[SABER_L][SABER_L]; | |||
poly s[SABER_L]; | |||
poly res[SABER_L]; | |||
#define h1 4 //2^(EQ-EP-1) | |||
uint8_t rand[SABER_NOISESEEDBYTES]; | |||
uint8_t *seed_A = pk + SABER_POLYVECCOMPRESSEDBYTES; | |||
#define h2 ( (1<<(SABER_EP-2)) - (1<<(SABER_EP-SABER_ET-1)) + (1<<(SABER_EQ-SABER_EP-1)) ) | |||
randombytes(seed_A, SABER_SEEDBYTES); | |||
shake128(seed_A, SABER_SEEDBYTES, seed_A, SABER_SEEDBYTES); // for not revealing system RNG state | |||
static void InnerProd(uint16_t pkcl[SABER_K][SABER_N], uint16_t skpv[SABER_K][SABER_N], uint16_t mod, uint16_t res[SABER_N]); | |||
static void MatrixVectorMul(polyvec *a, uint16_t skpv[SABER_K][SABER_N], uint16_t res[SABER_K][SABER_N], uint16_t mod, int16_t transpose); | |||
randombytes(rand, SABER_NOISESEEDBYTES); | |||
PQCLEAN_LIGHTSABER_CLEAN_GenSecret(s, rand); | |||
PQCLEAN_LIGHTSABER_CLEAN_POLVECq2BS(sk, s); | |||
static void POL2MSG(const uint16_t *message_dec_unpacked, unsigned char *message_dec); | |||
PQCLEAN_LIGHTSABER_CLEAN_GenMatrix(A, seed_A); // sample matrix A | |||
PQCLEAN_LIGHTSABER_CLEAN_MatrixVectorMul(res, (const poly (*)[SABER_L])A, (const poly *)s, 1); // Matrix in transposed order | |||
static void GenMatrix(polyvec *a, const unsigned char *seed) { | |||
unsigned char buf[SABER_K * SABER_K * (13 * SABER_N / 8)]; | |||
uint16_t temp_ar[SABER_N]; | |||
int i, j, k; | |||
uint16_t mod = (SABER_Q - 1); | |||
shake128(buf, sizeof(buf), seed, SABER_SEEDBYTES); | |||
for (i = 0; i < SABER_K; i++) { | |||
for (j = 0; j < SABER_K; j++) { | |||
PQCLEAN_LIGHTSABER_CLEAN_BS2POL(buf + (i * SABER_K + j) * (13 * SABER_N / 8), temp_ar); | |||
for (k = 0; k < SABER_N; k++) { | |||
a[i].vec[j].coeffs[k] = (temp_ar[k])& mod ; | |||
} | |||
} | |||
} | |||
} | |||
void PQCLEAN_LIGHTSABER_CLEAN_indcpa_kem_keypair(unsigned char *pk, unsigned char *sk) { | |||
polyvec a[SABER_K]; | |||
uint16_t skpv[SABER_K][SABER_N]; | |||
unsigned char seed[SABER_SEEDBYTES]; | |||
unsigned char noiseseed[SABER_COINBYTES]; | |||
int32_t i, j; | |||
uint16_t mod_q = SABER_Q - 1; | |||
uint16_t res[SABER_K][SABER_N]; | |||
randombytes(seed, SABER_SEEDBYTES); | |||
// for not revealing system RNG state | |||
shake128(seed, SABER_SEEDBYTES, seed, SABER_SEEDBYTES); | |||
randombytes(noiseseed, SABER_COINBYTES); | |||
GenMatrix(a, seed); //sample matrix A | |||
// generate secret from constant-time binomial distribution | |||
PQCLEAN_LIGHTSABER_CLEAN_GenSecret(skpv, noiseseed); | |||
// do the matrix vector multiplication and rounding | |||
for (i = 0; i < SABER_K; i++) { | |||
for (j = 0; j < SABER_N; j++) { | |||
res[i][j] = 0; | |||
} | |||
} | |||
MatrixVectorMul(a, skpv, res, SABER_Q - 1, 1); | |||
// now rounding | |||
for (i = 0; i < SABER_K; i++) { | |||
// rounding | |||
for (i = 0; i < SABER_L; i++) { | |||
for (j = 0; j < SABER_N; j++) { | |||
// shift right 3 bits | |||
res[i][j] = (res[i][j] + h1) & (mod_q); | |||
res[i][j] = (res[i][j] >> (SABER_EQ - SABER_EP)); | |||
res[i].coeffs[j] += h1; | |||
res[i].coeffs[j] >>= SABER_EQ - SABER_EP; | |||
res[i].coeffs[j] &= SABER_Q - 1; | |||
} | |||
} | |||
// unload and pack sk=3 x (256 coefficients of 14 bits) | |||
PQCLEAN_LIGHTSABER_CLEAN_POLVEC2BS(sk, skpv, SABER_Q); | |||
// unload and pack pk=256 bits seed and 3 x (256 coefficients of 11 bits) | |||
// load the public-key coefficients | |||
PQCLEAN_LIGHTSABER_CLEAN_POLVEC2BS(pk, res, SABER_P); | |||
// now load the seedbytes in PK. Easy since seed bytes are kept in byte format. | |||
for (i = 0; i < SABER_SEEDBYTES; i++) { | |||
pk[SABER_POLYVECCOMPRESSEDBYTES + i] = seed[i]; | |||
} | |||
PQCLEAN_LIGHTSABER_CLEAN_POLVECp2BS(pk, res); // pack public key | |||
} | |||
void PQCLEAN_LIGHTSABER_CLEAN_indcpa_kem_enc(const unsigned char *message_received, unsigned char *noiseseed, const unsigned char *pk, unsigned char *ciphertext) { | |||
uint32_t i, j, k; | |||
polyvec a[SABER_K]; | |||
unsigned char seed[SABER_SEEDBYTES]; | |||
// public key of received by the client | |||
uint16_t pkcl[SABER_K][SABER_N]; | |||
uint16_t skpv1[SABER_K][SABER_N]; | |||
uint16_t message[SABER_KEYBYTES * 8]; | |||
uint16_t res[SABER_K][SABER_N]; | |||
uint16_t mod_p = SABER_P - 1; | |||
uint16_t mod_q = SABER_Q - 1; | |||
uint16_t vprime[SABER_N]; | |||
unsigned char msk_c[SABER_SCALEBYTES_KEM]; | |||
void PQCLEAN_LIGHTSABER_CLEAN_indcpa_kem_enc(uint8_t ciphertext[SABER_BYTES_CCA_DEC], const uint8_t m[SABER_KEYBYTES], const uint8_t noiseseed[SABER_NOISESEEDBYTES], const uint8_t pk[SABER_INDCPA_PUBLICKEYBYTES]) { | |||
size_t i, j; | |||
// extract the seedbytes from Public Key. | |||
for (i = 0; i < SABER_SEEDBYTES; i++) { | |||
seed[i] = pk[ SABER_POLYVECCOMPRESSEDBYTES + i]; | |||
} | |||
poly A[SABER_L][SABER_L]; | |||
poly res[SABER_L]; | |||
poly s[SABER_L]; | |||
poly *temp = A[0]; // re-use stack space | |||
poly *vprime = &A[0][0]; | |||
poly *message = &A[0][1]; | |||
GenMatrix(a, seed); | |||
const uint8_t *seed_A = pk + SABER_POLYVECCOMPRESSEDBYTES; | |||
uint8_t *msk_c = ciphertext + SABER_POLYVECCOMPRESSEDBYTES; | |||
// generate secret from constant-time binomial distribution | |||
PQCLEAN_LIGHTSABER_CLEAN_GenSecret(skpv1, noiseseed); | |||
PQCLEAN_LIGHTSABER_CLEAN_GenSecret(s, noiseseed); | |||
PQCLEAN_LIGHTSABER_CLEAN_GenMatrix(A, seed_A); | |||
PQCLEAN_LIGHTSABER_CLEAN_MatrixVectorMul(res, (const poly (*)[SABER_L])A, (const poly *)s, 0); // 0 => not transposed | |||
// matrix-vector multiplication and rounding | |||
for (i = 0; i < SABER_K; i++) { | |||
for (j = 0; j < SABER_N; j++) { | |||
res[i][j] = 0; | |||
} | |||
} | |||
MatrixVectorMul(a, skpv1, res, SABER_Q - 1, 0); | |||
// now rounding | |||
//shift right 3 bits | |||
for (i = 0; i < SABER_K; i++) { | |||
for (j = 0; j < SABER_N; j++) { | |||
res[i][j] = ( res[i][j] + h1 ) & mod_q; | |||
res[i][j] = (res[i][j] >> (SABER_EQ - SABER_EP) ); | |||
} | |||
} | |||
PQCLEAN_LIGHTSABER_CLEAN_POLVEC2BS(ciphertext, res, SABER_P); | |||
// ************client matrix-vector multiplication ends************ | |||
// now calculate the v' | |||
// unpack the public_key | |||
// pkcl is the b in the protocol | |||
PQCLEAN_LIGHTSABER_CLEAN_BS2POLVEC(pk, pkcl, SABER_P); | |||
for (i = 0; i < SABER_N; i++) { | |||
vprime[i] = 0; | |||
} | |||
for (i = 0; i < SABER_K; i++) { | |||
// rounding | |||
for (i = 0; i < SABER_L; i++) { //shift right EQ-EP bits | |||
for (j = 0; j < SABER_N; j++) { | |||
skpv1[i][j] = skpv1[i][j] & (mod_p); | |||
res[i].coeffs[j] += h1; | |||
res[i].coeffs[j] >>= SABER_EQ - SABER_EP; | |||
res[i].coeffs[j] &= SABER_Q - 1; | |||
} | |||
} | |||
PQCLEAN_LIGHTSABER_CLEAN_POLVECp2BS(ciphertext, res); | |||
// vector-vector scalar multiplication with mod p | |||
InnerProd(pkcl, skpv1, mod_p, vprime); | |||
PQCLEAN_LIGHTSABER_CLEAN_BS2POLVECp(temp, pk); | |||
PQCLEAN_LIGHTSABER_CLEAN_InnerProd(vprime, temp, s); | |||
PQCLEAN_LIGHTSABER_CLEAN_BS2POLmsg(message, m); | |||
// addition of h1 to vprime | |||
for (i = 0; i < SABER_N; i++) { | |||
vprime[i] = vprime[i] + h1; | |||
vprime->coeffs[i] += h1 - (message->coeffs[i] << (SABER_EP - 1)); | |||
vprime->coeffs[i] &= SABER_P - 1; | |||
vprime->coeffs[i] >>= SABER_EP - SABER_ET; | |||
} | |||
// unpack message_received; | |||
for (j = 0; j < SABER_KEYBYTES; j++) { | |||
for (i = 0; i < 8; i++) { | |||
message[8 * j + i] = ((message_received[j] >> i) & 0x01); | |||
} | |||
} | |||
// message encoding | |||
for (i = 0; i < SABER_N; i++) { | |||
message[i] = (message[i] << (SABER_EP - 1)); | |||
} | |||
for (k = 0; k < SABER_N; k++) { | |||
vprime[k] = ( (vprime[k] - message[k]) & (mod_p) ) >> (SABER_EP - SABER_ET); | |||
} | |||
PQCLEAN_LIGHTSABER_CLEAN_pack_3bit(msk_c, vprime); | |||
for (j = 0; j < SABER_SCALEBYTES_KEM; j++) { | |||
ciphertext[SABER_POLYVECCOMPRESSEDBYTES + j] = msk_c[j]; | |||
} | |||
PQCLEAN_LIGHTSABER_CLEAN_POLT2BS(msk_c, vprime); | |||
} | |||
void PQCLEAN_LIGHTSABER_CLEAN_indcpa_kem_dec(const unsigned char *sk, const unsigned char *ciphertext, unsigned char message_dec[]) { | |||
uint32_t i, j; | |||
// secret key of the server | |||
uint16_t sksv[SABER_K][SABER_N]; | |||
uint16_t pksv[SABER_K][SABER_N]; | |||
uint8_t scale_ar[SABER_SCALEBYTES_KEM]; | |||
uint16_t mod_p = SABER_P - 1; | |||
uint16_t v[SABER_N]; | |||
uint16_t op[SABER_N]; | |||
void PQCLEAN_LIGHTSABER_CLEAN_indcpa_kem_dec(uint8_t m[SABER_KEYBYTES], const uint8_t sk[SABER_INDCPA_SECRETKEYBYTES], const uint8_t ciphertext[SABER_BYTES_CCA_DEC]) { | |||
size_t i; | |||
// sksv is the secret-key | |||
PQCLEAN_LIGHTSABER_CLEAN_BS2POLVEC(sk, sksv, SABER_Q); | |||
// pksv is the ciphertext | |||
PQCLEAN_LIGHTSABER_CLEAN_BS2POLVEC(ciphertext, pksv, SABER_P); | |||
poly temp[SABER_L]; | |||
poly s[SABER_L]; | |||
// vector-vector scalar multiplication with mod p | |||
for (i = 0; i < SABER_N; i++) { | |||
v[i] = 0; | |||
} | |||
for (i = 0; i < SABER_K; i++) { | |||
for (j = 0; j < SABER_N; j++) { | |||
sksv[i][j] = sksv[i][j] & (mod_p); | |||
} | |||
} | |||
InnerProd(pksv, sksv, mod_p, v); | |||
const uint8_t *packed_cm = ciphertext + SABER_POLYVECCOMPRESSEDBYTES; | |||
poly *v = &temp[0]; | |||
poly *cm = &temp[1]; | |||
//Extraction | |||
for (i = 0; i < SABER_SCALEBYTES_KEM; i++) { | |||
scale_ar[i] = ciphertext[SABER_POLYVECCOMPRESSEDBYTES + i]; | |||
} | |||
PQCLEAN_LIGHTSABER_CLEAN_BS2POLVECq(s, sk); | |||
PQCLEAN_LIGHTSABER_CLEAN_BS2POLVECp(temp, ciphertext); | |||
PQCLEAN_LIGHTSABER_CLEAN_InnerProd(&temp[0], temp, s); | |||
PQCLEAN_LIGHTSABER_CLEAN_un_pack3bit(scale_ar, op); | |||
PQCLEAN_LIGHTSABER_CLEAN_BS2POLT(cm, packed_cm); | |||
//addition of h1 | |||
for (i = 0; i < SABER_N; i++) { | |||
v[i] = ( ( v[i] + h2 - (op[i] << (SABER_EP - SABER_ET)) ) & (mod_p) ) >> (SABER_EP - 1); | |||
v->coeffs[i] += h2 - (cm->coeffs[i] << (SABER_EP - SABER_ET)); | |||
v->coeffs[i] &= SABER_P - 1; | |||
v->coeffs[i] >>= SABER_EP - 1; | |||
} | |||
// pack decrypted message | |||
POL2MSG(v, message_dec); | |||
} | |||
static void MatrixVectorMul(polyvec *a, uint16_t skpv[SABER_K][SABER_N], uint16_t res[SABER_K][SABER_N], uint16_t mod, int16_t transpose) { | |||
uint16_t acc[SABER_N]; | |||
int32_t i, j, k; | |||
if (transpose == 1) { | |||
for (i = 0; i < SABER_K; i++) { | |||
for (j = 0; j < SABER_K; j++) { | |||
PQCLEAN_LIGHTSABER_CLEAN_pol_mul((uint16_t *)&a[j].vec[i], skpv[j], acc, SABER_Q, SABER_N); | |||
for (k = 0; k < SABER_N; k++) { | |||
res[i][k] = res[i][k] + acc[k]; | |||
//reduction mod p | |||
res[i][k] = (res[i][k] & mod); | |||
//clear the accumulator | |||
acc[k] = 0; | |||
} | |||
} | |||
} | |||
} else { | |||
for (i = 0; i < SABER_K; i++) { | |||
for (j = 0; j < SABER_K; j++) { | |||
PQCLEAN_LIGHTSABER_CLEAN_pol_mul((uint16_t *)&a[i].vec[j], skpv[j], acc, SABER_Q, SABER_N); | |||
for (k = 0; k < SABER_N; k++) { | |||
res[i][k] = res[i][k] + acc[k]; | |||
// reduction | |||
res[i][k] = res[i][k] & mod; | |||
// clear the accumulator | |||
acc[k] = 0; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
static void POL2MSG(const uint16_t *message_dec_unpacked, unsigned char *message_dec) { | |||
int32_t i, j; | |||
for (j = 0; j < SABER_KEYBYTES; j++) { | |||
message_dec[j] = 0; | |||
for (i = 0; i < 8; i++) { | |||
message_dec[j] = message_dec[j] | (uint8_t) (message_dec_unpacked[j * 8 + i] << i); | |||
} | |||
} | |||
} | |||
static void InnerProd(uint16_t pkcl[SABER_K][SABER_N], uint16_t skpv[SABER_K][SABER_N], uint16_t mod, uint16_t res[SABER_N]) { | |||
uint32_t j, k; | |||
uint16_t acc[SABER_N]; | |||
// vector-vector scalar multiplication with mod p | |||
for (j = 0; j < SABER_K; j++) { | |||
PQCLEAN_LIGHTSABER_CLEAN_pol_mul(pkcl[j], skpv[j], acc, SABER_P, SABER_N); | |||
for (k = 0; k < SABER_N; k++) { | |||
res[k] = res[k] + acc[k]; | |||
// reduction | |||
res[k] = res[k] & mod; | |||
// clear the accumulator | |||
acc[k] = 0; | |||
} | |||
} | |||
PQCLEAN_LIGHTSABER_CLEAN_POLmsg2BS(m, v); | |||
} |
@@ -1,9 +1,13 @@ | |||
#ifndef INDCPA_H | |||
#define INDCPA_H | |||
#include "SABER_params.h" | |||
#include <stdint.h> | |||
void PQCLEAN_LIGHTSABER_CLEAN_indcpa_kem_keypair(unsigned char *pk, unsigned char *sk); | |||
void PQCLEAN_LIGHTSABER_CLEAN_indcpa_kem_enc(const unsigned char *message, unsigned char *noiseseed, const unsigned char *pk, unsigned char *ciphertext); | |||
void PQCLEAN_LIGHTSABER_CLEAN_indcpa_kem_dec(const unsigned char *sk, const unsigned char *ciphertext, unsigned char *message_dec); | |||
void PQCLEAN_LIGHTSABER_CLEAN_indcpa_kem_keypair(uint8_t pk[SABER_INDCPA_PUBLICKEYBYTES], uint8_t sk[SABER_INDCPA_SECRETKEYBYTES]); | |||
#endif | |||
void PQCLEAN_LIGHTSABER_CLEAN_indcpa_kem_enc(uint8_t ciphertext[SABER_BYTES_CCA_DEC], const uint8_t m[SABER_KEYBYTES], const uint8_t noiseseed[SABER_NOISESEEDBYTES], const uint8_t pk[SABER_INDCPA_PUBLICKEYBYTES]); | |||
void PQCLEAN_LIGHTSABER_CLEAN_indcpa_kem_dec(uint8_t m[SABER_KEYBYTES], const uint8_t sk[SABER_INDCPA_SECRETKEYBYTES], const uint8_t ciphertext[SABER_BYTES_CCA_DEC]); | |||
#endif |
@@ -1,50 +1,41 @@ | |||
#ifndef PARAMS_H | |||
#define PARAMS_H | |||
#include "api.h" | |||
#define SABER_K 2 | |||
/* Don't change anything below this line */ | |||
#define SABER_L 2 | |||
#define SABER_MU 10 | |||
#define SABER_ET 3 | |||
#define SABER_EQ 13 | |||
#define SABER_EP 10 | |||
#define SABER_N 256 | |||
#define SABER_Q 8192 | |||
#define SABER_P 1024 | |||
#define SABER_SEEDBYTES 32 | |||
#define SABER_NOISESEEDBYTES 32 | |||
#define SABER_COINBYTES 32 | |||
#define SABER_KEYBYTES 32 | |||
#define SABER_HASHBYTES 32 | |||
#define SABER_EP 10 | |||
#define SABER_P (1 << SABER_EP) | |||
#define SABER_POLYBYTES 416 //13*256/8 | |||
#define SABER_EQ 13 | |||
#define SABER_Q (1 << SABER_EQ) | |||
#define SABER_POLYVECBYTES (SABER_K * SABER_POLYBYTES) | |||
#define SABER_SEEDBYTES 32 | |||
#define SABER_NOISESEEDBYTES 32 | |||
#define SABER_KEYBYTES 32 | |||
#define SABER_HASHBYTES 32 | |||
#define SABER_POLYVECCOMPRESSEDBYTES (SABER_K * 320) //10*256/8 NOTE : changed till here due to parameter adaptation | |||
#define SABER_POLYCOINBYTES (SABER_MU * SABER_N / 8) | |||
#define SABER_CIPHERTEXTBYTES (SABER_POLYVECCOMPRESSEDBYTES) | |||
#define SABER_POLYBYTES (SABER_EQ * SABER_N / 8) | |||
#define SABER_POLYVECBYTES (SABER_L * SABER_POLYBYTES) | |||
#define SABER_SCALEBYTES (SABER_DELTA*SABER_N/8) | |||
#define SABER_POLYCOMPRESSEDBYTES (SABER_EP * SABER_N / 8) | |||
#define SABER_POLYVECCOMPRESSEDBYTES (SABER_L * SABER_POLYCOMPRESSEDBYTES) | |||
#define SABER_SCALEBYTES_KEM ((SABER_ET)*SABER_N/8) | |||
#define SABER_SCALEBYTES_KEM (SABER_ET * SABER_N / 8) | |||
#define SABER_INDCPA_PUBLICKEYBYTES (SABER_POLYVECCOMPRESSEDBYTES + SABER_SEEDBYTES) | |||
#define SABER_INDCPA_SECRETKEYBYTES (SABER_POLYVECBYTES) | |||
#define SABER_PUBLICKEYBYTES (SABER_INDCPA_PUBLICKEYBYTES) | |||
#define SABER_SECRETKEYBYTES (SABER_INDCPA_SECRETKEYBYTES + SABER_INDCPA_PUBLICKEYBYTES + SABER_HASHBYTES + SABER_KEYBYTES) | |||
#define SABER_SECRETKEYBYTES (SABER_INDCPA_SECRETKEYBYTES + SABER_INDCPA_PUBLICKEYBYTES + SABER_HASHBYTES + SABER_KEYBYTES) | |||
#define SABER_BYTES_CCA_DEC (SABER_POLYVECCOMPRESSEDBYTES + SABER_SCALEBYTES_KEM) /* Second part is for Targhi-Unruh */ | |||
#define SABER_BYTES_CCA_DEC (SABER_POLYVECCOMPRESSEDBYTES + SABER_SCALEBYTES_KEM) | |||
#endif | |||
@@ -1,14 +1,18 @@ | |||
#ifndef PQCLEAN_LIGHTSABER_CLEAN_API_H | |||
#define PQCLEAN_LIGHTSABER_CLEAN_API_H | |||
#define PQCLEAN_LIGHTSABER_CLEAN_CRYPTO_ALGNAME "LightSaber" | |||
#define PQCLEAN_LIGHTSABER_CLEAN_CRYPTO_SECRETKEYBYTES 1568 | |||
#define PQCLEAN_LIGHTSABER_CLEAN_CRYPTO_PUBLICKEYBYTES (2*320+32) | |||
#define PQCLEAN_LIGHTSABER_CLEAN_CRYPTO_BYTES 32 | |||
#define PQCLEAN_LIGHTSABER_CLEAN_CRYPTO_CIPHERTEXTBYTES 736 | |||
#define PQCLEAN_LIGHTSABER_CLEAN_CRYPTO_PUBLICKEYBYTES 672 | |||
#define PQCLEAN_LIGHTSABER_CLEAN_CRYPTO_SECRETKEYBYTES 1568 | |||
int PQCLEAN_LIGHTSABER_CLEAN_crypto_kem_keypair(unsigned char *pk, unsigned char *sk); | |||
int PQCLEAN_LIGHTSABER_CLEAN_crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk); | |||
int PQCLEAN_LIGHTSABER_CLEAN_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk); | |||
#endif /* api_h */ | |||
int PQCLEAN_LIGHTSABER_CLEAN_crypto_kem_enc(unsigned char *ct, unsigned char *k, const unsigned char *pk); | |||
int PQCLEAN_LIGHTSABER_CLEAN_crypto_kem_dec(unsigned char *k, const unsigned char *ct, const unsigned char *sk); | |||
#endif /* PQCLEAN_LIGHTSABER_CLEAN_API_H */ |
@@ -1,3 +1,7 @@ | |||
#include "SABER_params.h" | |||
#include "api.h" | |||
#include "cbd.h" | |||
#include <stdint.h> | |||
/*--------------------------------------------------------------------- | |||
This file has been adapted from the implementation | |||
(available at, Public Domain https://github.com/pq-crystals/kyber) | |||
@@ -6,12 +10,8 @@ by : Joppe Bos, Leo Ducas, Eike Kiltz, Tancrede Lepoint, | |||
Vadim Lyubashevsky, John M. Schanck, Peter Schwabe & Damien stehle | |||
----------------------------------------------------------------------*/ | |||
#include "SABER_params.h" | |||
#include "api.h" | |||
#include "cbd.h" | |||
#include <stdint.h> | |||
static uint64_t load_littleendian(const unsigned char *x, int bytes) { | |||
static uint64_t load_littleendian(const uint8_t *x, int bytes) { | |||
int i; | |||
uint64_t r = x[0]; | |||
for (i = 1; i < bytes; i++) { | |||
@@ -20,10 +20,7 @@ static uint64_t load_littleendian(const unsigned char *x, int bytes) { | |||
return r; | |||
} | |||
void PQCLEAN_LIGHTSABER_CLEAN_cbd(uint16_t *r, const unsigned char *buf) { | |||
uint16_t Qmod_minus1 = SABER_Q - 1; | |||
void PQCLEAN_LIGHTSABER_CLEAN_cbd(uint16_t s[SABER_N], const uint8_t buf[SABER_POLYCOINBYTES]) { | |||
uint64_t t, d, a[4], b[4]; | |||
int i, j; | |||
@@ -34,8 +31,8 @@ void PQCLEAN_LIGHTSABER_CLEAN_cbd(uint16_t *r, const unsigned char *buf) { | |||
d += (t >> j) & 0x0842108421UL; | |||
} | |||
a[0] = d & 0x1f; | |||
b[0] = (d >> 5) & 0x1f; | |||
a[0] = d & 0x1f; | |||
b[0] = (d >> 5) & 0x1f; | |||
a[1] = (d >> 10) & 0x1f; | |||
b[1] = (d >> 15) & 0x1f; | |||
a[2] = (d >> 20) & 0x1f; | |||
@@ -43,9 +40,9 @@ void PQCLEAN_LIGHTSABER_CLEAN_cbd(uint16_t *r, const unsigned char *buf) { | |||
a[3] = (d >> 30) & 0x1f; | |||
b[3] = (d >> 35); | |||
r[4 * i + 0] = (uint16_t)(a[0] - b[0]) & Qmod_minus1; | |||
r[4 * i + 1] = (uint16_t)(a[1] - b[1]) & Qmod_minus1; | |||
r[4 * i + 2] = (uint16_t)(a[2] - b[2]) & Qmod_minus1; | |||
r[4 * i + 3] = (uint16_t)(a[3] - b[3]) & Qmod_minus1; | |||
s[4 * i + 0] = (uint16_t)(a[0] - b[0]); | |||
s[4 * i + 1] = (uint16_t)(a[1] - b[1]); | |||
s[4 * i + 2] = (uint16_t)(a[2] - b[2]); | |||
s[4 * i + 3] = (uint16_t)(a[3] - b[3]); | |||
} | |||
} |
@@ -1,6 +1,5 @@ | |||
#ifndef CBD_H | |||
#define CBD_H | |||
/*--------------------------------------------------------------------- | |||
This file has been adapted from the implementation | |||
(available at, Public Domain https://github.com/pq-crystals/kyber) | |||
@@ -8,10 +7,10 @@ of "CRYSTALS – Kyber: a CCA-secure module-lattice-based KEM" | |||
by : Joppe Bos, Leo Ducas, Eike Kiltz, Tancrede Lepoint, | |||
Vadim Lyubashevsky, John M. Schanck, Peter Schwabe & Damien stehle | |||
----------------------------------------------------------------------*/ | |||
#include "poly.h" | |||
#include "SABER_params.h" | |||
#include <stdint.h> | |||
void PQCLEAN_LIGHTSABER_CLEAN_cbd(uint16_t *r, const unsigned char *buf); | |||
void PQCLEAN_LIGHTSABER_CLEAN_cbd(uint16_t s[SABER_N], const uint8_t buf[SABER_POLYCOINBYTES]); | |||
#endif |
@@ -1,96 +1,77 @@ | |||
#include "SABER_indcpa.h" | |||
#include "SABER_params.h" | |||
#include "api.h" | |||
#include "fips202.h" | |||
#include "randombytes.h" | |||
#include "verify.h" | |||
#include <stddef.h> | |||
#include <stdint.h> | |||
#include <stdio.h> | |||
#include <string.h> | |||
int PQCLEAN_LIGHTSABER_CLEAN_crypto_kem_keypair(unsigned char *pk, unsigned char *sk) { | |||
int i; | |||
// sk[0:SABER_INDCPA_SECRETKEYBYTES-1] <-- sk | |||
PQCLEAN_LIGHTSABER_CLEAN_indcpa_kem_keypair(pk, sk); | |||
int PQCLEAN_LIGHTSABER_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk) { | |||
size_t i; | |||
// sk[SABER_INDCPA_SECRETKEYBYTES:SABER_INDCPA_SECRETKEYBYTES+SABER_INDCPA_SECRETKEYBYTES-1] <-- pk | |||
PQCLEAN_LIGHTSABER_CLEAN_indcpa_kem_keypair(pk, sk); // sk[0:SABER_INDCPA_SECRETKEYBYTES-1] <-- sk | |||
for (i = 0; i < SABER_INDCPA_PUBLICKEYBYTES; i++) { | |||
sk[i + SABER_INDCPA_SECRETKEYBYTES] = pk[i]; | |||
sk[i + SABER_INDCPA_SECRETKEYBYTES] = pk[i]; // sk[SABER_INDCPA_SECRETKEYBYTES:SABER_INDCPA_SECRETKEYBYTES+SABER_INDCPA_SECRETKEYBYTES-1] <-- pk | |||
} | |||
// Then hash(pk) is appended. | |||
sha3_256(sk + SABER_SECRETKEYBYTES - 64, pk, SABER_INDCPA_PUBLICKEYBYTES); | |||
sha3_256(sk + SABER_SECRETKEYBYTES - 64, pk, SABER_INDCPA_PUBLICKEYBYTES); // Then hash(pk) is appended. | |||
// Remaining part of sk contains a pseudo-random number. | |||
// This is output when check in crypto_kem_dec() fails. | |||
randombytes(sk + SABER_SECRETKEYBYTES - SABER_KEYBYTES, SABER_KEYBYTES ); | |||
randombytes(sk + SABER_SECRETKEYBYTES - SABER_KEYBYTES, SABER_KEYBYTES); // Remaining part of sk contains a pseudo-random number. | |||
// This is output when check in PQCLEAN_LIGHTSABER_CLEAN_crypto_kem_dec() fails. | |||
return (0); | |||
} | |||
int PQCLEAN_LIGHTSABER_CLEAN_crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk) { | |||
// Will contain key, coins | |||
unsigned char kr[64]; | |||
unsigned char buf[64]; | |||
int PQCLEAN_LIGHTSABER_CLEAN_crypto_kem_enc(uint8_t *c, uint8_t *k, const uint8_t *pk) { | |||
randombytes(buf, 32); | |||
uint8_t kr[64]; // Will contain key, coins | |||
uint8_t buf[64]; | |||
// BUF[0:31] <-- random message (will be used as the key for client) Note: hash doesnot release system RNG output | |||
sha3_256(buf, buf, 32); | |||
randombytes(buf, 32); | |||
// BUF[32:63] <-- Hash(public key); Multitarget countermeasure for coins + contributory KEM | |||
sha3_256(buf + 32, pk, SABER_INDCPA_PUBLICKEYBYTES); | |||
sha3_256(buf, buf, 32); // BUF[0:31] <-- random message (will be used as the key for client) Note: hash doesnot release system RNG output | |||
// kr[0:63] <-- Hash(buf[0:63]); | |||
sha3_512(kr, buf, 64); | |||
sha3_256(buf + 32, pk, SABER_INDCPA_PUBLICKEYBYTES); // BUF[32:63] <-- Hash(public key); Multitarget countermeasure for coins + contributory KEM | |||
sha3_512(kr, buf, 64); // kr[0:63] <-- Hash(buf[0:63]); | |||
// K^ <-- kr[0:31] | |||
// noiseseed (r) <-- kr[32:63]; | |||
// buf[0:31] contains message; kr[32:63] contains randomness r; | |||
PQCLEAN_LIGHTSABER_CLEAN_indcpa_kem_enc(buf, kr + 32, pk, ct); | |||
PQCLEAN_LIGHTSABER_CLEAN_indcpa_kem_enc(c, buf, kr + 32, pk); // buf[0:31] contains message; kr[32:63] contains randomness r; | |||
sha3_256(kr + 32, ct, SABER_BYTES_CCA_DEC); | |||
sha3_256(kr + 32, c, SABER_BYTES_CCA_DEC); | |||
// hash concatenation of pre-k and h(c) to k | |||
sha3_256(ss, kr, 64); | |||
sha3_256(k, kr, 64); // hash concatenation of pre-k and h(c) to k | |||
return (0); | |||
} | |||
int PQCLEAN_LIGHTSABER_CLEAN_crypto_kem_dec(uint8_t *k, const uint8_t *c, const uint8_t *sk) { | |||
size_t i; | |||
uint8_t fail; | |||
uint8_t cmp[SABER_BYTES_CCA_DEC]; | |||
uint8_t buf[64]; | |||
uint8_t kr[64]; // Will contain key, coins | |||
const uint8_t *pk = sk + SABER_INDCPA_SECRETKEYBYTES; | |||
int PQCLEAN_LIGHTSABER_CLEAN_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk) { | |||
int i; | |||
unsigned char fail; | |||
unsigned char cmp[SABER_BYTES_CCA_DEC]; | |||
unsigned char buf[64]; | |||
// Will contain key, coins | |||
unsigned char kr[64]; | |||
const unsigned char *pk = sk + SABER_INDCPA_SECRETKEYBYTES; | |||
// buf[0:31] <-- message | |||
PQCLEAN_LIGHTSABER_CLEAN_indcpa_kem_dec(sk, ct, buf); | |||
PQCLEAN_LIGHTSABER_CLEAN_indcpa_kem_dec(buf, sk, c); // buf[0:31] <-- message | |||
// Multitarget countermeasure for coins + contributory KEM | |||
// Save hash by storing h(pk) in sk | |||
for (i = 0; i < 32; i++) { | |||
for (i = 0; i < 32; i++) { // Save hash by storing h(pk) in sk | |||
buf[32 + i] = sk[SABER_SECRETKEYBYTES - 64 + i]; | |||
} | |||
sha3_512(kr, buf, 64); | |||
PQCLEAN_LIGHTSABER_CLEAN_indcpa_kem_enc(buf, kr + 32, pk, cmp); | |||
PQCLEAN_LIGHTSABER_CLEAN_indcpa_kem_enc(cmp, buf, kr + 32, pk); | |||
fail = PQCLEAN_LIGHTSABER_CLEAN_verify(ct, cmp, SABER_BYTES_CCA_DEC); | |||
fail = PQCLEAN_LIGHTSABER_CLEAN_verify(c, cmp, SABER_BYTES_CCA_DEC); | |||
// overwrite coins in kr with h(c) | |||
sha3_256(kr + 32, ct, SABER_BYTES_CCA_DEC); | |||
sha3_256(kr + 32, c, SABER_BYTES_CCA_DEC); // overwrite coins in kr with h(c) | |||
PQCLEAN_LIGHTSABER_CLEAN_cmov(kr, sk + SABER_SECRETKEYBYTES - SABER_KEYBYTES, SABER_KEYBYTES, fail); | |||
// hash concatenation of pre-k and h(c) to k | |||
sha3_256(ss, kr, 64); | |||
sha3_256(k, kr, 64); // hash concatenation of pre-k and h(c) to k | |||
return (0); | |||
} |
@@ -1,254 +1,155 @@ | |||
#include "SABER_params.h" | |||
#include "pack_unpack.h" | |||
#include "poly.h" | |||
#include <string.h> | |||
void PQCLEAN_LIGHTSABER_CLEAN_pack_3bit(uint8_t *bytes, const uint16_t *data) { | |||
uint32_t j; | |||
uint32_t offset_data, offset_byte; | |||
void PQCLEAN_LIGHTSABER_CLEAN_POLT2BS(uint8_t bytes[SABER_SCALEBYTES_KEM], const poly *data) { | |||
size_t j; | |||
const uint16_t *in = data->coeffs; | |||
uint8_t *out = bytes; | |||
for (j = 0; j < SABER_N / 8; j++) { | |||
offset_byte = 3 * j; | |||
offset_data = 8 * j; | |||
bytes[offset_byte + 0] = (data[offset_data + 0] & 0x7) | | |||
((data[offset_data + 1] & 0x7) << 3) | | |||
((data[offset_data + 2] & 0x3) << 6); | |||
bytes[offset_byte + 1] = ((data[offset_data + 2] >> 2 ) & 0x01) | | |||
((data[offset_data + 3] & 0x7) << 1) | | |||
((data[offset_data + 4] & 0x7) << 4) | | |||
(((data[offset_data + 5]) & 0x01) << 7); | |||
bytes[offset_byte + 2] = ((data[offset_data + 5] >> 1 ) & 0x03) | | |||
((data[offset_data + 6] & 0x7) << 2) | | |||
((data[offset_data + 7] & 0x7) << 5); | |||
out[0] = (uint8_t) ((in[0] & 0x7) | ((in[1] & 0x7) << 3) | (in[2] << 6)); | |||
out[1] = (uint8_t) (((in[2] >> 2) & 0x01) | ((in[3] & 0x7) << 1) | ((in[4] & 0x7) << 4) | (in[5] << 7)); | |||
out[2] = (uint8_t) (((in[5] >> 1) & 0x03) | ((in[6] & 0x7) << 2) | (in[7] << 5)); | |||
in += 8; | |||
out += 3; | |||
} | |||
} | |||
void PQCLEAN_LIGHTSABER_CLEAN_un_pack3bit(const uint8_t *bytes, uint16_t *data) { | |||
uint32_t j; | |||
uint32_t offset_data, offset_byte; | |||
void PQCLEAN_LIGHTSABER_CLEAN_BS2POLT(poly *data, const uint8_t bytes[SABER_SCALEBYTES_KEM]) { | |||
/* This function does not reduce its output mod T */ | |||
size_t j; | |||
const uint8_t *in = bytes; | |||
uint16_t *out = data->coeffs; | |||
for (j = 0; j < SABER_N / 8; j++) { | |||
offset_byte = 3 * j; | |||
offset_data = 8 * j; | |||
data[offset_data + 0] = (bytes[offset_byte + 0]) & 0x07; | |||
data[offset_data + 1] = ((bytes[offset_byte + 0]) >> 3 ) & 0x07; | |||
data[offset_data + 2] = (((bytes[offset_byte + 0]) >> 6 ) & 0x03) | | |||
(((bytes[offset_byte + 1]) & 0x01) << 2); | |||
data[offset_data + 3] = ((bytes[offset_byte + 1]) >> 1 ) & 0x07; | |||
data[offset_data + 4] = ((bytes[offset_byte + 1]) >> 4 ) & 0x07; | |||
data[offset_data + 5] = (((bytes[offset_byte + 1]) >> 7 ) & 0x01) | | |||
(((bytes[offset_byte + 2]) & 0x03) << 1); | |||
data[offset_data + 6] = ((bytes[offset_byte + 2] >> 2) & 0x07); | |||
data[offset_data + 7] = ((bytes[offset_byte + 2] >> 5) & 0x07); | |||
out[0] = in[0]; | |||
out[1] = in[0] >> 3; | |||
out[2] = (in[0] >> 6) | (in[1] << 2); | |||
out[3] = in[1] >> 1; | |||
out[4] = in[1] >> 4; | |||
out[5] = (in[1] >> 7) | (in[2] << 1); | |||
out[6] = in[2] >> 2; | |||
out[7] = in[2] >> 5; | |||
in += 3; | |||
out += 8; | |||
} | |||
} | |||
void PQCLEAN_LIGHTSABER_CLEAN_pack_4bit(uint8_t *bytes, const uint16_t *data) { | |||
uint32_t j; | |||
uint32_t offset_data; | |||
for (j = 0; j < SABER_N / 2; j++) { | |||
offset_data = 2 * j; | |||
bytes[j] = (data[offset_data] & 0x0f) | | |||
((data[offset_data + 1] & 0x0f) << 4); | |||
static void POLq2BS(uint8_t bytes[SABER_POLYBYTES], const poly *data) { | |||
size_t j; | |||
const uint16_t *in = data->coeffs; | |||
uint8_t *out = bytes; | |||
for (j = 0; j < SABER_N / 8; j++) { | |||
out[0] = (uint8_t) (in[0]); | |||
out[1] = (uint8_t) (((in[0] >> 8) & 0x1f) | (in[1] << 5)); | |||
out[2] = (uint8_t) (in[1] >> 3); | |||
out[3] = (uint8_t) (((in[1] >> 11) & 0x03) | (in[2] << 2)); | |||
out[4] = (uint8_t) (((in[2] >> 6) & 0x7f) | (in[3] << 7)); | |||
out[5] = (uint8_t) (in[3] >> 1); | |||
out[6] = (uint8_t) (((in[3] >> 9) & 0x0f) | (in[4] << 4)); | |||
out[7] = (uint8_t) (in[4] >> 4); | |||
out[8] = (uint8_t) (((in[4] >> 12) & 0x01) | (in[5] << 1)); | |||
out[9] = (uint8_t) (((in[5] >> 7) & 0x3f) | (in[6] << 6)); | |||
out[10] = (uint8_t) (in[6] >> 2); | |||
out[11] = (uint8_t) (((in[6] >> 10) & 0x07) | (in[7] << 3)); | |||
out[12] = (uint8_t) (in[7] >> 5); | |||
in += 8; | |||
out += 13; | |||
} | |||
} | |||
void PQCLEAN_LIGHTSABER_CLEAN_un_pack4bit(const unsigned char *bytes, uint16_t *ar) { | |||
uint32_t j; | |||
uint32_t offset_data; | |||
for (j = 0; j < SABER_N / 2; j++) { | |||
offset_data = 2 * j; | |||
ar[offset_data] = bytes[j] & 0x0f; | |||
ar[offset_data + 1] = (bytes[j] >> 4) & 0x0f; | |||
static void BS2POLq(poly *data, const uint8_t bytes[SABER_POLYBYTES]) { | |||
/* This function does not reduce its output mod Q */ | |||
size_t j; | |||
const uint8_t *in = bytes; | |||
uint16_t *out = data->coeffs; | |||
for (j = 0; j < SABER_N / 8; j++) { | |||
out[0] = (in[0]) | (in[1] << 8); | |||
out[1] = (in[1] >> 5) | (in[2] << 3) | (in[3] << 11); | |||
out[2] = (in[3] >> 2) | (in[4] << 6); | |||
out[3] = (in[4] >> 7) | (in[5] << 1) | (in[6] << 9); | |||
out[4] = (in[6] >> 4) | (in[7] << 4) | (in[8] << 12); | |||
out[5] = (in[8] >> 1) | (in[9] << 7); | |||
out[6] = (in[9] >> 6) | (in[10] << 2) | (in[11] << 10); | |||
out[7] = (in[11] >> 3) | (in[12] << 5); | |||
in += 13; | |||
out += 8; | |||
} | |||
} | |||
void PQCLEAN_LIGHTSABER_CLEAN_pack_6bit(uint8_t *bytes, const uint16_t *data) { | |||
uint32_t j; | |||
uint32_t offset_data, offset_byte; | |||
static void POLp2BS(uint8_t bytes[SABER_POLYCOMPRESSEDBYTES], const poly *data) { | |||
size_t j; | |||
const uint16_t *in = data->coeffs; | |||
uint8_t *out = bytes; | |||
for (j = 0; j < SABER_N / 4; j++) { | |||
offset_byte = 3 * j; | |||
offset_data = 4 * j; | |||
bytes[offset_byte + 0] = (data[offset_data + 0] & 0x3f) | | |||
((data[offset_data + 1] & 0x03) << 6); | |||
bytes[offset_byte + 1] = ((data[offset_data + 1] >> 2) & 0x0f) | | |||
((data[offset_data + 2] & 0x0f) << 4); | |||
bytes[offset_byte + 2] = ((data[offset_data + 2] >> 4) & 0x03) | | |||
((data[offset_data + 3] & 0x3f) << 2); | |||
out[0] = (uint8_t) (in[0]); | |||
out[1] = (uint8_t) (((in[0] >> 8) & 0x03) | (in[1] << 2)); | |||
out[2] = (uint8_t) (((in[1] >> 6) & 0x0f) | (in[2] << 4)); | |||
out[3] = (uint8_t) (((in[2] >> 4) & 0x3f) | (in[3] << 6)); | |||
out[4] = (uint8_t) (in[3] >> 2); | |||
in += 4; | |||
out += 5; | |||
} | |||
} | |||
void PQCLEAN_LIGHTSABER_CLEAN_un_pack6bit(const unsigned char *bytes, uint16_t *data) { | |||
uint32_t j; | |||
uint32_t offset_data, offset_byte; | |||
static void BS2POLp(poly *data, const uint8_t bytes[SABER_POLYCOMPRESSEDBYTES]) { | |||
size_t j; | |||
const uint8_t *in = bytes; | |||
uint16_t *out = data->coeffs; | |||
for (j = 0; j < SABER_N / 4; j++) { | |||
offset_byte = 3 * j; | |||
offset_data = 4 * j; | |||
data[offset_data + 0] = bytes[offset_byte + 0] & 0x3f; | |||
data[offset_data + 1] = ((bytes[offset_byte + 0] >> 6) & 0x03) | | |||
((bytes[offset_byte + 1] & 0x0f) << 2); | |||
data[offset_data + 2] = ((bytes[offset_byte + 1] & 0xff) >> 4) | | |||
((bytes[offset_byte + 2] & 0x03) << 4); | |||
data[offset_data + 3] = ((bytes[offset_byte + 2] & 0xff) >> 2); | |||
out[0] = in[0] | (in[1] << 8); | |||
out[1] = (in[1] >> 2) | (in[2] << 6); | |||
out[2] = (in[2] >> 4) | (in[3] << 4); | |||
out[3] = (in[3] >> 6) | (in[4] << 2); | |||
in += 5; | |||
out += 4; | |||
} | |||
} | |||
static void POLVECp2BS(uint8_t *bytes, uint16_t data[SABER_K][SABER_N]) { | |||
uint32_t i, j; | |||
uint32_t offset_data, offset_byte, offset_byte1; | |||
for (i = 0; i < SABER_K; i++) { | |||
offset_byte1 = i * (SABER_N * 10) / 8; | |||
for (j = 0; j < SABER_N / 4; j++) { | |||
offset_byte = offset_byte1 + 5 * j; | |||
offset_data = 4 * j; | |||
bytes[offset_byte + 0] = (data[i][offset_data + 0] & (0xff)); | |||
bytes[offset_byte + 1] = ((data[i][offset_data + 0] >> 8) & 0x03) | | |||
((data[i][offset_data + 1] & 0x3f) << 2); | |||
bytes[offset_byte + 2] = ((data[i][offset_data + 1] >> 6) & 0x0f) | | |||
((data[i][offset_data + 2] & 0x0f) << 4); | |||
bytes[offset_byte + 3] = ((data[i][offset_data + 2] >> 4) & 0x3f) | | |||
((data[i][offset_data + 3] & 0x03) << 6); | |||
bytes[offset_byte + 4] = ((data[i][offset_data + 3] >> 2) & 0xff); | |||
} | |||
void PQCLEAN_LIGHTSABER_CLEAN_POLVECq2BS(uint8_t bytes[SABER_POLYVECBYTES], const poly data[SABER_L]) { | |||
size_t i; | |||
for (i = 0; i < SABER_L; i++) { | |||
POLq2BS(bytes + i * SABER_POLYBYTES, &data[i]); | |||
} | |||
} | |||
static void BS2POLVECp(const unsigned char *bytes, uint16_t data[SABER_K][SABER_N]) { | |||
uint32_t i, j; | |||
uint32_t offset_data, offset_byte, offset_byte1; | |||
for (i = 0; i < SABER_K; i++) { | |||
offset_byte1 = i * (SABER_N * 10) / 8; | |||
for (j = 0; j < SABER_N / 4; j++) { | |||
offset_byte = offset_byte1 + 5 * j; | |||
offset_data = 4 * j; | |||
data[i][offset_data + 0] = (bytes[offset_byte + 0] & (0xff)) | | |||
((bytes[offset_byte + 1] & 0x03) << 8); | |||
data[i][offset_data + 1] = ((bytes[offset_byte + 1] >> 2) & (0x3f)) | | |||
((bytes[offset_byte + 2] & 0x0f) << 6); | |||
data[i][offset_data + 2] = ((bytes[offset_byte + 2] >> 4) & (0x0f)) | | |||
((bytes[offset_byte + 3] & 0x3f) << 4); | |||
data[i][offset_data + 3] = ((bytes[offset_byte + 3] >> 6) & (0x03)) | | |||
((bytes[offset_byte + 4] & 0xff) << 2); | |||
} | |||
void PQCLEAN_LIGHTSABER_CLEAN_BS2POLVECq(poly data[SABER_L], const uint8_t bytes[SABER_POLYVECBYTES]) { | |||
size_t i; | |||
for (i = 0; i < SABER_L; i++) { | |||
BS2POLq(&data[i], bytes + i * SABER_POLYBYTES); | |||
} | |||
} | |||
static void POLVECq2BS(uint8_t *bytes, uint16_t data[SABER_K][SABER_N]) { | |||
uint32_t i, j; | |||
uint32_t offset_data, offset_byte, offset_byte1; | |||
for (i = 0; i < SABER_K; i++) { | |||
offset_byte1 = i * (SABER_N * 13) / 8; | |||
for (j = 0; j < SABER_N / 8; j++) { | |||
offset_byte = offset_byte1 + 13 * j; | |||
offset_data = 8 * j; | |||
bytes[offset_byte + 0] = (data[i][offset_data + 0] & (0xff)); | |||
bytes[offset_byte + 1] = ((data[i][offset_data + 0] >> 8) & 0x1f) | | |||
((data[i][offset_data + 1] & 0x07) << 5); | |||
bytes[offset_byte + 2] = ((data[i][offset_data + 1] >> 3) & 0xff); | |||
bytes[offset_byte + 3] = ((data[i][offset_data + 1] >> 11) & 0x03) | | |||
((data[i][offset_data + 2] & 0x3f) << 2); | |||
bytes[offset_byte + 4] = ((data[i][offset_data + 2] >> 6) & 0x7f) | | |||
((data[i][offset_data + 3] & 0x01) << 7); | |||
bytes[offset_byte + 5] = ((data[i][offset_data + 3] >> 1) & 0xff); | |||
bytes[offset_byte + 6] = ((data[i][offset_data + 3] >> 9) & 0x0f) | | |||
((data[i][offset_data + 4] & 0x0f) << 4); | |||
bytes[offset_byte + 7] = ((data[i][offset_data + 4] >> 4) & 0xff); | |||
bytes[offset_byte + 8] = ((data[i][offset_data + 4] >> 12) & 0x01) | | |||
((data[i][offset_data + 5] & 0x7f) << 1); | |||
bytes[offset_byte + 9] = ((data[i][offset_data + 5] >> 7) & 0x3f) | | |||
((data[i][offset_data + 6] & 0x03) << 6); | |||
bytes[offset_byte + 10] = ((data[i][offset_data + 6] >> 2) & 0xff); | |||
bytes[offset_byte + 11] = ((data[i][offset_data + 6] >> 10) & 0x07) | | |||
((data[i][offset_data + 7] & 0x1f) << 3); | |||
bytes[offset_byte + 12] = ((data[i][offset_data + 7] >> 5) & 0xff); | |||
} | |||
void PQCLEAN_LIGHTSABER_CLEAN_POLVECp2BS(uint8_t bytes[SABER_POLYVECCOMPRESSEDBYTES], const poly data[SABER_L]) { | |||
size_t i; | |||
for (i = 0; i < SABER_L; i++) { | |||
POLp2BS(bytes + i * SABER_POLYCOMPRESSEDBYTES, &data[i]); | |||
} | |||
} | |||
static void BS2POLVECq(const unsigned char *bytes, uint16_t data[SABER_K][SABER_N]) { | |||
uint32_t i, j; | |||
uint32_t offset_data, offset_byte, offset_byte1; | |||
for (i = 0; i < SABER_K; i++) { | |||
offset_byte1 = i * (SABER_N * 13) / 8; | |||
for (j = 0; j < SABER_N / 8; j++) { | |||
offset_byte = offset_byte1 + 13 * j; | |||
offset_data = 8 * j; | |||
data[i][offset_data + 0] = (bytes[offset_byte + 0] & (0xff)) | | |||
((bytes[offset_byte + 1] & 0x1f) << 8); | |||
data[i][offset_data + 1] = (bytes[offset_byte + 1] >> 5 & (0x07)) | | |||
((bytes[offset_byte + 2] & 0xff) << 3) | | |||
((bytes[offset_byte + 3] & 0x03) << 11); | |||
data[i][offset_data + 2] = (bytes[offset_byte + 3] >> 2 & (0x3f)) | | |||
((bytes[offset_byte + 4] & 0x7f) << 6); | |||
data[i][offset_data + 3] = (bytes[offset_byte + 4] >> 7 & (0x01)) | | |||
((bytes[offset_byte + 5] & 0xff) << 1) | | |||
((bytes[offset_byte + 6] & 0x0f) << 9); | |||
data[i][offset_data + 4] = (bytes[offset_byte + 6] >> 4 & (0x0f)) | | |||
((bytes[offset_byte + 7] & 0xff) << 4) | | |||
((bytes[offset_byte + 8] & 0x01) << 12); | |||
data[i][offset_data + 5] = (bytes[offset_byte + 8] >> 1 & (0x7f)) | | |||
((bytes[offset_byte + 9] & 0x3f) << 7); | |||
data[i][offset_data + 6] = (bytes[offset_byte + 9] >> 6 & (0x03)) | | |||
((bytes[offset_byte + 10] & 0xff) << 2) | | |||
((bytes[offset_byte + 11] & 0x07) << 10); | |||
data[i][offset_data + 7] = (bytes[offset_byte + 11] >> 3 & (0x1f)) | | |||
((bytes[offset_byte + 12] & 0xff) << 5); | |||
} | |||
void PQCLEAN_LIGHTSABER_CLEAN_BS2POLVECp(poly data[SABER_L], const uint8_t bytes[SABER_POLYVECCOMPRESSEDBYTES]) { | |||
size_t i; | |||
for (i = 0; i < SABER_L; i++) { | |||
BS2POLp(&data[i], bytes + i * SABER_POLYCOMPRESSEDBYTES); | |||
} | |||
} | |||
//only BS2POLq no BS2POLp | |||
void PQCLEAN_LIGHTSABER_CLEAN_BS2POL(const unsigned char *bytes, uint16_t data[SABER_N]) { | |||
uint32_t j; | |||
uint32_t offset_data, offset_byte; | |||
for (j = 0; j < SABER_N / 8; j++) { | |||
offset_byte = 13 * j; | |||
offset_data = 8 * j; | |||
data[offset_data + 0] = (bytes[offset_byte + 0] & (0xff)) | | |||
((bytes[offset_byte + 1] & 0x1f) << 8); | |||
data[offset_data + 1] = (bytes[offset_byte + 1] >> 5 & (0x07)) | | |||
((bytes[offset_byte + 2] & 0xff) << 3) | | |||
((bytes[offset_byte + 3] & 0x03) << 11); | |||
data[offset_data + 2] = (bytes[offset_byte + 3] >> 2 & (0x3f)) | | |||
((bytes[offset_byte + 4] & 0x7f) << 6); | |||
data[offset_data + 3] = (bytes[offset_byte + 4] >> 7 & (0x01)) | | |||
((bytes[offset_byte + 5] & 0xff) << 1) | | |||
((bytes[offset_byte + 6] & 0x0f) << 9); | |||
data[offset_data + 4] = (bytes[offset_byte + 6] >> 4 & (0x0f)) | | |||
((bytes[offset_byte + 7] & 0xff) << 4) | | |||
((bytes[offset_byte + 8] & 0x01) << 12); | |||
data[offset_data + 5] = (bytes[offset_byte + 8] >> 1 & (0x7f)) | | |||
((bytes[offset_byte + 9] & 0x3f) << 7); | |||
data[offset_data + 6] = (bytes[offset_byte + 9] >> 6 & (0x03)) | | |||
((bytes[offset_byte + 10] & 0xff) << 2) | | |||
((bytes[offset_byte + 11] & 0x07) << 10); | |||
data[offset_data + 7] = (bytes[offset_byte + 11] >> 3 & (0x1f)) | | |||
((bytes[offset_byte + 12] & 0xff) << 5); | |||
void PQCLEAN_LIGHTSABER_CLEAN_BS2POLmsg(poly *data, const uint8_t bytes[SABER_KEYBYTES]) { | |||
size_t i, j; | |||
for (j = 0; j < SABER_KEYBYTES; j++) { | |||
for (i = 0; i < 8; i++) { | |||
data->coeffs[j * 8 + i] = ((bytes[j] >> i) & 0x01); | |||
} | |||
} | |||
} | |||
void PQCLEAN_LIGHTSABER_CLEAN_POLVEC2BS(uint8_t *bytes, uint16_t data[SABER_K][SABER_N], uint16_t modulus) { | |||
if (modulus == 1024) { | |||
POLVECp2BS(bytes, data); | |||
} else if (modulus == 8192) { | |||
POLVECq2BS(bytes, data); | |||
} | |||
} | |||
void PQCLEAN_LIGHTSABER_CLEAN_POLmsg2BS(uint8_t bytes[SABER_KEYBYTES], const poly *data) { | |||
size_t i, j; | |||
memset(bytes, 0, SABER_KEYBYTES); | |||
void PQCLEAN_LIGHTSABER_CLEAN_BS2POLVEC(const unsigned char *bytes, uint16_t data[SABER_K][SABER_N], uint16_t modulus) { | |||
if (modulus == 1024) { | |||
BS2POLVECp(bytes, data); | |||
} else if (modulus == 8192) { | |||
BS2POLVECq(bytes, data); | |||
for (j = 0; j < SABER_KEYBYTES; j++) { | |||
for (i = 0; i < 8; i++) { | |||
bytes[j] = bytes[j] | ((data->coeffs[j * 8 + i] & 0x01) << i); | |||
} | |||
} | |||
} |
@@ -1,28 +1,28 @@ | |||
#ifndef PACK_UNPACK_H | |||
#define PACK_UNPACK_H | |||
#include "SABER_params.h" | |||
#include "poly.h" | |||
#include <stdint.h> | |||
#include <stdio.h> | |||
void PQCLEAN_LIGHTSABER_CLEAN_POLT2BS(uint8_t bytes[SABER_SCALEBYTES_KEM], const poly *data); | |||
void PQCLEAN_LIGHTSABER_CLEAN_BS2POLT(poly *data, const uint8_t bytes[SABER_SCALEBYTES_KEM]); | |||
void PQCLEAN_LIGHTSABER_CLEAN_pack_3bit(uint8_t *bytes, const uint16_t *data); | |||
void PQCLEAN_LIGHTSABER_CLEAN_un_pack3bit(const uint8_t *bytes, uint16_t *data); | |||
void PQCLEAN_LIGHTSABER_CLEAN_POLVECq2BS(uint8_t bytes[SABER_POLYVECBYTES], const poly data[SABER_L]); | |||
void PQCLEAN_LIGHTSABER_CLEAN_pack_4bit(uint8_t *bytes, const uint16_t *data); | |||
void PQCLEAN_LIGHTSABER_CLEAN_POLVECp2BS(uint8_t bytes[SABER_POLYVECCOMPRESSEDBYTES], const poly data[SABER_L]); | |||
void PQCLEAN_LIGHTSABER_CLEAN_un_pack4bit(const unsigned char *bytes, uint16_t *ar); | |||
void PQCLEAN_LIGHTSABER_CLEAN_pack_6bit(uint8_t *bytes, const uint16_t *data); | |||
void PQCLEAN_LIGHTSABER_CLEAN_BS2POLVECq(poly data[SABER_L], const uint8_t bytes[SABER_POLYVECBYTES]); | |||
void PQCLEAN_LIGHTSABER_CLEAN_un_pack6bit(const unsigned char *bytes, uint16_t *data); | |||
void PQCLEAN_LIGHTSABER_CLEAN_BS2POLVECp(poly data[SABER_L], const uint8_t bytes[SABER_POLYVECCOMPRESSEDBYTES]); | |||
void PQCLEAN_LIGHTSABER_CLEAN_BS2POL(const unsigned char *bytes, uint16_t data[SABER_N]); | |||
void PQCLEAN_LIGHTSABER_CLEAN_BS2POLmsg(poly *data, const uint8_t bytes[SABER_KEYBYTES]); | |||
void PQCLEAN_LIGHTSABER_CLEAN_POLVEC2BS(uint8_t *bytes, uint16_t data[SABER_K][SABER_N], uint16_t modulus); | |||
void PQCLEAN_LIGHTSABER_CLEAN_POLmsg2BS(uint8_t bytes[SABER_KEYBYTES], const poly *data); | |||
void PQCLEAN_LIGHTSABER_CLEAN_BS2POLVEC(const unsigned char *bytes, uint16_t data[SABER_K][SABER_N], uint16_t modulus); | |||
#endif |
@@ -1,21 +1,57 @@ | |||
/*--------------------------------------------------------------------- | |||
This file has been adapted from the implementation | |||
(available at, Public Domain https://github.com/pq-crystals/kyber) | |||
of "CRYSTALS – Kyber: a CCA-secure module-lattice-based KEM" | |||
by : Joppe Bos, Leo Ducas, Eike Kiltz, Tancrede Lepoint, | |||
Vadim Lyubashevsky, John M. Schanck, Peter Schwabe & Damien stehle | |||
#include "SABER_params.h" | |||
#include "api.h" | |||
#include "cbd.h" | |||
#include "fips202.h" | |||
#include "pack_unpack.h" | |||
#include "poly.h" | |||
#include <stddef.h> | |||
void PQCLEAN_LIGHTSABER_CLEAN_GenSecret(uint16_t r[SABER_K][SABER_N], const unsigned char *seed) { | |||
uint8_t buf[SABER_MU * SABER_N * SABER_K / 8]; | |||
void PQCLEAN_LIGHTSABER_CLEAN_MatrixVectorMul(poly c[SABER_L], const poly A[SABER_L][SABER_L], const poly s[SABER_L], int16_t transpose) { | |||
size_t i, j; | |||
if (transpose) { | |||
for (i = 0; i < SABER_L; i++) { | |||
PQCLEAN_LIGHTSABER_CLEAN_poly_mul(&c[i], &A[0][i], &s[0], 0); | |||
for (j = 1; j < SABER_L; j++) { | |||
PQCLEAN_LIGHTSABER_CLEAN_poly_mul(&c[i], &A[j][i], &s[j], 1); | |||
} | |||
} | |||
} else { | |||
for (i = 0; i < SABER_L; i++) { | |||
PQCLEAN_LIGHTSABER_CLEAN_poly_mul(&c[i], &A[i][0], &s[0], 0); | |||
for (j = 1; j < SABER_L; j++) { | |||
PQCLEAN_LIGHTSABER_CLEAN_poly_mul(&c[i], &A[i][j], &s[j], 1); | |||
} | |||
} | |||
} | |||
} | |||
void PQCLEAN_LIGHTSABER_CLEAN_InnerProd(poly *c, const poly b[SABER_L], const poly s[SABER_L]) { | |||
size_t i; | |||
PQCLEAN_LIGHTSABER_CLEAN_poly_mul(c, &b[0], &s[0], 0); | |||
for (i = 1; i < SABER_L; i++) { | |||
PQCLEAN_LIGHTSABER_CLEAN_poly_mul(c, &b[i], &s[i], 1); | |||
} | |||
} | |||
void PQCLEAN_LIGHTSABER_CLEAN_GenMatrix(poly A[SABER_L][SABER_L], const uint8_t seed[SABER_SEEDBYTES]) { | |||
size_t i; | |||
uint8_t buf[SABER_L * SABER_POLYVECBYTES]; | |||
shake128(buf, sizeof(buf), seed, SABER_SEEDBYTES); | |||
for (i = 0; i < SABER_L; i++) { | |||
PQCLEAN_LIGHTSABER_CLEAN_BS2POLVECq(A[i], buf + i * SABER_POLYVECBYTES); | |||
} | |||
} | |||
void PQCLEAN_LIGHTSABER_CLEAN_GenSecret(poly s[SABER_L], const uint8_t seed[SABER_NOISESEEDBYTES]) { | |||
size_t i; | |||
uint8_t buf[SABER_L * SABER_POLYCOINBYTES]; | |||
shake128(buf, sizeof(buf), seed, SABER_NOISESEEDBYTES); | |||
for (size_t i = 0; i < SABER_K; i++) { | |||
PQCLEAN_LIGHTSABER_CLEAN_cbd(r[i], buf + i * SABER_MU * SABER_N / 8); | |||
for (i = 0; i < SABER_L; i++) { | |||
PQCLEAN_LIGHTSABER_CLEAN_cbd(s[i].coeffs, buf + i * SABER_POLYCOINBYTES); | |||
} | |||
} |
@@ -1,26 +1,23 @@ | |||
#ifndef POLY_H | |||
#define POLY_H | |||
/*--------------------------------------------------------------------- | |||
This file has been adapted from the implementation | |||
(available at, Public Domain https://github.com/pq-crystals/kyber) | |||
of "CRYSTALS – Kyber: a CCA-secure module-lattice-based KEM" | |||
by : Joppe Bos, Leo Ducas, Eike Kiltz, Tancrede Lepoint, | |||
Vadim Lyubashevsky, John M. Schanck, Peter Schwabe & Damien stehle | |||
#include "SABER_params.h" | |||
#include <stdint.h> | |||
typedef struct { | |||
typedef union { | |||
uint16_t coeffs[SABER_N]; | |||
} poly; | |||
typedef struct { | |||
poly vec[SABER_K]; | |||
} polyvec; | |||
void PQCLEAN_LIGHTSABER_CLEAN_GenSecret(uint16_t r[SABER_K][SABER_N], const unsigned char *seed); | |||
void PQCLEAN_LIGHTSABER_CLEAN_MatrixVectorMul(poly c[SABER_L], const poly A[SABER_L][SABER_L], const poly s[SABER_L], int16_t transpose); | |||
void PQCLEAN_LIGHTSABER_CLEAN_InnerProd(poly *c, const poly b[SABER_L], const poly s[SABER_L]); | |||
void PQCLEAN_LIGHTSABER_CLEAN_GenMatrix(poly A[SABER_L][SABER_L], const uint8_t seed[SABER_SEEDBYTES]); | |||
void PQCLEAN_LIGHTSABER_CLEAN_GenSecret(poly s[SABER_L], const uint8_t seed[SABER_NOISESEEDBYTES]); | |||
void PQCLEAN_LIGHTSABER_CLEAN_poly_mul(poly *c, const poly *a, const poly *b, int accumulate); | |||
#endif |
@@ -1,4 +1,4 @@ | |||
#include "poly_mul.h" | |||
#include "poly.h" | |||
#include <stdint.h> | |||
#include <string.h> | |||
@@ -11,13 +11,13 @@ | |||
#define OVERFLOWING_MUL(X, Y) ((uint16_t)((uint32_t)(X) * (uint32_t)(Y))) | |||
#define KARATSUBA_N 64 | |||
static void karatsuba_simple(const uint16_t *a_1, const uint16_t *b_1, uint16_t *result_final) { | |||
static void karatsuba_simple(uint16_t *result_final, const uint16_t *a_1, const uint16_t *b_1) { | |||
uint16_t d01[KARATSUBA_N / 2 - 1]; | |||
uint16_t d0123[KARATSUBA_N / 2 - 1]; | |||
uint16_t d23[KARATSUBA_N / 2 - 1]; | |||
uint16_t result_d01[KARATSUBA_N - 1]; | |||
int32_t i, j; | |||
size_t i, j; | |||
memset(result_d01, 0, (KARATSUBA_N - 1)*sizeof(uint16_t)); | |||
memset(d01, 0, (KARATSUBA_N / 2 - 1)*sizeof(uint16_t)); | |||
@@ -110,7 +110,7 @@ static void karatsuba_simple(const uint16_t *a_1, const uint16_t *b_1, uint16_t | |||
static void toom_cook_4way (const uint16_t *a1, const uint16_t *b1, uint16_t *result) { | |||
static void toom_cook_4way (uint16_t *result, const uint16_t *a1, const uint16_t *b1) { | |||
uint16_t inv3 = 43691, inv9 = 36409, inv15 = 61167; | |||
uint16_t aw1[N_SB], aw2[N_SB], aw3[N_SB], aw4[N_SB], aw5[N_SB], aw6[N_SB], aw7[N_SB]; | |||
@@ -181,13 +181,13 @@ static void toom_cook_4way (const uint16_t *a1, const uint16_t *b1, uint16_t *re | |||
// MULTIPLICATION | |||
karatsuba_simple(aw1, bw1, w1); | |||
karatsuba_simple(aw2, bw2, w2); | |||
karatsuba_simple(aw3, bw3, w3); | |||
karatsuba_simple(aw4, bw4, w4); | |||
karatsuba_simple(aw5, bw5, w5); | |||
karatsuba_simple(aw6, bw6, w6); | |||
karatsuba_simple(aw7, bw7, w7); | |||
karatsuba_simple(w1, aw1, bw1); | |||
karatsuba_simple(w2, aw2, bw2); | |||
karatsuba_simple(w3, aw3, bw3); | |||
karatsuba_simple(w4, aw4, bw4); | |||
karatsuba_simple(w5, aw5, bw5); | |||
karatsuba_simple(w6, aw6, bw6); | |||
karatsuba_simple(w7, aw7, bw7); | |||
// INTERPOLATION | |||
for (i = 0; i < N_SB_RES; ++i) { | |||
@@ -228,19 +228,21 @@ static void toom_cook_4way (const uint16_t *a1, const uint16_t *b1, uint16_t *re | |||
} | |||
} | |||
void PQCLEAN_LIGHTSABER_CLEAN_pol_mul(uint16_t *a, uint16_t *b, uint16_t *res, uint16_t p, uint32_t n) { | |||
uint32_t i; | |||
// normal multiplication | |||
uint16_t c[512]; | |||
/* res += a*b */ | |||
void PQCLEAN_LIGHTSABER_CLEAN_poly_mul(poly *c, const poly *a, const poly *b, const int accumulate) { | |||
uint16_t C[2 * SABER_N] = {0}; | |||
size_t i; | |||
for (i = 0; i < 512; i++) { | |||
c[i] = 0; | |||
} | |||
toom_cook_4way(a, b, c); | |||
toom_cook_4way(C, a->coeffs, b->coeffs); | |||
// reduction | |||
for (i = n; i < 2 * n; i++) { | |||
res[i - n] = (c[i - n] - c[i]) & (p - 1); | |||
/* reduction */ | |||
if (accumulate == 0) { | |||
for (i = SABER_N; i < 2 * SABER_N; i++) { | |||
c->coeffs[i - SABER_N] = (C[i - SABER_N] - C[i]); | |||
} | |||
} else { | |||
for (i = SABER_N; i < 2 * SABER_N; i++) { | |||
c->coeffs[i - SABER_N] += (C[i - SABER_N] - C[i]); | |||
} | |||
} | |||
} |
@@ -1,9 +1,3 @@ | |||
#ifndef POLYMUL_H | |||
#define POLYMUL_H | |||
#include "SABER_params.h" | |||
#include <stdint.h> | |||
void PQCLEAN_LIGHTSABER_CLEAN_pol_mul(uint16_t *a, uint16_t *b, uint16_t *res, uint16_t p, uint32_t n); | |||
#endif |
@@ -1,3 +1,5 @@ | |||
#include "verify.h" | |||
/*------------------------------------------------- | |||
This file has been adapted from the implementation | |||
(available at https://github.com/pq-crystals/kyber) of | |||
@@ -5,26 +7,25 @@ This file has been adapted from the implementation | |||
by : Joppe Bos, Leo Ducas, Eike Kiltz, Tancrede Lepoint, | |||
Vadim Lyubashevsky, John M. Schanck, Peter Schwabe & Damien stehle | |||
----------------------------------------------------*/ | |||
#include "verify.h" | |||
#include <stdint.h> | |||
/* returns 0 for equal strings, 1 for non-equal strings */ | |||
unsigned char PQCLEAN_LIGHTSABER_CLEAN_verify(const unsigned char *a, const unsigned char *b, size_t len) { | |||
uint8_t PQCLEAN_LIGHTSABER_CLEAN_verify(const uint8_t *a, const uint8_t *b, size_t len) { | |||
uint64_t r; | |||
size_t i; | |||
r = 0; | |||
for (i = 0; i < len; i++) { | |||
r |= a[i] ^ b[i]; | |||
} | |||
r = (~r + 1); // Two's complement | |||
r >>= 63; | |||
return (unsigned char)r; | |||
return (uint8_t) r; | |||
} | |||
/* b = 1 means mov, b = 0 means don't mov*/ | |||
void PQCLEAN_LIGHTSABER_CLEAN_cmov(unsigned char *r, const unsigned char *x, size_t len, unsigned char b) { | |||
void PQCLEAN_LIGHTSABER_CLEAN_cmov(uint8_t *r, const uint8_t *x, size_t len, uint8_t b) { | |||
size_t i; | |||
b = -b; | |||
@@ -1,6 +1,5 @@ | |||
#ifndef VERIFY_H | |||
#define VERIFY_H | |||
/*------------------------------------------------- | |||
This file has been adapted from the implementation | |||
(available at https://github.com/pq-crystals/kyber) of | |||
@@ -13,9 +12,11 @@ Vadim Lyubashevsky, John M. Schanck, Peter Schwabe & Damien stehle | |||
#include <stdint.h> | |||
/* returns 0 for equal strings, 1 for non-equal strings */ | |||
unsigned char PQCLEAN_LIGHTSABER_CLEAN_verify(const unsigned char *a, const unsigned char *b, size_t len); | |||
uint8_t PQCLEAN_LIGHTSABER_CLEAN_verify(const uint8_t *a, const uint8_t *b, size_t len); | |||
/* b = 1 means mov, b = 0 means don't mov*/ | |||
void PQCLEAN_LIGHTSABER_CLEAN_cmov(unsigned char *r, const unsigned char *x, size_t len, unsigned char b); | |||
void PQCLEAN_LIGHTSABER_CLEAN_cmov(uint8_t *r, const uint8_t *x, size_t len, uint8_t b); | |||
#endif |
@@ -14,4 +14,13 @@ principal-submitters: | |||
- Frederik Vercauteren | |||
implementations: | |||
- name: clean | |||
version: https://github.com/KULeuven-COSIC/SABER/commit/14ede83f1ff3bcc41f0464543542366c68b55871 | |||
version: https://github.com/KULeuven-COSIC/SABER/tree/509cc5ec3a7e12a751ccdd2ef5bd6e54e00bd350 via https://github.com/jschanck/package-pqclean/tree/1ae84c3c/saber | |||
- name: avx2 | |||
version: https://github.com/KULeuven-COSIC/SABER/tree/509cc5ec3a7e12a751ccdd2ef5bd6e54e00bd350 via https://github.com/jschanck/package-pqclean/tree/1ae84c3c/saber | |||
supported_platforms: | |||
- architecture: x86_64 | |||
operating_systems: | |||
- Linux | |||
- Darwin | |||
required_flags: | |||
- avx2 |
@@ -0,0 +1 @@ | |||
Public Domain |
@@ -0,0 +1,22 @@ | |||
# This Makefile can be used with GNU Make or BSD Make | |||
LIB=libsaber_avx2.a | |||
HEADERS=api.h cbd.h pack_unpack.h poly.h SABER_indcpa.h SABER_params.h verify.h | |||
OBJECTS=cbd.o kem.o pack_unpack.o poly.o poly_mul.o SABER_indcpa.o verify.o | |||
CFLAGS=-O3 -mavx2 -Wall -Wextra -Wpedantic -Wvla -Werror -Wredundant-decls -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) | |||
all: $(LIB) | |||
%.o: %.s $(HEADERS) | |||
$(AS) -o $@ $< | |||
%.o: %.c $(HEADERS) | |||
$(CC) $(CFLAGS) -c -o $@ $< | |||
$(LIB): $(OBJECTS) | |||
$(AR) -r $@ $(OBJECTS) | |||
clean: | |||
$(RM) $(OBJECTS) | |||
$(RM) $(LIB) |
@@ -0,0 +1,125 @@ | |||
#include "SABER_indcpa.h" | |||
#include "SABER_params.h" | |||
#include "fips202.h" | |||
#include "pack_unpack.h" | |||
#include "poly.h" | |||
#include "randombytes.h" | |||
#include <stdint.h> | |||
#include <string.h> | |||
#define h1 (1 << (SABER_EQ - SABER_EP - 1)) | |||
#define h2 ((1 << (SABER_EP - 2)) - (1 << (SABER_EP - SABER_ET - 1)) + (1 << (SABER_EQ - SABER_EP - 1))) | |||
void PQCLEAN_SABER_AVX2_indcpa_kem_keypair(uint8_t pk[SABER_INDCPA_PUBLICKEYBYTES], uint8_t sk[SABER_INDCPA_SECRETKEYBYTES]) { | |||
size_t i, j; | |||
poly A[SABER_L][SABER_L]; | |||
poly *skpv1 = A[0]; // use first row of A to hold sk temporarily | |||
toom4_points skpv1_eval[SABER_L]; | |||
poly res[SABER_L]; | |||
uint8_t rand[SABER_NOISESEEDBYTES]; | |||
uint8_t *seed_A = pk + SABER_POLYVECCOMPRESSEDBYTES; | |||
randombytes(seed_A, SABER_SEEDBYTES); | |||
shake128(seed_A, SABER_SEEDBYTES, seed_A, SABER_SEEDBYTES); // for not revealing system RNG state | |||
randombytes(rand, SABER_NOISESEEDBYTES); | |||
PQCLEAN_SABER_AVX2_GenSecret(skpv1, rand); | |||
PQCLEAN_SABER_AVX2_POLVECq2BS(sk, skpv1); // pack secret key | |||
for (j = 0; j < SABER_L; j++) { | |||
PQCLEAN_SABER_AVX2_toom4_eval(&skpv1_eval[j], &skpv1[j]); | |||
} | |||
PQCLEAN_SABER_AVX2_GenMatrix(A, seed_A); // sample matrix A | |||
PQCLEAN_SABER_AVX2_MatrixVectorMul(res, (const poly (*)[SABER_L])A, (const toom4_points *)skpv1_eval, 1); // Matrix in transposed order | |||
// rounding | |||
for (i = 0; i < SABER_L; i++) { | |||
for (j = 0; j < SABER_N; j++) { | |||
res[i].coeffs[j] += h1; | |||
res[i].coeffs[j] >>= SABER_EQ - SABER_EP; | |||
res[i].coeffs[j] &= SABER_Q - 1; | |||
} | |||
} | |||
PQCLEAN_SABER_AVX2_POLVECp2BS(pk, res); // pack public key | |||
} | |||
void PQCLEAN_SABER_AVX2_indcpa_kem_enc(uint8_t ciphertext[SABER_BYTES_CCA_DEC], const uint8_t m[SABER_KEYBYTES], const uint8_t noiseseed[SABER_NOISESEEDBYTES], const uint8_t pk[SABER_INDCPA_PUBLICKEYBYTES]) { | |||
size_t i, j; | |||
poly A[SABER_L][SABER_L]; | |||
poly res[SABER_L]; | |||
toom4_points skpv1_eval[SABER_L]; | |||
poly *temp = A[0]; // re-use stack space | |||
poly *vprime = &A[0][0]; | |||
poly *message = &A[0][1]; | |||
const uint8_t *seed_A = pk + SABER_POLYVECCOMPRESSEDBYTES; | |||
uint8_t *msk_c = ciphertext + SABER_POLYVECCOMPRESSEDBYTES; | |||
PQCLEAN_SABER_AVX2_GenSecret(temp, noiseseed); | |||
for (j = 0; j < SABER_L; j++) { | |||
PQCLEAN_SABER_AVX2_toom4_eval(&skpv1_eval[j], &temp[j]); | |||
} | |||
PQCLEAN_SABER_AVX2_GenMatrix(A, seed_A); | |||
PQCLEAN_SABER_AVX2_MatrixVectorMul(res, (const poly (*)[SABER_L])A, (const toom4_points *)skpv1_eval, 0); // 0 => not transposed | |||
// rounding | |||
for (i = 0; i < SABER_L; i++) { //shift right EQ-EP bits | |||
for (j = 0; j < SABER_N; j++) { | |||
res[i].coeffs[j] += h1; | |||
res[i].coeffs[j] >>= SABER_EQ - SABER_EP; | |||
res[i].coeffs[j] &= SABER_Q - 1; | |||
} | |||
} | |||
PQCLEAN_SABER_AVX2_POLVECp2BS(ciphertext, res); | |||
// vector-vector scalar multiplication with mod p | |||
PQCLEAN_SABER_AVX2_BS2POLVECp(temp, pk); | |||
PQCLEAN_SABER_AVX2_InnerProd(vprime, temp, skpv1_eval); | |||
PQCLEAN_SABER_AVX2_BS2POLmsg(message, m); | |||
for (i = 0; i < SABER_N; i++) { | |||
vprime->coeffs[i] += h1 - (message->coeffs[i] << (SABER_EP - 1)); | |||
vprime->coeffs[i] &= SABER_P - 1; | |||
vprime->coeffs[i] >>= SABER_EP - SABER_ET; | |||
} | |||
PQCLEAN_SABER_AVX2_POLT2BS(msk_c, vprime); | |||
} | |||
void PQCLEAN_SABER_AVX2_indcpa_kem_dec(uint8_t m[SABER_KEYBYTES], const uint8_t sk[SABER_INDCPA_SECRETKEYBYTES], const uint8_t ciphertext[SABER_BYTES_CCA_DEC]) { | |||
size_t i; | |||
poly temp[SABER_L]; | |||
toom4_points sksv_eval[SABER_L]; | |||
const uint8_t *packed_cm = ciphertext + SABER_POLYVECCOMPRESSEDBYTES; | |||
poly *v = &temp[0]; | |||
poly *cm = &temp[1]; | |||
PQCLEAN_SABER_AVX2_BS2POLVECq(temp, sk); | |||
for (i = 0; i < SABER_L; i++) { | |||
PQCLEAN_SABER_AVX2_toom4_eval(&sksv_eval[i], &temp[i]); | |||
} | |||
PQCLEAN_SABER_AVX2_BS2POLVECp(temp, ciphertext); | |||
PQCLEAN_SABER_AVX2_InnerProd(v, temp, sksv_eval); | |||
PQCLEAN_SABER_AVX2_BS2POLT(cm, packed_cm); | |||
for (i = 0; i < SABER_N; i++) { | |||
v->coeffs[i] += h2 - (cm->coeffs[i] << (SABER_EP - SABER_ET)); | |||
v->coeffs[i] &= SABER_P - 1; | |||
v->coeffs[i] >>= SABER_EP - 1; | |||
} | |||
PQCLEAN_SABER_AVX2_POLmsg2BS(m, v); | |||
} |
@@ -0,0 +1,13 @@ | |||
#ifndef INDCPA_H | |||
#define INDCPA_H | |||
#include "SABER_params.h" | |||
#include <stdint.h> | |||
void PQCLEAN_SABER_AVX2_indcpa_kem_keypair(uint8_t pk[SABER_INDCPA_PUBLICKEYBYTES], uint8_t sk[SABER_INDCPA_SECRETKEYBYTES]); | |||
void PQCLEAN_SABER_AVX2_indcpa_kem_enc(uint8_t ciphertext[SABER_BYTES_CCA_DEC], const uint8_t m[SABER_KEYBYTES], const uint8_t noiseseed[SABER_NOISESEEDBYTES], const uint8_t pk[SABER_INDCPA_PUBLICKEYBYTES]); | |||
void PQCLEAN_SABER_AVX2_indcpa_kem_dec(uint8_t m[SABER_KEYBYTES], const uint8_t sk[SABER_INDCPA_SECRETKEYBYTES], const uint8_t ciphertext[SABER_BYTES_CCA_DEC]); | |||
#endif |
@@ -0,0 +1,41 @@ | |||
#ifndef PARAMS_H | |||
#define PARAMS_H | |||
/* Don't change anything below this line */ | |||
#define SABER_L 3 | |||
#define SABER_MU 8 | |||
#define SABER_ET 4 | |||
#define SABER_N 256 | |||
#define SABER_EP 10 | |||
#define SABER_P (1 << SABER_EP) | |||
#define SABER_EQ 13 | |||
#define SABER_Q (1 << SABER_EQ) | |||
#define SABER_SEEDBYTES 32 | |||
#define SABER_NOISESEEDBYTES 32 | |||
#define SABER_KEYBYTES 32 | |||
#define SABER_HASHBYTES 32 | |||
#define SABER_POLYCOINBYTES (SABER_MU * SABER_N / 8) | |||
#define SABER_POLYBYTES (SABER_EQ * SABER_N / 8) | |||
#define SABER_POLYVECBYTES (SABER_L * SABER_POLYBYTES) | |||
#define SABER_POLYCOMPRESSEDBYTES (SABER_EP * SABER_N / 8) | |||
#define SABER_POLYVECCOMPRESSEDBYTES (SABER_L * SABER_POLYCOMPRESSEDBYTES) | |||
#define SABER_SCALEBYTES_KEM (SABER_ET * SABER_N / 8) | |||
#define SABER_INDCPA_PUBLICKEYBYTES (SABER_POLYVECCOMPRESSEDBYTES + SABER_SEEDBYTES) | |||
#define SABER_INDCPA_SECRETKEYBYTES (SABER_POLYVECBYTES) | |||
#define SABER_PUBLICKEYBYTES (SABER_INDCPA_PUBLICKEYBYTES) | |||
#define SABER_SECRETKEYBYTES (SABER_INDCPA_SECRETKEYBYTES + SABER_INDCPA_PUBLICKEYBYTES + SABER_HASHBYTES + SABER_KEYBYTES) | |||
#define SABER_BYTES_CCA_DEC (SABER_POLYVECCOMPRESSEDBYTES + SABER_SCALEBYTES_KEM) | |||
#endif |
@@ -0,0 +1,18 @@ | |||
#ifndef PQCLEAN_SABER_AVX2_API_H | |||
#define PQCLEAN_SABER_AVX2_API_H | |||
#define PQCLEAN_SABER_AVX2_CRYPTO_ALGNAME "Saber" | |||
#define PQCLEAN_SABER_AVX2_CRYPTO_BYTES 32 | |||
#define PQCLEAN_SABER_AVX2_CRYPTO_CIPHERTEXTBYTES 1088 | |||
#define PQCLEAN_SABER_AVX2_CRYPTO_PUBLICKEYBYTES 992 | |||
#define PQCLEAN_SABER_AVX2_CRYPTO_SECRETKEYBYTES 2304 | |||
int PQCLEAN_SABER_AVX2_crypto_kem_keypair(unsigned char *pk, unsigned char *sk); | |||
int PQCLEAN_SABER_AVX2_crypto_kem_enc(unsigned char *ct, unsigned char *k, const unsigned char *pk); | |||
int PQCLEAN_SABER_AVX2_crypto_kem_dec(unsigned char *k, const unsigned char *ct, const unsigned char *sk); | |||
#endif /* PQCLEAN_SABER_AVX2_API_H */ |
@@ -0,0 +1,48 @@ | |||
#include "SABER_params.h" | |||
#include "api.h" | |||
#include "cbd.h" | |||
#include <stdint.h> | |||
/*--------------------------------------------------------------------- | |||
This file has been adapted from the implementation | |||
(available at, Public Domain https://github.com/pq-crystals/kyber) | |||
of "CRYSTALS – Kyber: a CCA-secure module-lattice-based KEM" | |||
by : Joppe Bos, Leo Ducas, Eike Kiltz, Tancrede Lepoint, | |||
Vadim Lyubashevsky, John M. Schanck, Peter Schwabe & Damien stehle | |||
----------------------------------------------------------------------*/ | |||
static uint64_t load_littleendian(const uint8_t *x, int bytes) { | |||
int i; | |||
uint64_t r = x[0]; | |||
for (i = 1; i < bytes; i++) { | |||
r |= (uint64_t)x[i] << (8 * i); | |||
} | |||
return r; | |||
} | |||
void PQCLEAN_SABER_AVX2_cbd(uint16_t s[SABER_N], const uint8_t buf[SABER_POLYCOINBYTES]) { | |||
uint32_t t, d, a[4], b[4]; | |||
int i, j; | |||
for (i = 0; i < SABER_N / 4; i++) { | |||
t = (uint32_t) load_littleendian(buf + 4 * i, 4); | |||
d = 0; | |||
for (j = 0; j < 4; j++) { | |||
d += (t >> j) & 0x11111111; | |||
} | |||
a[0] = d & 0xf; | |||
b[0] = (d >> 4) & 0xf; | |||
a[1] = (d >> 8) & 0xf; | |||
b[1] = (d >> 12) & 0xf; | |||
a[2] = (d >> 16) & 0xf; | |||
b[2] = (d >> 20) & 0xf; | |||
a[3] = (d >> 24) & 0xf; | |||
b[3] = (d >> 28); | |||
s[4 * i + 0] = (uint16_t)(a[0] - b[0]); | |||
s[4 * i + 1] = (uint16_t)(a[1] - b[1]); | |||
s[4 * i + 2] = (uint16_t)(a[2] - b[2]); | |||
s[4 * i + 3] = (uint16_t)(a[3] - b[3]); | |||
} | |||
} |
@@ -0,0 +1,16 @@ | |||
#ifndef CBD_H | |||
#define CBD_H | |||
/*--------------------------------------------------------------------- | |||
This file has been adapted from the implementation | |||
(available at, Public Domain https://github.com/pq-crystals/kyber) | |||
of "CRYSTALS – Kyber: a CCA-secure module-lattice-based KEM" | |||
by : Joppe Bos, Leo Ducas, Eike Kiltz, Tancrede Lepoint, | |||
Vadim Lyubashevsky, John M. Schanck, Peter Schwabe & Damien stehle | |||
----------------------------------------------------------------------*/ | |||
#include "SABER_params.h" | |||
#include <stdint.h> | |||
void PQCLEAN_SABER_AVX2_cbd(uint16_t s[SABER_N], const uint8_t buf[SABER_POLYCOINBYTES]); | |||
#endif |
@@ -0,0 +1,77 @@ | |||
#include "SABER_indcpa.h" | |||
#include "SABER_params.h" | |||
#include "api.h" | |||
#include "fips202.h" | |||
#include "randombytes.h" | |||
#include "verify.h" | |||
#include <stddef.h> | |||
#include <stdint.h> | |||
int PQCLEAN_SABER_AVX2_crypto_kem_keypair(uint8_t *pk, uint8_t *sk) { | |||
size_t i; | |||
PQCLEAN_SABER_AVX2_indcpa_kem_keypair(pk, sk); // sk[0:SABER_INDCPA_SECRETKEYBYTES-1] <-- sk | |||
for (i = 0; i < SABER_INDCPA_PUBLICKEYBYTES; i++) { | |||
sk[i + SABER_INDCPA_SECRETKEYBYTES] = pk[i]; // sk[SABER_INDCPA_SECRETKEYBYTES:SABER_INDCPA_SECRETKEYBYTES+SABER_INDCPA_SECRETKEYBYTES-1] <-- pk | |||
} | |||
sha3_256(sk + SABER_SECRETKEYBYTES - 64, pk, SABER_INDCPA_PUBLICKEYBYTES); // Then hash(pk) is appended. | |||
randombytes(sk + SABER_SECRETKEYBYTES - SABER_KEYBYTES, SABER_KEYBYTES); // Remaining part of sk contains a pseudo-random number. | |||
// This is output when check in PQCLEAN_SABER_AVX2_crypto_kem_dec() fails. | |||
return (0); | |||
} | |||
int PQCLEAN_SABER_AVX2_crypto_kem_enc(uint8_t *c, uint8_t *k, const uint8_t *pk) { | |||
uint8_t kr[64]; // Will contain key, coins | |||
uint8_t buf[64]; | |||
randombytes(buf, 32); | |||
sha3_256(buf, buf, 32); // BUF[0:31] <-- random message (will be used as the key for client) Note: hash doesnot release system RNG output | |||
sha3_256(buf + 32, pk, SABER_INDCPA_PUBLICKEYBYTES); // BUF[32:63] <-- Hash(public key); Multitarget countermeasure for coins + contributory KEM | |||
sha3_512(kr, buf, 64); // kr[0:63] <-- Hash(buf[0:63]); | |||
// K^ <-- kr[0:31] | |||
// noiseseed (r) <-- kr[32:63]; | |||
PQCLEAN_SABER_AVX2_indcpa_kem_enc(c, buf, kr + 32, pk); // buf[0:31] contains message; kr[32:63] contains randomness r; | |||
sha3_256(kr + 32, c, SABER_BYTES_CCA_DEC); | |||
sha3_256(k, kr, 64); // hash concatenation of pre-k and h(c) to k | |||
return (0); | |||
} | |||
int PQCLEAN_SABER_AVX2_crypto_kem_dec(uint8_t *k, const uint8_t *c, const uint8_t *sk) { | |||
size_t i; | |||
uint8_t fail; | |||
uint8_t cmp[SABER_BYTES_CCA_DEC]; | |||
uint8_t buf[64]; | |||
uint8_t kr[64]; // Will contain key, coins | |||
const uint8_t *pk = sk + SABER_INDCPA_SECRETKEYBYTES; | |||
PQCLEAN_SABER_AVX2_indcpa_kem_dec(buf, sk, c); // buf[0:31] <-- message | |||
// Multitarget countermeasure for coins + contributory KEM | |||
for (i = 0; i < 32; i++) { // Save hash by storing h(pk) in sk | |||
buf[32 + i] = sk[SABER_SECRETKEYBYTES - 64 + i]; | |||
} | |||
sha3_512(kr, buf, 64); | |||
PQCLEAN_SABER_AVX2_indcpa_kem_enc(cmp, buf, kr + 32, pk); | |||
fail = PQCLEAN_SABER_AVX2_verify(c, cmp, SABER_BYTES_CCA_DEC); | |||
sha3_256(kr + 32, c, SABER_BYTES_CCA_DEC); // overwrite coins in kr with h(c) | |||
PQCLEAN_SABER_AVX2_cmov(kr, sk + SABER_SECRETKEYBYTES - SABER_KEYBYTES, SABER_KEYBYTES, fail); | |||
sha3_256(k, kr, 64); // hash concatenation of pre-k and h(c) to k | |||
return (0); | |||
} |
@@ -0,0 +1,147 @@ | |||
#include "SABER_params.h" | |||
#include "pack_unpack.h" | |||
#include "poly.h" | |||
#include <string.h> | |||
void PQCLEAN_SABER_AVX2_POLT2BS(uint8_t bytes[SABER_SCALEBYTES_KEM], const poly *data) { | |||
size_t j; | |||
const uint16_t *in = data->coeffs; | |||
uint8_t *out = bytes; | |||
for (j = 0; j < SABER_N / 2; j++) { | |||
out[0] = (uint8_t) ((in[0] & 0x0f) | (in[1] << 4)); | |||
in += 2; | |||
out += 1; | |||
} | |||
} | |||
void PQCLEAN_SABER_AVX2_BS2POLT(poly *data, const uint8_t bytes[SABER_SCALEBYTES_KEM]) { | |||
/* This function does not reduce its output mod T */ | |||
size_t j; | |||
const uint8_t *in = bytes; | |||
uint16_t *out = data->coeffs; | |||
for (j = 0; j < SABER_N / 2; j++) { | |||
out[0] = in[0]; | |||
out[1] = in[0] >> 4; | |||
in += 1; | |||
out += 2; | |||
} | |||
} | |||
static void POLq2BS(uint8_t bytes[SABER_POLYBYTES], const poly *data) { | |||
size_t j; | |||
const uint16_t *in = data->coeffs; | |||
uint8_t *out = bytes; | |||
for (j = 0; j < SABER_N / 8; j++) { | |||
out[0] = (uint8_t) (in[0]); | |||
out[1] = (uint8_t) (((in[0] >> 8) & 0x1f) | (in[1] << 5)); | |||
out[2] = (uint8_t) (in[1] >> 3); | |||
out[3] = (uint8_t) (((in[1] >> 11) & 0x03) | (in[2] << 2)); | |||
out[4] = (uint8_t) (((in[2] >> 6) & 0x7f) | (in[3] << 7)); | |||
out[5] = (uint8_t) (in[3] >> 1); | |||
out[6] = (uint8_t) (((in[3] >> 9) & 0x0f) | (in[4] << 4)); | |||
out[7] = (uint8_t) (in[4] >> 4); | |||
out[8] = (uint8_t) (((in[4] >> 12) & 0x01) | (in[5] << 1)); | |||
out[9] = (uint8_t) (((in[5] >> 7) & 0x3f) | (in[6] << 6)); | |||
out[10] = (uint8_t) (in[6] >> 2); | |||
out[11] = (uint8_t) (((in[6] >> 10) & 0x07) | (in[7] << 3)); | |||
out[12] = (uint8_t) (in[7] >> 5); | |||
in += 8; | |||
out += 13; | |||
} | |||
} | |||
static void BS2POLq(poly *data, const uint8_t bytes[SABER_POLYBYTES]) { | |||
/* This function does not reduce its output mod Q */ | |||
size_t j; | |||
const uint8_t *in = bytes; | |||
uint16_t *out = data->coeffs; | |||
for (j = 0; j < SABER_N / 8; j++) { | |||
out[0] = (in[0]) | (in[1] << 8); | |||
out[1] = (in[1] >> 5) | (in[2] << 3) | (in[3] << 11); | |||
out[2] = (in[3] >> 2) | (in[4] << 6); | |||
out[3] = (in[4] >> 7) | (in[5] << 1) | (in[6] << 9); | |||
out[4] = (in[6] >> 4) | (in[7] << 4) | (in[8] << 12); | |||
out[5] = (in[8] >> 1) | (in[9] << 7); | |||
out[6] = (in[9] >> 6) | (in[10] << 2) | (in[11] << 10); | |||
out[7] = (in[11] >> 3) | (in[12] << 5); | |||
in += 13; | |||
out += 8; | |||
} | |||
} | |||
static void POLp2BS(uint8_t bytes[SABER_POLYCOMPRESSEDBYTES], const poly *data) { | |||
size_t j; | |||
const uint16_t *in = data->coeffs; | |||
uint8_t *out = bytes; | |||
for (j = 0; j < SABER_N / 4; j++) { | |||
out[0] = (uint8_t) (in[0]); | |||
out[1] = (uint8_t) (((in[0] >> 8) & 0x03) | (in[1] << 2)); | |||
out[2] = (uint8_t) (((in[1] >> 6) & 0x0f) | (in[2] << 4)); | |||
out[3] = (uint8_t) (((in[2] >> 4) & 0x3f) | (in[3] << 6)); | |||
out[4] = (uint8_t) (in[3] >> 2); | |||
in += 4; | |||
out += 5; | |||
} | |||
} | |||
static void BS2POLp(poly *data, const uint8_t bytes[SABER_POLYCOMPRESSEDBYTES]) { | |||
size_t j; | |||
const uint8_t *in = bytes; | |||
uint16_t *out = data->coeffs; | |||
for (j = 0; j < SABER_N / 4; j++) { | |||
out[0] = in[0] | (in[1] << 8); | |||
out[1] = (in[1] >> 2) | (in[2] << 6); | |||
out[2] = (in[2] >> 4) | (in[3] << 4); | |||
out[3] = (in[3] >> 6) | (in[4] << 2); | |||
in += 5; | |||
out += 4; | |||
} | |||
} | |||
void PQCLEAN_SABER_AVX2_POLVECq2BS(uint8_t bytes[SABER_POLYVECBYTES], const poly data[SABER_L]) { | |||
size_t i; | |||
for (i = 0; i < SABER_L; i++) { | |||
POLq2BS(bytes + i * SABER_POLYBYTES, &data[i]); | |||
} | |||
} | |||
void PQCLEAN_SABER_AVX2_BS2POLVECq(poly data[SABER_L], const uint8_t bytes[SABER_POLYVECBYTES]) { | |||
size_t i; | |||
for (i = 0; i < SABER_L; i++) { | |||
BS2POLq(&data[i], bytes + i * SABER_POLYBYTES); | |||
} | |||
} | |||
void PQCLEAN_SABER_AVX2_POLVECp2BS(uint8_t bytes[SABER_POLYVECCOMPRESSEDBYTES], const poly data[SABER_L]) { | |||
size_t i; | |||
for (i = 0; i < SABER_L; i++) { | |||
POLp2BS(bytes + i * SABER_POLYCOMPRESSEDBYTES, &data[i]); | |||
} | |||
} | |||
void PQCLEAN_SABER_AVX2_BS2POLVECp(poly data[SABER_L], const uint8_t bytes[SABER_POLYVECCOMPRESSEDBYTES]) { | |||
size_t i; | |||
for (i = 0; i < SABER_L; i++) { | |||
BS2POLp(&data[i], bytes + i * SABER_POLYCOMPRESSEDBYTES); | |||
} | |||
} | |||
void PQCLEAN_SABER_AVX2_BS2POLmsg(poly *data, const uint8_t bytes[SABER_KEYBYTES]) { | |||
size_t i, j; | |||
for (j = 0; j < SABER_KEYBYTES; j++) { | |||
for (i = 0; i < 8; i++) { | |||
data->coeffs[j * 8 + i] = ((bytes[j] >> i) & 0x01); | |||
} | |||
} | |||
} | |||
void PQCLEAN_SABER_AVX2_POLmsg2BS(uint8_t bytes[SABER_KEYBYTES], const poly *data) { | |||
size_t i, j; | |||
memset(bytes, 0, SABER_KEYBYTES); | |||
for (j = 0; j < SABER_KEYBYTES; j++) { | |||
for (i = 0; i < 8; i++) { | |||
bytes[j] = bytes[j] | ((data->coeffs[j * 8 + i] & 0x01) << i); | |||
} | |||
} | |||
} |
@@ -0,0 +1,28 @@ | |||
#ifndef PACK_UNPACK_H | |||
#define PACK_UNPACK_H | |||
#include "SABER_params.h" | |||
#include "poly.h" | |||
#include <stdint.h> | |||
#include <stdio.h> | |||
void PQCLEAN_SABER_AVX2_POLT2BS(uint8_t bytes[SABER_SCALEBYTES_KEM], const poly *data); | |||
void PQCLEAN_SABER_AVX2_BS2POLT(poly *data, const uint8_t bytes[SABER_SCALEBYTES_KEM]); | |||
void PQCLEAN_SABER_AVX2_POLVECq2BS(uint8_t bytes[SABER_POLYVECBYTES], const poly data[SABER_L]); | |||
void PQCLEAN_SABER_AVX2_POLVECp2BS(uint8_t bytes[SABER_POLYVECCOMPRESSEDBYTES], const poly data[SABER_L]); | |||
void PQCLEAN_SABER_AVX2_BS2POLVECq(poly data[SABER_L], const uint8_t bytes[SABER_POLYVECBYTES]); | |||
void PQCLEAN_SABER_AVX2_BS2POLVECp(poly data[SABER_L], const uint8_t bytes[SABER_POLYVECCOMPRESSEDBYTES]); | |||
void PQCLEAN_SABER_AVX2_BS2POLmsg(poly *data, const uint8_t bytes[SABER_KEYBYTES]); | |||
void PQCLEAN_SABER_AVX2_POLmsg2BS(uint8_t bytes[SABER_KEYBYTES], const poly *data); | |||
#endif |
@@ -0,0 +1,62 @@ | |||
#include "cbd.h" | |||
#include "fips202.h" | |||
#include "pack_unpack.h" | |||
#include "poly.h" | |||
void PQCLEAN_SABER_AVX2_MatrixVectorMul(poly c[SABER_L], const poly A[SABER_L][SABER_L], const toom4_points s_eval[SABER_L], int transpose) { | |||
size_t i, j; | |||
toom4_points_product c_eval; | |||
if (transpose) { | |||
for (i = 0; i < SABER_L; i++) { | |||
PQCLEAN_SABER_AVX2_toom4_mul_A_by_B_eval(&c_eval, &A[0][i], &s_eval[0], 0); | |||
for (j = 1; j < SABER_L; j++) { | |||
PQCLEAN_SABER_AVX2_toom4_mul_A_by_B_eval(&c_eval, &A[j][i], &s_eval[j], 1); | |||
} | |||
PQCLEAN_SABER_AVX2_toom4_interp(&c[i], &c_eval); | |||
} | |||
} else { | |||
for (i = 0; i < SABER_L; i++) { | |||
PQCLEAN_SABER_AVX2_toom4_mul_A_by_B_eval(&c_eval, &A[i][0], &s_eval[0], 0); | |||
for (j = 1; j < SABER_L; j++) { | |||
PQCLEAN_SABER_AVX2_toom4_mul_A_by_B_eval(&c_eval, &A[i][j], &s_eval[j], 1); | |||
} | |||
PQCLEAN_SABER_AVX2_toom4_interp(&c[i], &c_eval); | |||
} | |||
} | |||
} | |||
void PQCLEAN_SABER_AVX2_InnerProd(poly *c, const poly b[SABER_L], const toom4_points s_eval[SABER_L]) { | |||
size_t i; | |||
toom4_points_product c_eval; //Holds results for 9 Karatsuba at a time | |||
PQCLEAN_SABER_AVX2_toom4_mul_A_by_B_eval(&c_eval, &b[0], &s_eval[0], 0); | |||
for (i = 1; i < SABER_L; i++) { | |||
PQCLEAN_SABER_AVX2_toom4_mul_A_by_B_eval(&c_eval, &b[i], &s_eval[i], 1); | |||
} | |||
PQCLEAN_SABER_AVX2_toom4_interp(c, &c_eval); | |||
} | |||
void PQCLEAN_SABER_AVX2_GenMatrix(poly A[SABER_L][SABER_L], const uint8_t seed[SABER_SEEDBYTES]) { | |||
size_t i; | |||
uint8_t buf[SABER_L * SABER_POLYVECBYTES]; | |||
shake128(buf, sizeof(buf), seed, SABER_SEEDBYTES); | |||
for (i = 0; i < SABER_L; i++) { | |||
PQCLEAN_SABER_AVX2_BS2POLVECq(A[i], buf + i * SABER_POLYVECBYTES); | |||
} | |||
} | |||
void PQCLEAN_SABER_AVX2_GenSecret(poly s[SABER_L], const uint8_t seed[SABER_NOISESEEDBYTES]) { | |||
size_t i; | |||
uint8_t buf[SABER_L * SABER_POLYCOINBYTES]; | |||
shake128(buf, sizeof(buf), seed, SABER_NOISESEEDBYTES); | |||
for (i = 0; i < SABER_L; i++) { | |||
PQCLEAN_SABER_AVX2_cbd(s[i].coeffs, buf + i * SABER_POLYCOINBYTES); | |||
} | |||
} |
@@ -0,0 +1,38 @@ | |||
#ifndef POLY_H | |||
#define POLY_H | |||
#include "SABER_params.h" | |||
#include <immintrin.h> | |||
#include <stdint.h> | |||
typedef union { | |||
uint16_t coeffs[SABER_N]; | |||
__m256i dummy; | |||
} poly; | |||
typedef union { | |||
uint16_t coeffs[4 * SABER_N]; | |||
__m256i dummy; | |||
} toom4_points; | |||
typedef union { | |||
uint16_t coeffs[8 * SABER_N]; | |||
__m256i dummy; | |||
} toom4_points_product; | |||
void PQCLEAN_SABER_AVX2_MatrixVectorMul(poly c[SABER_L], const poly A[SABER_L][SABER_L], const toom4_points s_eval[SABER_L], int transpose); | |||
void PQCLEAN_SABER_AVX2_InnerProd(poly *c, const poly b[SABER_L], const toom4_points s_eval[SABER_L]); | |||
void PQCLEAN_SABER_AVX2_GenMatrix(poly a[SABER_L][SABER_L], const uint8_t seed[SABER_SEEDBYTES]); | |||
void PQCLEAN_SABER_AVX2_GenSecret(poly s[SABER_L], const uint8_t seed[SABER_NOISESEEDBYTES]); | |||
void PQCLEAN_SABER_AVX2_toom4_interp(poly *res_avx, const toom4_points_product *c_eval); | |||
void PQCLEAN_SABER_AVX2_toom4_eval(toom4_points *b_eval, const poly *b); | |||
void PQCLEAN_SABER_AVX2_toom4_mul_A_by_B_eval(toom4_points_product *c_eval, const poly *a_avx, const toom4_points *b_eval, int accumulate); | |||
#endif |
@@ -0,0 +1,35 @@ | |||
#include "verify.h" | |||
/*------------------------------------------------- | |||
This file has been adapted from the implementation | |||
(available at https://github.com/pq-crystals/kyber) of | |||
"CRYSTALS – Kyber: a CCA-secure module-lattice-based KEM" | |||
by : Joppe Bos, Leo Ducas, Eike Kiltz, Tancrede Lepoint, | |||
Vadim Lyubashevsky, John M. Schanck, Peter Schwabe & Damien stehle | |||
----------------------------------------------------*/ | |||
/* returns 0 for equal strings, 1 for non-equal strings */ | |||
uint8_t PQCLEAN_SABER_AVX2_verify(const uint8_t *a, const uint8_t *b, size_t len) { | |||
uint64_t r; | |||
size_t i; | |||
r = 0; | |||
for (i = 0; i < len; i++) { | |||
r |= a[i] ^ b[i]; | |||
} | |||
r = (~r + 1); // Two's complement | |||
r >>= 63; | |||
return (uint8_t) r; | |||
} | |||
/* b = 1 means mov, b = 0 means don't mov*/ | |||
void PQCLEAN_SABER_AVX2_cmov(uint8_t *r, const uint8_t *x, size_t len, uint8_t b) { | |||
size_t i; | |||
b = -b; | |||
for (i = 0; i < len; i++) { | |||
r[i] ^= b & (x[i] ^ r[i]); | |||
} | |||
} |
@@ -0,0 +1,22 @@ | |||
#ifndef VERIFY_H | |||
#define VERIFY_H | |||
/*------------------------------------------------- | |||
This file has been adapted from the implementation | |||
(available at https://github.com/pq-crystals/kyber) of | |||
"CRYSTALS – Kyber: a CCA-secure module-lattice-based KEM" | |||
by : Joppe Bos, Leo Ducas, Eike Kiltz, Tancrede Lepoint, | |||
Vadim Lyubashevsky, John M. Schanck, Peter Schwabe & Damien stehle | |||
----------------------------------------------------*/ | |||
#include <stddef.h> | |||
#include <stdint.h> | |||
/* returns 0 for equal strings, 1 for non-equal strings */ | |||
uint8_t PQCLEAN_SABER_AVX2_verify(const uint8_t *a, const uint8_t *b, size_t len); | |||
/* b = 1 means mov, b = 0 means don't mov*/ | |||
void PQCLEAN_SABER_AVX2_cmov(uint8_t *r, const uint8_t *x, size_t len, uint8_t b); | |||
#endif |
@@ -1,8 +1 @@ | |||
SABER_v1.1 | |||
Public domain | |||
Authors: Jan-Pieter D'Anvers, Angshuman Karmakar, Sujoy Sinha Roy, | |||
Frederik Vercauteren | |||
Public Domain |
@@ -1,10 +1,10 @@ | |||
# This Makefile can be used with GNU Make or BSD Make | |||
LIB=libsaber_clean.a | |||
HEADERS=api.h cbd.h poly.h poly_mul.h SABER_indcpa.h SABER_params.h verify.h pack_unpack.h | |||
HEADERS=api.h cbd.h pack_unpack.h poly.h poly_mul.h SABER_indcpa.h SABER_params.h verify.h | |||
OBJECTS=cbd.o kem.o pack_unpack.o poly.o poly_mul.o SABER_indcpa.o verify.o | |||
CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) | |||
CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -Werror -Wredundant-decls -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) | |||
all: $(LIB) | |||
@@ -3,296 +3,111 @@ | |||
#include "fips202.h" | |||
#include "pack_unpack.h" | |||
#include "poly.h" | |||
#include "poly_mul.h" | |||
#include "randombytes.h" | |||
#include <stdint.h> | |||
#include <string.h> | |||
#define h1 (1 << (SABER_EQ - SABER_EP - 1)) | |||
#define h2 ((1 << (SABER_EP - 2)) - (1 << (SABER_EP - SABER_ET - 1)) + (1 << (SABER_EQ - SABER_EP - 1))) | |||
void PQCLEAN_SABER_CLEAN_indcpa_kem_keypair(uint8_t pk[SABER_INDCPA_PUBLICKEYBYTES], uint8_t sk[SABER_INDCPA_SECRETKEYBYTES]) { | |||
size_t i, j; | |||
/*----------------------------------------------------------------------------------- | |||
This routine generates a=[Matrix K x K] of 256-coefficient polynomials | |||
poly A[SABER_L][SABER_L]; | |||
poly s[SABER_L]; | |||
poly res[SABER_L]; | |||
#define h1 4 //2^(EQ-EP-1) | |||
uint8_t rand[SABER_NOISESEEDBYTES]; | |||
uint8_t *seed_A = pk + SABER_POLYVECCOMPRESSEDBYTES; | |||
#define h2 ( (1<<(SABER_EP-2)) - (1<<(SABER_EP-SABER_ET-1)) + (1<<(SABER_EQ-SABER_EP-1)) ) | |||
randombytes(seed_A, SABER_SEEDBYTES); | |||
shake128(seed_A, SABER_SEEDBYTES, seed_A, SABER_SEEDBYTES); // for not revealing system RNG state | |||
static void InnerProd(uint16_t pkcl[SABER_K][SABER_N], uint16_t skpv[SABER_K][SABER_N], uint16_t mod, uint16_t res[SABER_N]); | |||
static void MatrixVectorMul(polyvec *a, uint16_t skpv[SABER_K][SABER_N], uint16_t res[SABER_K][SABER_N], uint16_t mod, int16_t transpose); | |||
randombytes(rand, SABER_NOISESEEDBYTES); | |||
PQCLEAN_SABER_CLEAN_GenSecret(s, rand); | |||
PQCLEAN_SABER_CLEAN_POLVECq2BS(sk, s); | |||
static void POL2MSG(const uint16_t *message_dec_unpacked, unsigned char *message_dec); | |||
PQCLEAN_SABER_CLEAN_GenMatrix(A, seed_A); // sample matrix A | |||
PQCLEAN_SABER_CLEAN_MatrixVectorMul(res, (const poly (*)[SABER_L])A, (const poly *)s, 1); // Matrix in transposed order | |||
static void GenMatrix(polyvec *a, const unsigned char *seed) { | |||
unsigned char buf[SABER_K * SABER_K * (13 * SABER_N / 8)]; | |||
uint16_t temp_ar[SABER_N]; | |||
int i, j, k; | |||
uint16_t mod = (SABER_Q - 1); | |||
shake128(buf, sizeof(buf), seed, SABER_SEEDBYTES); | |||
for (i = 0; i < SABER_K; i++) { | |||
for (j = 0; j < SABER_K; j++) { | |||
PQCLEAN_SABER_CLEAN_BS2POL(buf + (i * SABER_K + j) * (13 * SABER_N / 8), temp_ar); | |||
for (k = 0; k < SABER_N; k++) { | |||
a[i].vec[j].coeffs[k] = (temp_ar[k])& mod ; | |||
} | |||
} | |||
} | |||
} | |||
void PQCLEAN_SABER_CLEAN_indcpa_kem_keypair(unsigned char *pk, unsigned char *sk) { | |||
polyvec a[SABER_K]; | |||
uint16_t skpv[SABER_K][SABER_N]; | |||
unsigned char seed[SABER_SEEDBYTES]; | |||
unsigned char noiseseed[SABER_COINBYTES]; | |||
int32_t i, j; | |||
uint16_t mod_q = SABER_Q - 1; | |||
uint16_t res[SABER_K][SABER_N]; | |||
randombytes(seed, SABER_SEEDBYTES); | |||
// for not revealing system RNG state | |||
shake128(seed, SABER_SEEDBYTES, seed, SABER_SEEDBYTES); | |||
randombytes(noiseseed, SABER_COINBYTES); | |||
GenMatrix(a, seed); //sample matrix A | |||
// generate secret from constant-time binomial distribution | |||
PQCLEAN_SABER_CLEAN_GenSecret(skpv, noiseseed); | |||
// do the matrix vector multiplication and rounding | |||
for (i = 0; i < SABER_K; i++) { | |||
for (j = 0; j < SABER_N; j++) { | |||
res[i][j] = 0; | |||
} | |||
} | |||
MatrixVectorMul(a, skpv, res, SABER_Q - 1, 1); | |||
// now rounding | |||
for (i = 0; i < SABER_K; i++) { | |||
// rounding | |||
for (i = 0; i < SABER_L; i++) { | |||
for (j = 0; j < SABER_N; j++) { | |||
// shift right 3 bits | |||
res[i][j] = (res[i][j] + h1) & (mod_q); | |||
res[i][j] = (res[i][j] >> (SABER_EQ - SABER_EP)); | |||
res[i].coeffs[j] += h1; | |||
res[i].coeffs[j] >>= SABER_EQ - SABER_EP; | |||
res[i].coeffs[j] &= SABER_Q - 1; | |||
} | |||
} | |||
// unload and pack sk=3 x (256 coefficients of 14 bits) | |||
PQCLEAN_SABER_CLEAN_POLVEC2BS(sk, skpv, SABER_Q); | |||
// unload and pack pk=256 bits seed and 3 x (256 coefficients of 11 bits) | |||
// load the public-key coefficients | |||
PQCLEAN_SABER_CLEAN_POLVEC2BS(pk, res, SABER_P); | |||
// now load the seedbytes in PK. Easy since seed bytes are kept in byte format. | |||
for (i = 0; i < SABER_SEEDBYTES; i++) { | |||
pk[SABER_POLYVECCOMPRESSEDBYTES + i] = seed[i]; | |||
} | |||
PQCLEAN_SABER_CLEAN_POLVECp2BS(pk, res); // pack public key | |||
} | |||
void PQCLEAN_SABER_CLEAN_indcpa_kem_enc(const unsigned char *message_received, unsigned char *noiseseed, const unsigned char *pk, unsigned char *ciphertext) { | |||
uint32_t i, j, k; | |||
polyvec a[SABER_K]; | |||
unsigned char seed[SABER_SEEDBYTES]; | |||
// public key of received by the client | |||
uint16_t pkcl[SABER_K][SABER_N]; | |||
uint16_t skpv1[SABER_K][SABER_N]; | |||
uint16_t message[SABER_KEYBYTES * 8]; | |||
uint16_t res[SABER_K][SABER_N]; | |||
uint16_t mod_p = SABER_P - 1; | |||
uint16_t mod_q = SABER_Q - 1; | |||
uint16_t vprime[SABER_N]; | |||
unsigned char msk_c[SABER_SCALEBYTES_KEM]; | |||
void PQCLEAN_SABER_CLEAN_indcpa_kem_enc(uint8_t ciphertext[SABER_BYTES_CCA_DEC], const uint8_t m[SABER_KEYBYTES], const uint8_t noiseseed[SABER_NOISESEEDBYTES], const uint8_t pk[SABER_INDCPA_PUBLICKEYBYTES]) { | |||
size_t i, j; | |||
// extract the seedbytes from Public Key. | |||
for (i = 0; i < SABER_SEEDBYTES; i++) { | |||
seed[i] = pk[ SABER_POLYVECCOMPRESSEDBYTES + i]; | |||
} | |||
poly A[SABER_L][SABER_L]; | |||
poly res[SABER_L]; | |||
poly s[SABER_L]; | |||
poly *temp = A[0]; // re-use stack space | |||
poly *vprime = &A[0][0]; | |||
poly *message = &A[0][1]; | |||
GenMatrix(a, seed); | |||
const uint8_t *seed_A = pk + SABER_POLYVECCOMPRESSEDBYTES; | |||
uint8_t *msk_c = ciphertext + SABER_POLYVECCOMPRESSEDBYTES; | |||
// generate secret from constant-time binomial distribution | |||
PQCLEAN_SABER_CLEAN_GenSecret(skpv1, noiseseed); | |||
PQCLEAN_SABER_CLEAN_GenSecret(s, noiseseed); | |||
PQCLEAN_SABER_CLEAN_GenMatrix(A, seed_A); | |||
PQCLEAN_SABER_CLEAN_MatrixVectorMul(res, (const poly (*)[SABER_L])A, (const poly *)s, 0); // 0 => not transposed | |||
// matrix-vector multiplication and rounding | |||
for (i = 0; i < SABER_K; i++) { | |||
for (j = 0; j < SABER_N; j++) { | |||
res[i][j] = 0; | |||
} | |||
} | |||
MatrixVectorMul(a, skpv1, res, SABER_Q - 1, 0); | |||
// now rounding | |||
//shift right 3 bits | |||
for (i = 0; i < SABER_K; i++) { | |||
for (j = 0; j < SABER_N; j++) { | |||
res[i][j] = ( res[i][j] + h1 ) & mod_q; | |||
res[i][j] = (res[i][j] >> (SABER_EQ - SABER_EP) ); | |||
} | |||
} | |||
PQCLEAN_SABER_CLEAN_POLVEC2BS(ciphertext, res, SABER_P); | |||
// ************client matrix-vector multiplication ends************ | |||
// now calculate the v' | |||
// unpack the public_key | |||
// pkcl is the b in the protocol | |||
PQCLEAN_SABER_CLEAN_BS2POLVEC(pk, pkcl, SABER_P); | |||
for (i = 0; i < SABER_N; i++) { | |||
vprime[i] = 0; | |||
} | |||
for (i = 0; i < SABER_K; i++) { | |||
// rounding | |||
for (i = 0; i < SABER_L; i++) { //shift right EQ-EP bits | |||
for (j = 0; j < SABER_N; j++) { | |||
skpv1[i][j] = skpv1[i][j] & (mod_p); | |||
res[i].coeffs[j] += h1; | |||
res[i].coeffs[j] >>= SABER_EQ - SABER_EP; | |||
res[i].coeffs[j] &= SABER_Q - 1; | |||
} | |||
} | |||
PQCLEAN_SABER_CLEAN_POLVECp2BS(ciphertext, res); | |||
// vector-vector scalar multiplication with mod p | |||
InnerProd(pkcl, skpv1, mod_p, vprime); | |||
PQCLEAN_SABER_CLEAN_BS2POLVECp(temp, pk); | |||
PQCLEAN_SABER_CLEAN_InnerProd(vprime, temp, s); | |||
PQCLEAN_SABER_CLEAN_BS2POLmsg(message, m); | |||
// addition of h1 to vprime | |||
for (i = 0; i < SABER_N; i++) { | |||
vprime[i] = vprime[i] + h1; | |||
vprime->coeffs[i] += h1 - (message->coeffs[i] << (SABER_EP - 1)); | |||
vprime->coeffs[i] &= SABER_P - 1; | |||
vprime->coeffs[i] >>= SABER_EP - SABER_ET; | |||
} | |||
// unpack message_received; | |||
for (j = 0; j < SABER_KEYBYTES; j++) { | |||
for (i = 0; i < 8; i++) { | |||
message[8 * j + i] = ((message_received[j] >> i) & 0x01); | |||
} | |||
} | |||
// message encoding | |||
for (i = 0; i < SABER_N; i++) { | |||
message[i] = (message[i] << (SABER_EP - 1)); | |||
} | |||
for (k = 0; k < SABER_N; k++) { | |||
vprime[k] = ( (vprime[k] - message[k]) & (mod_p) ) >> (SABER_EP - SABER_ET); | |||
} | |||
PQCLEAN_SABER_CLEAN_pack_4bit(msk_c, vprime); | |||
for (j = 0; j < SABER_SCALEBYTES_KEM; j++) { | |||
ciphertext[SABER_POLYVECCOMPRESSEDBYTES + j] = msk_c[j]; | |||
} | |||
PQCLEAN_SABER_CLEAN_POLT2BS(msk_c, vprime); | |||
} | |||
void PQCLEAN_SABER_CLEAN_indcpa_kem_dec(const unsigned char *sk, const unsigned char *ciphertext, unsigned char message_dec[]) { | |||
uint32_t i, j; | |||
// secret key of the server | |||
uint16_t sksv[SABER_K][SABER_N]; | |||
uint16_t pksv[SABER_K][SABER_N]; | |||
uint8_t scale_ar[SABER_SCALEBYTES_KEM]; | |||
uint16_t mod_p = SABER_P - 1; | |||
uint16_t v[SABER_N]; | |||
uint16_t op[SABER_N]; | |||
void PQCLEAN_SABER_CLEAN_indcpa_kem_dec(uint8_t m[SABER_KEYBYTES], const uint8_t sk[SABER_INDCPA_SECRETKEYBYTES], const uint8_t ciphertext[SABER_BYTES_CCA_DEC]) { | |||
size_t i; | |||
// sksv is the secret-key | |||
PQCLEAN_SABER_CLEAN_BS2POLVEC(sk, sksv, SABER_Q); | |||
// pksv is the ciphertext | |||
PQCLEAN_SABER_CLEAN_BS2POLVEC(ciphertext, pksv, SABER_P); | |||
poly temp[SABER_L]; | |||
poly s[SABER_L]; | |||
// vector-vector scalar multiplication with mod p | |||
for (i = 0; i < SABER_N; i++) { | |||
v[i] = 0; | |||
} | |||
for (i = 0; i < SABER_K; i++) { | |||
for (j = 0; j < SABER_N; j++) { | |||
sksv[i][j] = sksv[i][j] & (mod_p); | |||
} | |||
} | |||
InnerProd(pksv, sksv, mod_p, v); | |||
const uint8_t *packed_cm = ciphertext + SABER_POLYVECCOMPRESSEDBYTES; | |||
poly *v = &temp[0]; | |||
poly *cm = &temp[1]; | |||
//Extraction | |||
for (i = 0; i < SABER_SCALEBYTES_KEM; i++) { | |||
scale_ar[i] = ciphertext[SABER_POLYVECCOMPRESSEDBYTES + i]; | |||
} | |||
PQCLEAN_SABER_CLEAN_BS2POLVECq(s, sk); | |||
PQCLEAN_SABER_CLEAN_BS2POLVECp(temp, ciphertext); | |||
PQCLEAN_SABER_CLEAN_InnerProd(&temp[0], temp, s); | |||
PQCLEAN_SABER_CLEAN_un_pack4bit(scale_ar, op); | |||
PQCLEAN_SABER_CLEAN_BS2POLT(cm, packed_cm); | |||
//addition of h1 | |||
for (i = 0; i < SABER_N; i++) { | |||
v[i] = ( ( v[i] + h2 - (op[i] << (SABER_EP - SABER_ET)) ) & (mod_p) ) >> (SABER_EP - 1); | |||
v->coeffs[i] += h2 - (cm->coeffs[i] << (SABER_EP - SABER_ET)); | |||
v->coeffs[i] &= SABER_P - 1; | |||
v->coeffs[i] >>= SABER_EP - 1; | |||
} | |||
// pack decrypted message | |||
POL2MSG(v, message_dec); | |||
} | |||
static void MatrixVectorMul(polyvec *a, uint16_t skpv[SABER_K][SABER_N], uint16_t res[SABER_K][SABER_N], uint16_t mod, int16_t transpose) { | |||
uint16_t acc[SABER_N]; | |||
int32_t i, j, k; | |||
if (transpose == 1) { | |||
for (i = 0; i < SABER_K; i++) { | |||
for (j = 0; j < SABER_K; j++) { | |||
PQCLEAN_SABER_CLEAN_pol_mul((uint16_t *)&a[j].vec[i], skpv[j], acc, SABER_Q, SABER_N); | |||
for (k = 0; k < SABER_N; k++) { | |||
res[i][k] = res[i][k] + acc[k]; | |||
//reduction mod p | |||
res[i][k] = (res[i][k] & mod); | |||
//clear the accumulator | |||
acc[k] = 0; | |||
} | |||
} | |||
} | |||
} else { | |||
for (i = 0; i < SABER_K; i++) { | |||
for (j = 0; j < SABER_K; j++) { | |||
PQCLEAN_SABER_CLEAN_pol_mul((uint16_t *)&a[i].vec[j], skpv[j], acc, SABER_Q, SABER_N); | |||
for (k = 0; k < SABER_N; k++) { | |||
res[i][k] = res[i][k] + acc[k]; | |||
// reduction | |||
res[i][k] = res[i][k] & mod; | |||
// clear the accumulator | |||
acc[k] = 0; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
static void POL2MSG(const uint16_t *message_dec_unpacked, unsigned char *message_dec) { | |||
int32_t i, j; | |||
for (j = 0; j < SABER_KEYBYTES; j++) { | |||
message_dec[j] = 0; | |||
for (i = 0; i < 8; i++) { | |||
message_dec[j] = message_dec[j] | (uint8_t) (message_dec_unpacked[j * 8 + i] << i); | |||
} | |||
} | |||
} | |||
static void InnerProd(uint16_t pkcl[SABER_K][SABER_N], uint16_t skpv[SABER_K][SABER_N], uint16_t mod, uint16_t res[SABER_N]) { | |||
uint32_t j, k; | |||
uint16_t acc[SABER_N]; | |||
// vector-vector scalar multiplication with mod p | |||
for (j = 0; j < SABER_K; j++) { | |||
PQCLEAN_SABER_CLEAN_pol_mul(pkcl[j], skpv[j], acc, SABER_P, SABER_N); | |||
for (k = 0; k < SABER_N; k++) { | |||
res[k] = res[k] + acc[k]; | |||
// reduction | |||
res[k] = res[k] & mod; | |||
// clear the accumulator | |||
acc[k] = 0; | |||
} | |||
} | |||
PQCLEAN_SABER_CLEAN_POLmsg2BS(m, v); | |||
} |
@@ -1,9 +1,13 @@ | |||
#ifndef INDCPA_H | |||
#define INDCPA_H | |||
#include "SABER_params.h" | |||
#include <stdint.h> | |||
void PQCLEAN_SABER_CLEAN_indcpa_kem_keypair(unsigned char *pk, unsigned char *sk); | |||
void PQCLEAN_SABER_CLEAN_indcpa_kem_enc(const unsigned char *message, unsigned char *noiseseed, const unsigned char *pk, unsigned char *ciphertext); | |||
void PQCLEAN_SABER_CLEAN_indcpa_kem_dec(const unsigned char *sk, const unsigned char *ciphertext, unsigned char *message_dec); | |||
void PQCLEAN_SABER_CLEAN_indcpa_kem_keypair(uint8_t pk[SABER_INDCPA_PUBLICKEYBYTES], uint8_t sk[SABER_INDCPA_SECRETKEYBYTES]); | |||
#endif | |||
void PQCLEAN_SABER_CLEAN_indcpa_kem_enc(uint8_t ciphertext[SABER_BYTES_CCA_DEC], const uint8_t m[SABER_KEYBYTES], const uint8_t noiseseed[SABER_NOISESEEDBYTES], const uint8_t pk[SABER_INDCPA_PUBLICKEYBYTES]); | |||
void PQCLEAN_SABER_CLEAN_indcpa_kem_dec(uint8_t m[SABER_KEYBYTES], const uint8_t sk[SABER_INDCPA_SECRETKEYBYTES], const uint8_t ciphertext[SABER_BYTES_CCA_DEC]); | |||
#endif |
@@ -1,50 +1,41 @@ | |||
#ifndef PARAMS_H | |||
#define PARAMS_H | |||
#include "api.h" | |||
#define SABER_K 3 | |||
/* Don't change anything below this line */ | |||
#define SABER_L 3 | |||
#define SABER_MU 8 | |||
#define SABER_ET 4 | |||
#define SABER_EQ 13 | |||
#define SABER_EP 10 | |||
#define SABER_N 256 | |||
#define SABER_Q 8192 | |||
#define SABER_P 1024 | |||
#define SABER_SEEDBYTES 32 | |||
#define SABER_NOISESEEDBYTES 32 | |||
#define SABER_COINBYTES 32 | |||
#define SABER_KEYBYTES 32 | |||
#define SABER_HASHBYTES 32 | |||
#define SABER_EP 10 | |||
#define SABER_P (1 << SABER_EP) | |||
#define SABER_POLYBYTES 416 //13*256/8 | |||
#define SABER_EQ 13 | |||
#define SABER_Q (1 << SABER_EQ) | |||
#define SABER_POLYVECBYTES (SABER_K * SABER_POLYBYTES) | |||
#define SABER_SEEDBYTES 32 | |||
#define SABER_NOISESEEDBYTES 32 | |||
#define SABER_KEYBYTES 32 | |||
#define SABER_HASHBYTES 32 | |||
#define SABER_POLYVECCOMPRESSEDBYTES (SABER_K * 320) //10*256/8 NOTE : changed till here due to parameter adaptation | |||
#define SABER_POLYCOINBYTES (SABER_MU * SABER_N / 8) | |||
#define SABER_CIPHERTEXTBYTES (SABER_POLYVECCOMPRESSEDBYTES) | |||
#define SABER_POLYBYTES (SABER_EQ * SABER_N / 8) | |||
#define SABER_POLYVECBYTES (SABER_L * SABER_POLYBYTES) | |||
#define SABER_SCALEBYTES (SABER_DELTA*SABER_N/8) | |||
#define SABER_POLYCOMPRESSEDBYTES (SABER_EP * SABER_N / 8) | |||
#define SABER_POLYVECCOMPRESSEDBYTES (SABER_L * SABER_POLYCOMPRESSEDBYTES) | |||
#define SABER_SCALEBYTES_KEM ((SABER_ET)*SABER_N/8) | |||
#define SABER_SCALEBYTES_KEM (SABER_ET * SABER_N / 8) | |||
#define SABER_INDCPA_PUBLICKEYBYTES (SABER_POLYVECCOMPRESSEDBYTES + SABER_SEEDBYTES) | |||
#define SABER_INDCPA_SECRETKEYBYTES (SABER_POLYVECBYTES) | |||
#define SABER_PUBLICKEYBYTES (SABER_INDCPA_PUBLICKEYBYTES) | |||
#define SABER_SECRETKEYBYTES (SABER_INDCPA_SECRETKEYBYTES + SABER_INDCPA_PUBLICKEYBYTES + SABER_HASHBYTES + SABER_KEYBYTES) | |||
#define SABER_SECRETKEYBYTES (SABER_INDCPA_SECRETKEYBYTES + SABER_INDCPA_PUBLICKEYBYTES + SABER_HASHBYTES + SABER_KEYBYTES) | |||
#define SABER_BYTES_CCA_DEC (SABER_POLYVECCOMPRESSEDBYTES + SABER_SCALEBYTES_KEM) /* Second part is for Targhi-Unruh */ | |||
#define SABER_BYTES_CCA_DEC (SABER_POLYVECCOMPRESSEDBYTES + SABER_SCALEBYTES_KEM) | |||
#endif | |||
@@ -1,14 +1,18 @@ | |||
#ifndef PQCLEAN_SABER_CLEAN_API_H | |||
#define PQCLEAN_SABER_CLEAN_API_H | |||
#define PQCLEAN_SABER_CLEAN_CRYPTO_ALGNAME "Saber" | |||
#define PQCLEAN_SABER_CLEAN_CRYPTO_SECRETKEYBYTES 2304 | |||
#define PQCLEAN_SABER_CLEAN_CRYPTO_PUBLICKEYBYTES (3*320+32) | |||
#define PQCLEAN_SABER_CLEAN_CRYPTO_BYTES 32 | |||
#define PQCLEAN_SABER_CLEAN_CRYPTO_CIPHERTEXTBYTES 1088 | |||
#define PQCLEAN_SABER_CLEAN_CRYPTO_PUBLICKEYBYTES 992 | |||
#define PQCLEAN_SABER_CLEAN_CRYPTO_SECRETKEYBYTES 2304 | |||
int PQCLEAN_SABER_CLEAN_crypto_kem_keypair(unsigned char *pk, unsigned char *sk); | |||
int PQCLEAN_SABER_CLEAN_crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk); | |||
int PQCLEAN_SABER_CLEAN_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk); | |||
#endif /* api_h */ | |||
int PQCLEAN_SABER_CLEAN_crypto_kem_enc(unsigned char *ct, unsigned char *k, const unsigned char *pk); | |||
int PQCLEAN_SABER_CLEAN_crypto_kem_dec(unsigned char *k, const unsigned char *ct, const unsigned char *sk); | |||
#endif /* PQCLEAN_SABER_CLEAN_API_H */ |
@@ -1,3 +1,7 @@ | |||
#include "SABER_params.h" | |||
#include "api.h" | |||
#include "cbd.h" | |||
#include <stdint.h> | |||
/*--------------------------------------------------------------------- | |||
This file has been adapted from the implementation | |||
(available at, Public Domain https://github.com/pq-crystals/kyber) | |||
@@ -6,12 +10,8 @@ by : Joppe Bos, Leo Ducas, Eike Kiltz, Tancrede Lepoint, | |||
Vadim Lyubashevsky, John M. Schanck, Peter Schwabe & Damien stehle | |||
----------------------------------------------------------------------*/ | |||
#include "SABER_params.h" | |||
#include "api.h" | |||
#include "cbd.h" | |||
#include <stdint.h> | |||
static uint64_t load_littleendian(const unsigned char *x, int bytes) { | |||
static uint64_t load_littleendian(const uint8_t *x, int bytes) { | |||
int i; | |||
uint64_t r = x[0]; | |||
for (i = 1; i < bytes; i++) { | |||
@@ -20,10 +20,7 @@ static uint64_t load_littleendian(const unsigned char *x, int bytes) { | |||
return r; | |||
} | |||
void PQCLEAN_SABER_CLEAN_cbd(uint16_t *r, const unsigned char *buf) { | |||
uint16_t Qmod_minus1 = SABER_Q - 1; | |||
void PQCLEAN_SABER_CLEAN_cbd(uint16_t s[SABER_N], const uint8_t buf[SABER_POLYCOINBYTES]) { | |||
uint32_t t, d, a[4], b[4]; | |||
int i, j; | |||
@@ -34,18 +31,18 @@ void PQCLEAN_SABER_CLEAN_cbd(uint16_t *r, const unsigned char *buf) { | |||
d += (t >> j) & 0x11111111; | |||
} | |||
a[0] = d & 0xf; | |||
b[0] = (d >> 4) & 0xf; | |||
a[1] = (d >> 8) & 0xf; | |||
a[0] = d & 0xf; | |||
b[0] = (d >> 4) & 0xf; | |||
a[1] = (d >> 8) & 0xf; | |||
b[1] = (d >> 12) & 0xf; | |||
a[2] = (d >> 16) & 0xf; | |||
b[2] = (d >> 20) & 0xf; | |||
a[3] = (d >> 24) & 0xf; | |||
b[3] = (d >> 28); | |||
r[4 * i + 0] = (uint16_t)(a[0] - b[0]) & Qmod_minus1; | |||
r[4 * i + 1] = (uint16_t)(a[1] - b[1]) & Qmod_minus1; | |||
r[4 * i + 2] = (uint16_t)(a[2] - b[2]) & Qmod_minus1; | |||
r[4 * i + 3] = (uint16_t)(a[3] - b[3]) & Qmod_minus1; | |||
s[4 * i + 0] = (uint16_t)(a[0] - b[0]); | |||
s[4 * i + 1] = (uint16_t)(a[1] - b[1]); | |||
s[4 * i + 2] = (uint16_t)(a[2] - b[2]); | |||
s[4 * i + 3] = (uint16_t)(a[3] - b[3]); | |||
} | |||
} |
@@ -1,6 +1,5 @@ | |||
#ifndef CBD_H | |||
#define CBD_H | |||
/*--------------------------------------------------------------------- | |||
This file has been adapted from the implementation | |||
(available at, Public Domain https://github.com/pq-crystals/kyber) | |||
@@ -8,10 +7,10 @@ of "CRYSTALS – Kyber: a CCA-secure module-lattice-based KEM" | |||
by : Joppe Bos, Leo Ducas, Eike Kiltz, Tancrede Lepoint, | |||
Vadim Lyubashevsky, John M. Schanck, Peter Schwabe & Damien stehle | |||
----------------------------------------------------------------------*/ | |||
#include "poly.h" | |||
#include "SABER_params.h" | |||
#include <stdint.h> | |||
void PQCLEAN_SABER_CLEAN_cbd(uint16_t *r, const unsigned char *buf); | |||
void PQCLEAN_SABER_CLEAN_cbd(uint16_t s[SABER_N], const uint8_t buf[SABER_POLYCOINBYTES]); | |||
#endif |
@@ -1,96 +1,77 @@ | |||
#include "SABER_indcpa.h" | |||
#include "SABER_params.h" | |||
#include "api.h" | |||
#include "fips202.h" | |||
#include "randombytes.h" | |||
#include "verify.h" | |||
#include <stddef.h> | |||
#include <stdint.h> | |||
#include <stdio.h> | |||
#include <string.h> | |||
int PQCLEAN_SABER_CLEAN_crypto_kem_keypair(unsigned char *pk, unsigned char *sk) { | |||
int i; | |||
// sk[0:SABER_INDCPA_SECRETKEYBYTES-1] <-- sk | |||
PQCLEAN_SABER_CLEAN_indcpa_kem_keypair(pk, sk); | |||
int PQCLEAN_SABER_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk) { | |||
size_t i; | |||
// sk[SABER_INDCPA_SECRETKEYBYTES:SABER_INDCPA_SECRETKEYBYTES+SABER_INDCPA_SECRETKEYBYTES-1] <-- pk | |||
PQCLEAN_SABER_CLEAN_indcpa_kem_keypair(pk, sk); // sk[0:SABER_INDCPA_SECRETKEYBYTES-1] <-- sk | |||
for (i = 0; i < SABER_INDCPA_PUBLICKEYBYTES; i++) { | |||
sk[i + SABER_INDCPA_SECRETKEYBYTES] = pk[i]; | |||
sk[i + SABER_INDCPA_SECRETKEYBYTES] = pk[i]; // sk[SABER_INDCPA_SECRETKEYBYTES:SABER_INDCPA_SECRETKEYBYTES+SABER_INDCPA_SECRETKEYBYTES-1] <-- pk | |||
} | |||
// Then hash(pk) is appended. | |||
sha3_256(sk + SABER_SECRETKEYBYTES - 64, pk, SABER_INDCPA_PUBLICKEYBYTES); | |||
sha3_256(sk + SABER_SECRETKEYBYTES - 64, pk, SABER_INDCPA_PUBLICKEYBYTES); // Then hash(pk) is appended. | |||
// Remaining part of sk contains a pseudo-random number. | |||
// This is output when check in crypto_kem_dec() fails. | |||
randombytes(sk + SABER_SECRETKEYBYTES - SABER_KEYBYTES, SABER_KEYBYTES ); | |||
randombytes(sk + SABER_SECRETKEYBYTES - SABER_KEYBYTES, SABER_KEYBYTES); // Remaining part of sk contains a pseudo-random number. | |||
// This is output when check in PQCLEAN_SABER_CLEAN_crypto_kem_dec() fails. | |||
return (0); | |||
} | |||
int PQCLEAN_SABER_CLEAN_crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk) { | |||
// Will contain key, coins | |||
unsigned char kr[64]; | |||
unsigned char buf[64]; | |||
int PQCLEAN_SABER_CLEAN_crypto_kem_enc(uint8_t *c, uint8_t *k, const uint8_t *pk) { | |||
randombytes(buf, 32); | |||
uint8_t kr[64]; // Will contain key, coins | |||
uint8_t buf[64]; | |||
// BUF[0:31] <-- random message (will be used as the key for client) Note: hash doesnot release system RNG output | |||
sha3_256(buf, buf, 32); | |||
randombytes(buf, 32); | |||
// BUF[32:63] <-- Hash(public key); Multitarget countermeasure for coins + contributory KEM | |||
sha3_256(buf + 32, pk, SABER_INDCPA_PUBLICKEYBYTES); | |||
sha3_256(buf, buf, 32); // BUF[0:31] <-- random message (will be used as the key for client) Note: hash doesnot release system RNG output | |||
// kr[0:63] <-- Hash(buf[0:63]); | |||
sha3_512(kr, buf, 64); | |||
sha3_256(buf + 32, pk, SABER_INDCPA_PUBLICKEYBYTES); // BUF[32:63] <-- Hash(public key); Multitarget countermeasure for coins + contributory KEM | |||
sha3_512(kr, buf, 64); // kr[0:63] <-- Hash(buf[0:63]); | |||
// K^ <-- kr[0:31] | |||
// noiseseed (r) <-- kr[32:63]; | |||
// buf[0:31] contains message; kr[32:63] contains randomness r; | |||
PQCLEAN_SABER_CLEAN_indcpa_kem_enc(buf, kr + 32, pk, ct); | |||
PQCLEAN_SABER_CLEAN_indcpa_kem_enc(c, buf, kr + 32, pk); // buf[0:31] contains message; kr[32:63] contains randomness r; | |||
sha3_256(kr + 32, ct, SABER_BYTES_CCA_DEC); | |||
sha3_256(kr + 32, c, SABER_BYTES_CCA_DEC); | |||
// hash concatenation of pre-k and h(c) to k | |||
sha3_256(ss, kr, 64); | |||
sha3_256(k, kr, 64); // hash concatenation of pre-k and h(c) to k | |||
return (0); | |||
} | |||
int PQCLEAN_SABER_CLEAN_crypto_kem_dec(uint8_t *k, const uint8_t *c, const uint8_t *sk) { | |||
size_t i; | |||
uint8_t fail; | |||
uint8_t cmp[SABER_BYTES_CCA_DEC]; | |||
uint8_t buf[64]; | |||
uint8_t kr[64]; // Will contain key, coins | |||
const uint8_t *pk = sk + SABER_INDCPA_SECRETKEYBYTES; | |||
int PQCLEAN_SABER_CLEAN_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk) { | |||
int i; | |||
unsigned char fail; | |||
unsigned char cmp[SABER_BYTES_CCA_DEC]; | |||
unsigned char buf[64]; | |||
// Will contain key, coins | |||
unsigned char kr[64]; | |||
const unsigned char *pk = sk + SABER_INDCPA_SECRETKEYBYTES; | |||
// buf[0:31] <-- message | |||
PQCLEAN_SABER_CLEAN_indcpa_kem_dec(sk, ct, buf); | |||
PQCLEAN_SABER_CLEAN_indcpa_kem_dec(buf, sk, c); // buf[0:31] <-- message | |||
// Multitarget countermeasure for coins + contributory KEM | |||
// Save hash by storing h(pk) in sk | |||
for (i = 0; i < 32; i++) { | |||
for (i = 0; i < 32; i++) { // Save hash by storing h(pk) in sk | |||
buf[32 + i] = sk[SABER_SECRETKEYBYTES - 64 + i]; | |||
} | |||
sha3_512(kr, buf, 64); | |||
PQCLEAN_SABER_CLEAN_indcpa_kem_enc(buf, kr + 32, pk, cmp); | |||
PQCLEAN_SABER_CLEAN_indcpa_kem_enc(cmp, buf, kr + 32, pk); | |||
fail = PQCLEAN_SABER_CLEAN_verify(ct, cmp, SABER_BYTES_CCA_DEC); | |||
fail = PQCLEAN_SABER_CLEAN_verify(c, cmp, SABER_BYTES_CCA_DEC); | |||
// overwrite coins in kr with h(c) | |||
sha3_256(kr + 32, ct, SABER_BYTES_CCA_DEC); | |||
sha3_256(kr + 32, c, SABER_BYTES_CCA_DEC); // overwrite coins in kr with h(c) | |||
PQCLEAN_SABER_CLEAN_cmov(kr, sk + SABER_SECRETKEYBYTES - SABER_KEYBYTES, SABER_KEYBYTES, fail); | |||
// hash concatenation of pre-k and h(c) to k | |||
sha3_256(ss, kr, 64); | |||
sha3_256(k, kr, 64); // hash concatenation of pre-k and h(c) to k | |||
return (0); | |||
} |
@@ -1,254 +1,147 @@ | |||
#include "SABER_params.h" | |||
#include "pack_unpack.h" | |||
#include "poly.h" | |||
#include <string.h> | |||
void PQCLEAN_SABER_CLEAN_pack_3bit(uint8_t *bytes, const uint16_t *data) { | |||
uint32_t j; | |||
uint32_t offset_data, offset_byte; | |||
for (j = 0; j < SABER_N / 8; j++) { | |||
offset_byte = 3 * j; | |||
offset_data = 8 * j; | |||
bytes[offset_byte + 0] = (data[offset_data + 0] & 0x7) | | |||
((data[offset_data + 1] & 0x7) << 3) | | |||
((data[offset_data + 2] & 0x3) << 6); | |||
bytes[offset_byte + 1] = ((data[offset_data + 2] >> 2 ) & 0x01) | | |||
((data[offset_data + 3] & 0x7) << 1) | | |||
((data[offset_data + 4] & 0x7) << 4) | | |||
(((data[offset_data + 5]) & 0x01) << 7); | |||
bytes[offset_byte + 2] = ((data[offset_data + 5] >> 1 ) & 0x03) | | |||
((data[offset_data + 6] & 0x7) << 2) | | |||
((data[offset_data + 7] & 0x7) << 5); | |||
void PQCLEAN_SABER_CLEAN_POLT2BS(uint8_t bytes[SABER_SCALEBYTES_KEM], const poly *data) { | |||
size_t j; | |||
const uint16_t *in = data->coeffs; | |||
uint8_t *out = bytes; | |||
for (j = 0; j < SABER_N / 2; j++) { | |||
out[0] = (uint8_t) ((in[0] & 0x0f) | (in[1] << 4)); | |||
in += 2; | |||
out += 1; | |||
} | |||
} | |||
void PQCLEAN_SABER_CLEAN_un_pack3bit(const uint8_t *bytes, uint16_t *data) { | |||
uint32_t j; | |||
uint32_t offset_data, offset_byte; | |||
for (j = 0; j < SABER_N / 8; j++) { | |||
offset_byte = 3 * j; | |||
offset_data = 8 * j; | |||
data[offset_data + 0] = (bytes[offset_byte + 0]) & 0x07; | |||
data[offset_data + 1] = ((bytes[offset_byte + 0]) >> 3 ) & 0x07; | |||
data[offset_data + 2] = (((bytes[offset_byte + 0]) >> 6 ) & 0x03) | | |||
(((bytes[offset_byte + 1]) & 0x01) << 2); | |||
data[offset_data + 3] = ((bytes[offset_byte + 1]) >> 1 ) & 0x07; | |||
data[offset_data + 4] = ((bytes[offset_byte + 1]) >> 4 ) & 0x07; | |||
data[offset_data + 5] = (((bytes[offset_byte + 1]) >> 7 ) & 0x01) | | |||
(((bytes[offset_byte + 2]) & 0x03) << 1); | |||
data[offset_data + 6] = ((bytes[offset_byte + 2] >> 2) & 0x07); | |||
data[offset_data + 7] = ((bytes[offset_byte + 2] >> 5) & 0x07); | |||
void PQCLEAN_SABER_CLEAN_BS2POLT(poly *data, const uint8_t bytes[SABER_SCALEBYTES_KEM]) { | |||
/* This function does not reduce its output mod T */ | |||
size_t j; | |||
const uint8_t *in = bytes; | |||
uint16_t *out = data->coeffs; | |||
for (j = 0; j < SABER_N / 2; j++) { | |||
out[0] = in[0]; | |||
out[1] = in[0] >> 4; | |||
in += 1; | |||
out += 2; | |||
} | |||
} | |||
void PQCLEAN_SABER_CLEAN_pack_4bit(uint8_t *bytes, const uint16_t *data) { | |||
uint32_t j; | |||
uint32_t offset_data; | |||
for (j = 0; j < SABER_N / 2; j++) { | |||
offset_data = 2 * j; | |||
bytes[j] = (data[offset_data] & 0x0f) | | |||
((data[offset_data + 1] & 0x0f) << 4); | |||
static void POLq2BS(uint8_t bytes[SABER_POLYBYTES], const poly *data) { | |||
size_t j; | |||
const uint16_t *in = data->coeffs; | |||
uint8_t *out = bytes; | |||
for (j = 0; j < SABER_N / 8; j++) { | |||
out[0] = (uint8_t) (in[0]); | |||
out[1] = (uint8_t) (((in[0] >> 8) & 0x1f) | (in[1] << 5)); | |||
out[2] = (uint8_t) (in[1] >> 3); | |||
out[3] = (uint8_t) (((in[1] >> 11) & 0x03) | (in[2] << 2)); | |||
out[4] = (uint8_t) (((in[2] >> 6) & 0x7f) | (in[3] << 7)); | |||
out[5] = (uint8_t) (in[3] >> 1); | |||
out[6] = (uint8_t) (((in[3] >> 9) & 0x0f) | (in[4] << 4)); | |||
out[7] = (uint8_t) (in[4] >> 4); | |||
out[8] = (uint8_t) (((in[4] >> 12) & 0x01) | (in[5] << 1)); | |||
out[9] = (uint8_t) (((in[5] >> 7) & 0x3f) | (in[6] << 6)); | |||
out[10] = (uint8_t) (in[6] >> 2); | |||
out[11] = (uint8_t) (((in[6] >> 10) & 0x07) | (in[7] << 3)); | |||
out[12] = (uint8_t) (in[7] >> 5); | |||
in += 8; | |||
out += 13; | |||
} | |||
} | |||
void PQCLEAN_SABER_CLEAN_un_pack4bit(const unsigned char *bytes, uint16_t *ar) { | |||
uint32_t j; | |||
uint32_t offset_data; | |||
for (j = 0; j < SABER_N / 2; j++) { | |||
offset_data = 2 * j; | |||
ar[offset_data] = bytes[j] & 0x0f; | |||
ar[offset_data + 1] = (bytes[j] >> 4) & 0x0f; | |||
static void BS2POLq(poly *data, const uint8_t bytes[SABER_POLYBYTES]) { | |||
/* This function does not reduce its output mod Q */ | |||
size_t j; | |||
const uint8_t *in = bytes; | |||
uint16_t *out = data->coeffs; | |||
for (j = 0; j < SABER_N / 8; j++) { | |||
out[0] = (in[0]) | (in[1] << 8); | |||
out[1] = (in[1] >> 5) | (in[2] << 3) | (in[3] << 11); | |||
out[2] = (in[3] >> 2) | (in[4] << 6); | |||
out[3] = (in[4] >> 7) | (in[5] << 1) | (in[6] << 9); | |||
out[4] = (in[6] >> 4) | (in[7] << 4) | (in[8] << 12); | |||
out[5] = (in[8] >> 1) | (in[9] << 7); | |||
out[6] = (in[9] >> 6) | (in[10] << 2) | (in[11] << 10); | |||
out[7] = (in[11] >> 3) | (in[12] << 5); | |||
in += 13; | |||
out += 8; | |||
} | |||
} | |||
void PQCLEAN_SABER_CLEAN_pack_6bit(uint8_t *bytes, const uint16_t *data) { | |||
uint32_t j; | |||
uint32_t offset_data, offset_byte; | |||
static void POLp2BS(uint8_t bytes[SABER_POLYCOMPRESSEDBYTES], const poly *data) { | |||
size_t j; | |||
const uint16_t *in = data->coeffs; | |||
uint8_t *out = bytes; | |||
for (j = 0; j < SABER_N / 4; j++) { | |||
offset_byte = 3 * j; | |||
offset_data = 4 * j; | |||
bytes[offset_byte + 0] = (data[offset_data + 0] & 0x3f) | | |||
((data[offset_data + 1] & 0x03) << 6); | |||
bytes[offset_byte + 1] = ((data[offset_data + 1] >> 2) & 0x0f) | | |||
((data[offset_data + 2] & 0x0f) << 4); | |||
bytes[offset_byte + 2] = ((data[offset_data + 2] >> 4) & 0x03) | | |||
((data[offset_data + 3] & 0x3f) << 2); | |||
out[0] = (uint8_t) (in[0]); | |||
out[1] = (uint8_t) (((in[0] >> 8) & 0x03) | (in[1] << 2)); | |||
out[2] = (uint8_t) (((in[1] >> 6) & 0x0f) | (in[2] << 4)); | |||
out[3] = (uint8_t) (((in[2] >> 4) & 0x3f) | (in[3] << 6)); | |||
out[4] = (uint8_t) (in[3] >> 2); | |||
in += 4; | |||
out += 5; | |||
} | |||
} | |||
void PQCLEAN_SABER_CLEAN_un_pack6bit(const unsigned char *bytes, uint16_t *data) { | |||
uint32_t j; | |||
uint32_t offset_data, offset_byte; | |||
static void BS2POLp(poly *data, const uint8_t bytes[SABER_POLYCOMPRESSEDBYTES]) { | |||
size_t j; | |||
const uint8_t *in = bytes; | |||
uint16_t *out = data->coeffs; | |||
for (j = 0; j < SABER_N / 4; j++) { | |||
offset_byte = 3 * j; | |||
offset_data = 4 * j; | |||
data[offset_data + 0] = bytes[offset_byte + 0] & 0x3f; | |||
data[offset_data + 1] = ((bytes[offset_byte + 0] >> 6) & 0x03) | | |||
((bytes[offset_byte + 1] & 0x0f) << 2); | |||
data[offset_data + 2] = ((bytes[offset_byte + 1] & 0xff) >> 4) | | |||
((bytes[offset_byte + 2] & 0x03) << 4); | |||
data[offset_data + 3] = ((bytes[offset_byte + 2] & 0xff) >> 2); | |||
out[0] = in[0] | (in[1] << 8); | |||
out[1] = (in[1] >> 2) | (in[2] << 6); | |||
out[2] = (in[2] >> 4) | (in[3] << 4); | |||
out[3] = (in[3] >> 6) | (in[4] << 2); | |||
in += 5; | |||
out += 4; | |||
} | |||
} | |||
static void POLVECp2BS(uint8_t *bytes, uint16_t data[SABER_K][SABER_N]) { | |||
uint32_t i, j; | |||
uint32_t offset_data, offset_byte, offset_byte1; | |||
for (i = 0; i < SABER_K; i++) { | |||
offset_byte1 = i * (SABER_N * 10) / 8; | |||
for (j = 0; j < SABER_N / 4; j++) { | |||
offset_byte = offset_byte1 + 5 * j; | |||
offset_data = 4 * j; | |||
bytes[offset_byte + 0] = (data[i][offset_data + 0] & (0xff)); | |||
bytes[offset_byte + 1] = ((data[i][offset_data + 0] >> 8) & 0x03) | | |||
((data[i][offset_data + 1] & 0x3f) << 2); | |||
bytes[offset_byte + 2] = ((data[i][offset_data + 1] >> 6) & 0x0f) | | |||
((data[i][offset_data + 2] & 0x0f) << 4); | |||
bytes[offset_byte + 3] = ((data[i][offset_data + 2] >> 4) & 0x3f) | | |||
((data[i][offset_data + 3] & 0x03) << 6); | |||
bytes[offset_byte + 4] = ((data[i][offset_data + 3] >> 2) & 0xff); | |||
} | |||
void PQCLEAN_SABER_CLEAN_POLVECq2BS(uint8_t bytes[SABER_POLYVECBYTES], const poly data[SABER_L]) { | |||
size_t i; | |||
for (i = 0; i < SABER_L; i++) { | |||
POLq2BS(bytes + i * SABER_POLYBYTES, &data[i]); | |||
} | |||
} | |||
static void BS2POLVECp(const unsigned char *bytes, uint16_t data[SABER_K][SABER_N]) { | |||
uint32_t i, j; | |||
uint32_t offset_data, offset_byte, offset_byte1; | |||
for (i = 0; i < SABER_K; i++) { | |||
offset_byte1 = i * (SABER_N * 10) / 8; | |||
for (j = 0; j < SABER_N / 4; j++) { | |||
offset_byte = offset_byte1 + 5 * j; | |||
offset_data = 4 * j; | |||
data[i][offset_data + 0] = (bytes[offset_byte + 0] & (0xff)) | | |||
((bytes[offset_byte + 1] & 0x03) << 8); | |||
data[i][offset_data + 1] = ((bytes[offset_byte + 1] >> 2) & (0x3f)) | | |||
((bytes[offset_byte + 2] & 0x0f) << 6); | |||
data[i][offset_data + 2] = ((bytes[offset_byte + 2] >> 4) & (0x0f)) | | |||
((bytes[offset_byte + 3] & 0x3f) << 4); | |||
data[i][offset_data + 3] = ((bytes[offset_byte + 3] >> 6) & (0x03)) | | |||
((bytes[offset_byte + 4] & 0xff) << 2); | |||
} | |||
void PQCLEAN_SABER_CLEAN_BS2POLVECq(poly data[SABER_L], const uint8_t bytes[SABER_POLYVECBYTES]) { | |||
size_t i; | |||
for (i = 0; i < SABER_L; i++) { | |||
BS2POLq(&data[i], bytes + i * SABER_POLYBYTES); | |||
} | |||
} | |||
static void POLVECq2BS(uint8_t *bytes, uint16_t data[SABER_K][SABER_N]) { | |||
uint32_t i, j; | |||
uint32_t offset_data, offset_byte, offset_byte1; | |||
for (i = 0; i < SABER_K; i++) { | |||
offset_byte1 = i * (SABER_N * 13) / 8; | |||
for (j = 0; j < SABER_N / 8; j++) { | |||
offset_byte = offset_byte1 + 13 * j; | |||
offset_data = 8 * j; | |||
bytes[offset_byte + 0] = (data[i][offset_data + 0] & (0xff)); | |||
bytes[offset_byte + 1] = ((data[i][offset_data + 0] >> 8) & 0x1f) | | |||
((data[i][offset_data + 1] & 0x07) << 5); | |||
bytes[offset_byte + 2] = ((data[i][offset_data + 1] >> 3) & 0xff); | |||
bytes[offset_byte + 3] = ((data[i][offset_data + 1] >> 11) & 0x03) | | |||
((data[i][offset_data + 2] & 0x3f) << 2); | |||
bytes[offset_byte + 4] = ((data[i][offset_data + 2] >> 6) & 0x7f) | | |||
((data[i][offset_data + 3] & 0x01) << 7); | |||
bytes[offset_byte + 5] = ((data[i][offset_data + 3] >> 1) & 0xff); | |||
bytes[offset_byte + 6] = ((data[i][offset_data + 3] >> 9) & 0x0f) | | |||
((data[i][offset_data + 4] & 0x0f) << 4); | |||
bytes[offset_byte + 7] = ((data[i][offset_data + 4] >> 4) & 0xff); | |||
bytes[offset_byte + 8] = ((data[i][offset_data + 4] >> 12) & 0x01) | | |||
((data[i][offset_data + 5] & 0x7f) << 1); | |||
bytes[offset_byte + 9] = ((data[i][offset_data + 5] >> 7) & 0x3f) | | |||
((data[i][offset_data + 6] & 0x03) << 6); | |||
bytes[offset_byte + 10] = ((data[i][offset_data + 6] >> 2) & 0xff); | |||
bytes[offset_byte + 11] = ((data[i][offset_data + 6] >> 10) & 0x07) | | |||
((data[i][offset_data + 7] & 0x1f) << 3); | |||
bytes[offset_byte + 12] = ((data[i][offset_data + 7] >> 5) & 0xff); | |||
} | |||
void PQCLEAN_SABER_CLEAN_POLVECp2BS(uint8_t bytes[SABER_POLYVECCOMPRESSEDBYTES], const poly data[SABER_L]) { | |||
size_t i; | |||
for (i = 0; i < SABER_L; i++) { | |||
POLp2BS(bytes + i * SABER_POLYCOMPRESSEDBYTES, &data[i]); | |||
} | |||
} | |||
static void BS2POLVECq(const unsigned char *bytes, uint16_t data[SABER_K][SABER_N]) { | |||
uint32_t i, j; | |||
uint32_t offset_data, offset_byte, offset_byte1; | |||
for (i = 0; i < SABER_K; i++) { | |||
offset_byte1 = i * (SABER_N * 13) / 8; | |||
for (j = 0; j < SABER_N / 8; j++) { | |||
offset_byte = offset_byte1 + 13 * j; | |||
offset_data = 8 * j; | |||
data[i][offset_data + 0] = (bytes[offset_byte + 0] & (0xff)) | | |||
((bytes[offset_byte + 1] & 0x1f) << 8); | |||
data[i][offset_data + 1] = (bytes[offset_byte + 1] >> 5 & (0x07)) | | |||
((bytes[offset_byte + 2] & 0xff) << 3) | | |||
((bytes[offset_byte + 3] & 0x03) << 11); | |||
data[i][offset_data + 2] = (bytes[offset_byte + 3] >> 2 & (0x3f)) | | |||
((bytes[offset_byte + 4] & 0x7f) << 6); | |||
data[i][offset_data + 3] = (bytes[offset_byte + 4] >> 7 & (0x01)) | | |||
((bytes[offset_byte + 5] & 0xff) << 1) | | |||
((bytes[offset_byte + 6] & 0x0f) << 9); | |||
data[i][offset_data + 4] = (bytes[offset_byte + 6] >> 4 & (0x0f)) | | |||
((bytes[offset_byte + 7] & 0xff) << 4) | | |||
((bytes[offset_byte + 8] & 0x01) << 12); | |||
data[i][offset_data + 5] = (bytes[offset_byte + 8] >> 1 & (0x7f)) | | |||
((bytes[offset_byte + 9] & 0x3f) << 7); | |||
data[i][offset_data + 6] = (bytes[offset_byte + 9] >> 6 & (0x03)) | | |||
((bytes[offset_byte + 10] & 0xff) << 2) | | |||
((bytes[offset_byte + 11] & 0x07) << 10); | |||
data[i][offset_data + 7] = (bytes[offset_byte + 11] >> 3 & (0x1f)) | | |||
((bytes[offset_byte + 12] & 0xff) << 5); | |||
} | |||
void PQCLEAN_SABER_CLEAN_BS2POLVECp(poly data[SABER_L], const uint8_t bytes[SABER_POLYVECCOMPRESSEDBYTES]) { | |||
size_t i; | |||
for (i = 0; i < SABER_L; i++) { | |||
BS2POLp(&data[i], bytes + i * SABER_POLYCOMPRESSEDBYTES); | |||
} | |||
} | |||
//only BS2POLq no BS2POLp | |||
void PQCLEAN_SABER_CLEAN_BS2POL(const unsigned char *bytes, uint16_t data[SABER_N]) { | |||
uint32_t j; | |||
uint32_t offset_data, offset_byte; | |||
for (j = 0; j < SABER_N / 8; j++) { | |||
offset_byte = 13 * j; | |||
offset_data = 8 * j; | |||
data[offset_data + 0] = (bytes[offset_byte + 0] & (0xff)) | | |||
((bytes[offset_byte + 1] & 0x1f) << 8); | |||
data[offset_data + 1] = (bytes[offset_byte + 1] >> 5 & (0x07)) | | |||
((bytes[offset_byte + 2] & 0xff) << 3) | | |||
((bytes[offset_byte + 3] & 0x03) << 11); | |||
data[offset_data + 2] = (bytes[offset_byte + 3] >> 2 & (0x3f)) | | |||
((bytes[offset_byte + 4] & 0x7f) << 6); | |||
data[offset_data + 3] = (bytes[offset_byte + 4] >> 7 & (0x01)) | | |||
((bytes[offset_byte + 5] & 0xff) << 1) | | |||
((bytes[offset_byte + 6] & 0x0f) << 9); | |||
data[offset_data + 4] = (bytes[offset_byte + 6] >> 4 & (0x0f)) | | |||
((bytes[offset_byte + 7] & 0xff) << 4) | | |||
((bytes[offset_byte + 8] & 0x01) << 12); | |||
data[offset_data + 5] = (bytes[offset_byte + 8] >> 1 & (0x7f)) | | |||
((bytes[offset_byte + 9] & 0x3f) << 7); | |||
data[offset_data + 6] = (bytes[offset_byte + 9] >> 6 & (0x03)) | | |||
((bytes[offset_byte + 10] & 0xff) << 2) | | |||
((bytes[offset_byte + 11] & 0x07) << 10); | |||
data[offset_data + 7] = (bytes[offset_byte + 11] >> 3 & (0x1f)) | | |||
((bytes[offset_byte + 12] & 0xff) << 5); | |||
void PQCLEAN_SABER_CLEAN_BS2POLmsg(poly *data, const uint8_t bytes[SABER_KEYBYTES]) { | |||
size_t i, j; | |||
for (j = 0; j < SABER_KEYBYTES; j++) { | |||
for (i = 0; i < 8; i++) { | |||
data->coeffs[j * 8 + i] = ((bytes[j] >> i) & 0x01); | |||
} | |||
} | |||
} | |||
void PQCLEAN_SABER_CLEAN_POLVEC2BS(uint8_t *bytes, uint16_t data[SABER_K][SABER_N], uint16_t modulus) { | |||
if (modulus == 1024) { | |||
POLVECp2BS(bytes, data); | |||
} else if (modulus == 8192) { | |||
POLVECq2BS(bytes, data); | |||
} | |||
} | |||
void PQCLEAN_SABER_CLEAN_POLmsg2BS(uint8_t bytes[SABER_KEYBYTES], const poly *data) { | |||
size_t i, j; | |||
memset(bytes, 0, SABER_KEYBYTES); | |||
void PQCLEAN_SABER_CLEAN_BS2POLVEC(const unsigned char *bytes, uint16_t data[SABER_K][SABER_N], uint16_t modulus) { | |||
if (modulus == 1024) { | |||
BS2POLVECp(bytes, data); | |||
} else if (modulus == 8192) { | |||
BS2POLVECq(bytes, data); | |||
for (j = 0; j < SABER_KEYBYTES; j++) { | |||
for (i = 0; i < 8; i++) { | |||
bytes[j] = bytes[j] | ((data->coeffs[j * 8 + i] & 0x01) << i); | |||
} | |||
} | |||
} |
@@ -1,28 +1,28 @@ | |||
#ifndef PACK_UNPACK_H | |||
#define PACK_UNPACK_H | |||
#include "SABER_params.h" | |||
#include "poly.h" | |||
#include <stdint.h> | |||
#include <stdio.h> | |||
void PQCLEAN_SABER_CLEAN_POLT2BS(uint8_t bytes[SABER_SCALEBYTES_KEM], const poly *data); | |||
void PQCLEAN_SABER_CLEAN_BS2POLT(poly *data, const uint8_t bytes[SABER_SCALEBYTES_KEM]); | |||
void PQCLEAN_SABER_CLEAN_pack_3bit(uint8_t *bytes, const uint16_t *data); | |||
void PQCLEAN_SABER_CLEAN_un_pack3bit(const uint8_t *bytes, uint16_t *data); | |||
void PQCLEAN_SABER_CLEAN_POLVECq2BS(uint8_t bytes[SABER_POLYVECBYTES], const poly data[SABER_L]); | |||
void PQCLEAN_SABER_CLEAN_pack_4bit(uint8_t *bytes, const uint16_t *data); | |||
void PQCLEAN_SABER_CLEAN_POLVECp2BS(uint8_t bytes[SABER_POLYVECCOMPRESSEDBYTES], const poly data[SABER_L]); | |||
void PQCLEAN_SABER_CLEAN_un_pack4bit(const unsigned char *bytes, uint16_t *ar); | |||
void PQCLEAN_SABER_CLEAN_pack_6bit(uint8_t *bytes, const uint16_t *data); | |||
void PQCLEAN_SABER_CLEAN_BS2POLVECq(poly data[SABER_L], const uint8_t bytes[SABER_POLYVECBYTES]); | |||
void PQCLEAN_SABER_CLEAN_un_pack6bit(const unsigned char *bytes, uint16_t *data); | |||
void PQCLEAN_SABER_CLEAN_BS2POLVECp(poly data[SABER_L], const uint8_t bytes[SABER_POLYVECCOMPRESSEDBYTES]); | |||
void PQCLEAN_SABER_CLEAN_BS2POL(const unsigned char *bytes, uint16_t data[SABER_N]); | |||
void PQCLEAN_SABER_CLEAN_BS2POLmsg(poly *data, const uint8_t bytes[SABER_KEYBYTES]); | |||
void PQCLEAN_SABER_CLEAN_POLVEC2BS(uint8_t *bytes, uint16_t data[SABER_K][SABER_N], uint16_t modulus); | |||
void PQCLEAN_SABER_CLEAN_POLmsg2BS(uint8_t bytes[SABER_KEYBYTES], const poly *data); | |||
void PQCLEAN_SABER_CLEAN_BS2POLVEC(const unsigned char *bytes, uint16_t data[SABER_K][SABER_N], uint16_t modulus); | |||
#endif |
@@ -1,21 +1,57 @@ | |||
/*--------------------------------------------------------------------- | |||
This file has been adapted from the implementation | |||
(available at, Public Domain https://github.com/pq-crystals/kyber) | |||
of "CRYSTALS – Kyber: a CCA-secure module-lattice-based KEM" | |||
by : Joppe Bos, Leo Ducas, Eike Kiltz, Tancrede Lepoint, | |||
Vadim Lyubashevsky, John M. Schanck, Peter Schwabe & Damien stehle | |||
#include "SABER_params.h" | |||
#include "api.h" | |||
#include "cbd.h" | |||
#include "fips202.h" | |||
#include "pack_unpack.h" | |||
#include "poly.h" | |||
#include <stddef.h> | |||
void PQCLEAN_SABER_CLEAN_GenSecret(uint16_t r[SABER_K][SABER_N], const unsigned char *seed) { | |||
uint8_t buf[SABER_MU * SABER_N * SABER_K / 8]; | |||
void PQCLEAN_SABER_CLEAN_MatrixVectorMul(poly c[SABER_L], const poly A[SABER_L][SABER_L], const poly s[SABER_L], int16_t transpose) { | |||
size_t i, j; | |||
if (transpose) { | |||
for (i = 0; i < SABER_L; i++) { | |||
PQCLEAN_SABER_CLEAN_poly_mul(&c[i], &A[0][i], &s[0], 0); | |||
for (j = 1; j < SABER_L; j++) { | |||
PQCLEAN_SABER_CLEAN_poly_mul(&c[i], &A[j][i], &s[j], 1); | |||
} | |||
} | |||
} else { | |||
for (i = 0; i < SABER_L; i++) { | |||
PQCLEAN_SABER_CLEAN_poly_mul(&c[i], &A[i][0], &s[0], 0); | |||
for (j = 1; j < SABER_L; j++) { | |||
PQCLEAN_SABER_CLEAN_poly_mul(&c[i], &A[i][j], &s[j], 1); | |||
} | |||
} | |||
} | |||
} | |||
void PQCLEAN_SABER_CLEAN_InnerProd(poly *c, const poly b[SABER_L], const poly s[SABER_L]) { | |||
size_t i; | |||
PQCLEAN_SABER_CLEAN_poly_mul(c, &b[0], &s[0], 0); | |||
for (i = 1; i < SABER_L; i++) { | |||
PQCLEAN_SABER_CLEAN_poly_mul(c, &b[i], &s[i], 1); | |||
} | |||
} | |||
void PQCLEAN_SABER_CLEAN_GenMatrix(poly A[SABER_L][SABER_L], const uint8_t seed[SABER_SEEDBYTES]) { | |||
size_t i; | |||
uint8_t buf[SABER_L * SABER_POLYVECBYTES]; | |||
shake128(buf, sizeof(buf), seed, SABER_SEEDBYTES); | |||
for (i = 0; i < SABER_L; i++) { | |||
PQCLEAN_SABER_CLEAN_BS2POLVECq(A[i], buf + i * SABER_POLYVECBYTES); | |||
} | |||
} | |||
void PQCLEAN_SABER_CLEAN_GenSecret(poly s[SABER_L], const uint8_t seed[SABER_NOISESEEDBYTES]) { | |||
size_t i; | |||
uint8_t buf[SABER_L * SABER_POLYCOINBYTES]; | |||
shake128(buf, sizeof(buf), seed, SABER_NOISESEEDBYTES); | |||
for (size_t i = 0; i < SABER_K; i++) { | |||
PQCLEAN_SABER_CLEAN_cbd(r[i], buf + i * SABER_MU * SABER_N / 8); | |||
for (i = 0; i < SABER_L; i++) { | |||
PQCLEAN_SABER_CLEAN_cbd(s[i].coeffs, buf + i * SABER_POLYCOINBYTES); | |||
} | |||
} |
@@ -1,26 +1,23 @@ | |||
#ifndef POLY_H | |||
#define POLY_H | |||
/*--------------------------------------------------------------------- | |||
This file has been adapted from the implementation | |||
(available at, Public Domain https://github.com/pq-crystals/kyber) | |||
of "CRYSTALS – Kyber: a CCA-secure module-lattice-based KEM" | |||
by : Joppe Bos, Leo Ducas, Eike Kiltz, Tancrede Lepoint, | |||
Vadim Lyubashevsky, John M. Schanck, Peter Schwabe & Damien stehle | |||
#include "SABER_params.h" | |||
#include <stdint.h> | |||
typedef struct { | |||
typedef union { | |||
uint16_t coeffs[SABER_N]; | |||
} poly; | |||
typedef struct { | |||
poly vec[SABER_K]; | |||
} polyvec; | |||
void PQCLEAN_SABER_CLEAN_GenSecret(uint16_t r[SABER_K][SABER_N], const unsigned char *seed); | |||
void PQCLEAN_SABER_CLEAN_MatrixVectorMul(poly c[SABER_L], const poly A[SABER_L][SABER_L], const poly s[SABER_L], int16_t transpose); | |||
void PQCLEAN_SABER_CLEAN_InnerProd(poly *c, const poly b[SABER_L], const poly s[SABER_L]); | |||
void PQCLEAN_SABER_CLEAN_GenMatrix(poly A[SABER_L][SABER_L], const uint8_t seed[SABER_SEEDBYTES]); | |||
void PQCLEAN_SABER_CLEAN_GenSecret(poly s[SABER_L], const uint8_t seed[SABER_NOISESEEDBYTES]); | |||
void PQCLEAN_SABER_CLEAN_poly_mul(poly *c, const poly *a, const poly *b, int accumulate); | |||
#endif |
@@ -1,4 +1,4 @@ | |||
#include "poly_mul.h" | |||
#include "poly.h" | |||
#include <stdint.h> | |||
#include <string.h> | |||
@@ -11,13 +11,13 @@ | |||
#define OVERFLOWING_MUL(X, Y) ((uint16_t)((uint32_t)(X) * (uint32_t)(Y))) | |||
#define KARATSUBA_N 64 | |||
static void karatsuba_simple(const uint16_t *a_1, const uint16_t *b_1, uint16_t *result_final) { | |||
static void karatsuba_simple(uint16_t *result_final, const uint16_t *a_1, const uint16_t *b_1) { | |||
uint16_t d01[KARATSUBA_N / 2 - 1]; | |||
uint16_t d0123[KARATSUBA_N / 2 - 1]; | |||
uint16_t d23[KARATSUBA_N / 2 - 1]; | |||
uint16_t result_d01[KARATSUBA_N - 1]; | |||
int32_t i, j; | |||
size_t i, j; | |||
memset(result_d01, 0, (KARATSUBA_N - 1)*sizeof(uint16_t)); | |||
memset(d01, 0, (KARATSUBA_N / 2 - 1)*sizeof(uint16_t)); | |||
@@ -110,7 +110,7 @@ static void karatsuba_simple(const uint16_t *a_1, const uint16_t *b_1, uint16_t | |||
static void toom_cook_4way (const uint16_t *a1, const uint16_t *b1, uint16_t *result) { | |||
static void toom_cook_4way (uint16_t *result, const uint16_t *a1, const uint16_t *b1) { | |||
uint16_t inv3 = 43691, inv9 = 36409, inv15 = 61167; | |||
uint16_t aw1[N_SB], aw2[N_SB], aw3[N_SB], aw4[N_SB], aw5[N_SB], aw6[N_SB], aw7[N_SB]; | |||
@@ -181,13 +181,13 @@ static void toom_cook_4way (const uint16_t *a1, const uint16_t *b1, uint16_t *re | |||
// MULTIPLICATION | |||
karatsuba_simple(aw1, bw1, w1); | |||
karatsuba_simple(aw2, bw2, w2); | |||
karatsuba_simple(aw3, bw3, w3); | |||
karatsuba_simple(aw4, bw4, w4); | |||
karatsuba_simple(aw5, bw5, w5); | |||
karatsuba_simple(aw6, bw6, w6); | |||
karatsuba_simple(aw7, bw7, w7); | |||
karatsuba_simple(w1, aw1, bw1); | |||
karatsuba_simple(w2, aw2, bw2); | |||
karatsuba_simple(w3, aw3, bw3); | |||
karatsuba_simple(w4, aw4, bw4); | |||
karatsuba_simple(w5, aw5, bw5); | |||
karatsuba_simple(w6, aw6, bw6); | |||
karatsuba_simple(w7, aw7, bw7); | |||
// INTERPOLATION | |||
for (i = 0; i < N_SB_RES; ++i) { | |||
@@ -228,19 +228,21 @@ static void toom_cook_4way (const uint16_t *a1, const uint16_t *b1, uint16_t *re | |||
} | |||
} | |||
void PQCLEAN_SABER_CLEAN_pol_mul(uint16_t *a, uint16_t *b, uint16_t *res, uint16_t p, uint32_t n) { | |||
uint32_t i; | |||
// normal multiplication | |||
uint16_t c[512]; | |||
/* res += a*b */ | |||
void PQCLEAN_SABER_CLEAN_poly_mul(poly *c, const poly *a, const poly *b, const int accumulate) { | |||
uint16_t C[2 * SABER_N] = {0}; | |||
size_t i; | |||
for (i = 0; i < 512; i++) { | |||
c[i] = 0; | |||
} | |||
toom_cook_4way(a, b, c); | |||
toom_cook_4way(C, a->coeffs, b->coeffs); | |||
// reduction | |||
for (i = n; i < 2 * n; i++) { | |||
res[i - n] = (c[i - n] - c[i]) & (p - 1); | |||
/* reduction */ | |||
if (accumulate == 0) { | |||
for (i = SABER_N; i < 2 * SABER_N; i++) { | |||
c->coeffs[i - SABER_N] = (C[i - SABER_N] - C[i]); | |||
} | |||
} else { | |||
for (i = SABER_N; i < 2 * SABER_N; i++) { | |||
c->coeffs[i - SABER_N] += (C[i - SABER_N] - C[i]); | |||
} | |||
} | |||
} |
@@ -1,9 +1,3 @@ | |||
#ifndef POLYMUL_H | |||
#define POLYMUL_H | |||
#include "SABER_params.h" | |||
#include <stdint.h> | |||
void PQCLEAN_SABER_CLEAN_pol_mul(uint16_t *a, uint16_t *b, uint16_t *res, uint16_t p, uint32_t n); | |||
#endif |