Browse Source

Merge pull request #340 from jschanck/saber

Update Saber and add AVX2 implementation
master
Thom Wiggers 4 years ago
committed by GitHub
parent
commit
3c45712da6
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
100 changed files with 7694 additions and 1939 deletions
  1. +10
    -1
      crypto_kem/firesaber/META.yml
  2. +1
    -0
      crypto_kem/firesaber/avx2/LICENSE
  3. +22
    -0
      crypto_kem/firesaber/avx2/Makefile
  4. +125
    -0
      crypto_kem/firesaber/avx2/SABER_indcpa.c
  5. +13
    -0
      crypto_kem/firesaber/avx2/SABER_indcpa.h
  6. +41
    -0
      crypto_kem/firesaber/avx2/SABER_params.h
  7. +18
    -0
      crypto_kem/firesaber/avx2/api.h
  8. +48
    -0
      crypto_kem/firesaber/avx2/cbd.c
  9. +16
    -0
      crypto_kem/firesaber/avx2/cbd.h
  10. +77
    -0
      crypto_kem/firesaber/avx2/kem.c
  11. +151
    -0
      crypto_kem/firesaber/avx2/pack_unpack.c
  12. +28
    -0
      crypto_kem/firesaber/avx2/pack_unpack.h
  13. +62
    -0
      crypto_kem/firesaber/avx2/poly.c
  14. +38
    -0
      crypto_kem/firesaber/avx2/poly.h
  15. +1496
    -0
      crypto_kem/firesaber/avx2/poly_mul.c
  16. +35
    -0
      crypto_kem/firesaber/avx2/verify.c
  17. +22
    -0
      crypto_kem/firesaber/avx2/verify.h
  18. +1
    -6
      crypto_kem/firesaber/clean/LICENSE
  19. +2
    -2
      crypto_kem/firesaber/clean/Makefile
  20. +63
    -247
      crypto_kem/firesaber/clean/SABER_indcpa.c
  21. +8
    -4
      crypto_kem/firesaber/clean/SABER_indcpa.h
  22. +18
    -26
      crypto_kem/firesaber/clean/SABER_params.h
  23. +9
    -5
      crypto_kem/firesaber/clean/api.h
  24. +14
    -18
      crypto_kem/firesaber/clean/cbd.c
  25. +3
    -4
      crypto_kem/firesaber/clean/cbd.h
  26. +32
    -51
      crypto_kem/firesaber/clean/kem.c
  27. +111
    -214
      crypto_kem/firesaber/clean/pack_unpack.c
  28. +10
    -10
      crypto_kem/firesaber/clean/pack_unpack.h
  29. +48
    -11
      crypto_kem/firesaber/clean/poly.c
  30. +12
    -14
      crypto_kem/firesaber/clean/poly.h
  31. +25
    -23
      crypto_kem/firesaber/clean/poly_mul.c
  32. +0
    -6
      crypto_kem/firesaber/clean/poly_mul.h
  33. +7
    -6
      crypto_kem/firesaber/clean/verify.c
  34. +4
    -3
      crypto_kem/firesaber/clean/verify.h
  35. +10
    -1
      crypto_kem/lightsaber/META.yml
  36. +1
    -0
      crypto_kem/lightsaber/avx2/LICENSE
  37. +22
    -0
      crypto_kem/lightsaber/avx2/Makefile
  38. +125
    -0
      crypto_kem/lightsaber/avx2/SABER_indcpa.c
  39. +13
    -0
      crypto_kem/lightsaber/avx2/SABER_indcpa.h
  40. +41
    -0
      crypto_kem/lightsaber/avx2/SABER_params.h
  41. +18
    -0
      crypto_kem/lightsaber/avx2/api.h
  42. +48
    -0
      crypto_kem/lightsaber/avx2/cbd.c
  43. +16
    -0
      crypto_kem/lightsaber/avx2/cbd.h
  44. +77
    -0
      crypto_kem/lightsaber/avx2/kem.c
  45. +155
    -0
      crypto_kem/lightsaber/avx2/pack_unpack.c
  46. +28
    -0
      crypto_kem/lightsaber/avx2/pack_unpack.h
  47. +62
    -0
      crypto_kem/lightsaber/avx2/poly.c
  48. +38
    -0
      crypto_kem/lightsaber/avx2/poly.h
  49. +1496
    -0
      crypto_kem/lightsaber/avx2/poly_mul.c
  50. +35
    -0
      crypto_kem/lightsaber/avx2/verify.c
  51. +22
    -0
      crypto_kem/lightsaber/avx2/verify.h
  52. +1
    -6
      crypto_kem/lightsaber/clean/LICENSE
  53. +2
    -2
      crypto_kem/lightsaber/clean/Makefile
  54. +63
    -247
      crypto_kem/lightsaber/clean/SABER_indcpa.c
  55. +8
    -4
      crypto_kem/lightsaber/clean/SABER_indcpa.h
  56. +18
    -27
      crypto_kem/lightsaber/clean/SABER_params.h
  57. +9
    -5
      crypto_kem/lightsaber/clean/api.h
  58. +12
    -15
      crypto_kem/lightsaber/clean/cbd.c
  59. +3
    -4
      crypto_kem/lightsaber/clean/cbd.h
  60. +32
    -51
      crypto_kem/lightsaber/clean/kem.c
  61. +113
    -212
      crypto_kem/lightsaber/clean/pack_unpack.c
  62. +10
    -10
      crypto_kem/lightsaber/clean/pack_unpack.h
  63. +48
    -11
      crypto_kem/lightsaber/clean/poly.c
  64. +12
    -14
      crypto_kem/lightsaber/clean/poly.h
  65. +25
    -23
      crypto_kem/lightsaber/clean/poly_mul.c
  66. +0
    -6
      crypto_kem/lightsaber/clean/poly_mul.h
  67. +7
    -6
      crypto_kem/lightsaber/clean/verify.c
  68. +4
    -3
      crypto_kem/lightsaber/clean/verify.h
  69. +10
    -1
      crypto_kem/saber/META.yml
  70. +1
    -0
      crypto_kem/saber/avx2/LICENSE
  71. +22
    -0
      crypto_kem/saber/avx2/Makefile
  72. +125
    -0
      crypto_kem/saber/avx2/SABER_indcpa.c
  73. +13
    -0
      crypto_kem/saber/avx2/SABER_indcpa.h
  74. +41
    -0
      crypto_kem/saber/avx2/SABER_params.h
  75. +18
    -0
      crypto_kem/saber/avx2/api.h
  76. +48
    -0
      crypto_kem/saber/avx2/cbd.c
  77. +16
    -0
      crypto_kem/saber/avx2/cbd.h
  78. +77
    -0
      crypto_kem/saber/avx2/kem.c
  79. +147
    -0
      crypto_kem/saber/avx2/pack_unpack.c
  80. +28
    -0
      crypto_kem/saber/avx2/pack_unpack.h
  81. +62
    -0
      crypto_kem/saber/avx2/poly.c
  82. +38
    -0
      crypto_kem/saber/avx2/poly.h
  83. +1496
    -0
      crypto_kem/saber/avx2/poly_mul.c
  84. +35
    -0
      crypto_kem/saber/avx2/verify.c
  85. +22
    -0
      crypto_kem/saber/avx2/verify.h
  86. +1
    -6
      crypto_kem/saber/clean/LICENSE
  87. +2
    -2
      crypto_kem/saber/clean/Makefile
  88. +63
    -247
      crypto_kem/saber/clean/SABER_indcpa.c
  89. +8
    -4
      crypto_kem/saber/clean/SABER_indcpa.h
  90. +18
    -27
      crypto_kem/saber/clean/SABER_params.h
  91. +9
    -5
      crypto_kem/saber/clean/api.h
  92. +13
    -16
      crypto_kem/saber/clean/cbd.c
  93. +3
    -4
      crypto_kem/saber/clean/cbd.h
  94. +32
    -51
      crypto_kem/saber/clean/kem.c
  95. +107
    -214
      crypto_kem/saber/clean/pack_unpack.c
  96. +10
    -10
      crypto_kem/saber/clean/pack_unpack.h
  97. +48
    -11
      crypto_kem/saber/clean/poly.c
  98. +12
    -14
      crypto_kem/saber/clean/poly.h
  99. +25
    -23
      crypto_kem/saber/clean/poly_mul.c
  100. +0
    -6
      crypto_kem/saber/clean/poly_mul.h

