diff --git a/crypto_kem/kyber1024/META.yml b/crypto_kem/kyber1024/META.yml new file mode 100644 index 00000000..5055cd57 --- /dev/null +++ b/crypto_kem/kyber1024/META.yml @@ -0,0 +1,22 @@ +name: Kyber1024 +type: kem +claimed-nist-level: 5 +length-public-key: 1568 +length-ciphertext: 1568 +length-secret-key: 3168 +length-shared-secret: 32 +nistkat-sha256: b4b4fc1c2cbbb182252d2822ccb8cb704bcfe876122635c5dfa48ddc09b6e73f +principal-submitter: Peter Schwabe +auxiliary-submitters: + - Roberto Avanzi + - Joppe Bos + - Léo Ducas + - Eike Kiltz + - Tancrède Lepoint + - Vadim Lyubashevsky + - John M. Schanck + - Gregor Seiler + - Damien Stehlé +implementations: + - name: clean + version: https://github.com/pq-crystals/kyber/commit/46e283ab575ec92dfe82fb12229ae2d9d6246682 diff --git a/crypto_kem/kyber1024/clean/LICENSE b/crypto_kem/kyber1024/clean/LICENSE new file mode 100644 index 00000000..274dc1c8 --- /dev/null +++ b/crypto_kem/kyber1024/clean/LICENSE @@ -0,0 +1,15 @@ +Public Domain +Authors: Joppe Bos, + Léo Ducas, + Eike Kiltz , + Tancrède Lepoint, + Vadim Lyubashevsky, + John Schanck, + Peter Schwabe, + Gregor Seiler, + Damien Stehlé + +For Keccak and AES we are using public-domain +code from sources and by authors listed in +comments on top of the respective files. + diff --git a/crypto_kem/kyber1024/clean/Makefile b/crypto_kem/kyber1024/clean/Makefile new file mode 100644 index 00000000..e00741f7 --- /dev/null +++ b/crypto_kem/kyber1024/clean/Makefile @@ -0,0 +1,19 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libkyber1024_clean.a +HEADERS=api.h cbd.h indcpa.h ntt.h params.h poly.h polyvec.h reduce.h verify.h symmetric.h +OBJECTS=cbd.o indcpa.o kem.o ntt.o poly.o polyvec.o reduce.o verify.o symmetric-fips202.o + +CFLAGS=-O3 -Wall -Wextra -Wpedantic -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) + +all: $(LIB) + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(LIB): $(OBJECTS) + $(AR) -r $@ $(OBJECTS) + +clean: + $(RM) $(OBJECTS) + $(RM) $(LIB) diff --git a/crypto_kem/kyber1024/clean/Makefile.Microsoft_nmake b/crypto_kem/kyber1024/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..ef7a5dfd --- /dev/null +++ b/crypto_kem/kyber1024/clean/Makefile.Microsoft_nmake @@ -0,0 +1,19 @@ +# This Makefile can be used with Microsoft Visual Studio's nmake using the command: +# nmake /f Makefile.Microsoft_nmake + +LIBRARY=libkyber1024_clean.lib +OBJECTS=cbd.obj indcpa.obj kem.obj ntt.obj poly.obj polyvec.obj reduce.obj verify.obj symmetric-fips202.obj + +CFLAGS=/nologo /I ..\..\..\common /W4 /WX + +all: $(LIBRARY) + +# Make sure objects are recompiled if headers change. +$(OBJECTS): *.h + +$(LIBRARY): $(OBJECTS) + LIB.EXE /NOLOGO /WX /OUT:$@ $** + +clean: + -DEL $(OBJECTS) + -DEL $(LIBRARY) diff --git a/crypto_kem/kyber1024/clean/api.h b/crypto_kem/kyber1024/clean/api.h new file mode 100644 index 00000000..17c1df98 --- /dev/null +++ b/crypto_kem/kyber1024/clean/api.h @@ -0,0 +1,18 @@ +#ifndef PQCLEAN_KYBER1024_CLEAN_API_H +#define PQCLEAN_KYBER1024_CLEAN_API_H + +#define PQCLEAN_KYBER1024_CLEAN_CRYPTO_SECRETKEYBYTES 3168 +#define PQCLEAN_KYBER1024_CLEAN_CRYPTO_PUBLICKEYBYTES 1568 +#define PQCLEAN_KYBER1024_CLEAN_CRYPTO_CIPHERTEXTBYTES 1568 +#define PQCLEAN_KYBER1024_CLEAN_CRYPTO_BYTES 32 + +#define PQCLEAN_KYBER1024_CLEAN_CRYPTO_ALGNAME "Kyber1024" + +int PQCLEAN_KYBER1024_CLEAN_crypto_kem_keypair(unsigned char *pk, unsigned char *sk); + +int PQCLEAN_KYBER1024_CLEAN_crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk); + +int PQCLEAN_KYBER1024_CLEAN_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk); + + +#endif diff --git a/crypto_kem/kyber1024/clean/cbd.c b/crypto_kem/kyber1024/clean/cbd.c new file mode 100644 index 00000000..b9eea338 --- /dev/null +++ b/crypto_kem/kyber1024/clean/cbd.c @@ -0,0 +1,53 @@ +#include "cbd.h" + +#include "params.h" + +#include + +/************************************************* +* Name: load32_littleendian +* +* Description: load bytes into a 32-bit integer +* in little-endian order +* +* Arguments: - const unsigned char *x: pointer to input byte array +* +* Returns 32-bit unsigned integer loaded from x +**************************************************/ +static uint32_t load32_littleendian(const unsigned char *x) { + uint32_t r; + r = (uint32_t)x[0]; + r |= (uint32_t)x[1] << 8; + r |= (uint32_t)x[2] << 16; + r |= (uint32_t)x[3] << 24; + return r; +} + +/************************************************* +* Name: cbd +* +* Description: Given an array of uniformly random bytes, compute +* polynomial with coefficients distributed according to +* a centered binomial distribution with parameter KYBER_ETA +* specialized for KYBER_ETA=2 +* +* Arguments: - poly *r: pointer to output polynomial +* - const unsigned char *buf: pointer to input byte array +**************************************************/ +void PQCLEAN_KYBER1024_CLEAN_cbd(poly *r, const unsigned char *buf) { + uint32_t d, t; + int16_t a, b; + int i, j; + + for (i = 0; i < KYBER_N / 8; i++) { + t = load32_littleendian(buf + 4 * i); + d = t & 0x55555555; + d += (t >> 1) & 0x55555555; + + for (j = 0; j < 8; j++) { + a = (d >> 4 * j) & 0x3; + b = (d >> (4 * j + 2)) & 0x3; + r->coeffs[8 * i + j] = a - b; + } + } +} diff --git a/crypto_kem/kyber1024/clean/cbd.h b/crypto_kem/kyber1024/clean/cbd.h new file mode 100644 index 00000000..a50cc79f --- /dev/null +++ b/crypto_kem/kyber1024/clean/cbd.h @@ -0,0 +1,8 @@ +#ifndef CBD_H +#define CBD_H + +#include "poly.h" + +void PQCLEAN_KYBER1024_CLEAN_cbd(poly *r, const unsigned char *buf); + +#endif diff --git a/crypto_kem/kyber1024/clean/indcpa.c b/crypto_kem/kyber1024/clean/indcpa.c new file mode 100644 index 00000000..35244c1e --- /dev/null +++ b/crypto_kem/kyber1024/clean/indcpa.c @@ -0,0 +1,305 @@ +#include "indcpa.h" + +#include "ntt.h" +#include "poly.h" +#include "polyvec.h" +#include "randombytes.h" +#include "symmetric.h" + +#include + +/************************************************* +* Name: pack_pk +* +* Description: Serialize the public key as concatenation of the +* serialized vector of polynomials pk +* and the public seed used to generate the matrix A. +* +* Arguments: unsigned char *r: pointer to the output serialized public key +* const poly *pk: pointer to the input public-key polynomial +* const unsigned char *seed: pointer to the input public seed +**************************************************/ +static void pack_pk(unsigned char *r, polyvec *pk, const unsigned char *seed) { + int i; + PQCLEAN_KYBER1024_CLEAN_polyvec_tobytes(r, pk); + for (i = 0; i < KYBER_SYMBYTES; i++) { + r[i + KYBER_POLYVECBYTES] = seed[i]; + } +} + +/************************************************* +* Name: unpack_pk +* +* Description: De-serialize public key from a byte array; +* approximate inverse of pack_pk +* +* Arguments: - polyvec *pk: pointer to output public-key vector of polynomials +* - unsigned char *seed: pointer to output seed to generate matrix A +* - const unsigned char *packedpk: pointer to input serialized public key +**************************************************/ +static void unpack_pk(polyvec *pk, unsigned char *seed, const unsigned char *packedpk) { + int i; + PQCLEAN_KYBER1024_CLEAN_polyvec_frombytes(pk, packedpk); + for (i = 0; i < KYBER_SYMBYTES; i++) { + seed[i] = packedpk[i + KYBER_POLYVECBYTES]; + } +} + +/************************************************* +* Name: pack_sk +* +* Description: Serialize the secret key +* +* Arguments: - unsigned char *r: pointer to output serialized secret key +* - const polyvec *sk: pointer to input vector of polynomials (secret key) +**************************************************/ +static void pack_sk(unsigned char *r, polyvec *sk) { + PQCLEAN_KYBER1024_CLEAN_polyvec_tobytes(r, sk); +} + +/************************************************* +* Name: unpack_sk +* +* Description: De-serialize the secret key; +* inverse of pack_sk +* +* Arguments: - polyvec *sk: pointer to output vector of polynomials (secret key) +* - const unsigned char *packedsk: pointer to input serialized secret key +**************************************************/ +static void unpack_sk(polyvec *sk, const unsigned char *packedsk) { + PQCLEAN_KYBER1024_CLEAN_polyvec_frombytes(sk, packedsk); +} + +/************************************************* +* Name: pack_ciphertext +* +* Description: Serialize the ciphertext as concatenation of the +* compressed and serialized vector of polynomials b +* and the compressed and serialized polynomial v +* +* Arguments: unsigned char *r: pointer to the output serialized ciphertext +* const poly *pk: pointer to the input vector of polynomials b +* const unsigned char *seed: pointer to the input polynomial v +**************************************************/ +static void pack_ciphertext(unsigned char *r, polyvec *b, poly *v) { + PQCLEAN_KYBER1024_CLEAN_polyvec_compress(r, b); + PQCLEAN_KYBER1024_CLEAN_poly_compress(r + KYBER_POLYVECCOMPRESSEDBYTES, v); +} + +/************************************************* +* Name: unpack_ciphertext +* +* Description: De-serialize and decompress ciphertext from a byte array; +* approximate inverse of pack_ciphertext +* +* Arguments: - polyvec *b: pointer to the output vector of polynomials b +* - poly *v: pointer to the output polynomial v +* - const unsigned char *c: pointer to the input serialized ciphertext +**************************************************/ +static void unpack_ciphertext(polyvec *b, poly *v, const unsigned char *c) { + PQCLEAN_KYBER1024_CLEAN_polyvec_decompress(b, c); + PQCLEAN_KYBER1024_CLEAN_poly_decompress(v, c + KYBER_POLYVECCOMPRESSEDBYTES); +} + +/************************************************* +* Name: rej_uniform +* +* Description: Run rejection sampling on uniform random bytes to generate +* uniform random integers mod q +* +* Arguments: - int16_t *r: pointer to output buffer +* - unsigned int len: requested number of 16-bit integers (uniform mod q) +* - const unsigned char *buf: pointer to input buffer (assumed to be uniform random bytes) +* - unsigned int buflen: length of input buffer in bytes +* +* Returns number of sampled 16-bit integers (at most len) +**************************************************/ +static unsigned int rej_uniform(int16_t *r, unsigned int len, const unsigned char *buf, unsigned int buflen) { + unsigned int ctr, pos; + uint16_t val; + + ctr = pos = 0; + while (ctr < len && pos + 2 <= buflen) { + val = buf[pos] | ((uint16_t)buf[pos + 1] << 8); + pos += 2; + + if (val < 19 * KYBER_Q) { + val -= (val >> 12) * KYBER_Q; // Barrett reduction + r[ctr++] = (int16_t)val; + } + } + + return ctr; +} + +#define gen_a(A,B) PQCLEAN_KYBER1024_CLEAN_gen_matrix(A,B,0) +#define gen_at(A,B) PQCLEAN_KYBER1024_CLEAN_gen_matrix(A,B,1) + +#define GENMATRIX_MAXNBLOCKS ((530 + XOF_BLOCKBYTES) / XOF_BLOCKBYTES) /* 530 is expected number of required bytes */ + + +/************************************************* +* Name: gen_matrix +* +* Description: Deterministically generate matrix A (or the transpose of A) +* from a seed. Entries of the matrix are polynomials that look +* uniformly random. Performs rejection sampling on output of +* a XOF +* +* Arguments: - polyvec *a: pointer to ouptput matrix A +* - const unsigned char *seed: pointer to input seed +* - int transposed: boolean deciding whether A or A^T is generated +**************************************************/ +static void PQCLEAN_KYBER1024_CLEAN_gen_matrix(polyvec *a, const unsigned char *seed, int transposed) { + unsigned int ctr; + unsigned char i, j; + unsigned char buf[XOF_BLOCKBYTES * GENMATRIX_MAXNBLOCKS + 1]; + xof_state state; + + for (i = 0; i < KYBER_K; i++) { + for (j = 0; j < KYBER_K; j++) { + if (transposed) { + xof_absorb(&state, seed, i, j); + } else { + xof_absorb(&state, seed, j, i); + } + + xof_squeezeblocks(buf, GENMATRIX_MAXNBLOCKS, &state); + ctr = rej_uniform(a[i].vec[j].coeffs, KYBER_N, buf, GENMATRIX_MAXNBLOCKS * XOF_BLOCKBYTES); + + while (ctr < KYBER_N) { + xof_squeezeblocks(buf, 1, &state); + ctr += rej_uniform(a[i].vec[j].coeffs + ctr, KYBER_N - ctr, buf, XOF_BLOCKBYTES); + } + } + } +} + +/************************************************* +* Name: indcpa_keypair +* +* Description: Generates public and private key for the CPA-secure +* public-key encryption scheme underlying Kyber +* +* Arguments: - unsigned char *pk: pointer to output public key (of length KYBER_INDCPA_PUBLICKEYBYTES bytes) +* - unsigned char *sk: pointer to output private key (of length KYBER_INDCPA_SECRETKEYBYTES bytes) +**************************************************/ +void PQCLEAN_KYBER1024_CLEAN_indcpa_keypair(unsigned char *pk, unsigned char *sk) { + polyvec a[KYBER_K], e, pkpv, skpv; + unsigned char buf[2 * KYBER_SYMBYTES]; + unsigned char *publicseed = buf; + unsigned char *noiseseed = buf + KYBER_SYMBYTES; + int i; + unsigned char nonce = 0; + + randombytes(buf, KYBER_SYMBYTES); + hash_g(buf, buf, KYBER_SYMBYTES); + + gen_a(a, publicseed); + + for (i = 0; i < KYBER_K; i++) { + PQCLEAN_KYBER1024_CLEAN_poly_getnoise(skpv.vec + i, noiseseed, nonce++); + } + for (i = 0; i < KYBER_K; i++) { + PQCLEAN_KYBER1024_CLEAN_poly_getnoise(e.vec + i, noiseseed, nonce++); + } + + PQCLEAN_KYBER1024_CLEAN_polyvec_ntt(&skpv); + PQCLEAN_KYBER1024_CLEAN_polyvec_ntt(&e); + + // matrix-vector multiplication + for (i = 0; i < KYBER_K; i++) { + PQCLEAN_KYBER1024_CLEAN_polyvec_pointwise_acc(&pkpv.vec[i], &a[i], &skpv); + PQCLEAN_KYBER1024_CLEAN_poly_frommont(&pkpv.vec[i]); + } + + PQCLEAN_KYBER1024_CLEAN_polyvec_add(&pkpv, &pkpv, &e); + PQCLEAN_KYBER1024_CLEAN_polyvec_reduce(&pkpv); + + pack_sk(sk, &skpv); + pack_pk(pk, &pkpv, publicseed); +} + +/************************************************* +* Name: indcpa_enc +* +* Description: Encryption function of the CPA-secure +* public-key encryption scheme underlying Kyber. +* +* Arguments: - unsigned char *c: pointer to output ciphertext (of length KYBER_INDCPA_BYTES bytes) +* - const unsigned char *m: pointer to input message (of length KYBER_INDCPA_MSGBYTES bytes) +* - const unsigned char *pk: pointer to input public key (of length KYBER_INDCPA_PUBLICKEYBYTES bytes) +* - const unsigned char *coin: pointer to input random coins used as seed (of length KYBER_SYMBYTES bytes) +* to deterministically generate all randomness +**************************************************/ +void PQCLEAN_KYBER1024_CLEAN_indcpa_enc(unsigned char *c, + const unsigned char *m, + const unsigned char *pk, + const unsigned char *coins) { + polyvec sp, pkpv, ep, at[KYBER_K], bp; + poly v, k, epp; + unsigned char seed[KYBER_SYMBYTES]; + int i; + unsigned char nonce = 0; + + unpack_pk(&pkpv, seed, pk); + PQCLEAN_KYBER1024_CLEAN_poly_frommsg(&k, m); + gen_at(at, seed); + + for (i = 0; i < KYBER_K; i++) { + PQCLEAN_KYBER1024_CLEAN_poly_getnoise(sp.vec + i, coins, nonce++); + } + for (i = 0; i < KYBER_K; i++) { + PQCLEAN_KYBER1024_CLEAN_poly_getnoise(ep.vec + i, coins, nonce++); + } + PQCLEAN_KYBER1024_CLEAN_poly_getnoise(&epp, coins, nonce++); + + PQCLEAN_KYBER1024_CLEAN_polyvec_ntt(&sp); + + // matrix-vector multiplication + for (i = 0; i < KYBER_K; i++) { + PQCLEAN_KYBER1024_CLEAN_polyvec_pointwise_acc(&bp.vec[i], &at[i], &sp); + } + + PQCLEAN_KYBER1024_CLEAN_polyvec_pointwise_acc(&v, &pkpv, &sp); + + PQCLEAN_KYBER1024_CLEAN_polyvec_invntt(&bp); + PQCLEAN_KYBER1024_CLEAN_poly_invntt(&v); + + PQCLEAN_KYBER1024_CLEAN_polyvec_add(&bp, &bp, &ep); + PQCLEAN_KYBER1024_CLEAN_poly_add(&v, &v, &epp); + PQCLEAN_KYBER1024_CLEAN_poly_add(&v, &v, &k); + PQCLEAN_KYBER1024_CLEAN_polyvec_reduce(&bp); + PQCLEAN_KYBER1024_CLEAN_poly_reduce(&v); + + pack_ciphertext(c, &bp, &v); +} + +/************************************************* +* Name: indcpa_dec +* +* Description: Decryption function of the CPA-secure +* public-key encryption scheme underlying Kyber. +* +* Arguments: - unsigned char *m: pointer to output decrypted message (of length KYBER_INDCPA_MSGBYTES) +* - const unsigned char *c: pointer to input ciphertext (of length KYBER_INDCPA_BYTES) +* - const unsigned char *sk: pointer to input secret key (of length KYBER_INDCPA_SECRETKEYBYTES) +**************************************************/ +void PQCLEAN_KYBER1024_CLEAN_indcpa_dec(unsigned char *m, + const unsigned char *c, + const unsigned char *sk) { + polyvec bp, skpv; + poly v, mp; + + unpack_ciphertext(&bp, &v, c); + unpack_sk(&skpv, sk); + + PQCLEAN_KYBER1024_CLEAN_polyvec_ntt(&bp); + PQCLEAN_KYBER1024_CLEAN_polyvec_pointwise_acc(&mp, &skpv, &bp); + PQCLEAN_KYBER1024_CLEAN_poly_invntt(&mp); + + PQCLEAN_KYBER1024_CLEAN_poly_sub(&mp, &v, &mp); + PQCLEAN_KYBER1024_CLEAN_poly_reduce(&mp); + + PQCLEAN_KYBER1024_CLEAN_poly_tomsg(m, &mp); +} diff --git a/crypto_kem/kyber1024/clean/indcpa.h b/crypto_kem/kyber1024/clean/indcpa.h new file mode 100644 index 00000000..13fea401 --- /dev/null +++ b/crypto_kem/kyber1024/clean/indcpa.h @@ -0,0 +1,16 @@ +#ifndef INDCPA_H +#define INDCPA_H + +void PQCLEAN_KYBER1024_CLEAN_indcpa_keypair(unsigned char *pk, + unsigned char *sk); + +void PQCLEAN_KYBER1024_CLEAN_indcpa_enc(unsigned char *c, + const unsigned char *m, + const unsigned char *pk, + const unsigned char *coins); + +void PQCLEAN_KYBER1024_CLEAN_indcpa_dec(unsigned char *m, + const unsigned char *c, + const unsigned char *sk); + +#endif diff --git a/crypto_kem/kyber1024/clean/kem.c b/crypto_kem/kyber1024/clean/kem.c new file mode 100644 index 00000000..6e50a8ac --- /dev/null +++ b/crypto_kem/kyber1024/clean/kem.c @@ -0,0 +1,100 @@ +#include "api.h" +#include "indcpa.h" +#include "params.h" +#include "randombytes.h" +#include "symmetric.h" +#include "verify.h" + +#include + +/************************************************* +* Name: crypto_kem_keypair +* +* Description: Generates public and private key +* for CCA-secure Kyber key encapsulation mechanism +* +* Arguments: - unsigned char *pk: pointer to output public key (an already allocated array of CRYPTO_PUBLICKEYBYTES bytes) +* - unsigned char *sk: pointer to output private key (an already allocated array of CRYPTO_SECRETKEYBYTES bytes) +* +* Returns 0 (success) +**************************************************/ +int PQCLEAN_KYBER1024_CLEAN_crypto_kem_keypair(unsigned char *pk, unsigned char *sk) { + size_t i; + PQCLEAN_KYBER1024_CLEAN_indcpa_keypair(pk, sk); + for (i = 0; i < KYBER_INDCPA_PUBLICKEYBYTES; i++) { + sk[i + KYBER_INDCPA_SECRETKEYBYTES] = pk[i]; + } + hash_h(sk + KYBER_SECRETKEYBYTES - 2 * KYBER_SYMBYTES, pk, KYBER_PUBLICKEYBYTES); + randombytes(sk + KYBER_SECRETKEYBYTES - KYBER_SYMBYTES, KYBER_SYMBYTES); /* Value z for pseudo-random output on reject */ + return 0; +} + +/************************************************* +* Name: crypto_kem_enc +* +* Description: Generates cipher text and shared +* secret for given public key +* +* Arguments: - unsigned char *ct: pointer to output cipher text (an already allocated array of CRYPTO_CIPHERTEXTBYTES bytes) +* - unsigned char *ss: pointer to output shared secret (an already allocated array of CRYPTO_BYTES bytes) +* - const unsigned char *pk: pointer to input public key (an already allocated array of CRYPTO_PUBLICKEYBYTES bytes) +* +* Returns 0 (success) +**************************************************/ +int PQCLEAN_KYBER1024_CLEAN_crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk) { + unsigned char kr[2 * KYBER_SYMBYTES]; /* Will contain key, coins */ + unsigned char buf[2 * KYBER_SYMBYTES]; + + randombytes(buf, KYBER_SYMBYTES); + hash_h(buf, buf, KYBER_SYMBYTES); /* Don't release system RNG output */ + + hash_h(buf + KYBER_SYMBYTES, pk, KYBER_PUBLICKEYBYTES); /* Multitarget countermeasure for coins + contributory KEM */ + hash_g(kr, buf, 2 * KYBER_SYMBYTES); + + PQCLEAN_KYBER1024_CLEAN_indcpa_enc(ct, buf, pk, kr + KYBER_SYMBYTES); /* coins are in kr+KYBER_SYMBYTES */ + + hash_h(kr + KYBER_SYMBYTES, ct, KYBER_CIPHERTEXTBYTES); /* overwrite coins in kr with H(c) */ + kdf(ss, kr, 2 * KYBER_SYMBYTES); /* hash concatenation of pre-k and H(c) to k */ + return 0; +} + +/************************************************* +* Name: crypto_kem_dec +* +* Description: Generates shared secret for given +* cipher text and private key +* +* Arguments: - unsigned char *ss: pointer to output shared secret (an already allocated array of CRYPTO_BYTES bytes) +* - const unsigned char *ct: pointer to input cipher text (an already allocated array of CRYPTO_CIPHERTEXTBYTES bytes) +* - const unsigned char *sk: pointer to input private key (an already allocated array of CRYPTO_SECRETKEYBYTES bytes) +* +* Returns 0. +* +* On failure, ss will contain a pseudo-random value. +**************************************************/ +int PQCLEAN_KYBER1024_CLEAN_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk) { + size_t i; + unsigned char fail; + unsigned char cmp[KYBER_CIPHERTEXTBYTES]; + unsigned char buf[2 * KYBER_SYMBYTES]; + unsigned char kr[2 * KYBER_SYMBYTES]; /* Will contain key, coins */ + const unsigned char *pk = sk + KYBER_INDCPA_SECRETKEYBYTES; + + PQCLEAN_KYBER1024_CLEAN_indcpa_dec(buf, ct, sk); + + for (i = 0; i < KYBER_SYMBYTES; i++) { /* Multitarget countermeasure for coins + contributory KEM */ + buf[KYBER_SYMBYTES + i] = sk[KYBER_SECRETKEYBYTES - 2 * KYBER_SYMBYTES + i]; /* Save hash by storing H(pk) in sk */ + } + hash_g(kr, buf, 2 * KYBER_SYMBYTES); + + PQCLEAN_KYBER1024_CLEAN_indcpa_enc(cmp, buf, pk, kr + KYBER_SYMBYTES); /* coins are in kr+KYBER_SYMBYTES */ + + fail = PQCLEAN_KYBER1024_CLEAN_verify(ct, cmp, KYBER_CIPHERTEXTBYTES); + + hash_h(kr + KYBER_SYMBYTES, ct, KYBER_CIPHERTEXTBYTES); /* overwrite coins in kr with H(c) */ + + PQCLEAN_KYBER1024_CLEAN_cmov(kr, sk + KYBER_SECRETKEYBYTES - KYBER_SYMBYTES, KYBER_SYMBYTES, fail); /* Overwrite pre-k with z on re-encryption failure */ + + kdf(ss, kr, 2 * KYBER_SYMBYTES); /* hash concatenation of pre-k and H(c) to k */ + return 0; +} diff --git a/crypto_kem/kyber1024/clean/ntt.c b/crypto_kem/kyber1024/clean/ntt.c new file mode 100644 index 00000000..0c59d646 --- /dev/null +++ b/crypto_kem/kyber1024/clean/ntt.c @@ -0,0 +1,157 @@ +#include "ntt.h" + +#include "params.h" +#include "reduce.h" + +#include + +/* Code to generate zetas and zetas_inv used in the number-theoretic transform: + +#define KYBER_ROOT_OF_UNITY 17 + +static const uint16_t tree[128] = { + 0, 64, 32, 96, 16, 80, 48, 112, 8, 72, 40, 104, 24, 88, 56, 120, + 4, 68, 36, 100, 20, 84, 52, 116, 12, 76, 44, 108, 28, 92, 60, 124, + 2, 66, 34, 98, 18, 82, 50, 114, 10, 74, 42, 106, 26, 90, 58, 122, + 6, 70, 38, 102, 22, 86, 54, 118, 14, 78, 46, 110, 30, 94, 62, 126, + 1, 65, 33, 97, 17, 81, 49, 113, 9, 73, 41, 105, 25, 89, 57, 121, + 5, 69, 37, 101, 21, 85, 53, 117, 13, 77, 45, 109, 29, 93, 61, 125, + 3, 67, 35, 99, 19, 83, 51, 115, 11, 75, 43, 107, 27, 91, 59, 123, + 7, 71, 39, 103, 23, 87, 55, 119, 15, 79, 47, 111, 31, 95, 63, 127}; + + +static int16_t fqmul(int16_t a, int16_t b) { + return montgomery_reduce((int32_t)a*b); +} + +void init_ntt() { + unsigned int i, j, k; + int16_t tmp[128]; + + tmp[0] = MONT; + for(i = 1; i < 128; ++i) + tmp[i] = fqmul(tmp[i-1], KYBER_ROOT_OF_UNITY*MONT % KYBER_Q); + + for(i = 0; i < 128; ++i) + zetas[i] = tmp[tree[i]]; + + k = 0; + for(i = 64; i >= 1; i >>= 1) + for(j = i; j < 2*i; ++j) + zetas_inv[k++] = -tmp[128 - tree[j]]; + + zetas_inv[127] = MONT * (MONT * (KYBER_Q - 1) * ((KYBER_Q - 1)/128) % KYBER_Q) % KYBER_Q; +} + +*/ +int16_t PQCLEAN_KYBER1024_CLEAN_zetas[128] = { + 2285, 2571, 2970, 1812, 1493, 1422, 287, 202, 3158, 622, 1577, 182, 962, 2127, 1855, 1468, + 573, 2004, 264, 383, 2500, 1458, 1727, 3199, 2648, 1017, 732, 608, 1787, 411, 3124, 1758, + 1223, 652, 2777, 1015, 2036, 1491, 3047, 1785, 516, 3321, 3009, 2663, 1711, 2167, 126, 1469, + 2476, 3239, 3058, 830, 107, 1908, 3082, 2378, 2931, 961, 1821, 2604, 448, 2264, 677, 2054, + 2226, 430, 555, 843, 2078, 871, 1550, 105, 422, 587, 177, 3094, 3038, 2869, 1574, 1653, + 3083, 778, 1159, 3182, 2552, 1483, 2727, 1119, 1739, 644, 2457, 349, 418, 329, 3173, 3254, + 817, 1097, 603, 610, 1322, 2044, 1864, 384, 2114, 3193, 1218, 1994, 2455, 220, 2142, 1670, + 2144, 1799, 2051, 794, 1819, 2475, 2459, 478, 3221, 3021, 996, 991, 958, 1869, 1522, 1628 +}; + +int16_t PQCLEAN_KYBER1024_CLEAN_zetas_inv[128] = { + 1701, 1807, 1460, 2371, 2338, 2333, 308, 108, 2851, 870, 854, 1510, 2535, 1278, 1530, 1185, + 1659, 1187, 3109, 874, 1335, 2111, 136, 1215, 2945, 1465, 1285, 2007, 2719, 2726, 2232, 2512, + 75, 156, 3000, 2911, 2980, 872, 2685, 1590, 2210, 602, 1846, 777, 147, 2170, 2551, 246, + 1676, 1755, 460, 291, 235, 3152, 2742, 2907, 3224, 1779, 2458, 1251, 2486, 2774, 2899, 1103, + 1275, 2652, 1065, 2881, 725, 1508, 2368, 398, 951, 247, 1421, 3222, 2499, 271, 90, 853, + 1860, 3203, 1162, 1618, 666, 320, 8, 2813, 1544, 282, 1838, 1293, 2314, 552, 2677, 2106, + 1571, 205, 2918, 1542, 2721, 2597, 2312, 681, 130, 1602, 1871, 829, 2946, 3065, 1325, 2756, + 1861, 1474, 1202, 2367, 3147, 1752, 2707, 171, 3127, 3042, 1907, 1836, 1517, 359, 758, 1441 +}; + + +/************************************************* +* Name: fqmul +* +* Description: Multiplication followed by Montgomery reduction +* +* Arguments: - int16_t a: first factor +* - int16_t b: second factor +* +* Returns 16-bit integer congruent to a*b*R^{-1} mod q +**************************************************/ +static int16_t fqmul(int16_t a, int16_t b) { + return PQCLEAN_KYBER1024_CLEAN_montgomery_reduce((int32_t)a * b); +} + +/************************************************* +* Name: ntt +* +* Description: Inplace number-theoretic transform (NTT) in Rq +* input is in standard order, output is in bitreversed order +* +* Arguments: - int16_t *poly: pointer to input/output vector of 256 elements of Zq +**************************************************/ +void PQCLEAN_KYBER1024_CLEAN_ntt(int16_t *poly) { + unsigned int len, start, j, k; + int16_t t, zeta; + + k = 1; + for (len = 128; len >= 2; len >>= 1) { + for (start = 0; start < 256; start = j + len) { + zeta = PQCLEAN_KYBER1024_CLEAN_zetas[k++]; + for (j = start; j < start + len; ++j) { + t = fqmul(zeta, poly[j + len]); + poly[j + len] = poly[j] - t; + poly[j] = poly[j] + t; + } + } + } +} + +/************************************************* +* Name: invntt +* +* Description: Inplace inverse number-theoretic transform in Rq +* input is in bitreversed order, output is in standard order +* +* Arguments: - int16_t *poly: pointer to input/output vector of 256 elements of Zq +**************************************************/ +void PQCLEAN_KYBER1024_CLEAN_invntt(int16_t *poly) { + unsigned int start, len, j, k; + int16_t t, zeta; + + k = 0; + for (len = 2; len <= 128; len <<= 1) { + for (start = 0; start < 256; start = j + len) { + zeta = PQCLEAN_KYBER1024_CLEAN_zetas_inv[k++]; + for (j = start; j < start + len; ++j) { + t = poly[j]; + poly[j] = PQCLEAN_KYBER1024_CLEAN_barrett_reduce(t + poly[j + len]); + poly[j + len] = t - poly[j + len]; + poly[j + len] = fqmul(zeta, poly[j + len]); + } + } + } + + for (j = 0; j < 256; ++j) { + poly[j] = fqmul(poly[j], PQCLEAN_KYBER1024_CLEAN_zetas_inv[127]); + } +} + +/************************************************* +* Name: PQCLEAN_KYBER1024_CLEAN_basemul +* +* Description: Multiplication of polynomials in Zq[X]/((X^2-zeta)) +* used for multiplication of elements in Rq in NTT domain +* +* Arguments: - int16_t r[2]: pointer to the output polynomial +* - const int16_t a[2]: pointer to the first factor +* - const int16_t b[2]: pointer to the second factor +* - int16_t zeta: integer defining the reduction polynomial +**************************************************/ +void PQCLEAN_KYBER1024_CLEAN_basemul(int16_t r[2], const int16_t a[2], const int16_t b[2], int16_t zeta) { + r[0] = fqmul(a[1], b[1]); + r[0] = fqmul(r[0], zeta); + r[0] += fqmul(a[0], b[0]); + + r[1] = fqmul(a[0], b[1]); + r[1] += fqmul(a[1], b[0]); +} diff --git a/crypto_kem/kyber1024/clean/ntt.h b/crypto_kem/kyber1024/clean/ntt.h new file mode 100644 index 00000000..0827eab6 --- /dev/null +++ b/crypto_kem/kyber1024/clean/ntt.h @@ -0,0 +1,13 @@ +#ifndef NTT_H +#define NTT_H + +#include + +extern int16_t PQCLEAN_KYBER1024_CLEAN_zetas[128]; +extern int16_t PQCLEAN_KYBER1024_CLEAN_zetas_inv[128]; + +void PQCLEAN_KYBER1024_CLEAN_ntt(int16_t *poly); +void PQCLEAN_KYBER1024_CLEAN_invntt(int16_t *poly); +void PQCLEAN_KYBER1024_CLEAN_basemul(int16_t r[2], const int16_t a[2], const int16_t b[2], int16_t zeta); + +#endif diff --git a/crypto_kem/kyber1024/clean/params.h b/crypto_kem/kyber1024/clean/params.h new file mode 100644 index 00000000..a3153e7e --- /dev/null +++ b/crypto_kem/kyber1024/clean/params.h @@ -0,0 +1,31 @@ +#ifndef PARAMS_H +#define PARAMS_H + +#define KYBER_K 4 /* Change this for different security strengths */ + +/* Don't change parameters below this line */ + +#define KYBER_N 256 +#define KYBER_Q 3329 + +#define KYBER_ETA 2 + +#define KYBER_SYMBYTES 32 /* size in bytes of hashes, and seeds */ +#define KYBER_SSBYTES 32 /* size in bytes of shared key */ + +#define KYBER_POLYBYTES 384 +#define KYBER_POLYVECBYTES (KYBER_K * KYBER_POLYBYTES) + +#define KYBER_POLYCOMPRESSEDBYTES 160 +#define KYBER_POLYVECCOMPRESSEDBYTES (KYBER_K * 352) + +#define KYBER_INDCPA_MSGBYTES KYBER_SYMBYTES +#define KYBER_INDCPA_PUBLICKEYBYTES (KYBER_POLYVECBYTES + KYBER_SYMBYTES) +#define KYBER_INDCPA_SECRETKEYBYTES (KYBER_POLYVECBYTES) +#define KYBER_INDCPA_BYTES (KYBER_POLYVECCOMPRESSEDBYTES + KYBER_POLYCOMPRESSEDBYTES) + +#define KYBER_PUBLICKEYBYTES (KYBER_INDCPA_PUBLICKEYBYTES) +#define KYBER_SECRETKEYBYTES (KYBER_INDCPA_SECRETKEYBYTES + KYBER_INDCPA_PUBLICKEYBYTES + 2*KYBER_SYMBYTES) /* 32 bytes of additional space to save H(pk) */ +#define KYBER_CIPHERTEXTBYTES KYBER_INDCPA_BYTES + +#endif diff --git a/crypto_kem/kyber1024/clean/poly.c b/crypto_kem/kyber1024/clean/poly.c new file mode 100644 index 00000000..83bcb2f0 --- /dev/null +++ b/crypto_kem/kyber1024/clean/poly.c @@ -0,0 +1,289 @@ +#include "poly.h" + +#include "cbd.h" +#include "ntt.h" +#include "params.h" +#include "reduce.h" +#include "symmetric.h" + +#include + +/************************************************* +* Name: PQCLEAN_KYBER1024_CLEAN_poly_compress +* +* Description: Compression and subsequent serialization of a polynomial +* +* Arguments: - unsigned char *r: pointer to output byte array (needs space for KYBER_POLYCOMPRESSEDBYTES bytes) +* - const poly *a: pointer to input polynomial +**************************************************/ +void PQCLEAN_KYBER1024_CLEAN_poly_compress(unsigned char *r, poly *a) { + uint8_t t[8]; + int i, j, k = 0; + + PQCLEAN_KYBER1024_CLEAN_poly_csubq(a); + + for (i = 0; i < KYBER_N; i += 8) { + for (j = 0; j < 8; j++) { + t[j] = ((((uint32_t)a->coeffs[i + j] << 5) + KYBER_Q / 2) / KYBER_Q) & 31; + } + + r[k] = t[0] | (t[1] << 5); + r[k + 1] = (t[1] >> 3) | (t[2] << 2) | (t[3] << 7); + r[k + 2] = (t[3] >> 1) | (t[4] << 4); + r[k + 3] = (t[4] >> 4) | (t[5] << 1) | (t[6] << 6); + r[k + 4] = (t[6] >> 2) | (t[7] << 3); + k += 5; + } +} + +/************************************************* +* Name: PQCLEAN_KYBER1024_CLEAN_poly_decompress +* +* Description: De-serialization and subsequent decompression of a polynomial; +* approximate inverse of PQCLEAN_KYBER1024_CLEAN_poly_compress +* +* Arguments: - poly *r: pointer to output polynomial +* - const unsigned char *a: pointer to input byte array (of length KYBER_POLYCOMPRESSEDBYTES bytes) +**************************************************/ +void PQCLEAN_KYBER1024_CLEAN_poly_decompress(poly *r, const unsigned char *a) { + int i; + for (i = 0; i < KYBER_N; i += 8) { + r->coeffs[i + 0] = (((a[0] & 31) * KYBER_Q) + 16) >> 5; + r->coeffs[i + 1] = ((((a[0] >> 5) | ((a[1] & 3) << 3)) * KYBER_Q) + 16) >> 5; + r->coeffs[i + 2] = ((((a[1] >> 2) & 31) * KYBER_Q) + 16) >> 5; + r->coeffs[i + 3] = ((((a[1] >> 7) | ((a[2] & 15) << 1)) * KYBER_Q) + 16) >> 5; + r->coeffs[i + 4] = ((((a[2] >> 4) | ((a[3] & 1) << 4)) * KYBER_Q) + 16) >> 5; + r->coeffs[i + 5] = ((((a[3] >> 1) & 31) * KYBER_Q) + 16) >> 5; + r->coeffs[i + 6] = ((((a[3] >> 6) | ((a[4] & 7) << 2)) * KYBER_Q) + 16) >> 5; + r->coeffs[i + 7] = (((a[4] >> 3) * KYBER_Q) + 16) >> 5; + a += 5; + } +} + +/************************************************* +* Name: PQCLEAN_KYBER1024_CLEAN_poly_tobytes +* +* Description: Serialization of a polynomial +* +* Arguments: - unsigned char *r: pointer to output byte array (needs space for KYBER_POLYBYTES bytes) +* - const poly *a: pointer to input polynomial +**************************************************/ +void PQCLEAN_KYBER1024_CLEAN_poly_tobytes(unsigned char *r, poly *a) { + int i; + uint16_t t0, t1; + + PQCLEAN_KYBER1024_CLEAN_poly_csubq(a); + + for (i = 0; i < KYBER_N / 2; i++) { + t0 = a->coeffs[2 * i]; + t1 = a->coeffs[2 * i + 1]; + r[3 * i] = t0 & 0xff; + r[3 * i + 1] = (t0 >> 8) | ((t1 & 0xf) << 4); + r[3 * i + 2] = (t1 >> 4) & 0xff; + } +} + +/************************************************* +* Name: PQCLEAN_KYBER1024_CLEAN_poly_frombytes +* +* Description: De-serialization of a polynomial; +* inverse of PQCLEAN_KYBER1024_CLEAN_poly_tobytes +* +* Arguments: - poly *r: pointer to output polynomial +* - const unsigned char *a: pointer to input byte array (of KYBER_POLYBYTES bytes) +**************************************************/ +void PQCLEAN_KYBER1024_CLEAN_poly_frombytes(poly *r, const unsigned char *a) { + int i; + + for (i = 0; i < KYBER_N / 2; i++) { + r->coeffs[2 * i] = a[3 * i] | ((uint16_t)a[3 * i + 1] & 0x0f) << 8; + r->coeffs[2 * i + 1] = a[3 * i + 1] >> 4 | ((uint16_t)a[3 * i + 2] & 0xff) << 4; + } +} + +/************************************************* +* Name: PQCLEAN_KYBER1024_CLEAN_poly_getnoise +* +* Description: Sample a polynomial deterministically from a seed and a nonce, +* with output polynomial close to centered binomial distribution +* with parameter KYBER_ETA +* +* Arguments: - poly *r: pointer to output polynomial +* - const unsigned char *seed: pointer to input seed (pointing to array of length KYBER_SYMBYTES bytes) +* - unsigned char nonce: one-byte input nonce +**************************************************/ +void PQCLEAN_KYBER1024_CLEAN_poly_getnoise(poly *r, const unsigned char *seed, unsigned char nonce) { + unsigned char buf[KYBER_ETA * KYBER_N / 4]; + + prf(buf, KYBER_ETA * KYBER_N / 4, seed, nonce); + PQCLEAN_KYBER1024_CLEAN_cbd(r, buf); +} + +/************************************************* +* Name: PQCLEAN_KYBER1024_CLEAN_poly_ntt +* +* Description: Computes negacyclic number-theoretic transform (NTT) of +* a polynomial in place; +* inputs assumed to be in normal order, output in bitreversed order +* +* Arguments: - uint16_t *r: pointer to in/output polynomial +**************************************************/ +void PQCLEAN_KYBER1024_CLEAN_poly_ntt(poly *r) { + PQCLEAN_KYBER1024_CLEAN_ntt(r->coeffs); + PQCLEAN_KYBER1024_CLEAN_poly_reduce(r); +} + +/************************************************* +* Name: PQCLEAN_KYBER1024_CLEAN_poly_invntt +* +* Description: Computes inverse of negacyclic number-theoretic transform (NTT) of +* a polynomial in place; +* inputs assumed to be in bitreversed order, output in normal order +* +* Arguments: - uint16_t *a: pointer to in/output polynomial +**************************************************/ +void PQCLEAN_KYBER1024_CLEAN_poly_invntt(poly *r) { + PQCLEAN_KYBER1024_CLEAN_invntt(r->coeffs); +} + +/************************************************* +* Name: PQCLEAN_KYBER1024_CLEAN_poly_basemul +* +* Description: Multiplication of two polynomials in NTT domain +* +* Arguments: - poly *r: pointer to output polynomial +* - const poly *a: pointer to first input polynomial +* - const poly *b: pointer to second input polynomial +**************************************************/ +void PQCLEAN_KYBER1024_CLEAN_poly_basemul(poly *r, const poly *a, const poly *b) { + unsigned int i; + + for (i = 0; i < KYBER_N / 4; ++i) { + PQCLEAN_KYBER1024_CLEAN_basemul(r->coeffs + 4 * i, a->coeffs + 4 * i, b->coeffs + 4 * i, PQCLEAN_KYBER1024_CLEAN_zetas[64 + i]); + PQCLEAN_KYBER1024_CLEAN_basemul(r->coeffs + 4 * i + 2, a->coeffs + 4 * i + 2, b->coeffs + 4 * i + 2, - PQCLEAN_KYBER1024_CLEAN_zetas[64 + i]); + } +} + +/************************************************* +* Name: PQCLEAN_KYBER1024_CLEAN_poly_frommont +* +* Description: Inplace conversion of all coefficients of a polynomial +* from Montgomery domain to normal domain +* +* Arguments: - poly *r: pointer to input/output polynomial +**************************************************/ +void PQCLEAN_KYBER1024_CLEAN_poly_frommont(poly *r) { + int i; + const int16_t f = (1ULL << 32) % KYBER_Q; + + for (i = 0; i < KYBER_N; i++) { + r->coeffs[i] = PQCLEAN_KYBER1024_CLEAN_montgomery_reduce((int32_t)r->coeffs[i] * f); + } +} + +/************************************************* +* Name: PQCLEAN_KYBER1024_CLEAN_poly_reduce +* +* Description: Applies Barrett reduction to all coefficients of a polynomial +* for details of the Barrett reduction see comments in reduce.c +* +* Arguments: - poly *r: pointer to input/output polynomial +**************************************************/ +void PQCLEAN_KYBER1024_CLEAN_poly_reduce(poly *r) { + int i; + + for (i = 0; i < KYBER_N; i++) { + r->coeffs[i] = PQCLEAN_KYBER1024_CLEAN_barrett_reduce(r->coeffs[i]); + } +} + +/************************************************* +* Name: PQCLEAN_KYBER1024_CLEAN_poly_csubq +* +* Description: Applies conditional subtraction of q to each coefficient of a polynomial +* for details of conditional subtraction of q see comments in reduce.c +* +* Arguments: - poly *r: pointer to input/output polynomial +**************************************************/ +void PQCLEAN_KYBER1024_CLEAN_poly_csubq(poly *r) { + int i; + + for (i = 0; i < KYBER_N; i++) { + r->coeffs[i] = PQCLEAN_KYBER1024_CLEAN_csubq(r->coeffs[i]); + } +} + +/************************************************* +* Name: PQCLEAN_KYBER1024_CLEAN_poly_add +* +* Description: Add two polynomials +* +* Arguments: - poly *r: pointer to output polynomial +* - const poly *a: pointer to first input polynomial +* - const poly *b: pointer to second input polynomial +**************************************************/ +void PQCLEAN_KYBER1024_CLEAN_poly_add(poly *r, const poly *a, const poly *b) { + int i; + for (i = 0; i < KYBER_N; i++) { + r->coeffs[i] = a->coeffs[i] + b->coeffs[i]; + } +} + +/************************************************* +* Name: PQCLEAN_KYBER1024_CLEAN_poly_sub +* +* Description: Subtract two polynomials +* +* Arguments: - poly *r: pointer to output polynomial +* - const poly *a: pointer to first input polynomial +* - const poly *b: pointer to second input polynomial +**************************************************/ +void PQCLEAN_KYBER1024_CLEAN_poly_sub(poly *r, const poly *a, const poly *b) { + int i; + for (i = 0; i < KYBER_N; i++) { + r->coeffs[i] = a->coeffs[i] - b->coeffs[i]; + } +} + +/************************************************* +* Name: PQCLEAN_KYBER1024_CLEAN_poly_frommsg +* +* Description: Convert 32-byte message to polynomial +* +* Arguments: - poly *r: pointer to output polynomial +* - const unsigned char *msg: pointer to input message +**************************************************/ +void PQCLEAN_KYBER1024_CLEAN_poly_frommsg(poly *r, const unsigned char msg[KYBER_SYMBYTES]) { + int i, j; + uint16_t mask; + + for (i = 0; i < KYBER_SYMBYTES; i++) { + for (j = 0; j < 8; j++) { + mask = -((msg[i] >> j) & 1); + r->coeffs[8 * i + j] = mask & ((KYBER_Q + 1) / 2); + } + } +} + +/************************************************* +* Name: PQCLEAN_KYBER1024_CLEAN_poly_tomsg +* +* Description: Convert polynomial to 32-byte message +* +* Arguments: - unsigned char *msg: pointer to output message +* - const poly *a: pointer to input polynomial +**************************************************/ +void PQCLEAN_KYBER1024_CLEAN_poly_tomsg(unsigned char msg[KYBER_SYMBYTES], poly *a) { + uint16_t t; + int i, j; + + PQCLEAN_KYBER1024_CLEAN_poly_csubq(a); + + for (i = 0; i < KYBER_SYMBYTES; i++) { + msg[i] = 0; + for (j = 0; j < 8; j++) { + t = (((a->coeffs[8 * i + j] << 1) + KYBER_Q / 2) / KYBER_Q) & 1; + msg[i] |= t << j; + } + } +} diff --git a/crypto_kem/kyber1024/clean/poly.h b/crypto_kem/kyber1024/clean/poly.h new file mode 100644 index 00000000..2948908d --- /dev/null +++ b/crypto_kem/kyber1024/clean/poly.h @@ -0,0 +1,38 @@ +#ifndef POLY_H +#define POLY_H + +#include "params.h" + +#include + +/* + * Elements of R_q = Z_q[X]/(X^n + 1). Represents polynomial + * coeffs[0] + X*coeffs[1] + X^2*xoeffs[2] + ... + X^{n-1}*coeffs[n-1] + */ +typedef struct { + int16_t coeffs[KYBER_N]; +} poly; + +void PQCLEAN_KYBER1024_CLEAN_poly_compress(unsigned char *r, poly *a); +void PQCLEAN_KYBER1024_CLEAN_poly_decompress(poly *r, const unsigned char *a); + +void PQCLEAN_KYBER1024_CLEAN_poly_tobytes(unsigned char *r, poly *a); +void PQCLEAN_KYBER1024_CLEAN_poly_frombytes(poly *r, const unsigned char *a); + +void PQCLEAN_KYBER1024_CLEAN_poly_frommsg(poly *r, const unsigned char msg[KYBER_SYMBYTES]); +void PQCLEAN_KYBER1024_CLEAN_poly_tomsg(unsigned char msg[KYBER_SYMBYTES], poly *a); + +void PQCLEAN_KYBER1024_CLEAN_poly_getnoise(poly *r, const unsigned char *seed, unsigned char nonce); + +void PQCLEAN_KYBER1024_CLEAN_poly_ntt(poly *r); +void PQCLEAN_KYBER1024_CLEAN_poly_invntt(poly *r); +void PQCLEAN_KYBER1024_CLEAN_poly_basemul(poly *r, const poly *a, const poly *b); +void PQCLEAN_KYBER1024_CLEAN_poly_frommont(poly *r); + +void PQCLEAN_KYBER1024_CLEAN_poly_reduce(poly *r); +void PQCLEAN_KYBER1024_CLEAN_poly_csubq(poly *r); + +void PQCLEAN_KYBER1024_CLEAN_poly_add(poly *r, const poly *a, const poly *b); +void PQCLEAN_KYBER1024_CLEAN_poly_sub(poly *r, const poly *a, const poly *b); + +#endif diff --git a/crypto_kem/kyber1024/clean/polyvec.c b/crypto_kem/kyber1024/clean/polyvec.c new file mode 100644 index 00000000..101d13fb --- /dev/null +++ b/crypto_kem/kyber1024/clean/polyvec.c @@ -0,0 +1,196 @@ +#include "polyvec.h" + +#include "poly.h" + +#include + +/************************************************* +* Name: PQCLEAN_KYBER1024_CLEAN_polyvec_compress +* +* Description: Compress and serialize vector of polynomials +* +* Arguments: - unsigned char *r: pointer to output byte array (needs space for KYBER_POLYVECCOMPRESSEDBYTES) +* - const polyvec *a: pointer to input vector of polynomials +**************************************************/ +void PQCLEAN_KYBER1024_CLEAN_polyvec_compress(unsigned char *r, polyvec *a) { + int i, j, k; + + PQCLEAN_KYBER1024_CLEAN_polyvec_csubq(a); + + uint16_t t[8]; + for (i = 0; i < KYBER_K; i++) { + for (j = 0; j < KYBER_N / 8; j++) { + for (k = 0; k < 8; k++) { + t[k] = ((((uint32_t)a->vec[i].coeffs[8 * j + k] << 11) + KYBER_Q / 2) / KYBER_Q) & 0x7ff; + } + + r[11 * j + 0] = t[0] & 0xff; + r[11 * j + 1] = ((t[0] >> 8) | ((t[1] & 0x1f) << 3)) & 0xff; + r[11 * j + 2] = ((t[1] >> 5) | ((t[2] & 0x03) << 6)) & 0xff; + r[11 * j + 3] = (t[2] >> 2) & 0xff; + r[11 * j + 4] = ((t[2] >> 10) | ((t[3] & 0x7f) << 1)) & 0xff; + r[11 * j + 5] = ((t[3] >> 7) | ((t[4] & 0x0f) << 4)) & 0xff; + r[11 * j + 6] = ((t[4] >> 4) | ((t[5] & 0x01) << 7)) & 0xff; + r[11 * j + 7] = (t[5] >> 1) & 0xff; + r[11 * j + 8] = ((t[5] >> 9) | ((t[6] & 0x3f) << 2)) & 0xff; + r[11 * j + 9] = ((t[6] >> 6) | ((t[7] & 0x07) << 5)) & 0xff; + r[11 * j + 10] = (t[7] >> 3) & 0xff; + } + r += 352; + } +} + +/************************************************* +* Name: PQCLEAN_KYBER1024_CLEAN_polyvec_decompress +* +* Description: De-serialize and decompress vector of polynomials; +* approximate inverse of PQCLEAN_KYBER1024_CLEAN_polyvec_compress +* +* Arguments: - polyvec *r: pointer to output vector of polynomials +* - unsigned char *a: pointer to input byte array (of length KYBER_POLYVECCOMPRESSEDBYTES) +**************************************************/ +void PQCLEAN_KYBER1024_CLEAN_polyvec_decompress(polyvec *r, const unsigned char *a) { + int i, j; + for (i = 0; i < KYBER_K; i++) { + for (j = 0; j < KYBER_N / 8; j++) { + r->vec[i].coeffs[8 * j + 0] = (((a[11 * j + 0] | (((uint32_t)a[11 * j + 1] & 0x07) << 8)) * KYBER_Q) + 1024) >> 11; + r->vec[i].coeffs[8 * j + 1] = ((((a[11 * j + 1] >> 3) | (((uint32_t)a[11 * j + 2] & 0x3f) << 5)) * KYBER_Q) + 1024) >> 11; + r->vec[i].coeffs[8 * j + 2] = ((((a[11 * j + 2] >> 6) | (((uint32_t)a[11 * j + 3] & 0xff) << 2) | (((uint32_t)a[11 * j + 4] & 0x01) << 10)) * KYBER_Q) + 1024) >> 11; + r->vec[i].coeffs[8 * j + 3] = ((((a[11 * j + 4] >> 1) | (((uint32_t)a[11 * j + 5] & 0x0f) << 7)) * KYBER_Q) + 1024) >> 11; + r->vec[i].coeffs[8 * j + 4] = ((((a[11 * j + 5] >> 4) | (((uint32_t)a[11 * j + 6] & 0x7f) << 4)) * KYBER_Q) + 1024) >> 11; + r->vec[i].coeffs[8 * j + 5] = ((((a[11 * j + 6] >> 7) | (((uint32_t)a[11 * j + 7] & 0xff) << 1) | (((uint32_t)a[11 * j + 8] & 0x03) << 9)) * KYBER_Q) + 1024) >> 11; + r->vec[i].coeffs[8 * j + 6] = ((((a[11 * j + 8] >> 2) | (((uint32_t)a[11 * j + 9] & 0x1f) << 6)) * KYBER_Q) + 1024) >> 11; + r->vec[i].coeffs[8 * j + 7] = ((((a[11 * j + 9] >> 5) | (((uint32_t)a[11 * j + 10] & 0xff) << 3)) * KYBER_Q) + 1024) >> 11; + } + a += 352; + } +} + +/************************************************* +* Name: PQCLEAN_KYBER1024_CLEAN_polyvec_tobytes +* +* Description: Serialize vector of polynomials +* +* Arguments: - unsigned char *r: pointer to output byte array (needs space for KYBER_POLYVECBYTES) +* - const polyvec *a: pointer to input vector of polynomials +**************************************************/ +void PQCLEAN_KYBER1024_CLEAN_polyvec_tobytes(unsigned char *r, polyvec *a) { + int i; + for (i = 0; i < KYBER_K; i++) { + PQCLEAN_KYBER1024_CLEAN_poly_tobytes(r + i * KYBER_POLYBYTES, &a->vec[i]); + } +} + +/************************************************* +* Name: PQCLEAN_KYBER1024_CLEAN_polyvec_frombytes +* +* Description: De-serialize vector of polynomials; +* inverse of PQCLEAN_KYBER1024_CLEAN_polyvec_tobytes +* +* Arguments: - unsigned char *r: pointer to output byte array +* - const polyvec *a: pointer to input vector of polynomials (of length KYBER_POLYVECBYTES) +**************************************************/ +void PQCLEAN_KYBER1024_CLEAN_polyvec_frombytes(polyvec *r, const unsigned char *a) { + int i; + for (i = 0; i < KYBER_K; i++) { + PQCLEAN_KYBER1024_CLEAN_poly_frombytes(&r->vec[i], a + i * KYBER_POLYBYTES); + } +} + +/************************************************* +* Name: PQCLEAN_KYBER1024_CLEAN_polyvec_ntt +* +* Description: Apply forward NTT to all elements of a vector of polynomials +* +* Arguments: - polyvec *r: pointer to in/output vector of polynomials +**************************************************/ +void PQCLEAN_KYBER1024_CLEAN_polyvec_ntt(polyvec *r) { + int i; + for (i = 0; i < KYBER_K; i++) { + PQCLEAN_KYBER1024_CLEAN_poly_ntt(&r->vec[i]); + } +} + +/************************************************* +* Name: PQCLEAN_KYBER1024_CLEAN_polyvec_invntt +* +* Description: Apply inverse NTT to all elements of a vector of polynomials +* +* Arguments: - polyvec *r: pointer to in/output vector of polynomials +**************************************************/ +void PQCLEAN_KYBER1024_CLEAN_polyvec_invntt(polyvec *r) { + int i; + for (i = 0; i < KYBER_K; i++) { + PQCLEAN_KYBER1024_CLEAN_poly_invntt(&r->vec[i]); + } +} + +/************************************************* +* Name: PQCLEAN_KYBER1024_CLEAN_polyvec_pointwise_acc +* +* Description: Pointwise multiply elements of a and b and accumulate into r +* +* Arguments: - poly *r: pointer to output polynomial +* - const polyvec *a: pointer to first input vector of polynomials +* - const polyvec *b: pointer to second input vector of polynomials +**************************************************/ +void PQCLEAN_KYBER1024_CLEAN_polyvec_pointwise_acc(poly *r, const polyvec *a, const polyvec *b) { + int i; + poly t; + + PQCLEAN_KYBER1024_CLEAN_poly_basemul(r, &a->vec[0], &b->vec[0]); + for (i = 1; i < KYBER_K; i++) { + PQCLEAN_KYBER1024_CLEAN_poly_basemul(&t, &a->vec[i], &b->vec[i]); + PQCLEAN_KYBER1024_CLEAN_poly_add(r, r, &t); + } + + PQCLEAN_KYBER1024_CLEAN_poly_reduce(r); +} + +/************************************************* +* Name: PQCLEAN_KYBER1024_CLEAN_polyvec_reduce +* +* Description: Applies Barrett reduction to each coefficient +* of each element of a vector of polynomials +* for details of the Barrett reduction see comments in reduce.c +* +* Arguments: - poly *r: pointer to input/output polynomial +**************************************************/ +void PQCLEAN_KYBER1024_CLEAN_polyvec_reduce(polyvec *r) { + int i; + for (i = 0; i < KYBER_K; i++) { + PQCLEAN_KYBER1024_CLEAN_poly_reduce(&r->vec[i]); + } +} + +/************************************************* +* Name: PQCLEAN_KYBER1024_CLEAN_polyvec_csubq +* +* Description: Applies conditional subtraction of q to each coefficient +* of each element of a vector of polynomials +* for details of conditional subtraction of q see comments in reduce.c +* +* Arguments: - poly *r: pointer to input/output polynomial +**************************************************/ +void PQCLEAN_KYBER1024_CLEAN_polyvec_csubq(polyvec *r) { + int i; + for (i = 0; i < KYBER_K; i++) { + PQCLEAN_KYBER1024_CLEAN_poly_csubq(&r->vec[i]); + } +} + +/************************************************* +* Name: PQCLEAN_KYBER1024_CLEAN_polyvec_add +* +* Description: Add vectors of polynomials +* +* Arguments: - polyvec *r: pointer to output vector of polynomials +* - const polyvec *a: pointer to first input vector of polynomials +* - const polyvec *b: pointer to second input vector of polynomials +**************************************************/ +void PQCLEAN_KYBER1024_CLEAN_polyvec_add(polyvec *r, const polyvec *a, const polyvec *b) { + int i; + for (i = 0; i < KYBER_K; i++) { + PQCLEAN_KYBER1024_CLEAN_poly_add(&r->vec[i], &a->vec[i], &b->vec[i]); + } +} diff --git a/crypto_kem/kyber1024/clean/polyvec.h b/crypto_kem/kyber1024/clean/polyvec.h new file mode 100644 index 00000000..85d8df9c --- /dev/null +++ b/crypto_kem/kyber1024/clean/polyvec.h @@ -0,0 +1,27 @@ +#ifndef POLYVEC_H +#define POLYVEC_H + +#include "params.h" +#include "poly.h" + +typedef struct { + poly vec[KYBER_K]; +} polyvec; + +void PQCLEAN_KYBER1024_CLEAN_polyvec_compress(unsigned char *r, polyvec *a); +void PQCLEAN_KYBER1024_CLEAN_polyvec_decompress(polyvec *r, const unsigned char *a); + +void PQCLEAN_KYBER1024_CLEAN_polyvec_tobytes(unsigned char *r, polyvec *a); +void PQCLEAN_KYBER1024_CLEAN_polyvec_frombytes(polyvec *r, const unsigned char *a); + +void PQCLEAN_KYBER1024_CLEAN_polyvec_ntt(polyvec *r); +void PQCLEAN_KYBER1024_CLEAN_polyvec_invntt(polyvec *r); + +void PQCLEAN_KYBER1024_CLEAN_polyvec_pointwise_acc(poly *r, const polyvec *a, const polyvec *b); + +void PQCLEAN_KYBER1024_CLEAN_polyvec_reduce(polyvec *r); +void PQCLEAN_KYBER1024_CLEAN_polyvec_csubq(polyvec *r); + +void PQCLEAN_KYBER1024_CLEAN_polyvec_add(polyvec *r, const polyvec *a, const polyvec *b); + +#endif diff --git a/crypto_kem/kyber1024/clean/reduce.c b/crypto_kem/kyber1024/clean/reduce.c new file mode 100644 index 00000000..d704e3c9 --- /dev/null +++ b/crypto_kem/kyber1024/clean/reduce.c @@ -0,0 +1,62 @@ +#include "reduce.h" + +#include "params.h" + +#include + +/************************************************* +* Name: PQCLEAN_KYBER1024_CLEAN_montgomery_reduce +* +* Description: Montgomery reduction; given a 32-bit integer a, computes +* 16-bit integer congruent to a * R^-1 mod q, +* where R=2^16 +* +* Arguments: - int32_t a: input integer to be reduced; has to be in {-q2^15,...,q2^15-1} +* +* Returns: integer in {-q+1,...,q-1} congruent to a * R^-1 modulo q. +**************************************************/ +int16_t PQCLEAN_KYBER1024_CLEAN_montgomery_reduce(int32_t a) { + int32_t t; + int16_t u; + + u = (int16_t)(a * QINV); + t = (int32_t)u * KYBER_Q; + t = a - t; + t >>= 16; + return (int16_t)t; +} + +/************************************************* +* Name: PQCLEAN_KYBER1024_CLEAN_barrett_reduce +* +* Description: Barrett reduction; given a 16-bit integer a, computes +* 16-bit integer congruent to a mod q in {0,...,q} +* +* Arguments: - int16_t a: input integer to be reduced +* +* Returns: integer in {0,...,q} congruent to a modulo q. +**************************************************/ +int16_t PQCLEAN_KYBER1024_CLEAN_barrett_reduce(int16_t a) { + int32_t t; + const int32_t v = (1U << 26) / KYBER_Q + 1; + + t = v * a; + t >>= 26; + t *= KYBER_Q; + return (int16_t)(a - t); +} + +/************************************************* +* Name: PQCLEAN_KYBER1024_CLEAN_csubq +* +* Description: Conditionallly subtract q +* +* Arguments: - int16_t x: input integer +* +* Returns: a - q if a >= q, else a +**************************************************/ +int16_t PQCLEAN_KYBER1024_CLEAN_csubq(int16_t a) { + a -= KYBER_Q; + a += (a >> 15) & KYBER_Q; + return a; +} diff --git a/crypto_kem/kyber1024/clean/reduce.h b/crypto_kem/kyber1024/clean/reduce.h new file mode 100644 index 00000000..248fd8e1 --- /dev/null +++ b/crypto_kem/kyber1024/clean/reduce.h @@ -0,0 +1,15 @@ +#ifndef REDUCE_H +#define REDUCE_H + +#include + +#define MONT 2285 // 2^16 % Q +#define QINV 62209 // q^(-1) mod 2^16 + +int16_t PQCLEAN_KYBER1024_CLEAN_montgomery_reduce(int32_t a); + +int16_t PQCLEAN_KYBER1024_CLEAN_barrett_reduce(int16_t a); + +int16_t PQCLEAN_KYBER1024_CLEAN_csubq(int16_t a); + +#endif diff --git a/crypto_kem/kyber1024/clean/symmetric-fips202.c b/crypto_kem/kyber1024/clean/symmetric-fips202.c new file mode 100644 index 00000000..b1dbf478 --- /dev/null +++ b/crypto_kem/kyber1024/clean/symmetric-fips202.c @@ -0,0 +1,64 @@ +#include "fips202.h" +#include "symmetric.h" + +#include + +/************************************************* +* Name: PQCLEAN_KYBER1024_CLEAN_kyber_shake128_absorb +* +* Description: Absorb step of the SHAKE128 specialized for the Kyber context. +* +* Arguments: - uint64_t *s: pointer to (uninitialized) output Keccak state +* - const unsigned char *input: pointer to KYBER_SYMBYTES input to be absorbed into s +* - unsigned char i additional byte of input +* - unsigned char j additional byte of input +**************************************************/ +void PQCLEAN_KYBER1024_CLEAN_kyber_shake128_absorb(keccak_state *s, const unsigned char *input, unsigned char x, unsigned char y) { + unsigned char extseed[KYBER_SYMBYTES + 2]; + int i; + + for (i = 0; i < KYBER_SYMBYTES; i++) { + extseed[i] = input[i]; + } + extseed[i++] = x; + extseed[i] = y; + shake128_absorb(s->s, extseed, KYBER_SYMBYTES + 2); +} + +/************************************************* +* Name: PQCLEAN_KYBER1024_CLEAN_kyber_shake128_squeezeblocks +* +* Description: Squeeze step of SHAKE128 XOF. Squeezes full blocks of SHAKE128_RATE bytes each. +* Modifies the state. Can be called multiple times to keep squeezing, +* i.e., is incremental. +* +* Arguments: - unsigned char *output: pointer to output blocks +* - size_t nblocks: number of blocks to be squeezed (written to output) +* - keccak_state *s: pointer to in/output Keccak state +**************************************************/ +void PQCLEAN_KYBER1024_CLEAN_kyber_shake128_squeezeblocks(unsigned char *output, size_t nblocks, keccak_state *s) { + shake128_squeezeblocks(output, nblocks, s->s); +} + +/************************************************* +* Name: PQCLEAN_KYBER1024_CLEAN_shake256_prf +* +* Description: Usage of SHAKE256 as a PRF, concatenates secret and public input +* and then generates outlen bytes of SHAKE256 output +* +* Arguments: - unsigned char *output: pointer to output +* - size_t outlen: number of requested output bytes +* - const unsigned char * key: pointer to the key (of length KYBER_SYMBYTES) +* - const unsigned char nonce: single-byte nonce (public PRF input) +**************************************************/ +void PQCLEAN_KYBER1024_CLEAN_shake256_prf(unsigned char *output, size_t outlen, const unsigned char *key, unsigned char nonce) { + unsigned char extkey[KYBER_SYMBYTES + 1]; + size_t i; + + for (i = 0; i < KYBER_SYMBYTES; i++) { + extkey[i] = key[i]; + } + extkey[i] = nonce; + + shake256(output, outlen, extkey, KYBER_SYMBYTES + 1); +} diff --git a/crypto_kem/kyber1024/clean/symmetric.h b/crypto_kem/kyber1024/clean/symmetric.h new file mode 100644 index 00000000..c67fbd6a --- /dev/null +++ b/crypto_kem/kyber1024/clean/symmetric.h @@ -0,0 +1,28 @@ +#ifndef SYMMETRIC_H +#define SYMMETRIC_H + +#include "fips202.h" +#include "params.h" + +#include + +typedef struct { + uint64_t s[25]; +} keccak_state; + +void PQCLEAN_KYBER1024_CLEAN_kyber_shake128_absorb(keccak_state *s, const unsigned char *input, unsigned char x, unsigned char y); +void PQCLEAN_KYBER1024_CLEAN_kyber_shake128_squeezeblocks(unsigned char *output, size_t nblocks, keccak_state *s); +void PQCLEAN_KYBER1024_CLEAN_shake256_prf(unsigned char *output, size_t outlen, const unsigned char *key, unsigned char nonce); + +#define hash_h(OUT, IN, INBYTES) sha3_256(OUT, IN, INBYTES) +#define hash_g(OUT, IN, INBYTES) sha3_512(OUT, IN, INBYTES) +#define xof_absorb(STATE, IN, X, Y) PQCLEAN_KYBER1024_CLEAN_kyber_shake128_absorb(STATE, IN, X, Y) +#define xof_squeezeblocks(OUT, OUTBLOCKS, STATE) PQCLEAN_KYBER1024_CLEAN_kyber_shake128_squeezeblocks(OUT, OUTBLOCKS, STATE) +#define prf(OUT, OUTBYTES, KEY, NONCE) PQCLEAN_KYBER1024_CLEAN_shake256_prf(OUT, OUTBYTES, KEY, NONCE) +#define kdf(OUT, IN, INBYTES) shake256(OUT, KYBER_SSBYTES, IN, INBYTES) + +#define XOF_BLOCKBYTES 168 + +typedef keccak_state xof_state; + +#endif /* SYMMETRIC_H */ diff --git a/crypto_kem/kyber1024/clean/verify.c b/crypto_kem/kyber1024/clean/verify.c new file mode 100644 index 00000000..1b580c8f --- /dev/null +++ b/crypto_kem/kyber1024/clean/verify.c @@ -0,0 +1,51 @@ +#include "verify.h" + +#include +#include + +/************************************************* +* Name: verify +* +* Description: Compare two arrays for equality in constant time. +* +* Arguments: const unsigned char *a: pointer to first byte array +* const unsigned char *b: pointer to second byte array +* size_t len: length of the byte arrays +* +* Returns 0 if the byte arrays are equal, 1 otherwise +**************************************************/ +unsigned char PQCLEAN_KYBER1024_CLEAN_verify(const unsigned char *a, const unsigned char *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; +} + +/************************************************* +* Name: cmov +* +* Description: Copy len bytes from x to r if b is 1; +* don't modify x if b is 0. Requires b to be in {0,1}; +* assumes two's complement representation of negative integers. +* Runs in constant time. +* +* Arguments: unsigned char *r: pointer to output byte array +* const unsigned char *x: pointer to input byte array +* size_t len: Amount of bytes to be copied +* unsigned char b: Condition bit; has to be in {0,1} +**************************************************/ +void PQCLEAN_KYBER1024_CLEAN_cmov(unsigned char *r, const unsigned char *x, size_t len, unsigned char b) { + size_t i; + + b = -b; + for (i = 0; i < len; i++) { + r[i] ^= b & (x[i] ^ r[i]); + } +} diff --git a/crypto_kem/kyber1024/clean/verify.h b/crypto_kem/kyber1024/clean/verify.h new file mode 100644 index 00000000..d55b09ac --- /dev/null +++ b/crypto_kem/kyber1024/clean/verify.h @@ -0,0 +1,10 @@ +#ifndef VERIFY_H +#define VERIFY_H + +#include + +unsigned char PQCLEAN_KYBER1024_CLEAN_verify(const unsigned char *a, const unsigned char *b, size_t len); + +void PQCLEAN_KYBER1024_CLEAN_cmov(unsigned char *r, const unsigned char *x, size_t len, unsigned char b); + +#endif diff --git a/crypto_kem/kyber512/META.yml b/crypto_kem/kyber512/META.yml new file mode 100644 index 00000000..47148557 --- /dev/null +++ b/crypto_kem/kyber512/META.yml @@ -0,0 +1,22 @@ +name: Kyber512 +type: kem +claimed-nist-level: 1 +length-public-key: 800 +length-ciphertext: 736 +length-secret-key: 1632 +length-shared-secret: 32 +nistkat-sha256: bdd9b46001de4595a4f185aec8d5d04d217705e65e10711c99fa3f0ac3d61c21 +principal-submitter: Peter Schwabe +auxiliary-submitters: + - Roberto Avanzi + - Joppe Bos + - Léo Ducas + - Eike Kiltz + - Tancrède Lepoint + - Vadim Lyubashevsky + - John M. Schanck + - Gregor Seiler + - Damien Stehlé +implementations: + - name: clean + version: https://github.com/pq-crystals/kyber/commit/46e283ab575ec92dfe82fb12229ae2d9d6246682 diff --git a/crypto_kem/kyber512/clean/LICENSE b/crypto_kem/kyber512/clean/LICENSE new file mode 100644 index 00000000..274dc1c8 --- /dev/null +++ b/crypto_kem/kyber512/clean/LICENSE @@ -0,0 +1,15 @@ +Public Domain +Authors: Joppe Bos, + Léo Ducas, + Eike Kiltz , + Tancrède Lepoint, + Vadim Lyubashevsky, + John Schanck, + Peter Schwabe, + Gregor Seiler, + Damien Stehlé + +For Keccak and AES we are using public-domain +code from sources and by authors listed in +comments on top of the respective files. + diff --git a/crypto_kem/kyber512/clean/Makefile b/crypto_kem/kyber512/clean/Makefile new file mode 100644 index 00000000..84dc881b --- /dev/null +++ b/crypto_kem/kyber512/clean/Makefile @@ -0,0 +1,19 @@ +# This Makefile can be used with GNU Make or BSD Make + +LIB=libkyber512_clean.a +HEADERS=api.h cbd.h indcpa.h ntt.h params.h poly.h polyvec.h reduce.h verify.h symmetric.h +OBJECTS=cbd.o indcpa.o kem.o ntt.o poly.o polyvec.o reduce.o verify.o symmetric-fips202.o + +CFLAGS=-Wall -O3 -Wmissing-prototypes -Wextra -Wpedantic -Werror -std=c99 -I../../../common $(EXTRAFLAGS) + +all: $(LIB) + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(LIB): $(OBJECTS) + $(AR) -r $@ $(OBJECTS) + +clean: + $(RM) $(OBJECTS) + $(RM) $(LIB) diff --git a/crypto_kem/kyber512/clean/Makefile.Microsoft_nmake b/crypto_kem/kyber512/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..cead5b32 --- /dev/null +++ b/crypto_kem/kyber512/clean/Makefile.Microsoft_nmake @@ -0,0 +1,19 @@ +# This Makefile can be used with Microsoft Visual Studio's nmake using the command: +# nmake /f Makefile.Microsoft_nmake + +LIBRARY=libkyber512_clean.lib +OBJECTS=cbd.obj indcpa.obj kem.obj ntt.obj poly.obj polyvec.obj reduce.obj verify.obj symmetric-fips202.obj + +CFLAGS=/nologo /I ..\..\..\common /W4 /WX + +all: $(LIBRARY) + +# Make sure objects are recompiled if headers change. +$(OBJECTS): *.h + +$(LIBRARY): $(OBJECTS) + LIB.EXE /NOLOGO /WX /OUT:$@ $** + +clean: + -DEL $(OBJECTS) + -DEL $(LIBRARY) diff --git a/crypto_kem/kyber512/clean/api.h b/crypto_kem/kyber512/clean/api.h new file mode 100644 index 00000000..57c8f3bd --- /dev/null +++ b/crypto_kem/kyber512/clean/api.h @@ -0,0 +1,18 @@ +#ifndef PQCLEAN_KYBER512_CLEAN_API_H +#define PQCLEAN_KYBER512_CLEAN_API_H + +#define PQCLEAN_KYBER512_CLEAN_CRYPTO_SECRETKEYBYTES 1632 +#define PQCLEAN_KYBER512_CLEAN_CRYPTO_PUBLICKEYBYTES 800 +#define PQCLEAN_KYBER512_CLEAN_CRYPTO_CIPHERTEXTBYTES 736 +#define PQCLEAN_KYBER512_CLEAN_CRYPTO_BYTES 32 + +#define PQCLEAN_KYBER512_CLEAN_CRYPTO_ALGNAME "Kyber512" + +int PQCLEAN_KYBER512_CLEAN_crypto_kem_keypair(unsigned char *pk, unsigned char *sk); + +int PQCLEAN_KYBER512_CLEAN_crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk); + +int PQCLEAN_KYBER512_CLEAN_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk); + + +#endif diff --git a/crypto_kem/kyber512/clean/cbd.c b/crypto_kem/kyber512/clean/cbd.c new file mode 100644 index 00000000..b1567c5b --- /dev/null +++ b/crypto_kem/kyber512/clean/cbd.c @@ -0,0 +1,53 @@ +#include "cbd.h" + +#include "params.h" + +#include + +/************************************************* +* Name: load32_littleendian +* +* Description: load bytes into a 32-bit integer +* in little-endian order +* +* Arguments: - const unsigned char *x: pointer to input byte array +* +* Returns 32-bit unsigned integer loaded from x +**************************************************/ +static uint32_t load32_littleendian(const unsigned char *x) { + uint32_t r; + r = (uint32_t)x[0]; + r |= (uint32_t)x[1] << 8; + r |= (uint32_t)x[2] << 16; + r |= (uint32_t)x[3] << 24; + return r; +} + +/************************************************* +* Name: cbd +* +* Description: Given an array of uniformly random bytes, compute +* polynomial with coefficients distributed according to +* a centered binomial distribution with parameter KYBER_ETA +* specialized for KYBER_ETA=2 +* +* Arguments: - poly *r: pointer to output polynomial +* - const unsigned char *buf: pointer to input byte array +**************************************************/ +void PQCLEAN_KYBER512_CLEAN_cbd(poly *r, const unsigned char *buf) { + uint32_t d, t; + int16_t a, b; + int i, j; + + for (i = 0; i < KYBER_N / 8; i++) { + t = load32_littleendian(buf + 4 * i); + d = t & 0x55555555; + d += (t >> 1) & 0x55555555; + + for (j = 0; j < 8; j++) { + a = (d >> 4 * j) & 0x3; + b = (d >> (4 * j + 2)) & 0x3; + r->coeffs[8 * i + j] = a - b; + } + } +} diff --git a/crypto_kem/kyber512/clean/cbd.h b/crypto_kem/kyber512/clean/cbd.h new file mode 100644 index 00000000..2ed43edc --- /dev/null +++ b/crypto_kem/kyber512/clean/cbd.h @@ -0,0 +1,8 @@ +#ifndef CBD_H +#define CBD_H + +#include "poly.h" + +void PQCLEAN_KYBER512_CLEAN_cbd(poly *r, const unsigned char *buf); + +#endif diff --git a/crypto_kem/kyber512/clean/indcpa.c b/crypto_kem/kyber512/clean/indcpa.c new file mode 100644 index 00000000..7bb6867b --- /dev/null +++ b/crypto_kem/kyber512/clean/indcpa.c @@ -0,0 +1,305 @@ +#include "indcpa.h" + +#include "ntt.h" +#include "poly.h" +#include "polyvec.h" +#include "randombytes.h" +#include "symmetric.h" + +#include + +/************************************************* +* Name: pack_pk +* +* Description: Serialize the public key as concatenation of the +* serialized vector of polynomials pk +* and the public seed used to generate the matrix A. +* +* Arguments: unsigned char *r: pointer to the output serialized public key +* const poly *pk: pointer to the input public-key polynomial +* const unsigned char *seed: pointer to the input public seed +**************************************************/ +static void pack_pk(unsigned char *r, polyvec *pk, const unsigned char *seed) { + int i; + PQCLEAN_KYBER512_CLEAN_polyvec_tobytes(r, pk); + for (i = 0; i < KYBER_SYMBYTES; i++) { + r[i + KYBER_POLYVECBYTES] = seed[i]; + } +} + +/************************************************* +* Name: unpack_pk +* +* Description: De-serialize public key from a byte array; +* approximate inverse of pack_pk +* +* Arguments: - polyvec *pk: pointer to output public-key vector of polynomials +* - unsigned char *seed: pointer to output seed to generate matrix A +* - const unsigned char *packedpk: pointer to input serialized public key +**************************************************/ +static void unpack_pk(polyvec *pk, unsigned char *seed, const unsigned char *packedpk) { + int i; + PQCLEAN_KYBER512_CLEAN_polyvec_frombytes(pk, packedpk); + for (i = 0; i < KYBER_SYMBYTES; i++) { + seed[i] = packedpk[i + KYBER_POLYVECBYTES]; + } +} + +/************************************************* +* Name: pack_sk +* +* Description: Serialize the secret key +* +* Arguments: - unsigned char *r: pointer to output serialized secret key +* - const polyvec *sk: pointer to input vector of polynomials (secret key) +**************************************************/ +static void pack_sk(unsigned char *r, polyvec *sk) { + PQCLEAN_KYBER512_CLEAN_polyvec_tobytes(r, sk); +} + +/************************************************* +* Name: unpack_sk +* +* Description: De-serialize the secret key; +* inverse of pack_sk +* +* Arguments: - polyvec *sk: pointer to output vector of polynomials (secret key) +* - const unsigned char *packedsk: pointer to input serialized secret key +**************************************************/ +static void unpack_sk(polyvec *sk, const unsigned char *packedsk) { + PQCLEAN_KYBER512_CLEAN_polyvec_frombytes(sk, packedsk); +} + +/************************************************* +* Name: pack_ciphertext +* +* Description: Serialize the ciphertext as concatenation of the +* compressed and serialized vector of polynomials b +* and the compressed and serialized polynomial v +* +* Arguments: unsigned char *r: pointer to the output serialized ciphertext +* const poly *pk: pointer to the input vector of polynomials b +* const unsigned char *seed: pointer to the input polynomial v +**************************************************/ +static void pack_ciphertext(unsigned char *r, polyvec *b, poly *v) { + PQCLEAN_KYBER512_CLEAN_polyvec_compress(r, b); + PQCLEAN_KYBER512_CLEAN_poly_compress(r + KYBER_POLYVECCOMPRESSEDBYTES, v); +} + +/************************************************* +* Name: unpack_ciphertext +* +* Description: De-serialize and decompress ciphertext from a byte array; +* approximate inverse of pack_ciphertext +* +* Arguments: - polyvec *b: pointer to the output vector of polynomials b +* - poly *v: pointer to the output polynomial v +* - const unsigned char *c: pointer to the input serialized ciphertext +**************************************************/ +static void unpack_ciphertext(polyvec *b, poly *v, const unsigned char *c) { + PQCLEAN_KYBER512_CLEAN_polyvec_decompress(b, c); + PQCLEAN_KYBER512_CLEAN_poly_decompress(v, c + KYBER_POLYVECCOMPRESSEDBYTES); +} + +/************************************************* +* Name: rej_uniform +* +* Description: Run rejection sampling on uniform random bytes to generate +* uniform random integers mod q +* +* Arguments: - int16_t *r: pointer to output buffer +* - unsigned int len: requested number of 16-bit integers (uniform mod q) +* - const unsigned char *buf: pointer to input buffer (assumed to be uniform random bytes) +* - unsigned int buflen: length of input buffer in bytes +* +* Returns number of sampled 16-bit integers (at most len) +**************************************************/ +static unsigned int rej_uniform(int16_t *r, unsigned int len, const unsigned char *buf, unsigned int buflen) { + unsigned int ctr, pos; + uint16_t val; + + ctr = pos = 0; + while (ctr < len && pos + 2 <= buflen) { + val = buf[pos] | ((uint16_t)buf[pos + 1] << 8); + pos += 2; + + if (val < 19 * KYBER_Q) { + val -= (val >> 12) * KYBER_Q; // Barrett reduction + r[ctr++] = (int16_t)val; + } + } + + return ctr; +} + +#define gen_a(A,B) PQCLEAN_KYBER512_CLEAN_gen_matrix(A,B,0) +#define gen_at(A,B) PQCLEAN_KYBER512_CLEAN_gen_matrix(A,B,1) + +#define GENMATRIX_MAXNBLOCKS ((530 + XOF_BLOCKBYTES) / XOF_BLOCKBYTES) /* 530 is expected number of required bytes */ + + +/************************************************* +* Name: gen_matrix +* +* Description: Deterministically generate matrix A (or the transpose of A) +* from a seed. Entries of the matrix are polynomials that look +* uniformly random. Performs rejection sampling on output of +* a XOF +* +* Arguments: - polyvec *a: pointer to ouptput matrix A +* - const unsigned char *seed: pointer to input seed +* - int transposed: boolean deciding whether A or A^T is generated +**************************************************/ +static void PQCLEAN_KYBER512_CLEAN_gen_matrix(polyvec *a, const unsigned char *seed, int transposed) { + unsigned int ctr; + unsigned char i, j; + unsigned char buf[XOF_BLOCKBYTES * GENMATRIX_MAXNBLOCKS + 1]; + xof_state state; + + for (i = 0; i < KYBER_K; i++) { + for (j = 0; j < KYBER_K; j++) { + if (transposed) { + xof_absorb(&state, seed, i, j); + } else { + xof_absorb(&state, seed, j, i); + } + + xof_squeezeblocks(buf, GENMATRIX_MAXNBLOCKS, &state); + ctr = rej_uniform(a[i].vec[j].coeffs, KYBER_N, buf, GENMATRIX_MAXNBLOCKS * XOF_BLOCKBYTES); + + while (ctr < KYBER_N) { + xof_squeezeblocks(buf, 1, &state); + ctr += rej_uniform(a[i].vec[j].coeffs + ctr, KYBER_N - ctr, buf, XOF_BLOCKBYTES); + } + } + } +} + +/************************************************* +* Name: indcpa_keypair +* +* Description: Generates public and private key for the CPA-secure +* public-key encryption scheme underlying Kyber +* +* Arguments: - unsigned char *pk: pointer to output public key (of length KYBER_INDCPA_PUBLICKEYBYTES bytes) +* - unsigned char *sk: pointer to output private key (of length KYBER_INDCPA_SECRETKEYBYTES bytes) +**************************************************/ +void PQCLEAN_KYBER512_CLEAN_indcpa_keypair(unsigned char *pk, unsigned char *sk) { + polyvec a[KYBER_K], e, pkpv, skpv; + unsigned char buf[2 * KYBER_SYMBYTES]; + unsigned char *publicseed = buf; + unsigned char *noiseseed = buf + KYBER_SYMBYTES; + int i; + unsigned char nonce = 0; + + randombytes(buf, KYBER_SYMBYTES); + hash_g(buf, buf, KYBER_SYMBYTES); + + gen_a(a, publicseed); + + for (i = 0; i < KYBER_K; i++) { + PQCLEAN_KYBER512_CLEAN_poly_getnoise(skpv.vec + i, noiseseed, nonce++); + } + for (i = 0; i < KYBER_K; i++) { + PQCLEAN_KYBER512_CLEAN_poly_getnoise(e.vec + i, noiseseed, nonce++); + } + + PQCLEAN_KYBER512_CLEAN_polyvec_ntt(&skpv); + PQCLEAN_KYBER512_CLEAN_polyvec_ntt(&e); + + // matrix-vector multiplication + for (i = 0; i < KYBER_K; i++) { + PQCLEAN_KYBER512_CLEAN_polyvec_pointwise_acc(&pkpv.vec[i], &a[i], &skpv); + PQCLEAN_KYBER512_CLEAN_poly_frommont(&pkpv.vec[i]); + } + + PQCLEAN_KYBER512_CLEAN_polyvec_add(&pkpv, &pkpv, &e); + PQCLEAN_KYBER512_CLEAN_polyvec_reduce(&pkpv); + + pack_sk(sk, &skpv); + pack_pk(pk, &pkpv, publicseed); +} + +/************************************************* +* Name: indcpa_enc +* +* Description: Encryption function of the CPA-secure +* public-key encryption scheme underlying Kyber. +* +* Arguments: - unsigned char *c: pointer to output ciphertext (of length KYBER_INDCPA_BYTES bytes) +* - const unsigned char *m: pointer to input message (of length KYBER_INDCPA_MSGBYTES bytes) +* - const unsigned char *pk: pointer to input public key (of length KYBER_INDCPA_PUBLICKEYBYTES bytes) +* - const unsigned char *coin: pointer to input random coins used as seed (of length KYBER_SYMBYTES bytes) +* to deterministically generate all randomness +**************************************************/ +void PQCLEAN_KYBER512_CLEAN_indcpa_enc(unsigned char *c, + const unsigned char *m, + const unsigned char *pk, + const unsigned char *coins) { + polyvec sp, pkpv, ep, at[KYBER_K], bp; + poly v, k, epp; + unsigned char seed[KYBER_SYMBYTES]; + int i; + unsigned char nonce = 0; + + unpack_pk(&pkpv, seed, pk); + PQCLEAN_KYBER512_CLEAN_poly_frommsg(&k, m); + gen_at(at, seed); + + for (i = 0; i < KYBER_K; i++) { + PQCLEAN_KYBER512_CLEAN_poly_getnoise(sp.vec + i, coins, nonce++); + } + for (i = 0; i < KYBER_K; i++) { + PQCLEAN_KYBER512_CLEAN_poly_getnoise(ep.vec + i, coins, nonce++); + } + PQCLEAN_KYBER512_CLEAN_poly_getnoise(&epp, coins, nonce++); + + PQCLEAN_KYBER512_CLEAN_polyvec_ntt(&sp); + + // matrix-vector multiplication + for (i = 0; i < KYBER_K; i++) { + PQCLEAN_KYBER512_CLEAN_polyvec_pointwise_acc(&bp.vec[i], &at[i], &sp); + } + + PQCLEAN_KYBER512_CLEAN_polyvec_pointwise_acc(&v, &pkpv, &sp); + + PQCLEAN_KYBER512_CLEAN_polyvec_invntt(&bp); + PQCLEAN_KYBER512_CLEAN_poly_invntt(&v); + + PQCLEAN_KYBER512_CLEAN_polyvec_add(&bp, &bp, &ep); + PQCLEAN_KYBER512_CLEAN_poly_add(&v, &v, &epp); + PQCLEAN_KYBER512_CLEAN_poly_add(&v, &v, &k); + PQCLEAN_KYBER512_CLEAN_polyvec_reduce(&bp); + PQCLEAN_KYBER512_CLEAN_poly_reduce(&v); + + pack_ciphertext(c, &bp, &v); +} + +/************************************************* +* Name: indcpa_dec +* +* Description: Decryption function of the CPA-secure +* public-key encryption scheme underlying Kyber. +* +* Arguments: - unsigned char *m: pointer to output decrypted message (of length KYBER_INDCPA_MSGBYTES) +* - const unsigned char *c: pointer to input ciphertext (of length KYBER_INDCPA_BYTES) +* - const unsigned char *sk: pointer to input secret key (of length KYBER_INDCPA_SECRETKEYBYTES) +**************************************************/ +void PQCLEAN_KYBER512_CLEAN_indcpa_dec(unsigned char *m, + const unsigned char *c, + const unsigned char *sk) { + polyvec bp, skpv; + poly v, mp; + + unpack_ciphertext(&bp, &v, c); + unpack_sk(&skpv, sk); + + PQCLEAN_KYBER512_CLEAN_polyvec_ntt(&bp); + PQCLEAN_KYBER512_CLEAN_polyvec_pointwise_acc(&mp, &skpv, &bp); + PQCLEAN_KYBER512_CLEAN_poly_invntt(&mp); + + PQCLEAN_KYBER512_CLEAN_poly_sub(&mp, &v, &mp); + PQCLEAN_KYBER512_CLEAN_poly_reduce(&mp); + + PQCLEAN_KYBER512_CLEAN_poly_tomsg(m, &mp); +} diff --git a/crypto_kem/kyber512/clean/indcpa.h b/crypto_kem/kyber512/clean/indcpa.h new file mode 100644 index 00000000..2d77ff22 --- /dev/null +++ b/crypto_kem/kyber512/clean/indcpa.h @@ -0,0 +1,16 @@ +#ifndef INDCPA_H +#define INDCPA_H + +void PQCLEAN_KYBER512_CLEAN_indcpa_keypair(unsigned char *pk, + unsigned char *sk); + +void PQCLEAN_KYBER512_CLEAN_indcpa_enc(unsigned char *c, + const unsigned char *m, + const unsigned char *pk, + const unsigned char *coins); + +void PQCLEAN_KYBER512_CLEAN_indcpa_dec(unsigned char *m, + const unsigned char *c, + const unsigned char *sk); + +#endif diff --git a/crypto_kem/kyber512/clean/kem.c b/crypto_kem/kyber512/clean/kem.c new file mode 100644 index 00000000..175a9a71 --- /dev/null +++ b/crypto_kem/kyber512/clean/kem.c @@ -0,0 +1,100 @@ +#include "api.h" +#include "indcpa.h" +#include "params.h" +#include "randombytes.h" +#include "symmetric.h" +#include "verify.h" + +#include + +/************************************************* +* Name: crypto_kem_keypair +* +* Description: Generates public and private key +* for CCA-secure Kyber key encapsulation mechanism +* +* Arguments: - unsigned char *pk: pointer to output public key (an already allocated array of CRYPTO_PUBLICKEYBYTES bytes) +* - unsigned char *sk: pointer to output private key (an already allocated array of CRYPTO_SECRETKEYBYTES bytes) +* +* Returns 0 (success) +**************************************************/ +int PQCLEAN_KYBER512_CLEAN_crypto_kem_keypair(unsigned char *pk, unsigned char *sk) { + size_t i; + PQCLEAN_KYBER512_CLEAN_indcpa_keypair(pk, sk); + for (i = 0; i < KYBER_INDCPA_PUBLICKEYBYTES; i++) { + sk[i + KYBER_INDCPA_SECRETKEYBYTES] = pk[i]; + } + hash_h(sk + KYBER_SECRETKEYBYTES - 2 * KYBER_SYMBYTES, pk, KYBER_PUBLICKEYBYTES); + randombytes(sk + KYBER_SECRETKEYBYTES - KYBER_SYMBYTES, KYBER_SYMBYTES); /* Value z for pseudo-random output on reject */ + return 0; +} + +/************************************************* +* Name: crypto_kem_enc +* +* Description: Generates cipher text and shared +* secret for given public key +* +* Arguments: - unsigned char *ct: pointer to output cipher text (an already allocated array of CRYPTO_CIPHERTEXTBYTES bytes) +* - unsigned char *ss: pointer to output shared secret (an already allocated array of CRYPTO_BYTES bytes) +* - const unsigned char *pk: pointer to input public key (an already allocated array of CRYPTO_PUBLICKEYBYTES bytes) +* +* Returns 0 (success) +**************************************************/ +int PQCLEAN_KYBER512_CLEAN_crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk) { + unsigned char kr[2 * KYBER_SYMBYTES]; /* Will contain key, coins */ + unsigned char buf[2 * KYBER_SYMBYTES]; + + randombytes(buf, KYBER_SYMBYTES); + hash_h(buf, buf, KYBER_SYMBYTES); /* Don't release system RNG output */ + + hash_h(buf + KYBER_SYMBYTES, pk, KYBER_PUBLICKEYBYTES); /* Multitarget countermeasure for coins + contributory KEM */ + hash_g(kr, buf, 2 * KYBER_SYMBYTES); + + PQCLEAN_KYBER512_CLEAN_indcpa_enc(ct, buf, pk, kr + KYBER_SYMBYTES); /* coins are in kr+KYBER_SYMBYTES */ + + hash_h(kr + KYBER_SYMBYTES, ct, KYBER_CIPHERTEXTBYTES); /* overwrite coins in kr with H(c) */ + kdf(ss, kr, 2 * KYBER_SYMBYTES); /* hash concatenation of pre-k and H(c) to k */ + return 0; +} + +/************************************************* +* Name: crypto_kem_dec +* +* Description: Generates shared secret for given +* cipher text and private key +* +* Arguments: - unsigned char *ss: pointer to output shared secret (an already allocated array of CRYPTO_BYTES bytes) +* - const unsigned char *ct: pointer to input cipher text (an already allocated array of CRYPTO_CIPHERTEXTBYTES bytes) +* - const unsigned char *sk: pointer to input private key (an already allocated array of CRYPTO_SECRETKEYBYTES bytes) +* +* Returns 0. +* +* On failure, ss will contain a pseudo-random value. +**************************************************/ +int PQCLEAN_KYBER512_CLEAN_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk) { + size_t i; + unsigned char fail; + unsigned char cmp[KYBER_CIPHERTEXTBYTES]; + unsigned char buf[2 * KYBER_SYMBYTES]; + unsigned char kr[2 * KYBER_SYMBYTES]; /* Will contain key, coins */ + const unsigned char *pk = sk + KYBER_INDCPA_SECRETKEYBYTES; + + PQCLEAN_KYBER512_CLEAN_indcpa_dec(buf, ct, sk); + + for (i = 0; i < KYBER_SYMBYTES; i++) { /* Multitarget countermeasure for coins + contributory KEM */ + buf[KYBER_SYMBYTES + i] = sk[KYBER_SECRETKEYBYTES - 2 * KYBER_SYMBYTES + i]; /* Save hash by storing H(pk) in sk */ + } + hash_g(kr, buf, 2 * KYBER_SYMBYTES); + + PQCLEAN_KYBER512_CLEAN_indcpa_enc(cmp, buf, pk, kr + KYBER_SYMBYTES); /* coins are in kr+KYBER_SYMBYTES */ + + fail = PQCLEAN_KYBER512_CLEAN_verify(ct, cmp, KYBER_CIPHERTEXTBYTES); + + hash_h(kr + KYBER_SYMBYTES, ct, KYBER_CIPHERTEXTBYTES); /* overwrite coins in kr with H(c) */ + + PQCLEAN_KYBER512_CLEAN_cmov(kr, sk + KYBER_SECRETKEYBYTES - KYBER_SYMBYTES, KYBER_SYMBYTES, fail); /* Overwrite pre-k with z on re-encryption failure */ + + kdf(ss, kr, 2 * KYBER_SYMBYTES); /* hash concatenation of pre-k and H(c) to k */ + return 0; +} diff --git a/crypto_kem/kyber512/clean/ntt.c b/crypto_kem/kyber512/clean/ntt.c new file mode 100644 index 00000000..3295aaac --- /dev/null +++ b/crypto_kem/kyber512/clean/ntt.c @@ -0,0 +1,157 @@ +#include "ntt.h" + +#include "params.h" +#include "reduce.h" + +#include + +/* Code to generate zetas and zetas_inv used in the number-theoretic transform: + +#define KYBER_ROOT_OF_UNITY 17 + +static const uint16_t tree[128] = { + 0, 64, 32, 96, 16, 80, 48, 112, 8, 72, 40, 104, 24, 88, 56, 120, + 4, 68, 36, 100, 20, 84, 52, 116, 12, 76, 44, 108, 28, 92, 60, 124, + 2, 66, 34, 98, 18, 82, 50, 114, 10, 74, 42, 106, 26, 90, 58, 122, + 6, 70, 38, 102, 22, 86, 54, 118, 14, 78, 46, 110, 30, 94, 62, 126, + 1, 65, 33, 97, 17, 81, 49, 113, 9, 73, 41, 105, 25, 89, 57, 121, + 5, 69, 37, 101, 21, 85, 53, 117, 13, 77, 45, 109, 29, 93, 61, 125, + 3, 67, 35, 99, 19, 83, 51, 115, 11, 75, 43, 107, 27, 91, 59, 123, + 7, 71, 39, 103, 23, 87, 55, 119, 15, 79, 47, 111, 31, 95, 63, 127}; + + +static int16_t fqmul(int16_t a, int16_t b) { + return montgomery_reduce((int32_t)a*b); +} + +void init_ntt() { + unsigned int i, j, k; + int16_t tmp[128]; + + tmp[0] = MONT; + for(i = 1; i < 128; ++i) + tmp[i] = fqmul(tmp[i-1], KYBER_ROOT_OF_UNITY*MONT % KYBER_Q); + + for(i = 0; i < 128; ++i) + zetas[i] = tmp[tree[i]]; + + k = 0; + for(i = 64; i >= 1; i >>= 1) + for(j = i; j < 2*i; ++j) + zetas_inv[k++] = -tmp[128 - tree[j]]; + + zetas_inv[127] = MONT * (MONT * (KYBER_Q - 1) * ((KYBER_Q - 1)/128) % KYBER_Q) % KYBER_Q; +} + +*/ +int16_t PQCLEAN_KYBER512_CLEAN_zetas[128] = { + 2285, 2571, 2970, 1812, 1493, 1422, 287, 202, 3158, 622, 1577, 182, 962, 2127, 1855, 1468, + 573, 2004, 264, 383, 2500, 1458, 1727, 3199, 2648, 1017, 732, 608, 1787, 411, 3124, 1758, + 1223, 652, 2777, 1015, 2036, 1491, 3047, 1785, 516, 3321, 3009, 2663, 1711, 2167, 126, 1469, + 2476, 3239, 3058, 830, 107, 1908, 3082, 2378, 2931, 961, 1821, 2604, 448, 2264, 677, 2054, + 2226, 430, 555, 843, 2078, 871, 1550, 105, 422, 587, 177, 3094, 3038, 2869, 1574, 1653, + 3083, 778, 1159, 3182, 2552, 1483, 2727, 1119, 1739, 644, 2457, 349, 418, 329, 3173, 3254, + 817, 1097, 603, 610, 1322, 2044, 1864, 384, 2114, 3193, 1218, 1994, 2455, 220, 2142, 1670, + 2144, 1799, 2051, 794, 1819, 2475, 2459, 478, 3221, 3021, 996, 991, 958, 1869, 1522, 1628 +}; + +int16_t PQCLEAN_KYBER512_CLEAN_zetas_inv[128] = { + 1701, 1807, 1460, 2371, 2338, 2333, 308, 108, 2851, 870, 854, 1510, 2535, 1278, 1530, 1185, + 1659, 1187, 3109, 874, 1335, 2111, 136, 1215, 2945, 1465, 1285, 2007, 2719, 2726, 2232, 2512, + 75, 156, 3000, 2911, 2980, 872, 2685, 1590, 2210, 602, 1846, 777, 147, 2170, 2551, 246, + 1676, 1755, 460, 291, 235, 3152, 2742, 2907, 3224, 1779, 2458, 1251, 2486, 2774, 2899, 1103, + 1275, 2652, 1065, 2881, 725, 1508, 2368, 398, 951, 247, 1421, 3222, 2499, 271, 90, 853, + 1860, 3203, 1162, 1618, 666, 320, 8, 2813, 1544, 282, 1838, 1293, 2314, 552, 2677, 2106, + 1571, 205, 2918, 1542, 2721, 2597, 2312, 681, 130, 1602, 1871, 829, 2946, 3065, 1325, 2756, + 1861, 1474, 1202, 2367, 3147, 1752, 2707, 171, 3127, 3042, 1907, 1836, 1517, 359, 758, 1441 +}; + + +/************************************************* +* Name: fqmul +* +* Description: Multiplication followed by Montgomery reduction +* +* Arguments: - int16_t a: first factor +* - int16_t b: second factor +* +* Returns 16-bit integer congruent to a*b*R^{-1} mod q +**************************************************/ +static int16_t fqmul(int16_t a, int16_t b) { + return PQCLEAN_KYBER512_CLEAN_montgomery_reduce((int32_t)a * b); +} + +/************************************************* +* Name: ntt +* +* Description: Inplace number-theoretic transform (NTT) in Rq +* input is in standard order, output is in bitreversed order +* +* Arguments: - int16_t *poly: pointer to input/output vector of 256 elements of Zq +**************************************************/ +void PQCLEAN_KYBER512_CLEAN_ntt(int16_t *poly) { + unsigned int len, start, j, k; + int16_t t, zeta; + + k = 1; + for (len = 128; len >= 2; len >>= 1) { + for (start = 0; start < 256; start = j + len) { + zeta = PQCLEAN_KYBER512_CLEAN_zetas[k++]; + for (j = start; j < start + len; ++j) { + t = fqmul(zeta, poly[j + len]); + poly[j + len] = poly[j] - t; + poly[j] = poly[j] + t; + } + } + } +} + +/************************************************* +* Name: invntt +* +* Description: Inplace inverse number-theoretic transform in Rq +* input is in bitreversed order, output is in standard order +* +* Arguments: - int16_t *poly: pointer to input/output vector of 256 elements of Zq +**************************************************/ +void PQCLEAN_KYBER512_CLEAN_invntt(int16_t *poly) { + unsigned int start, len, j, k; + int16_t t, zeta; + + k = 0; + for (len = 2; len <= 128; len <<= 1) { + for (start = 0; start < 256; start = j + len) { + zeta = PQCLEAN_KYBER512_CLEAN_zetas_inv[k++]; + for (j = start; j < start + len; ++j) { + t = poly[j]; + poly[j] = PQCLEAN_KYBER512_CLEAN_barrett_reduce(t + poly[j + len]); + poly[j + len] = t - poly[j + len]; + poly[j + len] = fqmul(zeta, poly[j + len]); + } + } + } + + for (j = 0; j < 256; ++j) { + poly[j] = fqmul(poly[j], PQCLEAN_KYBER512_CLEAN_zetas_inv[127]); + } +} + +/************************************************* +* Name: PQCLEAN_KYBER512_CLEAN_basemul +* +* Description: Multiplication of polynomials in Zq[X]/((X^2-zeta)) +* used for multiplication of elements in Rq in NTT domain +* +* Arguments: - int16_t r[2]: pointer to the output polynomial +* - const int16_t a[2]: pointer to the first factor +* - const int16_t b[2]: pointer to the second factor +* - int16_t zeta: integer defining the reduction polynomial +**************************************************/ +void PQCLEAN_KYBER512_CLEAN_basemul(int16_t r[2], const int16_t a[2], const int16_t b[2], int16_t zeta) { + r[0] = fqmul(a[1], b[1]); + r[0] = fqmul(r[0], zeta); + r[0] += fqmul(a[0], b[0]); + + r[1] = fqmul(a[0], b[1]); + r[1] += fqmul(a[1], b[0]); +} diff --git a/crypto_kem/kyber512/clean/ntt.h b/crypto_kem/kyber512/clean/ntt.h new file mode 100644 index 00000000..678c311d --- /dev/null +++ b/crypto_kem/kyber512/clean/ntt.h @@ -0,0 +1,13 @@ +#ifndef NTT_H +#define NTT_H + +#include + +extern int16_t PQCLEAN_KYBER512_CLEAN_zetas[128]; +extern int16_t PQCLEAN_KYBER512_CLEAN_zetas_inv[128]; + +void PQCLEAN_KYBER512_CLEAN_ntt(int16_t *poly); +void PQCLEAN_KYBER512_CLEAN_invntt(int16_t *poly); +void PQCLEAN_KYBER512_CLEAN_basemul(int16_t r[2], const int16_t a[2], const int16_t b[2], int16_t zeta); + +#endif diff --git a/crypto_kem/kyber512/clean/params.h b/crypto_kem/kyber512/clean/params.h new file mode 100644 index 00000000..b9865f7b --- /dev/null +++ b/crypto_kem/kyber512/clean/params.h @@ -0,0 +1,31 @@ +#ifndef PARAMS_H +#define PARAMS_H + +#define KYBER_K 2 /* Change this for different security strengths */ + +/* Don't change parameters below this line */ + +#define KYBER_N 256 +#define KYBER_Q 3329 + +#define KYBER_ETA 2 + +#define KYBER_SYMBYTES 32 /* size in bytes of hashes, and seeds */ +#define KYBER_SSBYTES 32 /* size in bytes of shared key */ + +#define KYBER_POLYBYTES 384 +#define KYBER_POLYVECBYTES (KYBER_K * KYBER_POLYBYTES) + +#define KYBER_POLYCOMPRESSEDBYTES 96 +#define KYBER_POLYVECCOMPRESSEDBYTES (KYBER_K * 320) + +#define KYBER_INDCPA_MSGBYTES KYBER_SYMBYTES +#define KYBER_INDCPA_PUBLICKEYBYTES (KYBER_POLYVECBYTES + KYBER_SYMBYTES) +#define KYBER_INDCPA_SECRETKEYBYTES (KYBER_POLYVECBYTES) +#define KYBER_INDCPA_BYTES (KYBER_POLYVECCOMPRESSEDBYTES + KYBER_POLYCOMPRESSEDBYTES) + +#define KYBER_PUBLICKEYBYTES (KYBER_INDCPA_PUBLICKEYBYTES) +#define KYBER_SECRETKEYBYTES (KYBER_INDCPA_SECRETKEYBYTES + KYBER_INDCPA_PUBLICKEYBYTES + 2*KYBER_SYMBYTES) /* 32 bytes of additional space to save H(pk) */ +#define KYBER_CIPHERTEXTBYTES KYBER_INDCPA_BYTES + +#endif diff --git a/crypto_kem/kyber512/clean/poly.c b/crypto_kem/kyber512/clean/poly.c new file mode 100644 index 00000000..f72508d9 --- /dev/null +++ b/crypto_kem/kyber512/clean/poly.c @@ -0,0 +1,287 @@ +#include "poly.h" + +#include "cbd.h" +#include "ntt.h" +#include "params.h" +#include "reduce.h" +#include "symmetric.h" + +#include + +/************************************************* +* Name: PQCLEAN_KYBER512_CLEAN_poly_compress +* +* Description: Compression and subsequent serialization of a polynomial +* +* Arguments: - unsigned char *r: pointer to output byte array (needs space for KYBER_POLYCOMPRESSEDBYTES bytes) +* - const poly *a: pointer to input polynomial +**************************************************/ +void PQCLEAN_KYBER512_CLEAN_poly_compress(unsigned char *r, poly *a) { + uint8_t t[8]; + int i, j, k = 0; + + PQCLEAN_KYBER512_CLEAN_poly_csubq(a); + + for (i = 0; i < KYBER_N; i += 8) { + for (j = 0; j < 8; j++) { + t[j] = ((((uint32_t)a->coeffs[i + j] << 3) + KYBER_Q / 2) / KYBER_Q) & 7; + } + + r[k] = t[0] | (t[1] << 3) | (t[2] << 6); + r[k + 1] = (t[2] >> 2) | (t[3] << 1) | (t[4] << 4) | (t[5] << 7); + r[k + 2] = (t[5] >> 1) | (t[6] << 2) | (t[7] << 5); + k += 3; + } +} + +/************************************************* +* Name: PQCLEAN_KYBER512_CLEAN_poly_decompress +* +* Description: De-serialization and subsequent decompression of a polynomial; +* approximate inverse of PQCLEAN_KYBER512_CLEAN_poly_compress +* +* Arguments: - poly *r: pointer to output polynomial +* - const unsigned char *a: pointer to input byte array (of length KYBER_POLYCOMPRESSEDBYTES bytes) +**************************************************/ +void PQCLEAN_KYBER512_CLEAN_poly_decompress(poly *r, const unsigned char *a) { + int i; + for (i = 0; i < KYBER_N; i += 8) { + r->coeffs[i + 0] = (((a[0] & 7) * KYBER_Q) + 4) >> 3; + r->coeffs[i + 1] = ((((a[0] >> 3) & 7) * KYBER_Q) + 4) >> 3; + r->coeffs[i + 2] = ((((a[0] >> 6) | ((a[1] << 2) & 4)) * KYBER_Q) + 4) >> 3; + r->coeffs[i + 3] = ((((a[1] >> 1) & 7) * KYBER_Q) + 4) >> 3; + r->coeffs[i + 4] = ((((a[1] >> 4) & 7) * KYBER_Q) + 4) >> 3; + r->coeffs[i + 5] = ((((a[1] >> 7) | ((a[2] << 1) & 6)) * KYBER_Q) + 4) >> 3; + r->coeffs[i + 6] = ((((a[2] >> 2) & 7) * KYBER_Q) + 4) >> 3; + r->coeffs[i + 7] = ((((a[2] >> 5)) * KYBER_Q) + 4) >> 3; + a += 3; + } +} + +/************************************************* +* Name: PQCLEAN_KYBER512_CLEAN_poly_tobytes +* +* Description: Serialization of a polynomial +* +* Arguments: - unsigned char *r: pointer to output byte array (needs space for KYBER_POLYBYTES bytes) +* - const poly *a: pointer to input polynomial +**************************************************/ +void PQCLEAN_KYBER512_CLEAN_poly_tobytes(unsigned char *r, poly *a) { + int i; + uint16_t t0, t1; + + PQCLEAN_KYBER512_CLEAN_poly_csubq(a); + + for (i = 0; i < KYBER_N / 2; i++) { + t0 = a->coeffs[2 * i]; + t1 = a->coeffs[2 * i + 1]; + r[3 * i] = t0 & 0xff; + r[3 * i + 1] = (t0 >> 8) | ((t1 & 0xf) << 4); + r[3 * i + 2] = (t1 >> 4) & 0xff; + } +} + +/************************************************* +* Name: PQCLEAN_KYBER512_CLEAN_poly_frombytes +* +* Description: De-serialization of a polynomial; +* inverse of PQCLEAN_KYBER512_CLEAN_poly_tobytes +* +* Arguments: - poly *r: pointer to output polynomial +* - const unsigned char *a: pointer to input byte array (of KYBER_POLYBYTES bytes) +**************************************************/ +void PQCLEAN_KYBER512_CLEAN_poly_frombytes(poly *r, const unsigned char *a) { + int i; + + for (i = 0; i < KYBER_N / 2; i++) { + r->coeffs[2 * i] = a[3 * i] | ((uint16_t)a[3 * i + 1] & 0x0f) << 8; + r->coeffs[2 * i + 1] = a[3 * i + 1] >> 4 | ((uint16_t)a[3 * i + 2] & 0xff) << 4; + } +} + +/************************************************* +* Name: PQCLEAN_KYBER512_CLEAN_poly_getnoise +* +* Description: Sample a polynomial deterministically from a seed and a nonce, +* with output polynomial close to centered binomial distribution +* with parameter KYBER_ETA +* +* Arguments: - poly *r: pointer to output polynomial +* - const unsigned char *seed: pointer to input seed (pointing to array of length KYBER_SYMBYTES bytes) +* - unsigned char nonce: one-byte input nonce +**************************************************/ +void PQCLEAN_KYBER512_CLEAN_poly_getnoise(poly *r, const unsigned char *seed, unsigned char nonce) { + unsigned char buf[KYBER_ETA * KYBER_N / 4]; + + prf(buf, KYBER_ETA * KYBER_N / 4, seed, nonce); + PQCLEAN_KYBER512_CLEAN_cbd(r, buf); +} + +/************************************************* +* Name: PQCLEAN_KYBER512_CLEAN_poly_ntt +* +* Description: Computes negacyclic number-theoretic transform (NTT) of +* a polynomial in place; +* inputs assumed to be in normal order, output in bitreversed order +* +* Arguments: - uint16_t *r: pointer to in/output polynomial +**************************************************/ +void PQCLEAN_KYBER512_CLEAN_poly_ntt(poly *r) { + PQCLEAN_KYBER512_CLEAN_ntt(r->coeffs); + PQCLEAN_KYBER512_CLEAN_poly_reduce(r); +} + +/************************************************* +* Name: PQCLEAN_KYBER512_CLEAN_poly_invntt +* +* Description: Computes inverse of negacyclic number-theoretic transform (NTT) of +* a polynomial in place; +* inputs assumed to be in bitreversed order, output in normal order +* +* Arguments: - uint16_t *a: pointer to in/output polynomial +**************************************************/ +void PQCLEAN_KYBER512_CLEAN_poly_invntt(poly *r) { + PQCLEAN_KYBER512_CLEAN_invntt(r->coeffs); +} + +/************************************************* +* Name: PQCLEAN_KYBER512_CLEAN_poly_basemul +* +* Description: Multiplication of two polynomials in NTT domain +* +* Arguments: - poly *r: pointer to output polynomial +* - const poly *a: pointer to first input polynomial +* - const poly *b: pointer to second input polynomial +**************************************************/ +void PQCLEAN_KYBER512_CLEAN_poly_basemul(poly *r, const poly *a, const poly *b) { + unsigned int i; + + for (i = 0; i < KYBER_N / 4; ++i) { + PQCLEAN_KYBER512_CLEAN_basemul(r->coeffs + 4 * i, a->coeffs + 4 * i, b->coeffs + 4 * i, PQCLEAN_KYBER512_CLEAN_zetas[64 + i]); + PQCLEAN_KYBER512_CLEAN_basemul(r->coeffs + 4 * i + 2, a->coeffs + 4 * i + 2, b->coeffs + 4 * i + 2, - PQCLEAN_KYBER512_CLEAN_zetas[64 + i]); + } +} + +/************************************************* +* Name: PQCLEAN_KYBER512_CLEAN_poly_frommont +* +* Description: Inplace conversion of all coefficients of a polynomial +* from Montgomery domain to normal domain +* +* Arguments: - poly *r: pointer to input/output polynomial +**************************************************/ +void PQCLEAN_KYBER512_CLEAN_poly_frommont(poly *r) { + int i; + const int16_t f = (1ULL << 32) % KYBER_Q; + + for (i = 0; i < KYBER_N; i++) { + r->coeffs[i] = PQCLEAN_KYBER512_CLEAN_montgomery_reduce((int32_t)r->coeffs[i] * f); + } +} + +/************************************************* +* Name: PQCLEAN_KYBER512_CLEAN_poly_reduce +* +* Description: Applies Barrett reduction to all coefficients of a polynomial +* for details of the Barrett reduction see comments in reduce.c +* +* Arguments: - poly *r: pointer to input/output polynomial +**************************************************/ +void PQCLEAN_KYBER512_CLEAN_poly_reduce(poly *r) { + int i; + + for (i = 0; i < KYBER_N; i++) { + r->coeffs[i] = PQCLEAN_KYBER512_CLEAN_barrett_reduce(r->coeffs[i]); + } +} + +/************************************************* +* Name: PQCLEAN_KYBER512_CLEAN_poly_csubq +* +* Description: Applies conditional subtraction of q to each coefficient of a polynomial +* for details of conditional subtraction of q see comments in reduce.c +* +* Arguments: - poly *r: pointer to input/output polynomial +**************************************************/ +void PQCLEAN_KYBER512_CLEAN_poly_csubq(poly *r) { + int i; + + for (i = 0; i < KYBER_N; i++) { + r->coeffs[i] = PQCLEAN_KYBER512_CLEAN_csubq(r->coeffs[i]); + } +} + +/************************************************* +* Name: PQCLEAN_KYBER512_CLEAN_poly_add +* +* Description: Add two polynomials +* +* Arguments: - poly *r: pointer to output polynomial +* - const poly *a: pointer to first input polynomial +* - const poly *b: pointer to second input polynomial +**************************************************/ +void PQCLEAN_KYBER512_CLEAN_poly_add(poly *r, const poly *a, const poly *b) { + int i; + for (i = 0; i < KYBER_N; i++) { + r->coeffs[i] = a->coeffs[i] + b->coeffs[i]; + } +} + +/************************************************* +* Name: PQCLEAN_KYBER512_CLEAN_poly_sub +* +* Description: Subtract two polynomials +* +* Arguments: - poly *r: pointer to output polynomial +* - const poly *a: pointer to first input polynomial +* - const poly *b: pointer to second input polynomial +**************************************************/ +void PQCLEAN_KYBER512_CLEAN_poly_sub(poly *r, const poly *a, const poly *b) { + int i; + for (i = 0; i < KYBER_N; i++) { + r->coeffs[i] = a->coeffs[i] - b->coeffs[i]; + } +} + +/************************************************* +* Name: PQCLEAN_KYBER512_CLEAN_poly_frommsg +* +* Description: Convert 32-byte message to polynomial +* +* Arguments: - poly *r: pointer to output polynomial +* - const unsigned char *msg: pointer to input message +**************************************************/ +void PQCLEAN_KYBER512_CLEAN_poly_frommsg(poly *r, const unsigned char msg[KYBER_SYMBYTES]) { + int i, j; + uint16_t mask; + + for (i = 0; i < KYBER_SYMBYTES; i++) { + for (j = 0; j < 8; j++) { + mask = -((msg[i] >> j) & 1); + r->coeffs[8 * i + j] = mask & ((KYBER_Q + 1) / 2); + } + } +} + +/************************************************* +* Name: PQCLEAN_KYBER512_CLEAN_poly_tomsg +* +* Description: Convert polynomial to 32-byte message +* +* Arguments: - unsigned char *msg: pointer to output message +* - const poly *a: pointer to input polynomial +**************************************************/ +void PQCLEAN_KYBER512_CLEAN_poly_tomsg(unsigned char msg[KYBER_SYMBYTES], poly *a) { + uint16_t t; + int i, j; + + PQCLEAN_KYBER512_CLEAN_poly_csubq(a); + + for (i = 0; i < KYBER_SYMBYTES; i++) { + msg[i] = 0; + for (j = 0; j < 8; j++) { + t = (((a->coeffs[8 * i + j] << 1) + KYBER_Q / 2) / KYBER_Q) & 1; + msg[i] |= t << j; + } + } +} diff --git a/crypto_kem/kyber512/clean/poly.h b/crypto_kem/kyber512/clean/poly.h new file mode 100644 index 00000000..9002a530 --- /dev/null +++ b/crypto_kem/kyber512/clean/poly.h @@ -0,0 +1,38 @@ +#ifndef POLY_H +#define POLY_H + +#include "params.h" + +#include + +/* + * Elements of R_q = Z_q[X]/(X^n + 1). Represents polynomial + * coeffs[0] + X*coeffs[1] + X^2*xoeffs[2] + ... + X^{n-1}*coeffs[n-1] + */ +typedef struct { + int16_t coeffs[KYBER_N]; +} poly; + +void PQCLEAN_KYBER512_CLEAN_poly_compress(unsigned char *r, poly *a); +void PQCLEAN_KYBER512_CLEAN_poly_decompress(poly *r, const unsigned char *a); + +void PQCLEAN_KYBER512_CLEAN_poly_tobytes(unsigned char *r, poly *a); +void PQCLEAN_KYBER512_CLEAN_poly_frombytes(poly *r, const unsigned char *a); + +void PQCLEAN_KYBER512_CLEAN_poly_frommsg(poly *r, const unsigned char msg[KYBER_SYMBYTES]); +void PQCLEAN_KYBER512_CLEAN_poly_tomsg(unsigned char msg[KYBER_SYMBYTES], poly *a); + +void PQCLEAN_KYBER512_CLEAN_poly_getnoise(poly *r, const unsigned char *seed, unsigned char nonce); + +void PQCLEAN_KYBER512_CLEAN_poly_ntt(poly *r); +void PQCLEAN_KYBER512_CLEAN_poly_invntt(poly *r); +void PQCLEAN_KYBER512_CLEAN_poly_basemul(poly *r, const poly *a, const poly *b); +void PQCLEAN_KYBER512_CLEAN_poly_frommont(poly *r); + +void PQCLEAN_KYBER512_CLEAN_poly_reduce(poly *r); +void PQCLEAN_KYBER512_CLEAN_poly_csubq(poly *r); + +void PQCLEAN_KYBER512_CLEAN_poly_add(poly *r, const poly *a, const poly *b); +void PQCLEAN_KYBER512_CLEAN_poly_sub(poly *r, const poly *a, const poly *b); + +#endif diff --git a/crypto_kem/kyber512/clean/polyvec.c b/crypto_kem/kyber512/clean/polyvec.c new file mode 100644 index 00000000..2dbed8aa --- /dev/null +++ b/crypto_kem/kyber512/clean/polyvec.c @@ -0,0 +1,186 @@ +#include "polyvec.h" + +#include "poly.h" + +#include + +/************************************************* +* Name: PQCLEAN_KYBER512_CLEAN_polyvec_compress +* +* Description: Compress and serialize vector of polynomials +* +* Arguments: - unsigned char *r: pointer to output byte array (needs space for KYBER_POLYVECCOMPRESSEDBYTES) +* - const polyvec *a: pointer to input vector of polynomials +**************************************************/ +void PQCLEAN_KYBER512_CLEAN_polyvec_compress(unsigned char *r, polyvec *a) { + int i, j, k; + + PQCLEAN_KYBER512_CLEAN_polyvec_csubq(a); + + uint16_t t[4]; + for (i = 0; i < KYBER_K; i++) { + for (j = 0; j < KYBER_N / 4; j++) { + for (k = 0; k < 4; k++) { + t[k] = ((((uint32_t)a->vec[i].coeffs[4 * j + k] << 10) + KYBER_Q / 2) / KYBER_Q) & 0x3ff; + } + + r[5 * j + 0] = t[0] & 0xff; + r[5 * j + 1] = (t[0] >> 8) | ((t[1] & 0x3f) << 2); + r[5 * j + 2] = ((t[1] >> 6) | ((t[2] & 0x0f) << 4)) & 0xff; + r[5 * j + 3] = ((t[2] >> 4) | ((t[3] & 0x03) << 6)) & 0xff; + r[5 * j + 4] = (t[3] >> 2) & 0xff; + } + r += 320; + } +} + +/************************************************* +* Name: PQCLEAN_KYBER512_CLEAN_polyvec_decompress +* +* Description: De-serialize and decompress vector of polynomials; +* approximate inverse of PQCLEAN_KYBER512_CLEAN_polyvec_compress +* +* Arguments: - polyvec *r: pointer to output vector of polynomials +* - unsigned char *a: pointer to input byte array (of length KYBER_POLYVECCOMPRESSEDBYTES) +**************************************************/ +void PQCLEAN_KYBER512_CLEAN_polyvec_decompress(polyvec *r, const unsigned char *a) { + int i, j; + for (i = 0; i < KYBER_K; i++) { + for (j = 0; j < KYBER_N / 4; j++) { + r->vec[i].coeffs[4 * j + 0] = (((a[5 * j + 0] | (((uint32_t)a[5 * j + 1] & 0x03) << 8)) * KYBER_Q) + 512) >> 10; + r->vec[i].coeffs[4 * j + 1] = ((((a[5 * j + 1] >> 2) | (((uint32_t)a[5 * j + 2] & 0x0f) << 6)) * KYBER_Q) + 512) >> 10; + r->vec[i].coeffs[4 * j + 2] = ((((a[5 * j + 2] >> 4) | (((uint32_t)a[5 * j + 3] & 0x3f) << 4)) * KYBER_Q) + 512) >> 10; + r->vec[i].coeffs[4 * j + 3] = ((((a[5 * j + 3] >> 6) | (((uint32_t)a[5 * j + 4] & 0xff) << 2)) * KYBER_Q) + 512) >> 10; + } + a += 320; + } +} + +/************************************************* +* Name: PQCLEAN_KYBER512_CLEAN_polyvec_tobytes +* +* Description: Serialize vector of polynomials +* +* Arguments: - unsigned char *r: pointer to output byte array (needs space for KYBER_POLYVECBYTES) +* - const polyvec *a: pointer to input vector of polynomials +**************************************************/ +void PQCLEAN_KYBER512_CLEAN_polyvec_tobytes(unsigned char *r, polyvec *a) { + int i; + for (i = 0; i < KYBER_K; i++) { + PQCLEAN_KYBER512_CLEAN_poly_tobytes(r + i * KYBER_POLYBYTES, &a->vec[i]); + } +} + +/************************************************* +* Name: PQCLEAN_KYBER512_CLEAN_polyvec_frombytes +* +* Description: De-serialize vector of polynomials; +* inverse of PQCLEAN_KYBER512_CLEAN_polyvec_tobytes +* +* Arguments: - unsigned char *r: pointer to output byte array +* - const polyvec *a: pointer to input vector of polynomials (of length KYBER_POLYVECBYTES) +**************************************************/ +void PQCLEAN_KYBER512_CLEAN_polyvec_frombytes(polyvec *r, const unsigned char *a) { + int i; + for (i = 0; i < KYBER_K; i++) { + PQCLEAN_KYBER512_CLEAN_poly_frombytes(&r->vec[i], a + i * KYBER_POLYBYTES); + } +} + +/************************************************* +* Name: PQCLEAN_KYBER512_CLEAN_polyvec_ntt +* +* Description: Apply forward NTT to all elements of a vector of polynomials +* +* Arguments: - polyvec *r: pointer to in/output vector of polynomials +**************************************************/ +void PQCLEAN_KYBER512_CLEAN_polyvec_ntt(polyvec *r) { + int i; + for (i = 0; i < KYBER_K; i++) { + PQCLEAN_KYBER512_CLEAN_poly_ntt(&r->vec[i]); + } +} + +/************************************************* +* Name: PQCLEAN_KYBER512_CLEAN_polyvec_invntt +* +* Description: Apply inverse NTT to all elements of a vector of polynomials +* +* Arguments: - polyvec *r: pointer to in/output vector of polynomials +**************************************************/ +void PQCLEAN_KYBER512_CLEAN_polyvec_invntt(polyvec *r) { + int i; + for (i = 0; i < KYBER_K; i++) { + PQCLEAN_KYBER512_CLEAN_poly_invntt(&r->vec[i]); + } +} + +/************************************************* +* Name: PQCLEAN_KYBER512_CLEAN_polyvec_pointwise_acc +* +* Description: Pointwise multiply elements of a and b and accumulate into r +* +* Arguments: - poly *r: pointer to output polynomial +* - const polyvec *a: pointer to first input vector of polynomials +* - const polyvec *b: pointer to second input vector of polynomials +**************************************************/ +void PQCLEAN_KYBER512_CLEAN_polyvec_pointwise_acc(poly *r, const polyvec *a, const polyvec *b) { + int i; + poly t; + + PQCLEAN_KYBER512_CLEAN_poly_basemul(r, &a->vec[0], &b->vec[0]); + for (i = 1; i < KYBER_K; i++) { + PQCLEAN_KYBER512_CLEAN_poly_basemul(&t, &a->vec[i], &b->vec[i]); + PQCLEAN_KYBER512_CLEAN_poly_add(r, r, &t); + } + + PQCLEAN_KYBER512_CLEAN_poly_reduce(r); +} + +/************************************************* +* Name: PQCLEAN_KYBER512_CLEAN_polyvec_reduce +* +* Description: Applies Barrett reduction to each coefficient +* of each element of a vector of polynomials +* for details of the Barrett reduction see comments in reduce.c +* +* Arguments: - poly *r: pointer to input/output polynomial +**************************************************/ +void PQCLEAN_KYBER512_CLEAN_polyvec_reduce(polyvec *r) { + int i; + for (i = 0; i < KYBER_K; i++) { + PQCLEAN_KYBER512_CLEAN_poly_reduce(&r->vec[i]); + } +} + +/************************************************* +* Name: PQCLEAN_KYBER512_CLEAN_polyvec_csubq +* +* Description: Applies conditional subtraction of q to each coefficient +* of each element of a vector of polynomials +* for details of conditional subtraction of q see comments in reduce.c +* +* Arguments: - poly *r: pointer to input/output polynomial +**************************************************/ +void PQCLEAN_KYBER512_CLEAN_polyvec_csubq(polyvec *r) { + int i; + for (i = 0; i < KYBER_K; i++) { + PQCLEAN_KYBER512_CLEAN_poly_csubq(&r->vec[i]); + } +} + +/************************************************* +* Name: PQCLEAN_KYBER512_CLEAN_polyvec_add +* +* Description: Add vectors of polynomials +* +* Arguments: - polyvec *r: pointer to output vector of polynomials +* - const polyvec *a: pointer to first input vector of polynomials +* - const polyvec *b: pointer to second input vector of polynomials +**************************************************/ +void PQCLEAN_KYBER512_CLEAN_polyvec_add(polyvec *r, const polyvec *a, const polyvec *b) { + int i; + for (i = 0; i < KYBER_K; i++) { + PQCLEAN_KYBER512_CLEAN_poly_add(&r->vec[i], &a->vec[i], &b->vec[i]); + } +} diff --git a/crypto_kem/kyber512/clean/polyvec.h b/crypto_kem/kyber512/clean/polyvec.h new file mode 100644 index 00000000..5e2ed31f --- /dev/null +++ b/crypto_kem/kyber512/clean/polyvec.h @@ -0,0 +1,27 @@ +#ifndef POLYVEC_H +#define POLYVEC_H + +#include "params.h" +#include "poly.h" + +typedef struct { + poly vec[KYBER_K]; +} polyvec; + +void PQCLEAN_KYBER512_CLEAN_polyvec_compress(unsigned char *r, polyvec *a); +void PQCLEAN_KYBER512_CLEAN_polyvec_decompress(polyvec *r, const unsigned char *a); + +void PQCLEAN_KYBER512_CLEAN_polyvec_tobytes(unsigned char *r, polyvec *a); +void PQCLEAN_KYBER512_CLEAN_polyvec_frombytes(polyvec *r, const unsigned char *a); + +void PQCLEAN_KYBER512_CLEAN_polyvec_ntt(polyvec *r); +void PQCLEAN_KYBER512_CLEAN_polyvec_invntt(polyvec *r); + +void PQCLEAN_KYBER512_CLEAN_polyvec_pointwise_acc(poly *r, const polyvec *a, const polyvec *b); + +void PQCLEAN_KYBER512_CLEAN_polyvec_reduce(polyvec *r); +void PQCLEAN_KYBER512_CLEAN_polyvec_csubq(polyvec *r); + +void PQCLEAN_KYBER512_CLEAN_polyvec_add(polyvec *r, const polyvec *a, const polyvec *b); + +#endif diff --git a/crypto_kem/kyber512/clean/reduce.c b/crypto_kem/kyber512/clean/reduce.c new file mode 100644 index 00000000..ecc99dd4 --- /dev/null +++ b/crypto_kem/kyber512/clean/reduce.c @@ -0,0 +1,62 @@ +#include "reduce.h" + +#include "params.h" + +#include + +/************************************************* +* Name: PQCLEAN_KYBER512_CLEAN_montgomery_reduce +* +* Description: Montgomery reduction; given a 32-bit integer a, computes +* 16-bit integer congruent to a * R^-1 mod q, +* where R=2^16 +* +* Arguments: - int32_t a: input integer to be reduced; has to be in {-q2^15,...,q2^15-1} +* +* Returns: integer in {-q+1,...,q-1} congruent to a * R^-1 modulo q. +**************************************************/ +int16_t PQCLEAN_KYBER512_CLEAN_montgomery_reduce(int32_t a) { + int32_t t; + int16_t u; + + u = (int16_t)(a * QINV); + t = (int32_t)u * KYBER_Q; + t = a - t; + t >>= 16; + return (int16_t)t; +} + +/************************************************* +* Name: PQCLEAN_KYBER512_CLEAN_barrett_reduce +* +* Description: Barrett reduction; given a 16-bit integer a, computes +* 16-bit integer congruent to a mod q in {0,...,q} +* +* Arguments: - int16_t a: input integer to be reduced +* +* Returns: integer in {0,...,q} congruent to a modulo q. +**************************************************/ +int16_t PQCLEAN_KYBER512_CLEAN_barrett_reduce(int16_t a) { + int32_t t; + const int32_t v = (1U << 26) / KYBER_Q + 1; + + t = v * a; + t >>= 26; + t *= KYBER_Q; + return (int16_t)(a - t); +} + +/************************************************* +* Name: PQCLEAN_KYBER512_CLEAN_csubq +* +* Description: Conditionallly subtract q +* +* Arguments: - int16_t x: input integer +* +* Returns: a - q if a >= q, else a +**************************************************/ +int16_t PQCLEAN_KYBER512_CLEAN_csubq(int16_t a) { + a -= KYBER_Q; + a += (a >> 15) & KYBER_Q; + return a; +} diff --git a/crypto_kem/kyber512/clean/reduce.h b/crypto_kem/kyber512/clean/reduce.h new file mode 100644 index 00000000..68a7f570 --- /dev/null +++ b/crypto_kem/kyber512/clean/reduce.h @@ -0,0 +1,15 @@ +#ifndef REDUCE_H +#define REDUCE_H + +#include + +#define MONT 2285 // 2^16 % Q +#define QINV 62209 // q^(-1) mod 2^16 + +int16_t PQCLEAN_KYBER512_CLEAN_montgomery_reduce(int32_t a); + +int16_t PQCLEAN_KYBER512_CLEAN_barrett_reduce(int16_t a); + +int16_t PQCLEAN_KYBER512_CLEAN_csubq(int16_t a); + +#endif diff --git a/crypto_kem/kyber512/clean/symmetric-fips202.c b/crypto_kem/kyber512/clean/symmetric-fips202.c new file mode 100644 index 00000000..345cebb4 --- /dev/null +++ b/crypto_kem/kyber512/clean/symmetric-fips202.c @@ -0,0 +1,64 @@ +#include "fips202.h" +#include "symmetric.h" + +#include + +/************************************************* +* Name: PQCLEAN_KYBER512_CLEAN_kyber_shake128_absorb +* +* Description: Absorb step of the SHAKE128 specialized for the Kyber context. +* +* Arguments: - uint64_t *s: pointer to (uninitialized) output Keccak state +* - const unsigned char *input: pointer to KYBER_SYMBYTES input to be absorbed into s +* - unsigned char i additional byte of input +* - unsigned char j additional byte of input +**************************************************/ +void PQCLEAN_KYBER512_CLEAN_kyber_shake128_absorb(keccak_state *s, const unsigned char *input, unsigned char x, unsigned char y) { + unsigned char extseed[KYBER_SYMBYTES + 2]; + int i; + + for (i = 0; i < KYBER_SYMBYTES; i++) { + extseed[i] = input[i]; + } + extseed[i++] = x; + extseed[i] = y; + shake128_absorb(s->s, extseed, KYBER_SYMBYTES + 2); +} + +/************************************************* +* Name: PQCLEAN_KYBER512_CLEAN_kyber_shake128_squeezeblocks +* +* Description: Squeeze step of SHAKE128 XOF. Squeezes full blocks of SHAKE128_RATE bytes each. +* Modifies the state. Can be called multiple times to keep squeezing, +* i.e., is incremental. +* +* Arguments: - unsigned char *output: pointer to output blocks +* - size_t nblocks: number of blocks to be squeezed (written to output) +* - keccak_state *s: pointer to in/output Keccak state +**************************************************/ +void PQCLEAN_KYBER512_CLEAN_kyber_shake128_squeezeblocks(unsigned char *output, size_t nblocks, keccak_state *s) { + shake128_squeezeblocks(output, nblocks, s->s); +} + +/************************************************* +* Name: PQCLEAN_KYBER512_CLEAN_shake256_prf +* +* Description: Usage of SHAKE256 as a PRF, concatenates secret and public input +* and then generates outlen bytes of SHAKE256 output +* +* Arguments: - unsigned char *output: pointer to output +* - size_t outlen: number of requested output bytes +* - const unsigned char * key: pointer to the key (of length KYBER_SYMBYTES) +* - const unsigned char nonce: single-byte nonce (public PRF input) +**************************************************/ +void PQCLEAN_KYBER512_CLEAN_shake256_prf(unsigned char *output, size_t outlen, const unsigned char *key, unsigned char nonce) { + unsigned char extkey[KYBER_SYMBYTES + 1]; + size_t i; + + for (i = 0; i < KYBER_SYMBYTES; i++) { + extkey[i] = key[i]; + } + extkey[i] = nonce; + + shake256(output, outlen, extkey, KYBER_SYMBYTES + 1); +} diff --git a/crypto_kem/kyber512/clean/symmetric.h b/crypto_kem/kyber512/clean/symmetric.h new file mode 100644 index 00000000..b0f61aeb --- /dev/null +++ b/crypto_kem/kyber512/clean/symmetric.h @@ -0,0 +1,26 @@ +#ifndef SYMMETRIC_H +#define SYMMETRIC_H + +#include "fips202.h" +#include "params.h" + +typedef struct { + uint64_t s[25]; +} keccak_state; + +void PQCLEAN_KYBER512_CLEAN_kyber_shake128_absorb(keccak_state *s, const unsigned char *input, unsigned char x, unsigned char y); +void PQCLEAN_KYBER512_CLEAN_kyber_shake128_squeezeblocks(unsigned char *output, size_t nblocks, keccak_state *s); +void PQCLEAN_KYBER512_CLEAN_shake256_prf(unsigned char *output, size_t outlen, const unsigned char *key, unsigned char nonce); + +#define hash_h(OUT, IN, INBYTES) sha3_256(OUT, IN, INBYTES) +#define hash_g(OUT, IN, INBYTES) sha3_512(OUT, IN, INBYTES) +#define xof_absorb(STATE, IN, X, Y) PQCLEAN_KYBER512_CLEAN_kyber_shake128_absorb(STATE, IN, X, Y) +#define xof_squeezeblocks(OUT, OUTBLOCKS, STATE) PQCLEAN_KYBER512_CLEAN_kyber_shake128_squeezeblocks(OUT, OUTBLOCKS, STATE) +#define prf(OUT, OUTBYTES, KEY, NONCE) PQCLEAN_KYBER512_CLEAN_shake256_prf(OUT, OUTBYTES, KEY, NONCE) +#define kdf(OUT, IN, INBYTES) shake256(OUT, KYBER_SSBYTES, IN, INBYTES) + +#define XOF_BLOCKBYTES 168 + +typedef keccak_state xof_state; + +#endif /* SYMMETRIC_H */ diff --git a/crypto_kem/kyber512/clean/verify.c b/crypto_kem/kyber512/clean/verify.c new file mode 100644 index 00000000..b8f4dcff --- /dev/null +++ b/crypto_kem/kyber512/clean/verify.c @@ -0,0 +1,51 @@ +#include "verify.h" + +#include +#include + +/************************************************* +* Name: verify +* +* Description: Compare two arrays for equality in constant time. +* +* Arguments: const unsigned char *a: pointer to first byte array +* const unsigned char *b: pointer to second byte array +* size_t len: length of the byte arrays +* +* Returns 0 if the byte arrays are equal, 1 otherwise +**************************************************/ +unsigned char PQCLEAN_KYBER512_CLEAN_verify(const unsigned char *a, const unsigned char *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; +} + +/************************************************* +* Name: cmov +* +* Description: Copy len bytes from x to r if b is 1; +* don't modify x if b is 0. Requires b to be in {0,1}; +* assumes two's complement representation of negative integers. +* Runs in constant time. +* +* Arguments: unsigned char *r: pointer to output byte array +* const unsigned char *x: pointer to input byte array +* size_t len: Amount of bytes to be copied +* unsigned char b: Condition bit; has to be in {0,1} +**************************************************/ +void PQCLEAN_KYBER512_CLEAN_cmov(unsigned char *r, const unsigned char *x, size_t len, unsigned char b) { + size_t i; + + b = -b; + for (i = 0; i < len; i++) { + r[i] ^= b & (x[i] ^ r[i]); + } +} diff --git a/crypto_kem/kyber512/clean/verify.h b/crypto_kem/kyber512/clean/verify.h new file mode 100644 index 00000000..f2b6bbbc --- /dev/null +++ b/crypto_kem/kyber512/clean/verify.h @@ -0,0 +1,10 @@ +#ifndef VERIFY_H +#define VERIFY_H + +#include + +unsigned char PQCLEAN_KYBER512_CLEAN_verify(const unsigned char *a, const unsigned char *b, size_t len); + +void PQCLEAN_KYBER512_CLEAN_cmov(unsigned char *r, const unsigned char *x, size_t len, unsigned char b); + +#endif diff --git a/crypto_kem/kyber768/META.yml b/crypto_kem/kyber768/META.yml index 8a183ecc..2d8a309e 100644 --- a/crypto_kem/kyber768/META.yml +++ b/crypto_kem/kyber768/META.yml @@ -1,9 +1,9 @@ name: Kyber768 type: kem claimed-nist-level: 3 -length-public-key: 1088 +length-public-key: 1184 +length-ciphertext: 1088 length-secret-key: 2400 -length-ciphertext: 1152 length-shared-secret: 32 nistkat-sha256: d6dbb9399d1ba4ee2d986de3e54a461256b91d6c2f9b90ad2410cf41e09b64d1 principal-submitter: Peter Schwabe @@ -19,4 +19,4 @@ auxiliary-submitters: - Damien Stehlé implementations: - name: clean - version: https://github.com/pq-crystals/kyber/commit/ab996e7460e5356b0e23aa034e7c2fe6922e60e6 + version: https://github.com/pq-crystals/kyber/commit/46e283ab575ec92dfe82fb12229ae2d9d6246682 diff --git a/crypto_kem/kyber768/clean/Makefile b/crypto_kem/kyber768/clean/Makefile index d408dca7..c98f6e49 100644 --- a/crypto_kem/kyber768/clean/Makefile +++ b/crypto_kem/kyber768/clean/Makefile @@ -1,8 +1,8 @@ # This Makefile can be used with GNU Make or BSD Make LIB=libkyber768_clean.a -HEADERS=api.h cbd.h indcpa.h ntt.h params.h poly.h polyvec.h reduce.h verify.h -OBJECTS=cbd.o indcpa.o kem.o ntt.o poly.o polyvec.o precomp.o reduce.o verify.o +HEADERS=api.h cbd.h indcpa.h ntt.h params.h poly.h polyvec.h reduce.h verify.h symmetric.h +OBJECTS=cbd.o indcpa.o kem.o ntt.o poly.o polyvec.o reduce.o verify.o symmetric-fips202.o CFLAGS=-O3 -Wall -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -std=c99 -I../../../common $(EXTRAFLAGS) diff --git a/crypto_kem/kyber768/clean/Makefile.Microsoft_nmake b/crypto_kem/kyber768/clean/Makefile.Microsoft_nmake index eb7bb622..c037a87e 100644 --- a/crypto_kem/kyber768/clean/Makefile.Microsoft_nmake +++ b/crypto_kem/kyber768/clean/Makefile.Microsoft_nmake @@ -2,7 +2,7 @@ # nmake /f Makefile.Microsoft_nmake LIBRARY=libkyber768_clean.lib -OBJECTS=cbd.obj indcpa.obj kem.obj ntt.obj poly.obj polyvec.obj precomp.obj reduce.obj verify.obj +OBJECTS=cbd.obj indcpa.obj kem.obj ntt.obj poly.obj polyvec.obj reduce.obj verify.obj symmetric-fips202.obj CFLAGS=/nologo /I ..\..\..\common /W4 /WX diff --git a/crypto_kem/kyber768/clean/api.h b/crypto_kem/kyber768/clean/api.h index be974161..35823876 100644 --- a/crypto_kem/kyber768/clean/api.h +++ b/crypto_kem/kyber768/clean/api.h @@ -1,19 +1,18 @@ #ifndef PQCLEAN_KYBER768_CLEAN_API_H #define PQCLEAN_KYBER768_CLEAN_API_H -#include - -#define PQCLEAN_KYBER768_CLEAN_CRYPTO_SECRETKEYBYTES 2400 -#define PQCLEAN_KYBER768_CLEAN_CRYPTO_PUBLICKEYBYTES 1088 -#define PQCLEAN_KYBER768_CLEAN_CRYPTO_CIPHERTEXTBYTES 1152 -#define PQCLEAN_KYBER768_CLEAN_CRYPTO_BYTES 32 +#define PQCLEAN_KYBER768_CLEAN_CRYPTO_SECRETKEYBYTES 2400 +#define PQCLEAN_KYBER768_CLEAN_CRYPTO_PUBLICKEYBYTES 1184 +#define PQCLEAN_KYBER768_CLEAN_CRYPTO_CIPHERTEXTBYTES 1088 +#define PQCLEAN_KYBER768_CLEAN_CRYPTO_BYTES 32 #define PQCLEAN_KYBER768_CLEAN_CRYPTO_ALGNAME "Kyber768" -int PQCLEAN_KYBER768_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk); +int PQCLEAN_KYBER768_CLEAN_crypto_kem_keypair(unsigned char *pk, unsigned char *sk); -int PQCLEAN_KYBER768_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk); +int PQCLEAN_KYBER768_CLEAN_crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk); + +int PQCLEAN_KYBER768_CLEAN_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk); -int PQCLEAN_KYBER768_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk); #endif diff --git a/crypto_kem/kyber768/clean/cbd.c b/crypto_kem/kyber768/clean/cbd.c index 15b46021..eac6a514 100644 --- a/crypto_kem/kyber768/clean/cbd.c +++ b/crypto_kem/kyber768/clean/cbd.c @@ -1,59 +1,53 @@ #include "cbd.h" +#include "params.h" + +#include + /************************************************* - * Name: load_littleendian - * - * Description: load bytes into a 64-bit integer - * in little-endian order - * - * Arguments: - const unsigned char *x: pointer to input byte array - * - bytes: number of bytes to load, has to be <= - *8 - * - * Returns 64-bit unsigned integer loaded from x - **************************************************/ -static uint64_t load_littleendian(const unsigned char *x, int bytes) { - int i; - uint64_t r = x[0]; - for (i = 1; i < bytes; i++) { - r |= (uint64_t)x[i] << (8 * i); - } +* Name: load32_littleendian +* +* Description: load bytes into a 32-bit integer +* in little-endian order +* +* Arguments: - const unsigned char *x: pointer to input byte array +* +* Returns 32-bit unsigned integer loaded from x +**************************************************/ +static uint32_t load32_littleendian(const unsigned char *x) { + uint32_t r; + r = (uint32_t)x[0]; + r |= (uint32_t)x[1] << 8; + r |= (uint32_t)x[2] << 16; + r |= (uint32_t)x[3] << 24; return r; } /************************************************* - * Name: cbd - * - * Description: Given an array of uniformly random bytes, compute - * polynomial with coefficients distributed according to - * a centered binomial distribution with parameter KYBER_ETA - * - * Arguments: - poly *r: pointer to output polynomial - * - const unsigned char *buf: pointer to input byte array - **************************************************/ +* Name: cbd +* +* Description: Given an array of uniformly random bytes, compute +* polynomial with coefficients distributed according to +* a centered binomial distribution with parameter KYBER_ETA +* specialized for KYBER_ETA=2 +* +* Arguments: - poly *r: pointer to output polynomial +* - const unsigned char *buf: pointer to input byte array +**************************************************/ void PQCLEAN_KYBER768_CLEAN_cbd(poly *r, const unsigned char *buf) { - uint32_t t, d, a[4], b[4]; + uint32_t d, t; + int16_t a, b; int i, j; - for (i = 0; i < KYBER_N / 4; i++) { - t = (uint32_t)load_littleendian(buf + 4 * i, 4); - d = 0; - for (j = 0; j < 4; j++) { - d += (t >> j) & 0x11111111; + for (i = 0; i < KYBER_N / 8; i++) { + t = load32_littleendian(buf + 4 * i); + d = t & 0x55555555; + d += (t >> 1) & 0x55555555; + + for (j = 0; j < 8; j++) { + a = (d >> 4 * j) & 0x3; + b = (d >> (4 * j + 2)) & 0x3; + r->coeffs[8 * i + j] = a - b; } - - 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->coeffs[4 * i + 0] = (uint16_t)(a[0] + KYBER_Q - b[0]); - r->coeffs[4 * i + 1] = (uint16_t)(a[1] + KYBER_Q - b[1]); - r->coeffs[4 * i + 2] = (uint16_t)(a[2] + KYBER_Q - b[2]); - r->coeffs[4 * i + 3] = (uint16_t)(a[3] + KYBER_Q - b[3]); } } diff --git a/crypto_kem/kyber768/clean/cbd.h b/crypto_kem/kyber768/clean/cbd.h index 88436fb0..1179a584 100644 --- a/crypto_kem/kyber768/clean/cbd.h +++ b/crypto_kem/kyber768/clean/cbd.h @@ -2,7 +2,6 @@ #define CBD_H #include "poly.h" -#include void PQCLEAN_KYBER768_CLEAN_cbd(poly *r, const unsigned char *buf); diff --git a/crypto_kem/kyber768/clean/indcpa.c b/crypto_kem/kyber768/clean/indcpa.c index 1de2d599..3347434d 100644 --- a/crypto_kem/kyber768/clean/indcpa.c +++ b/crypto_kem/kyber768/clean/indcpa.c @@ -1,238 +1,239 @@ #include "indcpa.h" -#include "fips202.h" + #include "ntt.h" #include "poly.h" #include "polyvec.h" #include "randombytes.h" -#include +#include "symmetric.h" + +#include /************************************************* - * Name: pack_pk - * - * Description: Serialize the public key as concatenation of the - * compressed and serialized vector of polynomials pk - * and the public seed used to generate the matrix A. - * - * Arguments: unsigned char *r: pointer to the output serialized - *public key const poly *pk: pointer to the input public-key - *polynomial const unsigned char *seed: pointer to the input public seed - **************************************************/ -static void pack_pk(unsigned char *r, const polyvec *pk, const unsigned char *seed) { +* Name: pack_pk +* +* Description: Serialize the public key as concatenation of the +* serialized vector of polynomials pk +* and the public seed used to generate the matrix A. +* +* Arguments: unsigned char *r: pointer to the output serialized public key +* const poly *pk: pointer to the input public-key polynomial +* const unsigned char *seed: pointer to the input public seed +**************************************************/ +static void pack_pk(unsigned char *r, polyvec *pk, const unsigned char *seed) { int i; - PQCLEAN_KYBER768_CLEAN_polyvec_compress(r, pk); + PQCLEAN_KYBER768_CLEAN_polyvec_tobytes(r, pk); for (i = 0; i < KYBER_SYMBYTES; i++) { - r[i + KYBER_POLYVECCOMPRESSEDBYTES] = seed[i]; + r[i + KYBER_POLYVECBYTES] = seed[i]; } } /************************************************* - * Name: unpack_pk - * - * Description: De-serialize and decompress public key from a byte array; - * approximate inverse of pack_pk - * - * Arguments: - polyvec *pk: pointer to output public-key - *vector of polynomials - * - unsigned char *seed: pointer to output seed to - *generate matrix A - * - const unsigned char *packedpk: pointer to input serialized - *public key - **************************************************/ +* Name: unpack_pk +* +* Description: De-serialize public key from a byte array; +* approximate inverse of pack_pk +* +* Arguments: - polyvec *pk: pointer to output public-key vector of polynomials +* - unsigned char *seed: pointer to output seed to generate matrix A +* - const unsigned char *packedpk: pointer to input serialized public key +**************************************************/ static void unpack_pk(polyvec *pk, unsigned char *seed, const unsigned char *packedpk) { int i; - PQCLEAN_KYBER768_CLEAN_polyvec_decompress(pk, packedpk); - + PQCLEAN_KYBER768_CLEAN_polyvec_frombytes(pk, packedpk); for (i = 0; i < KYBER_SYMBYTES; i++) { - seed[i] = packedpk[i + KYBER_POLYVECCOMPRESSEDBYTES]; + seed[i] = packedpk[i + KYBER_POLYVECBYTES]; } } /************************************************* - * Name: pack_ciphertext - * - * Description: Serialize the ciphertext as concatenation of the - * compressed and serialized vector of polynomials b - * and the compressed and serialized polynomial v - * - * Arguments: unsigned char *r: pointer to the output serialized - *ciphertext const poly *pk: pointer to the input vector of - *polynomials b const unsigned char *seed: pointer to the input polynomial v - **************************************************/ -static void pack_ciphertext(unsigned char *r, const polyvec *b, const poly *v) { +* Name: pack_sk +* +* Description: Serialize the secret key +* +* Arguments: - unsigned char *r: pointer to output serialized secret key +* - const polyvec *sk: pointer to input vector of polynomials (secret key) +**************************************************/ +static void pack_sk(unsigned char *r, polyvec *sk) { + PQCLEAN_KYBER768_CLEAN_polyvec_tobytes(r, sk); +} + +/************************************************* +* Name: unpack_sk +* +* Description: De-serialize the secret key; +* inverse of pack_sk +* +* Arguments: - polyvec *sk: pointer to output vector of polynomials (secret key) +* - const unsigned char *packedsk: pointer to input serialized secret key +**************************************************/ +static void unpack_sk(polyvec *sk, const unsigned char *packedsk) { + PQCLEAN_KYBER768_CLEAN_polyvec_frombytes(sk, packedsk); +} + +/************************************************* +* Name: pack_ciphertext +* +* Description: Serialize the ciphertext as concatenation of the +* compressed and serialized vector of polynomials b +* and the compressed and serialized polynomial v +* +* Arguments: unsigned char *r: pointer to the output serialized ciphertext +* const poly *pk: pointer to the input vector of polynomials b +* const unsigned char *seed: pointer to the input polynomial v +**************************************************/ +static void pack_ciphertext(unsigned char *r, polyvec *b, poly *v) { PQCLEAN_KYBER768_CLEAN_polyvec_compress(r, b); PQCLEAN_KYBER768_CLEAN_poly_compress(r + KYBER_POLYVECCOMPRESSEDBYTES, v); } /************************************************* - * Name: unpack_ciphertext - * - * Description: De-serialize and decompress ciphertext from a byte array; - * approximate inverse of pack_ciphertext - * - * Arguments: - polyvec *b: pointer to the output vector of - *polynomials b - * - poly *v: pointer to the output polynomial v - * - const unsigned char *c: pointer to the input serialized - *ciphertext - **************************************************/ +* Name: unpack_ciphertext +* +* Description: De-serialize and decompress ciphertext from a byte array; +* approximate inverse of pack_ciphertext +* +* Arguments: - polyvec *b: pointer to the output vector of polynomials b +* - poly *v: pointer to the output polynomial v +* - const unsigned char *c: pointer to the input serialized ciphertext +**************************************************/ static void unpack_ciphertext(polyvec *b, poly *v, const unsigned char *c) { PQCLEAN_KYBER768_CLEAN_polyvec_decompress(b, c); PQCLEAN_KYBER768_CLEAN_poly_decompress(v, c + KYBER_POLYVECCOMPRESSEDBYTES); } /************************************************* - * Name: pack_sk - * - * Description: Serialize the secret key - * - * Arguments: - unsigned char *r: pointer to output serialized secret key - * - const polyvec *sk: pointer to input vector of polynomials - *(secret key) - **************************************************/ -static void pack_sk(unsigned char *r, const polyvec *sk) { - PQCLEAN_KYBER768_CLEAN_polyvec_tobytes(r, sk); -} - -/************************************************* - * Name: unpack_sk - * - * Description: De-serialize the secret key; - * inverse of pack_sk - * - * Arguments: - polyvec *sk: pointer to output vector of - *polynomials (secret key) - * - const unsigned char *packedsk: pointer to input serialized - *secret key - **************************************************/ -static void unpack_sk(polyvec *sk, const unsigned char *packedsk) { - PQCLEAN_KYBER768_CLEAN_polyvec_frombytes(sk, packedsk); -} - -#define gen_a(A, B) gen_matrix(A, B, 0) -#define gen_at(A, B) gen_matrix(A, B, 1) - -/************************************************* - * Name: gen_matrix - * - * Description: Deterministically generate matrix A (or the transpose of A) - * from a seed. Entries of the matrix are polynomials that look - * uniformly random. Performs rejection sampling on output of - * SHAKE-128 - * - * Arguments: - polyvec *a: pointer to ouptput matrix A - * - const unsigned char *seed: pointer to input seed - * - int transposed: boolean deciding whether A or A^T - *is generated - **************************************************/ -static void gen_matrix(polyvec *a, const unsigned char *seed, int transposed) { - unsigned int pos = 0, ctr; +* Name: rej_uniform +* +* Description: Run rejection sampling on uniform random bytes to generate +* uniform random integers mod q +* +* Arguments: - int16_t *r: pointer to output buffer +* - unsigned int len: requested number of 16-bit integers (uniform mod q) +* - const unsigned char *buf: pointer to input buffer (assumed to be uniform random bytes) +* - unsigned int buflen: length of input buffer in bytes +* +* Returns number of sampled 16-bit integers (at most len) +**************************************************/ +static unsigned int rej_uniform(int16_t *r, unsigned int len, const unsigned char *buf, unsigned int buflen) { + unsigned int ctr, pos; uint16_t val; - unsigned int nblocks; - const unsigned int maxnblocks = 4; - uint8_t buf[SHAKE128_RATE * /* maxnblocks = */ 4]; - int i, j; - uint64_t state[25]; // SHAKE state - unsigned char extseed[KYBER_SYMBYTES + 2]; - for (i = 0; i < KYBER_SYMBYTES; i++) { - extseed[i] = seed[i]; + ctr = pos = 0; + while (ctr < len && pos + 2 <= buflen) { + val = buf[pos] | ((uint16_t)buf[pos + 1] << 8); + pos += 2; + + if (val < 19 * KYBER_Q) { + val -= (val >> 12) * KYBER_Q; // Barrett reduction + r[ctr++] = (int16_t)val; + } } + return ctr; +} + +#define gen_a(A,B) PQCLEAN_KYBER768_CLEAN_gen_matrix(A,B,0) +#define gen_at(A,B) PQCLEAN_KYBER768_CLEAN_gen_matrix(A,B,1) + +#define GENMATRIX_MAXNBLOCKS ((530 + XOF_BLOCKBYTES) / XOF_BLOCKBYTES) /* 530 is expected number of required bytes */ + + +/************************************************* +* Name: gen_matrix +* +* Description: Deterministically generate matrix A (or the transpose of A) +* from a seed. Entries of the matrix are polynomials that look +* uniformly random. Performs rejection sampling on output of +* a XOF +* +* Arguments: - polyvec *a: pointer to ouptput matrix A +* - const unsigned char *seed: pointer to input seed +* - int transposed: boolean deciding whether A or A^T is generated +**************************************************/ +static void PQCLEAN_KYBER768_CLEAN_gen_matrix(polyvec *a, const unsigned char *seed, int transposed) { + unsigned int ctr; + unsigned char i, j; + unsigned char buf[XOF_BLOCKBYTES * GENMATRIX_MAXNBLOCKS + 1]; + xof_state state; + for (i = 0; i < KYBER_K; i++) { for (j = 0; j < KYBER_K; j++) { - ctr = pos = 0; - nblocks = maxnblocks; if (transposed) { - extseed[KYBER_SYMBYTES] = (unsigned char)i; - extseed[KYBER_SYMBYTES + 1] = (unsigned char)j; + xof_absorb(&state, seed, i, j); } else { - extseed[KYBER_SYMBYTES] = (unsigned char)j; - extseed[KYBER_SYMBYTES + 1] = (unsigned char)i; + xof_absorb(&state, seed, j, i); } - shake128_absorb(state, extseed, KYBER_SYMBYTES + 2); - shake128_squeezeblocks(buf, nblocks, state); + xof_squeezeblocks(buf, GENMATRIX_MAXNBLOCKS, &state); + ctr = rej_uniform(a[i].vec[j].coeffs, KYBER_N, buf, GENMATRIX_MAXNBLOCKS * XOF_BLOCKBYTES); while (ctr < KYBER_N) { - val = (buf[pos] | ((uint16_t)buf[pos + 1] << 8)) & 0x1fff; - if (val < KYBER_Q) { - a[i].vec[j].coeffs[ctr++] = val; - } - pos += 2; - - if (pos > SHAKE128_RATE * nblocks - 2) { - nblocks = 1; - shake128_squeezeblocks(buf, nblocks, state); - pos = 0; - } + xof_squeezeblocks(buf, 1, &state); + ctr += rej_uniform(a[i].vec[j].coeffs + ctr, KYBER_N - ctr, buf, XOF_BLOCKBYTES); } } } } /************************************************* - * Name: indcpa_keypair - * - * Description: Generates public and private key for the CPA-secure - * public-key encryption scheme underlying Kyber - * - * Arguments: - unsigned char *pk: pointer to output public key (of length - *KYBER_INDCPA_PUBLICKEYBYTES bytes) - * - unsigned char *sk: pointer to output private key (of length - *KYBER_INDCPA_SECRETKEYBYTES bytes) - **************************************************/ +* Name: indcpa_keypair +* +* Description: Generates public and private key for the CPA-secure +* public-key encryption scheme underlying Kyber +* +* Arguments: - unsigned char *pk: pointer to output public key (of length KYBER_INDCPA_PUBLICKEYBYTES bytes) +* - unsigned char *sk: pointer to output private key (of length KYBER_INDCPA_SECRETKEYBYTES bytes) +**************************************************/ void PQCLEAN_KYBER768_CLEAN_indcpa_keypair(unsigned char *pk, unsigned char *sk) { polyvec a[KYBER_K], e, pkpv, skpv; - unsigned char buf[KYBER_SYMBYTES + KYBER_SYMBYTES]; + unsigned char buf[2 * KYBER_SYMBYTES]; unsigned char *publicseed = buf; unsigned char *noiseseed = buf + KYBER_SYMBYTES; int i; unsigned char nonce = 0; randombytes(buf, KYBER_SYMBYTES); - sha3_512(buf, buf, KYBER_SYMBYTES); + hash_g(buf, buf, KYBER_SYMBYTES); gen_a(a, publicseed); for (i = 0; i < KYBER_K; i++) { PQCLEAN_KYBER768_CLEAN_poly_getnoise(skpv.vec + i, noiseseed, nonce++); } - - PQCLEAN_KYBER768_CLEAN_polyvec_ntt(&skpv); - for (i = 0; i < KYBER_K; i++) { PQCLEAN_KYBER768_CLEAN_poly_getnoise(e.vec + i, noiseseed, nonce++); } + PQCLEAN_KYBER768_CLEAN_polyvec_ntt(&skpv); + PQCLEAN_KYBER768_CLEAN_polyvec_ntt(&e); + // matrix-vector multiplication for (i = 0; i < KYBER_K; i++) { - PQCLEAN_KYBER768_CLEAN_polyvec_pointwise_acc(&pkpv.vec[i], &skpv, a + i); + PQCLEAN_KYBER768_CLEAN_polyvec_pointwise_acc(&pkpv.vec[i], &a[i], &skpv); + PQCLEAN_KYBER768_CLEAN_poly_frommont(&pkpv.vec[i]); } - PQCLEAN_KYBER768_CLEAN_polyvec_invntt(&pkpv); PQCLEAN_KYBER768_CLEAN_polyvec_add(&pkpv, &pkpv, &e); + PQCLEAN_KYBER768_CLEAN_polyvec_reduce(&pkpv); pack_sk(sk, &skpv); pack_pk(pk, &pkpv, publicseed); } /************************************************* - * Name: indcpa_enc - * - * Description: Encryption function of the CPA-secure - * public-key encryption scheme underlying Kyber. - * - * Arguments: - unsigned char *c: pointer to output ciphertext (of - *length KYBER_INDCPA_BYTES bytes) - * - const unsigned char *m: pointer to input message (of length - *KYBER_INDCPA_MSGBYTES bytes) - * - const unsigned char *pk: pointer to input public key (of - *length KYBER_INDCPA_PUBLICKEYBYTES bytes) - * - const unsigned char *coin: pointer to input random coins used - *as seed (of length KYBER_SYMBYTES bytes) to deterministically generate all - *randomness - **************************************************/ -void PQCLEAN_KYBER768_CLEAN_indcpa_enc(unsigned char *c, const unsigned char *m, +* Name: indcpa_enc +* +* Description: Encryption function of the CPA-secure +* public-key encryption scheme underlying Kyber. +* +* Arguments: - unsigned char *c: pointer to output ciphertext (of length KYBER_INDCPA_BYTES bytes) +* - const unsigned char *m: pointer to input message (of length KYBER_INDCPA_MSGBYTES bytes) +* - const unsigned char *pk: pointer to input public key (of length KYBER_INDCPA_PUBLICKEYBYTES bytes) +* - const unsigned char *coin: pointer to input random coins used as seed (of length KYBER_SYMBYTES bytes) +* to deterministically generate all randomness +**************************************************/ +void PQCLEAN_KYBER768_CLEAN_indcpa_enc(unsigned char *c, + const unsigned char *m, const unsigned char *pk, const unsigned char *coins) { polyvec sp, pkpv, ep, at[KYBER_K], bp; @@ -242,56 +243,50 @@ void PQCLEAN_KYBER768_CLEAN_indcpa_enc(unsigned char *c, const unsigned char *m, unsigned char nonce = 0; unpack_pk(&pkpv, seed, pk); - PQCLEAN_KYBER768_CLEAN_poly_frommsg(&k, m); - - PQCLEAN_KYBER768_CLEAN_polyvec_ntt(&pkpv); - gen_at(at, seed); for (i = 0; i < KYBER_K; i++) { PQCLEAN_KYBER768_CLEAN_poly_getnoise(sp.vec + i, coins, nonce++); } - - PQCLEAN_KYBER768_CLEAN_polyvec_ntt(&sp); - for (i = 0; i < KYBER_K; i++) { PQCLEAN_KYBER768_CLEAN_poly_getnoise(ep.vec + i, coins, nonce++); } + PQCLEAN_KYBER768_CLEAN_poly_getnoise(&epp, coins, nonce++); + + PQCLEAN_KYBER768_CLEAN_polyvec_ntt(&sp); // matrix-vector multiplication for (i = 0; i < KYBER_K; i++) { - PQCLEAN_KYBER768_CLEAN_polyvec_pointwise_acc(&bp.vec[i], &sp, at + i); + PQCLEAN_KYBER768_CLEAN_polyvec_pointwise_acc(&bp.vec[i], &at[i], &sp); } - PQCLEAN_KYBER768_CLEAN_polyvec_invntt(&bp); - PQCLEAN_KYBER768_CLEAN_polyvec_add(&bp, &bp, &ep); - PQCLEAN_KYBER768_CLEAN_polyvec_pointwise_acc(&v, &pkpv, &sp); + + PQCLEAN_KYBER768_CLEAN_polyvec_invntt(&bp); PQCLEAN_KYBER768_CLEAN_poly_invntt(&v); - PQCLEAN_KYBER768_CLEAN_poly_getnoise(&epp, coins, nonce++); - + PQCLEAN_KYBER768_CLEAN_polyvec_add(&bp, &bp, &ep); PQCLEAN_KYBER768_CLEAN_poly_add(&v, &v, &epp); PQCLEAN_KYBER768_CLEAN_poly_add(&v, &v, &k); + PQCLEAN_KYBER768_CLEAN_polyvec_reduce(&bp); + PQCLEAN_KYBER768_CLEAN_poly_reduce(&v); pack_ciphertext(c, &bp, &v); } /************************************************* - * Name: indcpa_dec - * - * Description: Decryption function of the CPA-secure - * public-key encryption scheme underlying Kyber. - * - * Arguments: - unsigned char *m: pointer to output decrypted message - *(of length KYBER_INDCPA_MSGBYTES) - * - const unsigned char *c: pointer to input ciphertext (of - *length KYBER_INDCPA_BYTES) - * - const unsigned char *sk: pointer to input secret key (of - *length KYBER_INDCPA_SECRETKEYBYTES) - **************************************************/ -void PQCLEAN_KYBER768_CLEAN_indcpa_dec(unsigned char *m, const unsigned char *c, +* Name: indcpa_dec +* +* Description: Decryption function of the CPA-secure +* public-key encryption scheme underlying Kyber. +* +* Arguments: - unsigned char *m: pointer to output decrypted message (of length KYBER_INDCPA_MSGBYTES) +* - const unsigned char *c: pointer to input ciphertext (of length KYBER_INDCPA_BYTES) +* - const unsigned char *sk: pointer to input secret key (of length KYBER_INDCPA_SECRETKEYBYTES) +**************************************************/ +void PQCLEAN_KYBER768_CLEAN_indcpa_dec(unsigned char *m, + const unsigned char *c, const unsigned char *sk) { polyvec bp, skpv; poly v, mp; @@ -300,11 +295,11 @@ void PQCLEAN_KYBER768_CLEAN_indcpa_dec(unsigned char *m, const unsigned char *c, unpack_sk(&skpv, sk); PQCLEAN_KYBER768_CLEAN_polyvec_ntt(&bp); - PQCLEAN_KYBER768_CLEAN_polyvec_pointwise_acc(&mp, &skpv, &bp); PQCLEAN_KYBER768_CLEAN_poly_invntt(&mp); - PQCLEAN_KYBER768_CLEAN_poly_sub(&mp, &mp, &v); + PQCLEAN_KYBER768_CLEAN_poly_sub(&mp, &v, &mp); + PQCLEAN_KYBER768_CLEAN_poly_reduce(&mp); PQCLEAN_KYBER768_CLEAN_poly_tomsg(m, &mp); } diff --git a/crypto_kem/kyber768/clean/kem.c b/crypto_kem/kyber768/clean/kem.c index bda53edf..aada88ff 100644 --- a/crypto_kem/kyber768/clean/kem.c +++ b/crypto_kem/kyber768/clean/kem.c @@ -1,108 +1,102 @@ #include "api.h" -#include "fips202.h" #include "indcpa.h" #include "params.h" #include "randombytes.h" +#include "symmetric.h" #include "verify.h" +#include + +#include + /************************************************* - * Name: crypto_kem_keypair - * - * Description: Generates public and private key - * for CCA-secure Kyber key encapsulation mechanism - * - * Arguments: - unsigned char *pk: pointer to output public key (an already - *allocated array of CRYPTO_PUBLICKEYBYTES bytes) - * - unsigned char *sk: pointer to output private key (an already - *allocated array of CRYPTO_SECRETKEYBYTES bytes) - * - * Returns 0 (success) - **************************************************/ +* Name: crypto_kem_keypair +* +* Description: Generates public and private key +* for CCA-secure Kyber key encapsulation mechanism +* +* Arguments: - unsigned char *pk: pointer to output public key (an already allocated array of CRYPTO_PUBLICKEYBYTES bytes) +* - unsigned char *sk: pointer to output private key (an already allocated array of CRYPTO_SECRETKEYBYTES bytes) +* +* Returns 0 (success) +**************************************************/ int PQCLEAN_KYBER768_CLEAN_crypto_kem_keypair(unsigned char *pk, unsigned char *sk) { size_t i; PQCLEAN_KYBER768_CLEAN_indcpa_keypair(pk, sk); for (i = 0; i < KYBER_INDCPA_PUBLICKEYBYTES; i++) { sk[i + KYBER_INDCPA_SECRETKEYBYTES] = pk[i]; } - sha3_256(sk + KYBER_SECRETKEYBYTES - 2 * KYBER_SYMBYTES, pk, KYBER_PUBLICKEYBYTES); - randombytes(sk + KYBER_SECRETKEYBYTES - KYBER_SYMBYTES, KYBER_SYMBYTES); /* Value z for pseudo-random output on reject */ + hash_h(sk + KYBER_SECRETKEYBYTES - 2 * KYBER_SYMBYTES, pk, KYBER_PUBLICKEYBYTES); + randombytes(sk + KYBER_SECRETKEYBYTES - KYBER_SYMBYTES, KYBER_SYMBYTES); /* Value z for pseudo-random output on reject */ return 0; } /************************************************* - * Name: crypto_kem_enc - * - * Description: Generates cipher text and shared - * secret for given public key - * - * Arguments: - unsigned char *ct: pointer to output cipher text (an - *already allocated array of CRYPTO_CIPHERTEXTBYTES bytes) - * - unsigned char *ss: pointer to output shared secret (an - *already allocated array of CRYPTO_BYTES bytes) - * - const unsigned char *pk: pointer to input public key (an - *already allocated array of CRYPTO_PUBLICKEYBYTES bytes) - * - * Returns 0 (success) - **************************************************/ +* Name: crypto_kem_enc +* +* Description: Generates cipher text and shared +* secret for given public key +* +* Arguments: - unsigned char *ct: pointer to output cipher text (an already allocated array of CRYPTO_CIPHERTEXTBYTES bytes) +* - unsigned char *ss: pointer to output shared secret (an already allocated array of CRYPTO_BYTES bytes) +* - const unsigned char *pk: pointer to input public key (an already allocated array of CRYPTO_PUBLICKEYBYTES bytes) +* +* Returns 0 (success) +**************************************************/ int PQCLEAN_KYBER768_CLEAN_crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk) { - unsigned char kr[2 * KYBER_SYMBYTES]; /* Will contain key, coins */ + unsigned char kr[2 * KYBER_SYMBYTES]; /* Will contain key, coins */ unsigned char buf[2 * KYBER_SYMBYTES]; randombytes(buf, KYBER_SYMBYTES); - sha3_256(buf, buf, KYBER_SYMBYTES); /* Don't release system RNG output */ + hash_h(buf, buf, KYBER_SYMBYTES); /* Don't release system RNG output */ - sha3_256(buf + KYBER_SYMBYTES, pk, KYBER_PUBLICKEYBYTES); /* Multitarget countermeasure for coins + contributory KEM */ - sha3_512(kr, buf, 2 * KYBER_SYMBYTES); + hash_h(buf + KYBER_SYMBYTES, pk, KYBER_PUBLICKEYBYTES); /* Multitarget countermeasure for coins + contributory KEM */ + hash_g(kr, buf, 2 * KYBER_SYMBYTES); - PQCLEAN_KYBER768_CLEAN_indcpa_enc(ct, buf, pk, kr + KYBER_SYMBYTES); /* coins are in kr+KYBER_SYMBYTES */ + PQCLEAN_KYBER768_CLEAN_indcpa_enc(ct, buf, pk, kr + KYBER_SYMBYTES); /* coins are in kr+KYBER_SYMBYTES */ - sha3_256(kr + KYBER_SYMBYTES, ct, KYBER_CIPHERTEXTBYTES); /* overwrite coins in kr with H(c) */ - sha3_256(ss, kr, 2 * KYBER_SYMBYTES); /* hash concatenation of pre-k and H(c) to k */ + hash_h(kr + KYBER_SYMBYTES, ct, KYBER_CIPHERTEXTBYTES); /* overwrite coins in kr with H(c) */ + kdf(ss, kr, 2 * KYBER_SYMBYTES); /* hash concatenation of pre-k and H(c) to k */ return 0; } /************************************************* - * Name: crypto_kem_dec - * - * Description: Generates shared secret for given - * cipher text and private key - * - * Arguments: - unsigned char *ss: pointer to output shared secret (an - *already allocated array of CRYPTO_BYTES bytes) - * - const unsigned char *ct: pointer to input cipher text (an - *already allocated array of CRYPTO_CIPHERTEXTBYTES bytes) - * - const unsigned char *sk: pointer to input private key (an - *already allocated array of CRYPTO_SECRETKEYBYTES bytes) - * - * Returns 0. - * - * On failure, ss will contain a pseudo-random value. - **************************************************/ +* Name: crypto_kem_dec +* +* Description: Generates shared secret for given +* cipher text and private key +* +* Arguments: - unsigned char *ss: pointer to output shared secret (an already allocated array of CRYPTO_BYTES bytes) +* - const unsigned char *ct: pointer to input cipher text (an already allocated array of CRYPTO_CIPHERTEXTBYTES bytes) +* - const unsigned char *sk: pointer to input private key (an already allocated array of CRYPTO_SECRETKEYBYTES bytes) +* +* Returns 0. +* +* On failure, ss will contain a pseudo-random value. +**************************************************/ int PQCLEAN_KYBER768_CLEAN_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk) { size_t i; - int fail; + unsigned char fail; unsigned char cmp[KYBER_CIPHERTEXTBYTES]; unsigned char buf[2 * KYBER_SYMBYTES]; - unsigned char - kr[2 * KYBER_SYMBYTES]; /* Will contain key, coins, qrom-hash */ + unsigned char kr[2 * KYBER_SYMBYTES]; /* Will contain key, coins */ const unsigned char *pk = sk + KYBER_INDCPA_SECRETKEYBYTES; PQCLEAN_KYBER768_CLEAN_indcpa_dec(buf, ct, sk); - for (i = 0; i < KYBER_SYMBYTES; i++) { /* Multitarget countermeasure for coins + contributory KEM */ - buf[KYBER_SYMBYTES + i] = sk[KYBER_SECRETKEYBYTES - 2 * KYBER_SYMBYTES + i]; /* Save hash by storing H(pk) in sk */ + for (i = 0; i < KYBER_SYMBYTES; i++) { /* Multitarget countermeasure for coins + contributory KEM */ + buf[KYBER_SYMBYTES + i] = sk[KYBER_SECRETKEYBYTES - 2 * KYBER_SYMBYTES + i]; /* Save hash by storing H(pk) in sk */ } - sha3_512(kr, buf, 2 * KYBER_SYMBYTES); + hash_g(kr, buf, 2 * KYBER_SYMBYTES); - PQCLEAN_KYBER768_CLEAN_indcpa_enc(cmp, buf, pk, kr + KYBER_SYMBYTES); /* coins are in kr+KYBER_SYMBYTES */ + PQCLEAN_KYBER768_CLEAN_indcpa_enc(cmp, buf, pk, kr + KYBER_SYMBYTES); /* coins are in kr+KYBER_SYMBYTES */ fail = PQCLEAN_KYBER768_CLEAN_verify(ct, cmp, KYBER_CIPHERTEXTBYTES); - sha3_256(kr + KYBER_SYMBYTES, ct, KYBER_CIPHERTEXTBYTES); /* overwrite coins in kr with H(c) */ + hash_h(kr + KYBER_SYMBYTES, ct, KYBER_CIPHERTEXTBYTES); /* overwrite coins in kr with H(c) */ - PQCLEAN_KYBER768_CLEAN_cmov(kr, sk + KYBER_SECRETKEYBYTES - KYBER_SYMBYTES, KYBER_SYMBYTES, (unsigned char)fail); /* Overwrite pre-k with z on re-encryption failure */ - - sha3_256(ss, kr, 2 * KYBER_SYMBYTES); /* hash concatenation of pre-k and H(c) to k */ + PQCLEAN_KYBER768_CLEAN_cmov(kr, sk + KYBER_SECRETKEYBYTES - KYBER_SYMBYTES, KYBER_SYMBYTES, fail); /* Overwrite pre-k with z on re-encryption failure */ + kdf(ss, kr, 2 * KYBER_SYMBYTES); /* hash concatenation of pre-k and H(c) to k */ return 0; } diff --git a/crypto_kem/kyber768/clean/ntt.c b/crypto_kem/kyber768/clean/ntt.c index 53fc4595..ea98c4c6 100644 --- a/crypto_kem/kyber768/clean/ntt.c +++ b/crypto_kem/kyber768/clean/ntt.c @@ -1,80 +1,157 @@ #include "ntt.h" -#include "inttypes.h" + #include "params.h" #include "reduce.h" -extern const uint16_t PQCLEAN_KYBER768_CLEAN_omegas_inv_bitrev_montgomery[]; -extern const uint16_t PQCLEAN_KYBER768_CLEAN_psis_inv_montgomery[]; -extern const uint16_t PQCLEAN_KYBER768_CLEAN_zetas[]; +#include + +/* Code to generate zetas and zetas_inv used in the number-theoretic transform: + +#define KYBER_ROOT_OF_UNITY 17 + +static const uint16_t tree[128] = { + 0, 64, 32, 96, 16, 80, 48, 112, 8, 72, 40, 104, 24, 88, 56, 120, + 4, 68, 36, 100, 20, 84, 52, 116, 12, 76, 44, 108, 28, 92, 60, 124, + 2, 66, 34, 98, 18, 82, 50, 114, 10, 74, 42, 106, 26, 90, 58, 122, + 6, 70, 38, 102, 22, 86, 54, 118, 14, 78, 46, 110, 30, 94, 62, 126, + 1, 65, 33, 97, 17, 81, 49, 113, 9, 73, 41, 105, 25, 89, 57, 121, + 5, 69, 37, 101, 21, 85, 53, 117, 13, 77, 45, 109, 29, 93, 61, 125, + 3, 67, 35, 99, 19, 83, 51, 115, 11, 75, 43, 107, 27, 91, 59, 123, + 7, 71, 39, 103, 23, 87, 55, 119, 15, 79, 47, 111, 31, 95, 63, 127}; + + +static int16_t fqmul(int16_t a, int16_t b) { + return montgomery_reduce((int32_t)a*b); +} + +void init_ntt() { + unsigned int i, j, k; + int16_t tmp[128]; + + tmp[0] = MONT; + for(i = 1; i < 128; ++i) + tmp[i] = fqmul(tmp[i-1], KYBER_ROOT_OF_UNITY*MONT % KYBER_Q); + + for(i = 0; i < 128; ++i) + zetas[i] = tmp[tree[i]]; + + k = 0; + for(i = 64; i >= 1; i >>= 1) + for(j = i; j < 2*i; ++j) + zetas_inv[k++] = -tmp[128 - tree[j]]; + + zetas_inv[127] = MONT * (MONT * (KYBER_Q - 1) * ((KYBER_Q - 1)/128) % KYBER_Q) % KYBER_Q; +} + +*/ +int16_t PQCLEAN_KYBER768_CLEAN_zetas[128] = { + 2285, 2571, 2970, 1812, 1493, 1422, 287, 202, 3158, 622, 1577, 182, 962, 2127, 1855, 1468, + 573, 2004, 264, 383, 2500, 1458, 1727, 3199, 2648, 1017, 732, 608, 1787, 411, 3124, 1758, + 1223, 652, 2777, 1015, 2036, 1491, 3047, 1785, 516, 3321, 3009, 2663, 1711, 2167, 126, 1469, + 2476, 3239, 3058, 830, 107, 1908, 3082, 2378, 2931, 961, 1821, 2604, 448, 2264, 677, 2054, + 2226, 430, 555, 843, 2078, 871, 1550, 105, 422, 587, 177, 3094, 3038, 2869, 1574, 1653, + 3083, 778, 1159, 3182, 2552, 1483, 2727, 1119, 1739, 644, 2457, 349, 418, 329, 3173, 3254, + 817, 1097, 603, 610, 1322, 2044, 1864, 384, 2114, 3193, 1218, 1994, 2455, 220, 2142, 1670, + 2144, 1799, 2051, 794, 1819, 2475, 2459, 478, 3221, 3021, 996, 991, 958, 1869, 1522, 1628 +}; + +int16_t PQCLEAN_KYBER768_CLEAN_zetas_inv[128] = { + 1701, 1807, 1460, 2371, 2338, 2333, 308, 108, 2851, 870, 854, 1510, 2535, 1278, 1530, 1185, + 1659, 1187, 3109, 874, 1335, 2111, 136, 1215, 2945, 1465, 1285, 2007, 2719, 2726, 2232, 2512, + 75, 156, 3000, 2911, 2980, 872, 2685, 1590, 2210, 602, 1846, 777, 147, 2170, 2551, 246, + 1676, 1755, 460, 291, 235, 3152, 2742, 2907, 3224, 1779, 2458, 1251, 2486, 2774, 2899, 1103, + 1275, 2652, 1065, 2881, 725, 1508, 2368, 398, 951, 247, 1421, 3222, 2499, 271, 90, 853, + 1860, 3203, 1162, 1618, 666, 320, 8, 2813, 1544, 282, 1838, 1293, 2314, 552, 2677, 2106, + 1571, 205, 2918, 1542, 2721, 2597, 2312, 681, 130, 1602, 1871, 829, 2946, 3065, 1325, 2756, + 1861, 1474, 1202, 2367, 3147, 1752, 2707, 171, 3127, 3042, 1907, 1836, 1517, 359, 758, 1441 +}; + /************************************************* - * Name: ntt - * - * Description: Computes negacyclic number-theoretic transform (NTT) of - * a polynomial (vector of 256 coefficients) in place; - * inputs assumed to be in normal order, output in bitreversed - *order - * - * Arguments: - uint16_t *p: pointer to in/output polynomial - **************************************************/ -void PQCLEAN_KYBER768_CLEAN_ntt(uint16_t *p) { - int level, start, j, k; - uint16_t zeta, t; +* Name: fqmul +* +* Description: Multiplication followed by Montgomery reduction +* +* Arguments: - int16_t a: first factor +* - int16_t b: second factor +* +* Returns 16-bit integer congruent to a*b*R^{-1} mod q +**************************************************/ +static int16_t fqmul(int16_t a, int16_t b) { + return PQCLEAN_KYBER768_CLEAN_montgomery_reduce((int32_t)a * b); +} + +/************************************************* +* Name: ntt +* +* Description: Inplace number-theoretic transform (NTT) in Rq +* input is in standard order, output is in bitreversed order +* +* Arguments: - int16_t *poly: pointer to input/output vector of 256 elements of Zq +**************************************************/ +void PQCLEAN_KYBER768_CLEAN_ntt(int16_t *poly) { + unsigned int len, start, j, k; + int16_t t, zeta; k = 1; - for (level = 7; level >= 0; level--) { - for (start = 0; start < KYBER_N; start = j + (1 << level)) { + for (len = 128; len >= 2; len >>= 1) { + for (start = 0; start < 256; start = j + len) { zeta = PQCLEAN_KYBER768_CLEAN_zetas[k++]; - for (j = start; j < start + (1 << level); ++j) { - t = PQCLEAN_KYBER768_CLEAN_montgomery_reduce((uint32_t)zeta * p[j + (1 << level)]); - - p[j + (1 << level)] = PQCLEAN_KYBER768_CLEAN_barrett_reduce(p[j] + 4 * KYBER_Q - t); - - if (level & 1) { /* odd level */ - p[j] = p[j] + t; /* Omit reduction (be lazy) */ - } else { - p[j] = PQCLEAN_KYBER768_CLEAN_barrett_reduce(p[j] + t); - } + for (j = start; j < start + len; ++j) { + t = fqmul(zeta, poly[j + len]); + poly[j + len] = poly[j] - t; + poly[j] = poly[j] + t; } } } } /************************************************* - * Name: invntt - * - * Description: Computes inverse of negacyclic number-theoretic transform (NTT) - *of a polynomial (vector of 256 coefficients) in place; inputs assumed to be in - *bitreversed order, output in normal order - * - * Arguments: - uint16_t *a: pointer to in/output polynomial - **************************************************/ -void PQCLEAN_KYBER768_CLEAN_invntt(uint16_t *a) { - int start, j, jTwiddle, level; - uint16_t temp, W; - uint32_t t; +* Name: invntt +* +* Description: Inplace inverse number-theoretic transform in Rq +* input is in bitreversed order, output is in standard order +* +* Arguments: - int16_t *poly: pointer to input/output vector of 256 elements of Zq +**************************************************/ +void PQCLEAN_KYBER768_CLEAN_invntt(int16_t *poly) { + unsigned int start, len, j, k; + int16_t t, zeta; - for (level = 0; level < 8; level++) { - for (start = 0; start < (1 << level); start++) { - jTwiddle = 0; - for (j = start; j < KYBER_N - 1; j += 2 * (1 << level)) { - W = PQCLEAN_KYBER768_CLEAN_omegas_inv_bitrev_montgomery[jTwiddle++]; - temp = a[j]; - - if (level & 1) { /* odd level */ - a[j] = PQCLEAN_KYBER768_CLEAN_barrett_reduce((temp + a[j + (1 << level)])); - } else { - a[j] = (temp + a[j + (1 << level)]); /* Omit reduction (be lazy) */ - } - - t = (W * ((uint32_t)temp + 4 * KYBER_Q - a[j + (1 << level)])); - - a[j + (1 << level)] = PQCLEAN_KYBER768_CLEAN_montgomery_reduce(t); + k = 0; + for (len = 2; len <= 128; len <<= 1) { + for (start = 0; start < 256; start = j + len) { + zeta = PQCLEAN_KYBER768_CLEAN_zetas_inv[k++]; + for (j = start; j < start + len; ++j) { + t = poly[j]; + poly[j] = PQCLEAN_KYBER768_CLEAN_barrett_reduce(t + poly[j + len]); + poly[j + len] = t - poly[j + len]; + poly[j + len] = fqmul(zeta, poly[j + len]); } } } - for (j = 0; j < KYBER_N; j++) { - a[j] = PQCLEAN_KYBER768_CLEAN_montgomery_reduce((a[j] * PQCLEAN_KYBER768_CLEAN_psis_inv_montgomery[j])); + for (j = 0; j < 256; ++j) { + poly[j] = fqmul(poly[j], PQCLEAN_KYBER768_CLEAN_zetas_inv[127]); } } + +/************************************************* +* Name: PQCLEAN_KYBER768_CLEAN_basemul +* +* Description: Multiplication of polynomials in Zq[X]/((X^2-zeta)) +* used for multiplication of elements in Rq in NTT domain +* +* Arguments: - int16_t r[2]: pointer to the output polynomial +* - const int16_t a[2]: pointer to the first factor +* - const int16_t b[2]: pointer to the second factor +* - int16_t zeta: integer defining the reduction polynomial +**************************************************/ +void PQCLEAN_KYBER768_CLEAN_basemul(int16_t r[2], const int16_t a[2], const int16_t b[2], int16_t zeta) { + r[0] = fqmul(a[1], b[1]); + r[0] = fqmul(r[0], zeta); + r[0] += fqmul(a[0], b[0]); + + r[1] = fqmul(a[0], b[1]); + r[1] += fqmul(a[1], b[0]); +} diff --git a/crypto_kem/kyber768/clean/ntt.h b/crypto_kem/kyber768/clean/ntt.h index e01d83a2..e0e169f1 100644 --- a/crypto_kem/kyber768/clean/ntt.h +++ b/crypto_kem/kyber768/clean/ntt.h @@ -3,7 +3,11 @@ #include -void PQCLEAN_KYBER768_CLEAN_ntt(uint16_t *p); -void PQCLEAN_KYBER768_CLEAN_invntt(uint16_t *a); +extern int16_t PQCLEAN_KYBER768_CLEAN_zetas[128]; +extern int16_t PQCLEAN_KYBER768_CLEAN_zetas_inv[128]; + +void PQCLEAN_KYBER768_CLEAN_ntt(int16_t *poly); +void PQCLEAN_KYBER768_CLEAN_invntt(int16_t *poly); +void PQCLEAN_KYBER768_CLEAN_basemul(int16_t r[2], const int16_t a[2], const int16_t b[2], int16_t zeta); #endif diff --git a/crypto_kem/kyber768/clean/params.h b/crypto_kem/kyber768/clean/params.h index f685061a..bd1dfe14 100644 --- a/crypto_kem/kyber768/clean/params.h +++ b/crypto_kem/kyber768/clean/params.h @@ -3,25 +3,29 @@ #define KYBER_K 3 +/* Don't change parameters below this line */ + #define KYBER_N 256 -#define KYBER_Q 7681 +#define KYBER_Q 3329 -#define KYBER_ETA 4 +#define KYBER_ETA 2 -#define KYBER_SYMBYTES 32 /* size in bytes of shared key, hashes, and seeds */ +#define KYBER_SYMBYTES 32 /* size in bytes of hashes, and seeds */ +#define KYBER_SSBYTES 32 /* size in bytes of shared key */ -#define KYBER_POLYBYTES 416 -#define KYBER_POLYCOMPRESSEDBYTES 96 +#define KYBER_POLYBYTES 384 #define KYBER_POLYVECBYTES (KYBER_K * KYBER_POLYBYTES) -#define KYBER_POLYVECCOMPRESSEDBYTES (KYBER_K * 352) + +#define KYBER_POLYCOMPRESSEDBYTES 128 +#define KYBER_POLYVECCOMPRESSEDBYTES (KYBER_K * 320) #define KYBER_INDCPA_MSGBYTES KYBER_SYMBYTES -#define KYBER_INDCPA_PUBLICKEYBYTES (KYBER_POLYVECCOMPRESSEDBYTES + KYBER_SYMBYTES) +#define KYBER_INDCPA_PUBLICKEYBYTES (KYBER_POLYVECBYTES + KYBER_SYMBYTES) #define KYBER_INDCPA_SECRETKEYBYTES (KYBER_POLYVECBYTES) #define KYBER_INDCPA_BYTES (KYBER_POLYVECCOMPRESSEDBYTES + KYBER_POLYCOMPRESSEDBYTES) #define KYBER_PUBLICKEYBYTES (KYBER_INDCPA_PUBLICKEYBYTES) -#define KYBER_SECRETKEYBYTES (KYBER_INDCPA_SECRETKEYBYTES + KYBER_INDCPA_PUBLICKEYBYTES + 2 * KYBER_SYMBYTES) /* 32 bytes of additional space to save H(pk) */ +#define KYBER_SECRETKEYBYTES (KYBER_INDCPA_SECRETKEYBYTES + KYBER_INDCPA_PUBLICKEYBYTES + 2*KYBER_SYMBYTES) /* 32 bytes of additional space to save H(pk) */ #define KYBER_CIPHERTEXTBYTES KYBER_INDCPA_BYTES #endif diff --git a/crypto_kem/kyber768/clean/poly.c b/crypto_kem/kyber768/clean/poly.c index 6eb18330..98730297 100644 --- a/crypto_kem/kyber768/clean/poly.c +++ b/crypto_kem/kyber768/clean/poly.c @@ -1,210 +1,260 @@ #include "poly.h" + #include "cbd.h" -#include "fips202.h" #include "ntt.h" -#include "polyvec.h" +#include "params.h" #include "reduce.h" -#include +#include "symmetric.h" + +#include /************************************************* - * Name: poly_compress - * - * Description: Compression and subsequent serialization of a polynomial - * - * Arguments: - unsigned char *r: pointer to output byte array - * - const poly *a: pointer to input polynomial - **************************************************/ -void PQCLEAN_KYBER768_CLEAN_poly_compress(unsigned char *r, const poly *a) { - uint32_t t[8]; - unsigned int i, j, k = 0; +* Name: PQCLEAN_KYBER768_CLEAN_poly_compress +* +* Description: Compression and subsequent serialization of a polynomial +* +* Arguments: - unsigned char *r: pointer to output byte array (needs space for KYBER_POLYCOMPRESSEDBYTES bytes) +* - const poly *a: pointer to input polynomial +**************************************************/ +void PQCLEAN_KYBER768_CLEAN_poly_compress(unsigned char *r, poly *a) { + uint8_t t[8]; + int i, j, k = 0; + + PQCLEAN_KYBER768_CLEAN_poly_csubq(a); for (i = 0; i < KYBER_N; i += 8) { for (j = 0; j < 8; j++) { - t[j] = (((PQCLEAN_KYBER768_CLEAN_freeze(a->coeffs[i + j]) << 3) + KYBER_Q / 2) / KYBER_Q) & 7; + t[j] = ((((uint32_t)a->coeffs[i + j] << 4) + KYBER_Q / 2) / KYBER_Q) & 15; } - r[k] = (unsigned char)( t[0] | (t[1] << 3) | (t[2] << 6)); - r[k + 1] = (unsigned char)((t[2] >> 2) | (t[3] << 1) | (t[4] << 4) | (t[5] << 7)); - r[k + 2] = (unsigned char)((t[5] >> 1) | (t[6] << 2) | (t[7] << 5)); - k += 3; + r[k] = t[0] | (t[1] << 4); + r[k + 1] = t[2] | (t[3] << 4); + r[k + 2] = t[4] | (t[5] << 4); + r[k + 3] = t[6] | (t[7] << 4); + k += 4; } } /************************************************* - * Name: poly_decompress - * - * Description: De-serialization and subsequent decompression of a polynomial; - * approximate inverse of poly_compress - * - * Arguments: - poly *r: pointer to output polynomial - * - const unsigned char *a: pointer to input byte array - **************************************************/ +* Name: PQCLEAN_KYBER768_CLEAN_poly_decompress +* +* Description: De-serialization and subsequent decompression of a polynomial; +* approximate inverse of PQCLEAN_KYBER768_CLEAN_poly_compress +* +* Arguments: - poly *r: pointer to output polynomial +* - const unsigned char *a: pointer to input byte array (of length KYBER_POLYCOMPRESSEDBYTES bytes) +**************************************************/ void PQCLEAN_KYBER768_CLEAN_poly_decompress(poly *r, const unsigned char *a) { - unsigned int i; + int i; for (i = 0; i < KYBER_N; i += 8) { - r->coeffs[i + 0] = (((a[0] & 7) * KYBER_Q) + 4) >> 3; - r->coeffs[i + 1] = ((((a[0] >> 3) & 7) * KYBER_Q) + 4) >> 3; - r->coeffs[i + 2] = ((((a[0] >> 6) | ((a[1] << 2) & 4)) * KYBER_Q) + 4) >> 3; - r->coeffs[i + 3] = ((((a[1] >> 1) & 7) * KYBER_Q) + 4) >> 3; - r->coeffs[i + 4] = ((((a[1] >> 4) & 7) * KYBER_Q) + 4) >> 3; - r->coeffs[i + 5] = ((((a[1] >> 7) | ((a[2] << 1) & 6)) * KYBER_Q) + 4) >> 3; - r->coeffs[i + 6] = ((((a[2] >> 2) & 7) * KYBER_Q) + 4) >> 3; - r->coeffs[i + 7] = ((((a[2] >> 5)) * KYBER_Q) + 4) >> 3; - a += 3; + r->coeffs[i + 0] = (((a[0] & 15) * KYBER_Q) + 8) >> 4; + r->coeffs[i + 1] = (((a[0] >> 4) * KYBER_Q) + 8) >> 4; + r->coeffs[i + 2] = (((a[1] & 15) * KYBER_Q) + 8) >> 4; + r->coeffs[i + 3] = (((a[1] >> 4) * KYBER_Q) + 8) >> 4; + r->coeffs[i + 4] = (((a[2] & 15) * KYBER_Q) + 8) >> 4; + r->coeffs[i + 5] = (((a[2] >> 4) * KYBER_Q) + 8) >> 4; + r->coeffs[i + 6] = (((a[3] & 15) * KYBER_Q) + 8) >> 4; + r->coeffs[i + 7] = (((a[3] >> 4) * KYBER_Q) + 8) >> 4; + a += 4; } } /************************************************* - * Name: poly_tobytes - * - * Description: Serialization of a polynomial - * - * Arguments: - unsigned char *r: pointer to output byte array - * - const poly *a: pointer to input polynomial - **************************************************/ -void PQCLEAN_KYBER768_CLEAN_poly_tobytes(unsigned char *r, const poly *a) { - int i, j; - uint16_t t[8]; +* Name: PQCLEAN_KYBER768_CLEAN_poly_tobytes +* +* Description: Serialization of a polynomial +* +* Arguments: - unsigned char *r: pointer to output byte array (needs space for KYBER_POLYBYTES bytes) +* - const poly *a: pointer to input polynomial +**************************************************/ +void PQCLEAN_KYBER768_CLEAN_poly_tobytes(unsigned char *r, poly *a) { + int i; + uint16_t t0, t1; - for (i = 0; i < KYBER_N / 8; i++) { - for (j = 0; j < 8; j++) { - t[j] = PQCLEAN_KYBER768_CLEAN_freeze(a->coeffs[8 * i + j]); - } + PQCLEAN_KYBER768_CLEAN_poly_csubq(a); - r[13 * i + 0] = (unsigned char)( t[0] & 0xff); - r[13 * i + 1] = (unsigned char)((t[0] >> 8) | ((t[1] & 0x07) << 5)); - r[13 * i + 2] = (unsigned char)((t[1] >> 3) & 0xff); - r[13 * i + 3] = (unsigned char)((t[1] >> 11) | ((t[2] & 0x3f) << 2)); - r[13 * i + 4] = (unsigned char)((t[2] >> 6) | ((t[3] & 0x01) << 7)); - r[13 * i + 5] = (unsigned char)((t[3] >> 1) & 0xff); - r[13 * i + 6] = (unsigned char)((t[3] >> 9) | ((t[4] & 0x0f) << 4)); - r[13 * i + 7] = (unsigned char)((t[4] >> 4) & 0xff); - r[13 * i + 8] = (unsigned char)((t[4] >> 12) | ((t[5] & 0x7f) << 1)); - r[13 * i + 9] = (unsigned char)((t[5] >> 7) | ((t[6] & 0x03) << 6)); - r[13 * i + 10] = (unsigned char)((t[6] >> 2) & 0xff); - r[13 * i + 11] = (unsigned char)((t[6] >> 10) | ((t[7] & 0x1f) << 3)); - r[13 * i + 12] = (unsigned char)((t[7] >> 5)); + for (i = 0; i < KYBER_N / 2; i++) { + t0 = a->coeffs[2 * i]; + t1 = a->coeffs[2 * i + 1]; + r[3 * i] = t0 & 0xff; + r[3 * i + 1] = (t0 >> 8) | ((t1 & 0xf) << 4); + r[3 * i + 2] = (t1 >> 4) & 0xff; } } /************************************************* - * Name: poly_frombytes - * - * Description: De-serialization of a polynomial; - * inverse of poly_tobytes - * - * Arguments: - poly *r: pointer to output polynomial - * - const unsigned char *a: pointer to input byte array - **************************************************/ +* Name: PQCLEAN_KYBER768_CLEAN_poly_frombytes +* +* Description: De-serialization of a polynomial; +* inverse of PQCLEAN_KYBER768_CLEAN_poly_tobytes +* +* Arguments: - poly *r: pointer to output polynomial +* - const unsigned char *a: pointer to input byte array (of KYBER_POLYBYTES bytes) +**************************************************/ void PQCLEAN_KYBER768_CLEAN_poly_frombytes(poly *r, const unsigned char *a) { int i; - for (i = 0; i < KYBER_N / 8; i++) { - r->coeffs[8 * i + 0] = a[13 * i + 0] | (((uint16_t)a[13 * i + 1] & 0x1f) << 8); - r->coeffs[8 * i + 1] = (a[13 * i + 1] >> 5) | (((uint16_t)a[13 * i + 2]) << 3) | (((uint16_t)a[13 * i + 3] & 0x03) << 11); - r->coeffs[8 * i + 2] = (a[13 * i + 3] >> 2) | (((uint16_t)a[13 * i + 4] & 0x7f) << 6); - r->coeffs[8 * i + 3] = (a[13 * i + 4] >> 7) | (((uint16_t)a[13 * i + 5]) << 1) | (((uint16_t)a[13 * i + 6] & 0x0f) << 9); - r->coeffs[8 * i + 4] = (a[13 * i + 6] >> 4) | (((uint16_t)a[13 * i + 7]) << 4) | (((uint16_t)a[13 * i + 8] & 0x01) << 12); - r->coeffs[8 * i + 5] = (a[13 * i + 8] >> 1) | (((uint16_t)a[13 * i + 9] & 0x3f) << 7); - r->coeffs[8 * i + 6] = (a[13 * i + 9] >> 6) | (((uint16_t)a[13 * i + 10]) << 2) | (((uint16_t)a[13 * i + 11] & 0x07) << 10); - r->coeffs[8 * i + 7] = (a[13 * i + 11] >> 3) | (((uint16_t)a[13 * i + 12]) << 5); + + for (i = 0; i < KYBER_N / 2; i++) { + r->coeffs[2 * i] = a[3 * i] | ((uint16_t)a[3 * i + 1] & 0x0f) << 8; + r->coeffs[2 * i + 1] = a[3 * i + 1] >> 4 | ((uint16_t)a[3 * i + 2] & 0xff) << 4; } } /************************************************* - * Name: poly_getnoise - * - * Description: Sample a polynomial deterministically from a seed and a nonce, - * with output polynomial close to centered binomial distribution - * with parameter KYBER_ETA - * - * Arguments: - poly *r: pointer to output polynomial - * - const unsigned char *seed: pointer to input seed - * - unsigned char nonce: one-byte input nonce - **************************************************/ +* Name: PQCLEAN_KYBER768_CLEAN_poly_getnoise +* +* Description: Sample a polynomial deterministically from a seed and a nonce, +* with output polynomial close to centered binomial distribution +* with parameter KYBER_ETA +* +* Arguments: - poly *r: pointer to output polynomial +* - const unsigned char *seed: pointer to input seed (pointing to array of length KYBER_SYMBYTES bytes) +* - unsigned char nonce: one-byte input nonce +**************************************************/ void PQCLEAN_KYBER768_CLEAN_poly_getnoise(poly *r, const unsigned char *seed, unsigned char nonce) { unsigned char buf[KYBER_ETA * KYBER_N / 4]; - unsigned char extseed[KYBER_SYMBYTES + 1]; - int i; - - for (i = 0; i < KYBER_SYMBYTES; i++) { - extseed[i] = seed[i]; - } - extseed[KYBER_SYMBYTES] = nonce; - - shake256(buf, KYBER_ETA * KYBER_N / 4, extseed, KYBER_SYMBYTES + 1); + prf(buf, KYBER_ETA * KYBER_N / 4, seed, nonce); PQCLEAN_KYBER768_CLEAN_cbd(r, buf); } /************************************************* - * Name: poly_ntt - * - * Description: Computes negacyclic number-theoretic transform (NTT) of - * a polynomial in place; - * inputs assumed to be in normal order, output in bitreversed - *order - * - * Arguments: - uint16_t *r: pointer to in/output polynomial - **************************************************/ +* Name: PQCLEAN_KYBER768_CLEAN_poly_ntt +* +* Description: Computes negacyclic number-theoretic transform (NTT) of +* a polynomial in place; +* inputs assumed to be in normal order, output in bitreversed order +* +* Arguments: - uint16_t *r: pointer to in/output polynomial +**************************************************/ void PQCLEAN_KYBER768_CLEAN_poly_ntt(poly *r) { PQCLEAN_KYBER768_CLEAN_ntt(r->coeffs); + PQCLEAN_KYBER768_CLEAN_poly_reduce(r); } /************************************************* - * Name: poly_invntt - * - * Description: Computes inverse of negacyclic number-theoretic transform (NTT) - *of a polynomial in place; inputs assumed to be in bitreversed order, output in - *normal order - * - * Arguments: - uint16_t *a: pointer to in/output polynomial - **************************************************/ +* Name: PQCLEAN_KYBER768_CLEAN_poly_invntt +* +* Description: Computes inverse of negacyclic number-theoretic transform (NTT) of +* a polynomial in place; +* inputs assumed to be in bitreversed order, output in normal order +* +* Arguments: - uint16_t *a: pointer to in/output polynomial +**************************************************/ void PQCLEAN_KYBER768_CLEAN_poly_invntt(poly *r) { PQCLEAN_KYBER768_CLEAN_invntt(r->coeffs); } /************************************************* - * Name: poly_add - * - * Description: Add two polynomials - * - * Arguments: - poly *r: pointer to output polynomial - * - const poly *a: pointer to first input polynomial - * - const poly *b: pointer to second input polynomial - **************************************************/ +* Name: PQCLEAN_KYBER768_CLEAN_poly_basemul +* +* Description: Multiplication of two polynomials in NTT domain +* +* Arguments: - poly *r: pointer to output polynomial +* - const poly *a: pointer to first input polynomial +* - const poly *b: pointer to second input polynomial +**************************************************/ +void PQCLEAN_KYBER768_CLEAN_poly_basemul(poly *r, const poly *a, const poly *b) { + unsigned int i; + + for (i = 0; i < KYBER_N / 4; ++i) { + PQCLEAN_KYBER768_CLEAN_basemul(r->coeffs + 4 * i, a->coeffs + 4 * i, b->coeffs + 4 * i, PQCLEAN_KYBER768_CLEAN_zetas[64 + i]); + PQCLEAN_KYBER768_CLEAN_basemul(r->coeffs + 4 * i + 2, a->coeffs + 4 * i + 2, b->coeffs + 4 * i + 2, - PQCLEAN_KYBER768_CLEAN_zetas[64 + i]); + } +} + +/************************************************* +* Name: PQCLEAN_KYBER768_CLEAN_poly_frommont +* +* Description: Inplace conversion of all coefficients of a polynomial +* from Montgomery domain to normal domain +* +* Arguments: - poly *r: pointer to input/output polynomial +**************************************************/ +void PQCLEAN_KYBER768_CLEAN_poly_frommont(poly *r) { + int i; + const int16_t f = (1ULL << 32) % KYBER_Q; + + for (i = 0; i < KYBER_N; i++) { + r->coeffs[i] = PQCLEAN_KYBER768_CLEAN_montgomery_reduce((int32_t)r->coeffs[i] * f); + } +} + +/************************************************* +* Name: PQCLEAN_KYBER768_CLEAN_poly_reduce +* +* Description: Applies Barrett reduction to all coefficients of a polynomial +* for details of the Barrett reduction see comments in reduce.c +* +* Arguments: - poly *r: pointer to input/output polynomial +**************************************************/ +void PQCLEAN_KYBER768_CLEAN_poly_reduce(poly *r) { + int i; + + for (i = 0; i < KYBER_N; i++) { + r->coeffs[i] = PQCLEAN_KYBER768_CLEAN_barrett_reduce(r->coeffs[i]); + } +} + +/************************************************* +* Name: PQCLEAN_KYBER768_CLEAN_poly_csubq +* +* Description: Applies conditional subtraction of q to each coefficient of a polynomial +* for details of conditional subtraction of q see comments in reduce.c +* +* Arguments: - poly *r: pointer to input/output polynomial +**************************************************/ +void PQCLEAN_KYBER768_CLEAN_poly_csubq(poly *r) { + int i; + + for (i = 0; i < KYBER_N; i++) { + r->coeffs[i] = PQCLEAN_KYBER768_CLEAN_csubq(r->coeffs[i]); + } +} + +/************************************************* +* Name: PQCLEAN_KYBER768_CLEAN_poly_add +* +* Description: Add two polynomials +* +* Arguments: - poly *r: pointer to output polynomial +* - const poly *a: pointer to first input polynomial +* - const poly *b: pointer to second input polynomial +**************************************************/ void PQCLEAN_KYBER768_CLEAN_poly_add(poly *r, const poly *a, const poly *b) { int i; for (i = 0; i < KYBER_N; i++) { - r->coeffs[i] = PQCLEAN_KYBER768_CLEAN_barrett_reduce(a->coeffs[i] + b->coeffs[i]); + r->coeffs[i] = a->coeffs[i] + b->coeffs[i]; } } /************************************************* - * Name: poly_sub - * - * Description: Subtract two polynomials - * - * Arguments: - poly *r: pointer to output polynomial - * - const poly *a: pointer to first input polynomial - * - const poly *b: pointer to second input polynomial - **************************************************/ +* Name: PQCLEAN_KYBER768_CLEAN_poly_sub +* +* Description: Subtract two polynomials +* +* Arguments: - poly *r: pointer to output polynomial +* - const poly *a: pointer to first input polynomial +* - const poly *b: pointer to second input polynomial +**************************************************/ void PQCLEAN_KYBER768_CLEAN_poly_sub(poly *r, const poly *a, const poly *b) { int i; for (i = 0; i < KYBER_N; i++) { - r->coeffs[i] = PQCLEAN_KYBER768_CLEAN_barrett_reduce(a->coeffs[i] + 3 * KYBER_Q - b->coeffs[i]); + r->coeffs[i] = a->coeffs[i] - b->coeffs[i]; } } /************************************************* - * Name: poly_frommsg - * - * Description: Convert 32-byte message to polynomial - * - * Arguments: - poly *r: pointer to output polynomial - * - const unsigned char *msg: pointer to input message - **************************************************/ +* Name: PQCLEAN_KYBER768_CLEAN_poly_frommsg +* +* Description: Convert 32-byte message to polynomial +* +* Arguments: - poly *r: pointer to output polynomial +* - const unsigned char *msg: pointer to input message +**************************************************/ void PQCLEAN_KYBER768_CLEAN_poly_frommsg(poly *r, const unsigned char msg[KYBER_SYMBYTES]) { - uint16_t i, j, mask; + int i, j; + uint16_t mask; for (i = 0; i < KYBER_SYMBYTES; i++) { for (j = 0; j < 8; j++) { @@ -215,21 +265,23 @@ void PQCLEAN_KYBER768_CLEAN_poly_frommsg(poly *r, const unsigned char msg[KYBER_ } /************************************************* - * Name: poly_tomsg - * - * Description: Convert polynomial to 32-byte message - * - * Arguments: - unsigned char *msg: pointer to output message - * - const poly *a: pointer to input polynomial - **************************************************/ -void PQCLEAN_KYBER768_CLEAN_poly_tomsg(unsigned char msg[KYBER_SYMBYTES], const poly *a) { +* Name: PQCLEAN_KYBER768_CLEAN_poly_tomsg +* +* Description: Convert polynomial to 32-byte message +* +* Arguments: - unsigned char *msg: pointer to output message +* - const poly *a: pointer to input polynomial +**************************************************/ +void PQCLEAN_KYBER768_CLEAN_poly_tomsg(unsigned char msg[KYBER_SYMBYTES], poly *a) { uint16_t t; int i, j; + PQCLEAN_KYBER768_CLEAN_poly_csubq(a); + for (i = 0; i < KYBER_SYMBYTES; i++) { msg[i] = 0; for (j = 0; j < 8; j++) { - t = (((PQCLEAN_KYBER768_CLEAN_freeze(a->coeffs[8 * i + j]) << 1) + KYBER_Q / 2) / KYBER_Q) & 1; + t = (((a->coeffs[8 * i + j] << 1) + KYBER_Q / 2) / KYBER_Q) & 1; msg[i] |= t << j; } } diff --git a/crypto_kem/kyber768/clean/poly.h b/crypto_kem/kyber768/clean/poly.h index 9b9f2968..4529c2dc 100644 --- a/crypto_kem/kyber768/clean/poly.h +++ b/crypto_kem/kyber768/clean/poly.h @@ -2,6 +2,7 @@ #define POLY_H #include "params.h" + #include /* @@ -9,22 +10,27 @@ * coeffs[0] + X*coeffs[1] + X^2*xoeffs[2] + ... + X^{n-1}*coeffs[n-1] */ typedef struct { - uint16_t coeffs[KYBER_N]; + int16_t coeffs[KYBER_N]; } poly; -void PQCLEAN_KYBER768_CLEAN_poly_compress(unsigned char *r, const poly *a); +void PQCLEAN_KYBER768_CLEAN_poly_compress(unsigned char *r, poly *a); void PQCLEAN_KYBER768_CLEAN_poly_decompress(poly *r, const unsigned char *a); -void PQCLEAN_KYBER768_CLEAN_poly_tobytes(unsigned char *r, const poly *a); +void PQCLEAN_KYBER768_CLEAN_poly_tobytes(unsigned char *r, poly *a); void PQCLEAN_KYBER768_CLEAN_poly_frombytes(poly *r, const unsigned char *a); void PQCLEAN_KYBER768_CLEAN_poly_frommsg(poly *r, const unsigned char msg[KYBER_SYMBYTES]); -void PQCLEAN_KYBER768_CLEAN_poly_tomsg(unsigned char msg[KYBER_SYMBYTES], const poly *a); +void PQCLEAN_KYBER768_CLEAN_poly_tomsg(unsigned char msg[KYBER_SYMBYTES], poly *a); void PQCLEAN_KYBER768_CLEAN_poly_getnoise(poly *r, const unsigned char *seed, unsigned char nonce); void PQCLEAN_KYBER768_CLEAN_poly_ntt(poly *r); void PQCLEAN_KYBER768_CLEAN_poly_invntt(poly *r); +void PQCLEAN_KYBER768_CLEAN_poly_basemul(poly *r, const poly *a, const poly *b); +void PQCLEAN_KYBER768_CLEAN_poly_frommont(poly *r); + +void PQCLEAN_KYBER768_CLEAN_poly_reduce(poly *r); +void PQCLEAN_KYBER768_CLEAN_poly_csubq(poly *r); void PQCLEAN_KYBER768_CLEAN_poly_add(poly *r, const poly *a, const poly *b); void PQCLEAN_KYBER768_CLEAN_poly_sub(poly *r, const poly *a, const poly *b); diff --git a/crypto_kem/kyber768/clean/polyvec.c b/crypto_kem/kyber768/clean/polyvec.c index 147a3854..91c35379 100644 --- a/crypto_kem/kyber768/clean/polyvec.c +++ b/crypto_kem/kyber768/clean/polyvec.c @@ -1,77 +1,70 @@ #include "polyvec.h" -#include "cbd.h" -#include "fips202.h" -#include "reduce.h" -#include + +#include "poly.h" + +#include /************************************************* - * Name: polyvec_compress - * - * Description: Compress and serialize vector of polynomials - * - * Arguments: - unsigned char *r: pointer to output byte array - * - const polyvec *a: pointer to input vector of polynomials - **************************************************/ -void PQCLEAN_KYBER768_CLEAN_polyvec_compress(unsigned char *r, const polyvec *a) { +* Name: PQCLEAN_KYBER768_CLEAN_polyvec_compress +* +* Description: Compress and serialize vector of polynomials +* +* Arguments: - unsigned char *r: pointer to output byte array (needs space for KYBER_POLYVECCOMPRESSEDBYTES) +* - const polyvec *a: pointer to input vector of polynomials +**************************************************/ +void PQCLEAN_KYBER768_CLEAN_polyvec_compress(unsigned char *r, polyvec *a) { int i, j, k; - uint16_t t[8]; + + PQCLEAN_KYBER768_CLEAN_polyvec_csubq(a); + + uint16_t t[4]; for (i = 0; i < KYBER_K; i++) { - for (j = 0; j < KYBER_N / 8; j++) { - for (k = 0; k < 8; k++) { - t[k] = ((((uint32_t)PQCLEAN_KYBER768_CLEAN_freeze(a->vec[i].coeffs[8 * j + k]) << 11) + KYBER_Q / 2) / KYBER_Q) & 0x7ff; + for (j = 0; j < KYBER_N / 4; j++) { + for (k = 0; k < 4; k++) { + t[k] = ((((uint32_t)a->vec[i].coeffs[4 * j + k] << 10) + KYBER_Q / 2) / KYBER_Q) & 0x3ff; } - r[11 * j + 0] = (unsigned char)( t[0] & 0xff); - r[11 * j + 1] = (unsigned char)((t[0] >> 8) | ((t[1] & 0x1f) << 3)); - r[11 * j + 2] = (unsigned char)((t[1] >> 5) | ((t[2] & 0x03) << 6)); - r[11 * j + 3] = (unsigned char)((t[2] >> 2) & 0xff); - r[11 * j + 4] = (unsigned char)((t[2] >> 10) | ((t[3] & 0x7f) << 1)); - r[11 * j + 5] = (unsigned char)((t[3] >> 7) | ((t[4] & 0x0f) << 4)); - r[11 * j + 6] = (unsigned char)((t[4] >> 4) | ((t[5] & 0x01) << 7)); - r[11 * j + 7] = (unsigned char)((t[5] >> 1) & 0xff); - r[11 * j + 8] = (unsigned char)((t[5] >> 9) | ((t[6] & 0x3f) << 2)); - r[11 * j + 9] = (unsigned char)((t[6] >> 6) | ((t[7] & 0x07) << 5)); - r[11 * j + 10] = (unsigned char)((t[7] >> 3)); + r[5 * j + 0] = t[0] & 0xff; + r[5 * j + 1] = (t[0] >> 8) | ((t[1] & 0x3f) << 2); + r[5 * j + 2] = ((t[1] >> 6) | ((t[2] & 0x0f) << 4)) & 0xff; + r[5 * j + 3] = ((t[2] >> 4) | ((t[3] & 0x03) << 6)) & 0xff; + r[5 * j + 4] = (t[3] >> 2) & 0xff; } - r += 352; + r += 320; } } /************************************************* - * Name: polyvec_decompress - * - * Description: De-serialize and decompress vector of polynomials; - * approximate inverse of polyvec_compress - * - * Arguments: - polyvec *r: pointer to output vector of polynomials - * - unsigned char *a: pointer to input byte array - **************************************************/ +* Name: PQCLEAN_KYBER768_CLEAN_polyvec_decompress +* +* Description: De-serialize and decompress vector of polynomials; +* approximate inverse of PQCLEAN_KYBER768_CLEAN_polyvec_compress +* +* Arguments: - polyvec *r: pointer to output vector of polynomials +* - unsigned char *a: pointer to input byte array (of length KYBER_POLYVECCOMPRESSEDBYTES) +**************************************************/ void PQCLEAN_KYBER768_CLEAN_polyvec_decompress(polyvec *r, const unsigned char *a) { int i, j; for (i = 0; i < KYBER_K; i++) { - for (j = 0; j < KYBER_N / 8; j++) { - r->vec[i].coeffs[8 * j + 0] = (((a[11 * j + 0] | (((uint32_t)a[11 * j + 1] & 0x07) << 8)) * KYBER_Q) + 1024) >> 11; - r->vec[i].coeffs[8 * j + 1] = ((((a[11 * j + 1] >> 3) | (((uint32_t)a[11 * j + 2] & 0x3f) << 5)) * KYBER_Q) + 1024) >> 11; - r->vec[i].coeffs[8 * j + 2] = ((((a[11 * j + 2] >> 6) | (((uint32_t)a[11 * j + 3] & 0xff) << 2) | (((uint32_t)a[11 * j + 4] & 0x01) << 10)) * KYBER_Q) + 1024) >> 11; - r->vec[i].coeffs[8 * j + 3] = ((((a[11 * j + 4] >> 1) | (((uint32_t)a[11 * j + 5] & 0x0f) << 7)) * KYBER_Q) + 1024) >> 11; - r->vec[i].coeffs[8 * j + 4] = ((((a[11 * j + 5] >> 4) | (((uint32_t)a[11 * j + 6] & 0x7f) << 4)) * KYBER_Q) + 1024) >> 11; - r->vec[i].coeffs[8 * j + 5] = ((((a[11 * j + 6] >> 7) | (((uint32_t)a[11 * j + 7] & 0xff) << 1) | (((uint32_t)a[11 * j + 8] & 0x03) << 9)) * KYBER_Q) + 1024) >> 11; - r->vec[i].coeffs[8 * j + 6] = ((((a[11 * j + 8] >> 2) | (((uint32_t)a[11 * j + 9] & 0x1f) << 6)) * KYBER_Q) + 1024) >> 11; - r->vec[i].coeffs[8 * j + 7] = ((((a[11 * j + 9] >> 5) | (((uint32_t)a[11 * j + 10] & 0xff) << 3)) * KYBER_Q) + 1024) >> 11; + for (j = 0; j < KYBER_N / 4; j++) { + r->vec[i].coeffs[4 * j + 0] = (((a[5 * j + 0] | (((uint32_t)a[5 * j + 1] & 0x03) << 8)) * KYBER_Q) + 512) >> 10; + r->vec[i].coeffs[4 * j + 1] = ((((a[5 * j + 1] >> 2) | (((uint32_t)a[5 * j + 2] & 0x0f) << 6)) * KYBER_Q) + 512) >> 10; + r->vec[i].coeffs[4 * j + 2] = ((((a[5 * j + 2] >> 4) | (((uint32_t)a[5 * j + 3] & 0x3f) << 4)) * KYBER_Q) + 512) >> 10; + r->vec[i].coeffs[4 * j + 3] = ((((a[5 * j + 3] >> 6) | (((uint32_t)a[5 * j + 4] & 0xff) << 2)) * KYBER_Q) + 512) >> 10; } - a += 352; + a += 320; } } /************************************************* - * Name: polyvec_tobytes - * - * Description: Serialize vector of polynomials - * - * Arguments: - unsigned char *r: pointer to output byte array - * - const polyvec *a: pointer to input vector of polynomials - **************************************************/ -void PQCLEAN_KYBER768_CLEAN_polyvec_tobytes(unsigned char *r, const polyvec *a) { +* Name: PQCLEAN_KYBER768_CLEAN_polyvec_tobytes +* +* Description: Serialize vector of polynomials +* +* Arguments: - unsigned char *r: pointer to output byte array (needs space for KYBER_POLYVECBYTES) +* - const polyvec *a: pointer to input vector of polynomials +**************************************************/ +void PQCLEAN_KYBER768_CLEAN_polyvec_tobytes(unsigned char *r, polyvec *a) { int i; for (i = 0; i < KYBER_K; i++) { PQCLEAN_KYBER768_CLEAN_poly_tobytes(r + i * KYBER_POLYBYTES, &a->vec[i]); @@ -79,14 +72,14 @@ void PQCLEAN_KYBER768_CLEAN_polyvec_tobytes(unsigned char *r, const polyvec *a) } /************************************************* - * Name: polyvec_frombytes - * - * Description: De-serialize vector of polynomials; - * inverse of polyvec_tobytes - * - * Arguments: - unsigned char *r: pointer to output byte array - * - const polyvec *a: pointer to input vector of polynomials - **************************************************/ +* Name: PQCLEAN_KYBER768_CLEAN_polyvec_frombytes +* +* Description: De-serialize vector of polynomials; +* inverse of PQCLEAN_KYBER768_CLEAN_polyvec_tobytes +* +* Arguments: - unsigned char *r: pointer to output byte array +* - const polyvec *a: pointer to input vector of polynomials (of length KYBER_POLYVECBYTES) +**************************************************/ void PQCLEAN_KYBER768_CLEAN_polyvec_frombytes(polyvec *r, const unsigned char *a) { int i; for (i = 0; i < KYBER_K; i++) { @@ -95,12 +88,12 @@ void PQCLEAN_KYBER768_CLEAN_polyvec_frombytes(polyvec *r, const unsigned char *a } /************************************************* - * Name: polyvec_ntt - * - * Description: Apply forward NTT to all elements of a vector of polynomials - * - * Arguments: - polyvec *r: pointer to in/output vector of polynomials - **************************************************/ +* Name: PQCLEAN_KYBER768_CLEAN_polyvec_ntt +* +* Description: Apply forward NTT to all elements of a vector of polynomials +* +* Arguments: - polyvec *r: pointer to in/output vector of polynomials +**************************************************/ void PQCLEAN_KYBER768_CLEAN_polyvec_ntt(polyvec *r) { int i; for (i = 0; i < KYBER_K; i++) { @@ -109,12 +102,12 @@ void PQCLEAN_KYBER768_CLEAN_polyvec_ntt(polyvec *r) { } /************************************************* - * Name: polyvec_invntt - * - * Description: Apply inverse NTT to all elements of a vector of polynomials - * - * Arguments: - polyvec *r: pointer to in/output vector of polynomials - **************************************************/ +* Name: PQCLEAN_KYBER768_CLEAN_polyvec_invntt +* +* Description: Apply inverse NTT to all elements of a vector of polynomials +* +* Arguments: - polyvec *r: pointer to in/output vector of polynomials +**************************************************/ void PQCLEAN_KYBER768_CLEAN_polyvec_invntt(polyvec *r) { int i; for (i = 0; i < KYBER_K; i++) { @@ -123,37 +116,68 @@ void PQCLEAN_KYBER768_CLEAN_polyvec_invntt(polyvec *r) { } /************************************************* - * Name: polyvec_pointwise_acc - * - * Description: Pointwise multiply elements of a and b and accumulate into r - * - * Arguments: - poly *r: pointer to output polynomial - * - const polyvec *a: pointer to first input vector of polynomials - * - const polyvec *b: pointer to second input vector of polynomials - **************************************************/ +* Name: PQCLEAN_KYBER768_CLEAN_polyvec_pointwise_acc +* +* Description: Pointwise multiply elements of a and b and accumulate into r +* +* Arguments: - poly *r: pointer to output polynomial +* - const polyvec *a: pointer to first input vector of polynomials +* - const polyvec *b: pointer to second input vector of polynomials +**************************************************/ void PQCLEAN_KYBER768_CLEAN_polyvec_pointwise_acc(poly *r, const polyvec *a, const polyvec *b) { - int i, j; - uint16_t t; - for (j = 0; j < KYBER_N; j++) { - t = PQCLEAN_KYBER768_CLEAN_montgomery_reduce(4613 * (uint32_t)b->vec[0].coeffs[j]); // 4613 = 2^{2*18} % q - r->coeffs[j] = PQCLEAN_KYBER768_CLEAN_montgomery_reduce(a->vec[0].coeffs[j] * t); - for (i = 1; i < KYBER_K; i++) { - t = PQCLEAN_KYBER768_CLEAN_montgomery_reduce(4613 * (uint32_t)b->vec[i].coeffs[j]); - r->coeffs[j] += PQCLEAN_KYBER768_CLEAN_montgomery_reduce(a->vec[i].coeffs[j] * t); - } - r->coeffs[j] = PQCLEAN_KYBER768_CLEAN_barrett_reduce(r->coeffs[j]); + int i; + poly t; + + PQCLEAN_KYBER768_CLEAN_poly_basemul(r, &a->vec[0], &b->vec[0]); + for (i = 1; i < KYBER_K; i++) { + PQCLEAN_KYBER768_CLEAN_poly_basemul(&t, &a->vec[i], &b->vec[i]); + PQCLEAN_KYBER768_CLEAN_poly_add(r, r, &t); + } + + PQCLEAN_KYBER768_CLEAN_poly_reduce(r); +} + +/************************************************* +* Name: PQCLEAN_KYBER768_CLEAN_polyvec_reduce +* +* Description: Applies Barrett reduction to each coefficient +* of each element of a vector of polynomials +* for details of the Barrett reduction see comments in reduce.c +* +* Arguments: - poly *r: pointer to input/output polynomial +**************************************************/ +void PQCLEAN_KYBER768_CLEAN_polyvec_reduce(polyvec *r) { + int i; + for (i = 0; i < KYBER_K; i++) { + PQCLEAN_KYBER768_CLEAN_poly_reduce(&r->vec[i]); } } /************************************************* - * Name: polyvec_add - * - * Description: Add vectors of polynomials - * - * Arguments: - polyvec *r: pointer to output vector of polynomials - * - const polyvec *a: pointer to first input vector of polynomials - * - const polyvec *b: pointer to second input vector of polynomials - **************************************************/ +* Name: PQCLEAN_KYBER768_CLEAN_polyvec_csubq +* +* Description: Applies conditional subtraction of q to each coefficient +* of each element of a vector of polynomials +* for details of conditional subtraction of q see comments in reduce.c +* +* Arguments: - poly *r: pointer to input/output polynomial +**************************************************/ +void PQCLEAN_KYBER768_CLEAN_polyvec_csubq(polyvec *r) { + int i; + for (i = 0; i < KYBER_K; i++) { + PQCLEAN_KYBER768_CLEAN_poly_csubq(&r->vec[i]); + } +} + +/************************************************* +* Name: PQCLEAN_KYBER768_CLEAN_polyvec_add +* +* Description: Add vectors of polynomials +* +* Arguments: - polyvec *r: pointer to output vector of polynomials +* - const polyvec *a: pointer to first input vector of polynomials +* - const polyvec *b: pointer to second input vector of polynomials +**************************************************/ void PQCLEAN_KYBER768_CLEAN_polyvec_add(polyvec *r, const polyvec *a, const polyvec *b) { int i; for (i = 0; i < KYBER_K; i++) { diff --git a/crypto_kem/kyber768/clean/polyvec.h b/crypto_kem/kyber768/clean/polyvec.h index c6fb61ad..41134e26 100644 --- a/crypto_kem/kyber768/clean/polyvec.h +++ b/crypto_kem/kyber768/clean/polyvec.h @@ -8,10 +8,10 @@ typedef struct { poly vec[KYBER_K]; } polyvec; -void PQCLEAN_KYBER768_CLEAN_polyvec_compress(unsigned char *r, const polyvec *a); +void PQCLEAN_KYBER768_CLEAN_polyvec_compress(unsigned char *r, polyvec *a); void PQCLEAN_KYBER768_CLEAN_polyvec_decompress(polyvec *r, const unsigned char *a); -void PQCLEAN_KYBER768_CLEAN_polyvec_tobytes(unsigned char *r, const polyvec *a); +void PQCLEAN_KYBER768_CLEAN_polyvec_tobytes(unsigned char *r, polyvec *a); void PQCLEAN_KYBER768_CLEAN_polyvec_frombytes(polyvec *r, const unsigned char *a); void PQCLEAN_KYBER768_CLEAN_polyvec_ntt(polyvec *r); @@ -19,6 +19,9 @@ void PQCLEAN_KYBER768_CLEAN_polyvec_invntt(polyvec *r); void PQCLEAN_KYBER768_CLEAN_polyvec_pointwise_acc(poly *r, const polyvec *a, const polyvec *b); +void PQCLEAN_KYBER768_CLEAN_polyvec_reduce(polyvec *r); +void PQCLEAN_KYBER768_CLEAN_polyvec_csubq(polyvec *r); + void PQCLEAN_KYBER768_CLEAN_polyvec_add(polyvec *r, const polyvec *a, const polyvec *b); #endif diff --git a/crypto_kem/kyber768/clean/precomp.c b/crypto_kem/kyber768/clean/precomp.c deleted file mode 100644 index 59f158b8..00000000 --- a/crypto_kem/kyber768/clean/precomp.c +++ /dev/null @@ -1,100 +0,0 @@ -#include "inttypes.h" -#include "ntt.h" -#include "params.h" - -/* Precomputed constants for the forward NTT and inverse NTT. - * Computed using Pari/GP as follows: - * -brv=[0,128,64,192,32,160,96,224,16,144,80,208,48,176,112,240, \ - 8,136,72,200,40,168,104,232,24,152,88,216,56,184,120,248, \ - 4,132,68,196,36,164,100,228,20,148,84,212,52,180,116,244, \ - 12,140,76,204,44,172,108,236,28,156,92,220,60,188,124,252, \ - 2,130,66,194,34,162,98,226,18,146,82,210,50,178,114,242, \ - 10,138,74,202,42,170,106,234,26,154,90,218,58,186,122,250, \ - 6,134,70,198,38,166,102,230,22,150,86,214,54,182,118,246, \ - 14,142,78,206,46,174,110,238,30,158,94,222,62,190,126,254, \ - 1,129,65,193,33,161,97,225,17,145,81,209,49,177,113,241, \ - 9,137,73,201,41,169,105,233,25,153,89,217,57,185,121,249, \ - 5,133,69,197,37,165,101,229,21,149,85,213,53,181,117,245, \ - 13,141,77,205,45,173,109,237,29,157,93,221,61,189,125,253, \ - 3,131,67,195,35,163,99,227,19,147,83,211,51,179,115,243, \ - 11,139,75,203,43,171,107,235,27,155,91,219,59,187,123,251, \ - 7,135,71,199,39,167,103,231,23,151,87,215,55,183,119,247, \ - 15,143,79,207,47,175,111,239,31,159,95,223,63,191,127,255]; - -q = 7681; -n = 256; -mont = Mod(2^18,q); - -g=0; for(i=2,q-1,if(znorder(Mod(i,q)) == 2*n, g=Mod(i,q); break)) - -zetas = lift(vector(n, i, g^(brv[i])*mont)) -omegas_inv_bitrev_montgomery = lift(vector(n/2, i, -(g^2)^(-brv[2*(i-1)+1])*mont)) psis_inv_montgomery = lift(vector(n, i, -g^(-(i-1))/n*mont)) - -*/ - -const uint16_t PQCLEAN_KYBER768_CLEAN_zetas[KYBER_N] = { - 990, 7427, 2634, 6819, 578, 3281, 2143, 1095, 484, 6362, 3336, 5382, - 6086, 3823, 877, 5656, 3583, 7010, 6414, 263, 1285, 291, 7143, 7338, - 1581, 5134, 5184, 5932, 4042, 5775, 2468, 3, 606, 729, 5383, 962, - 3240, 7548, 5129, 7653, 5929, 4965, 2461, 641, 1584, 2666, 1142, 157, - 7407, 5222, 5602, 5142, 6140, 5485, 4931, 1559, 2085, 5284, 2056, 3538, - 7269, 3535, 7190, 1957, 3465, 6792, 1538, 4664, 2023, 7643, 3660, 7673, - 1694, 6905, 3995, 3475, 5939, 1859, 6910, 4434, 1019, 1492, 7087, 4761, - 657, 4859, 5798, 2640, 1693, 2607, 2782, 5400, 6466, 1010, 957, 3851, - 2121, 6392, 7319, 3367, 3659, 3375, 6430, 7583, 1549, 5856, 4773, 6084, - 5544, 1650, 3997, 4390, 6722, 2915, 4245, 2635, 6128, 7676, 5737, 1616, - 3457, 3132, 7196, 4702, 6239, 851, 2122, 3009, 7613, 7295, 2007, 323, - 5112, 3716, 2289, 6442, 6965, 2713, 7126, 3401, 963, 6596, 607, 5027, - 7078, 4484, 5937, 944, 2860, 2680, 5049, 1777, 5850, 3387, 6487, 6777, - 4812, 4724, 7077, 186, 6848, 6793, 3463, 5877, 1174, 7116, 3077, 5945, - 6591, 590, 6643, 1337, 6036, 3991, 1675, 2053, 6055, 1162, 1679, 3883, - 4311, 2106, 6163, 4486, 6374, 5006, 4576, 4288, 5180, 4102, 282, 6119, - 7443, 6330, 3184, 4971, 2530, 5325, 4171, 7185, 5175, 5655, 1898, 382, - 7211, 43, 5965, 6073, 1730, 332, 1577, 3304, 2329, 1699, 6150, 2379, - 5113, 333, 3502, 4517, 1480, 1172, 5567, 651, 925, 4573, 599, 1367, - 4109, 1863, 6929, 1605, 3866, 2065, 4048, 839, 5764, 2447, 2022, 3345, - 1990, 4067, 2036, 2069, 3567, 7371, 2368, 339, 6947, 2159, 654, 7327, - 2768, 6676, 987, 2214 -}; - -const uint16_t PQCLEAN_KYBER768_CLEAN_omegas_inv_bitrev_montgomery[KYBER_N / 2] = { - 990, 254, 862, 5047, 6586, 5538, 4400, 7103, 2025, 6804, 3858, 1595, - 2299, 4345, 1319, 7197, 7678, 5213, 1906, 3639, 1749, 2497, 2547, 6100, - 343, 538, 7390, 6396, 7418, 1267, 671, 4098, 5724, 491, 4146, 412, - 4143, 5625, 2397, 5596, 6122, 2750, 2196, 1541, 2539, 2079, 2459, 274, - 7524, 6539, 5015, 6097, 7040, 5220, 2716, 1752, 28, 2552, 133, 4441, - 6719, 2298, 6952, 7075, 4672, 5559, 6830, 1442, 2979, 485, 4549, 4224, - 6065, 1944, 5, 1553, 5046, 3436, 4766, 959, 3291, 3684, 6031, 2137, - 1597, 2908, 1825, 6132, 98, 1251, 4306, 4022, 4314, 362, 1289, 5560, - 3830, 6724, 6671, 1215, 2281, 4899, 5074, 5988, 5041, 1883, 2822, 7024, - 2920, 594, 6189, 6662, 3247, 771, 5822, 1742, 4206, 3686, 776, 5987, - 8, 4021, 38, 5658, 3017, 6143, 889, 4216 -}; - -const uint16_t PQCLEAN_KYBER768_CLEAN_psis_inv_montgomery[KYBER_N] = { - 1024, 4972, 5779, 6907, 4943, 4168, 315, 5580, 90, 497, 1123, 142, - 4710, 5527, 2443, 4871, 698, 2489, 2394, 4003, 684, 2241, 2390, 7224, - 5072, 2064, 4741, 1687, 6841, 482, 7441, 1235, 2126, 4742, 2802, 5744, - 6287, 4933, 699, 3604, 1297, 2127, 5857, 1705, 3868, 3779, 4397, 2177, - 159, 622, 2240, 1275, 640, 6948, 4572, 5277, 209, 2605, 1157, 7328, - 5817, 3191, 1662, 2009, 4864, 574, 2487, 164, 6197, 4436, 7257, 3462, - 4268, 4281, 3414, 4515, 3170, 1290, 2003, 5855, 7156, 6062, 7531, 1732, - 3249, 4884, 7512, 3590, 1049, 2123, 1397, 6093, 3691, 6130, 6541, 3946, - 6258, 3322, 1788, 4241, 4900, 2309, 1400, 1757, 400, 502, 6698, 2338, - 3011, 668, 7444, 4580, 6516, 6795, 2959, 4136, 3040, 2279, 6355, 3943, - 2913, 6613, 7416, 4084, 6508, 5556, 4054, 3782, 61, 6567, 2212, 779, - 632, 5709, 5667, 4923, 4911, 6893, 4695, 4164, 3536, 2287, 7594, 2848, - 3267, 1911, 3128, 546, 1991, 156, 4958, 5531, 6903, 483, 875, 138, - 250, 2234, 2266, 7222, 2842, 4258, 812, 6703, 232, 5207, 6650, 2585, - 1900, 6225, 4932, 7265, 4701, 3173, 4635, 6393, 227, 7313, 4454, 4284, - 6759, 1224, 5223, 1447, 395, 2608, 4502, 4037, 189, 3348, 54, 6443, - 2210, 6230, 2826, 1780, 3002, 5995, 1955, 6102, 6045, 3938, 5019, 4417, - 1434, 1262, 1507, 5847, 5917, 7157, 7177, 6434, 7537, 741, 4348, 1309, - 145, 374, 2236, 4496, 5028, 6771, 6923, 7421, 1978, 1023, 3857, 6876, - 1102, 7451, 4704, 6518, 1344, 765, 384, 5705, 1207, 1630, 4734, 1563, - 6839, 5933, 1954, 4987, 7142, 5814, 7527, 4953, 7637, 4707, 2182, 5734, - 2818, 541, 4097, 5641 -}; diff --git a/crypto_kem/kyber768/clean/reduce.c b/crypto_kem/kyber768/clean/reduce.c index 8b023929..572f7e34 100644 --- a/crypto_kem/kyber768/clean/reduce.c +++ b/crypto_kem/kyber768/clean/reduce.c @@ -1,70 +1,62 @@ #include "reduce.h" + #include "params.h" -static const uint32_t qinv = 7679; // -inverse_mod(q,2^18) -static const uint32_t rlog = 18; +#include /************************************************* - * Name: montgomery_reduce - * - * Description: Montgomery reduction; given a 32-bit integer a, computes - * 16-bit integer congruent to a * R^-1 mod q, - * where R=2^18 (see value of rlog) - * - * Arguments: - uint32_t a: input unsigned integer to be reduced; has to be in - *{0,...,2281446912} - * - * Returns: unsigned integer in {0,...,2^13-1} congruent to a * R^-1 modulo - *q. - **************************************************/ -uint16_t PQCLEAN_KYBER768_CLEAN_montgomery_reduce(uint32_t a) { - uint32_t u; +* Name: PQCLEAN_KYBER768_CLEAN_montgomery_reduce +* +* Description: Montgomery reduction; given a 32-bit integer a, computes +* 16-bit integer congruent to a * R^-1 mod q, +* where R=2^16 +* +* Arguments: - int32_t a: input integer to be reduced; has to be in {-q2^15,...,q2^15-1} +* +* Returns: integer in {-q+1,...,q-1} congruent to a * R^-1 modulo q. +**************************************************/ +int16_t PQCLEAN_KYBER768_CLEAN_montgomery_reduce(int32_t a) { + int32_t t; + int16_t u; - u = (a * qinv); - u &= ((1 << rlog) - 1); - u *= KYBER_Q; - a = a + u; - return (uint16_t)(a >> rlog); + u = (int16_t)(a * QINV); + t = (int32_t)u * KYBER_Q; + t = a - t; + t >>= 16; + return (int16_t)t; } /************************************************* - * Name: barrett_reduce - * - * Description: Barrett reduction; given a 16-bit integer a, computes - * 16-bit integer congruent to a mod q in {0,...,11768} - * - * Arguments: - uint16_t a: input unsigned integer to be reduced - * - * Returns: unsigned integer in {0,...,11768} congruent to a modulo q. - **************************************************/ -uint16_t PQCLEAN_KYBER768_CLEAN_barrett_reduce(uint16_t a) { - uint16_t u; +* Name: PQCLEAN_KYBER768_CLEAN_barrett_reduce +* +* Description: Barrett reduction; given a 16-bit integer a, computes +* 16-bit integer congruent to a mod q in {0,...,q} +* +* Arguments: - int16_t a: input integer to be reduced +* +* Returns: integer in {0,...,q} congruent to a modulo q. +**************************************************/ +int16_t PQCLEAN_KYBER768_CLEAN_barrett_reduce(int16_t a) { + int32_t t; + const int32_t v = (1U << 26) / KYBER_Q + 1; - u = a >> 13; //((uint32_t) a * sinv) >> 16; - u *= KYBER_Q; - a -= u; + t = v * a; + t >>= 26; + t *= KYBER_Q; + return (int16_t)(a - t); +} + +/************************************************* +* Name: PQCLEAN_KYBER768_CLEAN_csubq +* +* Description: Conditionallly subtract q +* +* Arguments: - int16_t x: input integer +* +* Returns: a - q if a >= q, else a +**************************************************/ +int16_t PQCLEAN_KYBER768_CLEAN_csubq(int16_t a) { + a -= KYBER_Q; + a += (a >> 15) & KYBER_Q; return a; } - -/************************************************* - * Name: freeze - * - * Description: Full reduction; given a 16-bit integer a, computes - * unsigned integer a mod q. - * - * Arguments: - uint16_t x: input unsigned integer to be reduced - * - * Returns: unsigned integer in {0,...,q-1} congruent to a modulo q. - **************************************************/ -uint16_t PQCLEAN_KYBER768_CLEAN_freeze(uint16_t x) { - uint16_t m, r; - int16_t c; - r = PQCLEAN_KYBER768_CLEAN_barrett_reduce(x); - - m = r - KYBER_Q; - c = m; - c >>= 15; - r = m ^ ((r ^ m) & c); - - return r; -} diff --git a/crypto_kem/kyber768/clean/reduce.h b/crypto_kem/kyber768/clean/reduce.h index e7c4f0be..7a679969 100644 --- a/crypto_kem/kyber768/clean/reduce.h +++ b/crypto_kem/kyber768/clean/reduce.h @@ -3,10 +3,13 @@ #include -uint16_t PQCLEAN_KYBER768_CLEAN_freeze(uint16_t x); +#define MONT 2285 // 2^16 % Q +#define QINV 62209 // q^(-1) mod 2^16 -uint16_t PQCLEAN_KYBER768_CLEAN_montgomery_reduce(uint32_t a); +int16_t PQCLEAN_KYBER768_CLEAN_montgomery_reduce(int32_t a); -uint16_t PQCLEAN_KYBER768_CLEAN_barrett_reduce(uint16_t a); +int16_t PQCLEAN_KYBER768_CLEAN_barrett_reduce(int16_t a); + +int16_t PQCLEAN_KYBER768_CLEAN_csubq(int16_t a); #endif diff --git a/crypto_kem/kyber768/clean/symmetric-fips202.c b/crypto_kem/kyber768/clean/symmetric-fips202.c new file mode 100644 index 00000000..3d4e858c --- /dev/null +++ b/crypto_kem/kyber768/clean/symmetric-fips202.c @@ -0,0 +1,64 @@ +#include "fips202.h" +#include "symmetric.h" + +#include + +/************************************************* +* Name: PQCLEAN_KYBER768_CLEAN_kyber_shake128_absorb +* +* Description: Absorb step of the SHAKE128 specialized for the Kyber context. +* +* Arguments: - uint64_t *s: pointer to (uninitialized) output Keccak state +* - const unsigned char *input: pointer to KYBER_SYMBYTES input to be absorbed into s +* - unsigned char i additional byte of input +* - unsigned char j additional byte of input +**************************************************/ +void PQCLEAN_KYBER768_CLEAN_kyber_shake128_absorb(keccak_state *s, const unsigned char *input, unsigned char x, unsigned char y) { + unsigned char extseed[KYBER_SYMBYTES + 2]; + int i; + + for (i = 0; i < KYBER_SYMBYTES; i++) { + extseed[i] = input[i]; + } + extseed[i++] = x; + extseed[i] = y; + shake128_absorb(s->s, extseed, KYBER_SYMBYTES + 2); +} + +/************************************************* +* Name: PQCLEAN_KYBER768_CLEAN_kyber_shake128_squeezeblocks +* +* Description: Squeeze step of SHAKE128 XOF. Squeezes full blocks of SHAKE128_RATE bytes each. +* Modifies the state. Can be called multiple times to keep squeezing, +* i.e., is incremental. +* +* Arguments: - unsigned char *output: pointer to output blocks +* - size_t nblocks: number of blocks to be squeezed (written to output) +* - keccak_state *s: pointer to in/output Keccak state +**************************************************/ +void PQCLEAN_KYBER768_CLEAN_kyber_shake128_squeezeblocks(unsigned char *output, size_t nblocks, keccak_state *s) { + shake128_squeezeblocks(output, nblocks, s->s); +} + +/************************************************* +* Name: PQCLEAN_KYBER768_CLEAN_shake256_prf +* +* Description: Usage of SHAKE256 as a PRF, concatenates secret and public input +* and then generates outlen bytes of SHAKE256 output +* +* Arguments: - unsigned char *output: pointer to output +* - size_t outlen: number of requested output bytes +* - const unsigned char * key: pointer to the key (of length KYBER_SYMBYTES) +* - const unsigned char nonce: single-byte nonce (public PRF input) +**************************************************/ +void PQCLEAN_KYBER768_CLEAN_shake256_prf(unsigned char *output, size_t outlen, const unsigned char *key, unsigned char nonce) { + unsigned char extkey[KYBER_SYMBYTES + 1]; + size_t i; + + for (i = 0; i < KYBER_SYMBYTES; i++) { + extkey[i] = key[i]; + } + extkey[i] = nonce; + + shake256(output, outlen, extkey, KYBER_SYMBYTES + 1); +} diff --git a/crypto_kem/kyber768/clean/symmetric.h b/crypto_kem/kyber768/clean/symmetric.h new file mode 100644 index 00000000..7cdff295 --- /dev/null +++ b/crypto_kem/kyber768/clean/symmetric.h @@ -0,0 +1,26 @@ +#ifndef SYMMETRIC_H +#define SYMMETRIC_H + +#include "fips202.h" +#include "params.h" + +typedef struct { + uint64_t s[25]; +} keccak_state; + +void PQCLEAN_KYBER768_CLEAN_kyber_shake128_absorb(keccak_state *s, const unsigned char *input, unsigned char x, unsigned char y); +void PQCLEAN_KYBER768_CLEAN_kyber_shake128_squeezeblocks(unsigned char *output, size_t nblocks, keccak_state *s); +void PQCLEAN_KYBER768_CLEAN_shake256_prf(unsigned char *output, size_t outlen, const unsigned char *key, unsigned char nonce); + +#define hash_h(OUT, IN, INBYTES) sha3_256(OUT, IN, INBYTES) +#define hash_g(OUT, IN, INBYTES) sha3_512(OUT, IN, INBYTES) +#define xof_absorb(STATE, IN, X, Y) PQCLEAN_KYBER768_CLEAN_kyber_shake128_absorb(STATE, IN, X, Y) +#define xof_squeezeblocks(OUT, OUTBLOCKS, STATE) PQCLEAN_KYBER768_CLEAN_kyber_shake128_squeezeblocks(OUT, OUTBLOCKS, STATE) +#define prf(OUT, OUTBYTES, KEY, NONCE) PQCLEAN_KYBER768_CLEAN_shake256_prf(OUT, OUTBYTES, KEY, NONCE) +#define kdf(OUT, IN, INBYTES) shake256(OUT, KYBER_SSBYTES, IN, INBYTES) + +#define XOF_BLOCKBYTES 168 + +typedef keccak_state xof_state; + +#endif /* SYMMETRIC_H */ diff --git a/crypto_kem/kyber768/clean/verify.c b/crypto_kem/kyber768/clean/verify.c index bacaa0b7..2fa67412 100644 --- a/crypto_kem/kyber768/clean/verify.c +++ b/crypto_kem/kyber768/clean/verify.c @@ -1,45 +1,46 @@ -#include -#include - #include "verify.h" +#include +#include + /************************************************* - * Name: verify - * - * Description: Compare two arrays for equality in constant time. - * - * Arguments: const unsigned char *a: pointer to first byte array - * const unsigned char *b: pointer to second byte array - * size_t len: length of the byte arrays - * - * Returns 0 if the byte arrays are equal, 1 otherwise - **************************************************/ -int PQCLEAN_KYBER768_CLEAN_verify(const unsigned char *a, const unsigned char *b, size_t len) { +* Name: verify +* +* Description: Compare two arrays for equality in constant time. +* +* Arguments: const unsigned char *a: pointer to first byte array +* const unsigned char *b: pointer to second byte array +* size_t len: length of the byte arrays +* +* Returns 0 if the byte arrays are equal, 1 otherwise +**************************************************/ +unsigned char PQCLEAN_KYBER768_CLEAN_verify(const unsigned char *a, const unsigned char *b, size_t len) { uint64_t r; size_t i; - r = 0; + r = 0; for (i = 0; i < len; i++) { r |= a[i] ^ b[i]; } - r = (-(int64_t)r) >> 63; - return (int)r; + r = (~r + 1); // Two's complement + r >>= 63; + return (unsigned char)r; } /************************************************* - * Name: cmov - * - * Description: Copy len bytes from x to r if b is 1; - * don't modify x if b is 0. Requires b to be in {0,1}; - * assumes two's complement representation of negative integers. - * Runs in constant time. - * - * Arguments: unsigned char *r: pointer to output byte array - * const unsigned char *x: pointer to input byte array - * size_t len: Amount of bytes to be copied - * unsigned char b: Condition bit; has to be in {0,1} - **************************************************/ +* Name: cmov +* +* Description: Copy len bytes from x to r if b is 1; +* don't modify x if b is 0. Requires b to be in {0,1}; +* assumes two's complement representation of negative integers. +* Runs in constant time. +* +* Arguments: unsigned char *r: pointer to output byte array +* const unsigned char *x: pointer to input byte array +* size_t len: Amount of bytes to be copied +* unsigned char b: Condition bit; has to be in {0,1} +**************************************************/ void PQCLEAN_KYBER768_CLEAN_cmov(unsigned char *r, const unsigned char *x, size_t len, unsigned char b) { size_t i; diff --git a/crypto_kem/kyber768/clean/verify.h b/crypto_kem/kyber768/clean/verify.h index 8a1b81f4..ecfe79a9 100644 --- a/crypto_kem/kyber768/clean/verify.h +++ b/crypto_kem/kyber768/clean/verify.h @@ -3,7 +3,7 @@ #include -int PQCLEAN_KYBER768_CLEAN_verify(const unsigned char *a, const unsigned char *b, size_t len); +unsigned char PQCLEAN_KYBER768_CLEAN_verify(const unsigned char *a, const unsigned char *b, size_t len); void PQCLEAN_KYBER768_CLEAN_cmov(unsigned char *r, const unsigned char *x, size_t len, unsigned char b); diff --git a/test/test_nistkat.py b/test/test_nistkat.py index 97c8293f..daebca49 100644 --- a/test/test_nistkat.py +++ b/test/test_nistkat.py @@ -25,10 +25,6 @@ def test_nistkat(): @helpers.filtered_test def check_nistkat(implementation): - if implementation.scheme.name == "kyber768": - raise unittest.SkipTest( - "Temporarily skip NIST KAT check for kyber768 since it's " - "an outdated implementation") helpers.make('nistkat', TYPE=implementation.scheme.type, SCHEME=implementation.scheme.name,