From fa6aedb06899999d874089cea2fd027e0754affa Mon Sep 17 00:00:00 2001 From: Joost Rijneveld Date: Tue, 15 Jan 2019 16:03:38 +0100 Subject: [PATCH] Add minimal Makefile and kyber768 as startingpoint --- .gitignore | 1 + Makefile | 21 ++ crypto_kem/kyber768/clean/api.h | 19 ++ crypto_kem/kyber768/clean/cbd.c | 113 ++++++++++ crypto_kem/kyber768/clean/cbd.h | 9 + crypto_kem/kyber768/clean/indcpa.c | 308 ++++++++++++++++++++++++++++ crypto_kem/kyber768/clean/indcpa.h | 16 ++ crypto_kem/kyber768/clean/kem.c | 100 +++++++++ crypto_kem/kyber768/clean/kex.c | 55 +++++ crypto_kem/kyber768/clean/kex.h | 30 +++ crypto_kem/kyber768/clean/ntt.c | 84 ++++++++ crypto_kem/kyber768/clean/ntt.h | 9 + crypto_kem/kyber768/clean/params.h | 27 +++ crypto_kem/kyber768/clean/poly.c | 249 ++++++++++++++++++++++ crypto_kem/kyber768/clean/poly.h | 32 +++ crypto_kem/kyber768/clean/polyvec.c | 171 +++++++++++++++ crypto_kem/kyber768/clean/polyvec.h | 24 +++ crypto_kem/kyber768/clean/precomp.c | 82 ++++++++ crypto_kem/kyber768/clean/reduce.c | 73 +++++++ crypto_kem/kyber768/clean/reduce.h | 12 ++ crypto_kem/kyber768/clean/verify.c | 48 +++++ crypto_kem/kyber768/clean/verify.h | 10 + crypto_kem/test.c | 109 ++++++++++ 23 files changed, 1602 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 crypto_kem/kyber768/clean/api.h create mode 100644 crypto_kem/kyber768/clean/cbd.c create mode 100644 crypto_kem/kyber768/clean/cbd.h create mode 100644 crypto_kem/kyber768/clean/indcpa.c create mode 100644 crypto_kem/kyber768/clean/indcpa.h create mode 100644 crypto_kem/kyber768/clean/kem.c create mode 100644 crypto_kem/kyber768/clean/kex.c create mode 100644 crypto_kem/kyber768/clean/kex.h create mode 100644 crypto_kem/kyber768/clean/ntt.c create mode 100644 crypto_kem/kyber768/clean/ntt.h create mode 100644 crypto_kem/kyber768/clean/params.h create mode 100644 crypto_kem/kyber768/clean/poly.c create mode 100644 crypto_kem/kyber768/clean/poly.h create mode 100644 crypto_kem/kyber768/clean/polyvec.c create mode 100644 crypto_kem/kyber768/clean/polyvec.h create mode 100644 crypto_kem/kyber768/clean/precomp.c create mode 100644 crypto_kem/kyber768/clean/reduce.c create mode 100644 crypto_kem/kyber768/clean/reduce.h create mode 100644 crypto_kem/kyber768/clean/verify.c create mode 100644 crypto_kem/kyber768/clean/verify.h create mode 100644 crypto_kem/test.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..6dd29b7f --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +bin/ \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..ad72e2d5 --- /dev/null +++ b/Makefile @@ -0,0 +1,21 @@ + +# assumes a SCHEME variable; e.g. make functest_kem SCHEME=kyber768 +ifndef SCHEME + # TODO make this more granular, i.e. make clean should not require SCHEME +$(error SCHEME variable is not set) +endif + +functest_kem: crypto_kem/test.c $(wildcard crypto_kem/$(SCHEME)/clean/*.c) $(wildcard crypto_kem/$(SCHEME)/clean/*.h) + mkdir -p bin + $(CC) $(CFLAGS)\ + -I"./common/"\ + -I"crypto_kem/$(SCHEME)/clean/"\ + -o bin/functest_kem_$(SCHEME)\ + common/*.c\ + crypto_kem/$(SCHEME)/clean/*.c\ + crypto_kem/test.c + +.PHONY: clean + +clean: + rm -rf bin diff --git a/crypto_kem/kyber768/clean/api.h b/crypto_kem/kyber768/clean/api.h new file mode 100644 index 00000000..aaaa649b --- /dev/null +++ b/crypto_kem/kyber768/clean/api.h @@ -0,0 +1,19 @@ +#ifndef API_H +#define API_H + +#include "params.h" + +#define CRYPTO_SECRETKEYBYTES KYBER_SECRETKEYBYTES +#define CRYPTO_PUBLICKEYBYTES KYBER_PUBLICKEYBYTES +#define CRYPTO_CIPHERTEXTBYTES KYBER_CIPHERTEXTBYTES +#define CRYPTO_BYTES KYBER_SYMBYTES + +#define CRYPTO_ALGNAME "Kyber768" + +int crypto_kem_keypair(unsigned char *pk, unsigned char *sk); + +int crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk); + +int crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk); + +#endif diff --git a/crypto_kem/kyber768/clean/cbd.c b/crypto_kem/kyber768/clean/cbd.c new file mode 100644 index 00000000..d445e340 --- /dev/null +++ b/crypto_kem/kyber768/clean/cbd.c @@ -0,0 +1,113 @@ +#include "cbd.h" + +/************************************************* +* 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> j) & 0x249249; + + a[0] = d & 0x7; + b[0] = (d >> 3) & 0x7; + a[1] = (d >> 6) & 0x7; + b[1] = (d >> 9) & 0x7; + a[2] = (d >> 12) & 0x7; + b[2] = (d >> 15) & 0x7; + a[3] = (d >> 18) & 0x7; + b[3] = (d >> 21); + + r->coeffs[4*i+0] = a[0] + KYBER_Q - b[0]; + r->coeffs[4*i+1] = a[1] + KYBER_Q - b[1]; + r->coeffs[4*i+2] = a[2] + KYBER_Q - b[2]; + r->coeffs[4*i+3] = a[3] + KYBER_Q - b[3]; + } +#elif KYBER_ETA == 4 + uint32_t t,d, a[4], b[4]; + int i,j; + + for(i=0;i> j) & 0x11111111; + + a[0] = d & 0xf; + b[0] = (d >> 4) & 0xf; + a[1] = (d >> 8) & 0xf; + b[1] = (d >> 12) & 0xf; + a[2] = (d >> 16) & 0xf; + b[2] = (d >> 20) & 0xf; + a[3] = (d >> 24) & 0xf; + b[3] = (d >> 28); + + r->coeffs[4*i+0] = a[0] + KYBER_Q - b[0]; + r->coeffs[4*i+1] = a[1] + KYBER_Q - b[1]; + r->coeffs[4*i+2] = a[2] + KYBER_Q - b[2]; + r->coeffs[4*i+3] = a[3] + KYBER_Q - b[3]; + } +#elif KYBER_ETA == 5 + uint64_t t,d, a[4], b[4]; + int i,j; + + for(i=0;i> j) & 0x0842108421UL; + + a[0] = d & 0x1f; + b[0] = (d >> 5) & 0x1f; + a[1] = (d >> 10) & 0x1f; + b[1] = (d >> 15) & 0x1f; + a[2] = (d >> 20) & 0x1f; + b[2] = (d >> 25) & 0x1f; + a[3] = (d >> 30) & 0x1f; + b[3] = (d >> 35); + + r->coeffs[4*i+0] = a[0] + KYBER_Q - b[0]; + r->coeffs[4*i+1] = a[1] + KYBER_Q - b[1]; + r->coeffs[4*i+2] = a[2] + KYBER_Q - b[2]; + r->coeffs[4*i+3] = a[3] + KYBER_Q - b[3]; + } +#else +#error "poly_getnoise in poly.c only supports eta in {3,4,5}" +#endif +} diff --git a/crypto_kem/kyber768/clean/cbd.h b/crypto_kem/kyber768/clean/cbd.h new file mode 100644 index 00000000..e88caae1 --- /dev/null +++ b/crypto_kem/kyber768/clean/cbd.h @@ -0,0 +1,9 @@ +#ifndef CBD_H +#define CBD_H + +#include +#include "poly.h" + +void cbd(poly *r, const unsigned char *buf); + +#endif diff --git a/crypto_kem/kyber768/clean/indcpa.c b/crypto_kem/kyber768/clean/indcpa.c new file mode 100644 index 00000000..19ba7329 --- /dev/null +++ b/crypto_kem/kyber768/clean/indcpa.c @@ -0,0 +1,308 @@ +#include +#include "indcpa.h" +#include "poly.h" +#include "polyvec.h" +#include "randombytes.h" +#include "fips202.h" +#include "ntt.h" + +/************************************************* +* 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) +{ + int i; + polyvec_compress(r, pk); + for(i=0;i SHAKE128_RATE*nblocks-2) + { + nblocks = 1; + shake128_squeezeblocks(buf,nblocks,state); + pos = 0; + } + } + } + } +} + + +/************************************************* +* 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 indcpa_keypair(unsigned char *pk, + unsigned char *sk) +{ + polyvec a[KYBER_K], e, pkpv, skpv; + unsigned char buf[KYBER_SYMBYTES+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); + + gen_a(a, publicseed); + + for(i=0;i= 0; level--) + { + for(start = 0; start < KYBER_N; start = j + (1< + +void ntt(uint16_t* poly); +void invntt(uint16_t* poly); + +#endif diff --git a/crypto_kem/kyber768/clean/params.h b/crypto_kem/kyber768/clean/params.h new file mode 100644 index 00000000..8758ce29 --- /dev/null +++ b/crypto_kem/kyber768/clean/params.h @@ -0,0 +1,27 @@ +#ifndef PARAMS_H +#define PARAMS_H + +#define KYBER_K 3 + +#define KYBER_N 256 +#define KYBER_Q 7681 + +#define KYBER_ETA 4 + +#define KYBER_SYMBYTES 32 /* size in bytes of shared key, hashes, and seeds */ + +#define KYBER_POLYBYTES 416 +#define KYBER_POLYCOMPRESSEDBYTES 96 +#define KYBER_POLYVECBYTES (KYBER_K * KYBER_POLYBYTES) +#define KYBER_POLYVECCOMPRESSEDBYTES (KYBER_K * 352) + +#define KYBER_INDCPA_MSGBYTES KYBER_SYMBYTES +#define KYBER_INDCPA_PUBLICKEYBYTES (KYBER_POLYVECCOMPRESSEDBYTES + 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/kyber768/clean/poly.c b/crypto_kem/kyber768/clean/poly.c new file mode 100644 index 00000000..080296cb --- /dev/null +++ b/crypto_kem/kyber768/clean/poly.c @@ -0,0 +1,249 @@ +#include +#include "poly.h" +#include "ntt.h" +#include "polyvec.h" +#include "reduce.h" +#include "cbd.h" +#include "fips202.h" + +/************************************************* +* 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 poly_compress(unsigned char *r, const poly *a) +{ + uint32_t t[8]; + unsigned int i,j,k=0; + + for(i=0;icoeffs[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: 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 +**************************************************/ +void poly_decompress(poly *r, const unsigned char *a) +{ + unsigned int i; + for(i=0;icoeffs[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: poly_tobytes +* +* Description: Serialization of a polynomial +* +* Arguments: - unsigned char *r: pointer to output byte array +* - const poly *a: pointer to input polynomial +**************************************************/ +void poly_tobytes(unsigned char *r, const poly *a) +{ + int i,j; + uint16_t t[8]; + + for(i=0;icoeffs[8*i+j]); + + r[13*i+ 0] = t[0] & 0xff; + r[13*i+ 1] = (t[0] >> 8) | ((t[1] & 0x07) << 5); + r[13*i+ 2] = (t[1] >> 3) & 0xff; + r[13*i+ 3] = (t[1] >> 11) | ((t[2] & 0x3f) << 2); + r[13*i+ 4] = (t[2] >> 6) | ((t[3] & 0x01) << 7); + r[13*i+ 5] = (t[3] >> 1) & 0xff; + r[13*i+ 6] = (t[3] >> 9) | ((t[4] & 0x0f) << 4); + r[13*i+ 7] = (t[4] >> 4) & 0xff; + r[13*i+ 8] = (t[4] >> 12) | ((t[5] & 0x7f) << 1); + r[13*i+ 9] = (t[5] >> 7) | ((t[6] & 0x03) << 6); + r[13*i+10] = (t[6] >> 2) & 0xff; + r[13*i+11] = (t[6] >> 10) | ((t[7] & 0x1f) << 3); + r[13*i+12] = (t[7] >> 5); + } +} + +/************************************************* +* 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 +**************************************************/ +void poly_frombytes(poly *r, const unsigned char *a) +{ + int i; + for(i=0;icoeffs[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); + } +} + +/************************************************* +* 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 +**************************************************/ +void 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;icoeffs); +} + +/************************************************* +* 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 +**************************************************/ +void poly_invntt(poly *r) +{ + 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 +**************************************************/ +void poly_add(poly *r, const poly *a, const poly *b) +{ + int i; + for(i=0;icoeffs[i] = barrett_reduce(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 +**************************************************/ +void poly_sub(poly *r, const poly *a, const poly *b) +{ + int i; + for(i=0;icoeffs[i] = barrett_reduce(a->coeffs[i] + 3*KYBER_Q - 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 +**************************************************/ +void poly_frommsg(poly *r, const unsigned char msg[KYBER_SYMBYTES]) +{ + uint16_t i,j,mask; + + for(i=0;i> j)&1); + r->coeffs[8*i+j] = mask & ((KYBER_Q+1)/2); + } + } +} + +/************************************************* +* 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 poly_tomsg(unsigned char msg[KYBER_SYMBYTES], const poly *a) +{ + uint16_t t; + int i,j; + + for(i=0;icoeffs[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 new file mode 100644 index 00000000..a791c680 --- /dev/null +++ b/crypto_kem/kyber768/clean/poly.h @@ -0,0 +1,32 @@ +#ifndef POLY_H +#define POLY_H + +#include +#include "params.h" + +/* + * 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{ + uint16_t coeffs[KYBER_N]; +} poly; + +void poly_compress(unsigned char *r, const poly *a); +void poly_decompress(poly *r, const unsigned char *a); + +void poly_tobytes(unsigned char *r, const poly *a); +void poly_frombytes(poly *r, const unsigned char *a); + +void poly_frommsg(poly *r, const unsigned char msg[KYBER_SYMBYTES]); +void poly_tomsg(unsigned char msg[KYBER_SYMBYTES], const poly *r); + +void poly_getnoise(poly *r,const unsigned char *seed, unsigned char nonce); + +void poly_ntt(poly *r); +void poly_invntt(poly *r); + +void poly_add(poly *r, const poly *a, const poly *b); +void poly_sub(poly *r, const poly *a, const poly *b); + +#endif diff --git a/crypto_kem/kyber768/clean/polyvec.c b/crypto_kem/kyber768/clean/polyvec.c new file mode 100644 index 00000000..f61c26fe --- /dev/null +++ b/crypto_kem/kyber768/clean/polyvec.c @@ -0,0 +1,171 @@ +#include +#include "polyvec.h" +#include "fips202.h" +#include "cbd.h" +#include "reduce.h" + +/************************************************* +* 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 polyvec_compress(unsigned char *r, const polyvec *a) +{ + int i,j,k; + uint16_t t[8]; + for(i=0;ivec[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); + r[11*j+ 2] = (t[1] >> 5) | ((t[2] & 0x03) << 6); + r[11*j+ 3] = (t[2] >> 2) & 0xff; + r[11*j+ 4] = (t[2] >> 10) | ((t[3] & 0x7f) << 1); + r[11*j+ 5] = (t[3] >> 7) | ((t[4] & 0x0f) << 4); + r[11*j+ 6] = (t[4] >> 4) | ((t[5] & 0x01) << 7); + r[11*j+ 7] = (t[5] >> 1) & 0xff; + r[11*j+ 8] = (t[5] >> 9) | ((t[6] & 0x3f) << 2); + r[11*j+ 9] = (t[6] >> 6) | ((t[7] & 0x07) << 5); + r[11*j+10] = (t[7] >> 3); + } + r += 352; + } +} + +/************************************************* +* 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 +**************************************************/ +void polyvec_decompress(polyvec *r, const unsigned char *a) +{ + int i,j; + for(i=0;ivec[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: 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 polyvec_tobytes(unsigned char *r, const polyvec *a) +{ + int i; + for(i=0;ivec[i]); +} + +/************************************************* +* 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 +**************************************************/ +void polyvec_frombytes(polyvec *r, const unsigned char *a) +{ + int i; + for(i=0;ivec[i], a+i*KYBER_POLYBYTES); +} + +/************************************************* +* 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 +**************************************************/ +void polyvec_ntt(polyvec *r) +{ + int i; + for(i=0;ivec[i]); +} + +/************************************************* +* 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 +**************************************************/ +void polyvec_invntt(polyvec *r) +{ + int i; + for(i=0;ivec[i]); +} + +/************************************************* +* 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 +**************************************************/ +void polyvec_pointwise_acc(poly *r, const polyvec *a, const polyvec *b) +{ + int i,j; + uint16_t t; + for(j=0;jvec[0].coeffs[j]); // 4613 = 2^{2*18} % q + r->coeffs[j] = montgomery_reduce(a->vec[0].coeffs[j] * t); + for(i=1;ivec[i].coeffs[j]); + r->coeffs[j] += montgomery_reduce(a->vec[i].coeffs[j] * t); + } + r->coeffs[j] = barrett_reduce(r->coeffs[j]); + } +} + +/************************************************* +* 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 +**************************************************/ +void polyvec_add(polyvec *r, const polyvec *a, const polyvec *b) +{ + int i; + for(i=0;ivec[i], &a->vec[i], &b->vec[i]); + +} diff --git a/crypto_kem/kyber768/clean/polyvec.h b/crypto_kem/kyber768/clean/polyvec.h new file mode 100644 index 00000000..ad9fe941 --- /dev/null +++ b/crypto_kem/kyber768/clean/polyvec.h @@ -0,0 +1,24 @@ +#ifndef POLYVEC_H +#define POLYVEC_H + +#include "params.h" +#include "poly.h" + +typedef struct{ + poly vec[KYBER_K]; +} polyvec; + +void polyvec_compress(unsigned char *r, const polyvec *a); +void polyvec_decompress(polyvec *r, const unsigned char *a); + +void polyvec_tobytes(unsigned char *r, const polyvec *a); +void polyvec_frombytes(polyvec *r, const unsigned char *a); + +void polyvec_ntt(polyvec *r); +void polyvec_invntt(polyvec *r); + +void polyvec_pointwise_acc(poly *r, const polyvec *a, const polyvec *b); + +void 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 new file mode 100644 index 00000000..96edf275 --- /dev/null +++ b/crypto_kem/kyber768/clean/precomp.c @@ -0,0 +1,82 @@ +#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 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 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 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 new file mode 100644 index 00000000..c626a0d2 --- /dev/null +++ b/crypto_kem/kyber768/clean/reduce.c @@ -0,0 +1,73 @@ +#include "reduce.h" +#include "params.h" + + +static const uint32_t qinv = 7679; // -inverse_mod(q,2^18) +static const uint32_t rlog = 18; + +/************************************************* +* 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 montgomery_reduce(uint32_t a) +{ + uint32_t u; + + u = (a * qinv); + u &= ((1<> rlog; +} + + +/************************************************* +* 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 barrett_reduce(uint16_t a) +{ + uint32_t u; + + u = a >> 13;//((uint32_t) a * sinv) >> 16; + u *= KYBER_Q; + a -= u; + 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 freeze(uint16_t x) +{ + uint16_t m,r; + int16_t c; + r = 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 new file mode 100644 index 00000000..6deab6a0 --- /dev/null +++ b/crypto_kem/kyber768/clean/reduce.h @@ -0,0 +1,12 @@ +#ifndef REDUCE_H +#define REDUCE_H + +#include + +uint16_t freeze(uint16_t x); + +uint16_t montgomery_reduce(uint32_t a); + +uint16_t barrett_reduce(uint16_t a); + +#endif diff --git a/crypto_kem/kyber768/clean/verify.c b/crypto_kem/kyber768/clean/verify.c new file mode 100644 index 00000000..9ab6ecab --- /dev/null +++ b/crypto_kem/kyber768/clean/verify.c @@ -0,0 +1,48 @@ +#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 verify(const unsigned char *a, const unsigned char *b, size_t len) +{ + uint64_t r; + size_t i; + r = 0; + + for(i=0;i> 63; + return 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 cmov(unsigned char *r, const unsigned char *x, size_t len, unsigned char b) +{ + size_t i; + + b = -b; + for(i=0;i + +int verify(const unsigned char *a, const unsigned char *b, size_t len); + +void cmov(unsigned char *r, const unsigned char *x, size_t len, unsigned char b); + +#endif diff --git a/crypto_kem/test.c b/crypto_kem/test.c new file mode 100644 index 00000000..0641443a --- /dev/null +++ b/crypto_kem/test.c @@ -0,0 +1,109 @@ +#include "api.h" +#include "randombytes.h" +#include +#include + +#define NTESTS 10000 + +int test_keys() +{ + unsigned char key_a[CRYPTO_BYTES], key_b[CRYPTO_BYTES]; + unsigned char pk[CRYPTO_PUBLICKEYBYTES]; + unsigned char sendb[CRYPTO_CIPHERTEXTBYTES]; + unsigned char sk_a[CRYPTO_SECRETKEYBYTES]; + int i; + + for(i=0; i