+ 10
- 1
crypto_kem/firesaber/META.yml View File

@@ -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

+ 1
- 0
crypto_kem/firesaber/avx2/LICENSE View File

@@ -0,0 +1 @@
Public Domain

+ 22
- 0
crypto_kem/firesaber/avx2/Makefile View File

@@ -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)

+ 125
- 0
crypto_kem/firesaber/avx2/SABER_indcpa.c View File

@@ -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);
}

+ 13
- 0
crypto_kem/firesaber/avx2/SABER_indcpa.h View File

@@ -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

+ 41
- 0
crypto_kem/firesaber/avx2/SABER_params.h View File

@@ -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

+ 18
- 0
crypto_kem/firesaber/avx2/api.h View File

@@ -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 */

+ 48
- 0
crypto_kem/firesaber/avx2/cbd.c View File

@@ -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]);
}
}

+ 16
- 0
crypto_kem/firesaber/avx2/cbd.h View File

@@ -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

+ 77
- 0
crypto_kem/firesaber/avx2/kem.c View File

@@ -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);
}

+ 151
- 0
crypto_kem/firesaber/avx2/pack_unpack.c View File

@@ -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);
}
}
}

+ 28
- 0
crypto_kem/firesaber/avx2/pack_unpack.h View File

@@ -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

+ 62
- 0
crypto_kem/firesaber/avx2/poly.c View File

@@ -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);
}
}

+ 38
- 0
crypto_kem/firesaber/avx2/poly.h View File

@@ -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

+ 1496
- 0
crypto_kem/firesaber/avx2/poly_mul.c
File diff suppressed because it is too large
View File


+ 35
- 0
crypto_kem/firesaber/avx2/verify.c View File

@@ -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]);
}
}

+ 22
- 0
crypto_kem/firesaber/avx2/verify.h View File

@@ -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
- 6
crypto_kem/firesaber/clean/LICENSE View File

@@ -1,8 +1 @@
SABER_v1.1

Public domain

Authors: Jan-Pieter D'Anvers, Angshuman Karmakar, Sujoy Sinha Roy,
Frederik Vercauteren
Public Domain

+ 2
- 2
crypto_kem/firesaber/clean/Makefile View File

@@ -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)



+ 63
- 247
crypto_kem/firesaber/clean/SABER_indcpa.c View File

@@ -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);
}

+ 8
- 4
crypto_kem/firesaber/clean/SABER_indcpa.h View File

@@ -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

+ 18
- 26
crypto_kem/firesaber/clean/SABER_params.h View File

@@ -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


+ 9
- 5
crypto_kem/firesaber/clean/api.h View File

@@ -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 */

+ 14
- 18
crypto_kem/firesaber/clean/cbd.c View File

@@ -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]);
}
}

+ 3
- 4
crypto_kem/firesaber/clean/cbd.h View File

@@ -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

+ 32
- 51
crypto_kem/firesaber/clean/kem.c View File

@@ -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);
}

+ 111
- 214
crypto_kem/firesaber/clean/pack_unpack.c View File

@@ -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);
}
}
}

+ 10
- 10
crypto_kem/firesaber/clean/pack_unpack.h View File

@@ -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

+ 48
- 11
crypto_kem/firesaber/clean/poly.c View File

@@ -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);
}
}

+ 12
- 14
crypto_kem/firesaber/clean/poly.h View File

@@ -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

+ 25
- 23
crypto_kem/firesaber/clean/poly_mul.c View File

@@ -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]);
}
}
}

+ 0
- 6
crypto_kem/firesaber/clean/poly_mul.h View File

@@ -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

+ 7
- 6
crypto_kem/firesaber/clean/verify.c View File

@@ -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;


+ 4
- 3
crypto_kem/firesaber/clean/verify.h View File

@@ -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

+ 10
- 1
crypto_kem/lightsaber/META.yml View File

@@ -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

+ 1
- 0
crypto_kem/lightsaber/avx2/LICENSE View File

@@ -0,0 +1 @@
Public Domain

+ 22
- 0
crypto_kem/lightsaber/avx2/Makefile View File

@@ -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)

+ 125
- 0
crypto_kem/lightsaber/avx2/SABER_indcpa.c View File

@@ -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);
}

+ 13
- 0
crypto_kem/lightsaber/avx2/SABER_indcpa.h View File

@@ -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

+ 41
- 0
crypto_kem/lightsaber/avx2/SABER_params.h View File

@@ -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

+ 18
- 0
crypto_kem/lightsaber/avx2/api.h View File

@@ -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 */

+ 48
- 0
crypto_kem/lightsaber/avx2/cbd.c View File

@@ -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]);
}
}

+ 16
- 0
crypto_kem/lightsaber/avx2/cbd.h View File

@@ -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

+ 77
- 0
crypto_kem/lightsaber/avx2/kem.c View File

@@ -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);
}

+ 155
- 0
crypto_kem/lightsaber/avx2/pack_unpack.c View File

@@ -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);
}
}
}

+ 28
- 0
crypto_kem/lightsaber/avx2/pack_unpack.h View File

@@ -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

+ 62
- 0
crypto_kem/lightsaber/avx2/poly.c View File

@@ -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);
}
}

+ 38
- 0
crypto_kem/lightsaber/avx2/poly.h View File

@@ -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

+ 1496
- 0
crypto_kem/lightsaber/avx2/poly_mul.c
File diff suppressed because it is too large
View File


+ 35
- 0
crypto_kem/lightsaber/avx2/verify.c View File

@@ -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]);
}
}

+ 22
- 0
crypto_kem/lightsaber/avx2/verify.h View File

@@ -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
- 6
crypto_kem/lightsaber/clean/LICENSE View File

@@ -1,8 +1 @@
SABER_v1.1

Public domain

Authors: Jan-Pieter D'Anvers, Angshuman Karmakar, Sujoy Sinha Roy,
Frederik Vercauteren
Public Domain

+ 2
- 2
crypto_kem/lightsaber/clean/Makefile View File

@@ -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)



+ 63
- 247
crypto_kem/lightsaber/clean/SABER_indcpa.c View File

@@ -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);
}

+ 8
- 4
crypto_kem/lightsaber/clean/SABER_indcpa.h View File

@@ -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

+ 18
- 27
crypto_kem/lightsaber/clean/SABER_params.h View File

@@ -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


+ 9
- 5
crypto_kem/lightsaber/clean/api.h View File

@@ -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 */

+ 12
- 15
crypto_kem/lightsaber/clean/cbd.c View File

@@ -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]);
}
}

+ 3
- 4
crypto_kem/lightsaber/clean/cbd.h View File

@@ -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

+ 32
- 51
crypto_kem/lightsaber/clean/kem.c View File

@@ -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);
}

+ 113
- 212
crypto_kem/lightsaber/clean/pack_unpack.c View File

@@ -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);
}
}
}

+ 10
- 10
crypto_kem/lightsaber/clean/pack_unpack.h View File

@@ -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

+ 48
- 11
crypto_kem/lightsaber/clean/poly.c View File

@@ -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);
}
}

+ 12
- 14
crypto_kem/lightsaber/clean/poly.h View File

@@ -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

+ 25
- 23
crypto_kem/lightsaber/clean/poly_mul.c View File

@@ -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]);
}
}
}

+ 0
- 6
crypto_kem/lightsaber/clean/poly_mul.h View File

@@ -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

+ 7
- 6
crypto_kem/lightsaber/clean/verify.c View File

@@ -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;


+ 4
- 3
crypto_kem/lightsaber/clean/verify.h View File

@@ -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

+ 10
- 1
crypto_kem/saber/META.yml View File

@@ -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

+ 1
- 0
crypto_kem/saber/avx2/LICENSE View File

@@ -0,0 +1 @@
Public Domain

+ 22
- 0
crypto_kem/saber/avx2/Makefile View File

@@ -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)

+ 125
- 0
crypto_kem/saber/avx2/SABER_indcpa.c View File

@@ -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);
}

+ 13
- 0
crypto_kem/saber/avx2/SABER_indcpa.h View File

@@ -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

+ 41
- 0
crypto_kem/saber/avx2/SABER_params.h View File

@@ -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

+ 18
- 0
crypto_kem/saber/avx2/api.h View File

@@ -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 */

+ 48
- 0
crypto_kem/saber/avx2/cbd.c View File

@@ -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]);
}
}

+ 16
- 0
crypto_kem/saber/avx2/cbd.h View File

@@ -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

+ 77
- 0
crypto_kem/saber/avx2/kem.c View File

@@ -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);
}

+ 147
- 0
crypto_kem/saber/avx2/pack_unpack.c View File

@@ -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);
}
}
}

+ 28
- 0
crypto_kem/saber/avx2/pack_unpack.h View File

@@ -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

+ 62
- 0
crypto_kem/saber/avx2/poly.c View File

@@ -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);
}
}

+ 38
- 0
crypto_kem/saber/avx2/poly.h View File

@@ -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

+ 1496
- 0
crypto_kem/saber/avx2/poly_mul.c
File diff suppressed because it is too large
View File


+ 35
- 0
crypto_kem/saber/avx2/verify.c View File

@@ -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]);
}
}

+ 22
- 0
crypto_kem/saber/avx2/verify.h View File

@@ -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
- 6
crypto_kem/saber/clean/LICENSE View File

@@ -1,8 +1 @@
SABER_v1.1

Public domain

Authors: Jan-Pieter D'Anvers, Angshuman Karmakar, Sujoy Sinha Roy,
Frederik Vercauteren
Public Domain

+ 2
- 2
crypto_kem/saber/clean/Makefile View File

@@ -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)



+ 63
- 247
crypto_kem/saber/clean/SABER_indcpa.c View File

@@ -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);
}

+ 8
- 4
crypto_kem/saber/clean/SABER_indcpa.h View File

@@ -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

+ 18
- 27
crypto_kem/saber/clean/SABER_params.h View File

@@ -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


+ 9
- 5
crypto_kem/saber/clean/api.h View File

@@ -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 */

+ 13
- 16
crypto_kem/saber/clean/cbd.c View File

@@ -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]);
}
}

+ 3
- 4
crypto_kem/saber/clean/cbd.h View File

@@ -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

+ 32
- 51
crypto_kem/saber/clean/kem.c View File

@@ -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);
}

+ 107
- 214
crypto_kem/saber/clean/pack_unpack.c View File

@@ -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);
}
}
}

+ 10
- 10
crypto_kem/saber/clean/pack_unpack.h View File

@@ -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

+ 48
- 11
crypto_kem/saber/clean/poly.c View File

@@ -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);
}
}

+ 12
- 14
crypto_kem/saber/clean/poly.h View File

@@ -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

+ 25
- 23
crypto_kem/saber/clean/poly_mul.c View File

@@ -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]);
}
}
}

+ 0
- 6
crypto_kem/saber/clean/poly_mul.h View File

@@ -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

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save