diff --git a/boring-sys/patches/boring-pq.patch b/boring-sys/patches/boring-pq.patch index d4294dc5..2ffeee6c 100644 --- a/boring-sys/patches/boring-pq.patch +++ b/boring-sys/patches/boring-pq.patch @@ -1,4 +1,4 @@ -From 836d390deaf8b50fed0cafd55b17a63e80454d7f Mon Sep 17 00:00:00 2001 +From 4cba2164726c8d2647e38548a266a70c4942d567 Mon Sep 17 00:00:00 2001 From: Bas Westerbaan Date: Fri, 22 Jul 2022 16:43:48 +0200 Subject: [PATCH] Add temporary post-quantum key agreements @@ -20,55 +20,43 @@ This patch adds: key agreement should only be used for testing: to see if the smaller keyshare makes a difference. -4. Supportfor IPDWing under codepoint 0xfe41. This key agreement - is a preliminary version of X-Wing using the initial public draft - of ML-KEM. It should not be used. - The patch also replaces Google's implementation of Kyber, by the portable reference implementation, so as to support Kyber512. Cf RTG-2076 RTG-2051 RTG-2508 RTG-2707 RTG-2607 --- - BUILD.generated.bzl | 7 +- + BUILD.generated.bzl | 5 +- BUILD.generated_tests.bzl | 4 - - CMakeLists.txt | 6 +- - sources.json | 11 +- - src/crypto/CMakeLists.txt | 7 +- - src/crypto/kyber/fips202.c | 699 +++++++ - src/crypto/kyber/fips202.h | 29 + + CMakeLists.txt | 4 +- + sources.json | 9 +- + src/crypto/CMakeLists.txt | 5 +- src/crypto/kyber/internal.h | 91 - - src/crypto/kyber/ipdwing.c | 110 ++ src/crypto/kyber/keccak.c | 204 -- - src/crypto/kyber/kyber.c | 2319 +++++++++++++++------- - src/crypto/kyber/kyber.h | 29 + + src/crypto/kyber/kyber.c | 2865 ++++++++++++++++++++------- src/crypto/kyber/kyber512.c | 5 + src/crypto/kyber/kyber768.c | 4 + src/crypto/kyber/kyber_test.cc | 229 --- - src/crypto/obj/obj_dat.h | 17 +- - src/crypto/obj/obj_mac.num | 4 + - src/crypto/obj/objects.txt | 6 +- - src/include/openssl/kyber.h | 252 ++- - src/include/openssl/nid.h | 12 + - src/include/openssl/ssl.h | 4 + + src/crypto/obj/obj_dat.h | 14 +- + src/crypto/obj/obj_mac.num | 3 + + src/crypto/obj/objects.txt | 5 +- + src/include/openssl/kyber.h | 199 +- + src/include/openssl/nid.h | 9 + + src/include/openssl/ssl.h | 3 + src/sources.cmake | 2 - - src/ssl/extensions.cc | 4 + - src/ssl/ssl_key_share.cc | 493 ++++- + src/ssl/extensions.cc | 3 + + src/ssl/ssl_key_share.cc | 412 +++- src/ssl/ssl_lib.cc | 2 +- - src/ssl/ssl_test.cc | 29 +- + src/ssl/ssl_test.cc | 25 +- src/tool/speed.cc | 162 +- - 30 files changed, 3276 insertions(+), 5445 deletions(-) - create mode 100644 src/crypto/kyber/fips202.c - create mode 100644 src/crypto/kyber/fips202.h + 26 files changed, 2797 insertions(+), 5447 deletions(-) delete mode 100644 src/crypto/kyber/internal.h - create mode 100644 src/crypto/kyber/ipdwing.c delete mode 100644 src/crypto/kyber/keccak.c - create mode 100644 src/crypto/kyber/kyber.h create mode 100644 src/crypto/kyber/kyber512.c create mode 100644 src/crypto/kyber/kyber768.c delete mode 100644 src/crypto/kyber/kyber_test.cc diff --git a/BUILD.generated.bzl b/BUILD.generated.bzl -index 738e1055f..d1d232399 100644 +index 738e1055f..9466757a2 100644 --- a/BUILD.generated.bzl +++ b/BUILD.generated.bzl @@ -253,7 +253,6 @@ crypto_internal_headers = [ @@ -79,16 +67,14 @@ index 738e1055f..d1d232399 100644 "src/crypto/lhash/internal.h", "src/crypto/obj/obj_dat.h", "src/crypto/pkcs7/internal.h", -@@ -382,8 +381,10 @@ crypto_sources = [ +@@ -382,8 +381,8 @@ crypto_sources = [ "src/crypto/fipsmodule/fips_shared_support.c", "src/crypto/hpke/hpke.c", "src/crypto/hrss/hrss.c", - "src/crypto/kyber/keccak.c", - "src/crypto/kyber/kyber.c", -+ "src/crypto/kyber/fips202.c", + "src/crypto/kyber/kyber512.c", + "src/crypto/kyber/kyber768.c", -+ "src/crypto/kyber/ipdwing.c", "src/crypto/lhash/lhash.c", "src/crypto/mem.c", "src/crypto/obj/obj.c", @@ -122,40 +108,36 @@ index 92dec1e01..8f70dedc0 100644 "src/crypto/pkcs8/test/no_encryption.p12", "src/crypto/pkcs8/test/nss.p12", diff --git a/CMakeLists.txt b/CMakeLists.txt -index faed2befa..678a0167a 100644 +index faed2befa..931c0e3a8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt -@@ -375,8 +375,10 @@ add_library( +@@ -375,8 +375,8 @@ add_library( src/crypto/fipsmodule/fips_shared_support.c src/crypto/hpke/hpke.c src/crypto/hrss/hrss.c - src/crypto/kyber/keccak.c - src/crypto/kyber/kyber.c -+ src/crypto/kyber/fips202.c + src/crypto/kyber/kyber512.c + src/crypto/kyber/kyber768.c -+ src/crypto/kyber/ipdwing.c src/crypto/lhash/lhash.c src/crypto/mem.c src/crypto/obj/obj.c diff --git a/sources.json b/sources.json -index 4c0048e1d..d021a14b1 100644 +index 4c0048e1d..f6ea5c40f 100644 --- a/sources.json +++ b/sources.json -@@ -111,8 +111,10 @@ +@@ -111,8 +111,8 @@ "src/crypto/fipsmodule/fips_shared_support.c", "src/crypto/hpke/hpke.c", "src/crypto/hrss/hrss.c", - "src/crypto/kyber/keccak.c", - "src/crypto/kyber/kyber.c", -+ "src/crypto/kyber/fips202.c", + "src/crypto/kyber/kyber512.c", + "src/crypto/kyber/kyber768.c", -+ "src/crypto/kyber/ipdwing.c", "src/crypto/lhash/lhash.c", "src/crypto/mem.c", "src/crypto/obj/obj.c", -@@ -549,7 +551,6 @@ +@@ -549,7 +549,6 @@ "src/crypto/hpke/hpke_test.cc", "src/crypto/hrss/hrss_test.cc", "src/crypto/impl_dispatch_test.cc", @@ -163,7 +145,7 @@ index 4c0048e1d..d021a14b1 100644 "src/crypto/lhash/lhash_test.cc", "src/crypto/obj/obj_test.cc", "src/crypto/pem/pem_test.cc", -@@ -634,8 +635,6 @@ +@@ -634,8 +633,6 @@ "src/crypto/fipsmodule/rand/ctrdrbg_vectors.txt", "src/crypto/hmac_extra/hmac_tests.txt", "src/crypto/hpke/hpke_test_vectors.txt", @@ -172,7 +154,7 @@ index 4c0048e1d..d021a14b1 100644 "src/crypto/pkcs8/test/empty_password.p12", "src/crypto/pkcs8/test/no_encryption.p12", "src/crypto/pkcs8/test/nss.p12", -@@ -1060,4 +1059,4 @@ +@@ -1060,4 +1057,4 @@ "urandom_test": [ "src/crypto/fipsmodule/rand/urandom_test.cc" ] @@ -180,23 +162,21 @@ index 4c0048e1d..d021a14b1 100644 \ No newline at end of file +} diff --git a/src/crypto/CMakeLists.txt b/src/crypto/CMakeLists.txt -index cdb5ddca1..9dcb7a566 100644 +index cdb5ddca1..2052fa791 100644 --- a/src/crypto/CMakeLists.txt +++ b/src/crypto/CMakeLists.txt -@@ -170,8 +170,10 @@ add_library( +@@ -170,8 +170,8 @@ add_library( ex_data.c hpke/hpke.c hrss/hrss.c - kyber/keccak.c - kyber/kyber.c -+ kyber/fips202.c + kyber/kyber512.c + kyber/kyber768.c -+ kyber/ipdwing.c lhash/lhash.c mem.c obj/obj.c -@@ -400,7 +402,6 @@ add_executable( +@@ -400,7 +400,6 @@ add_executable( hmac_extra/hmac_test.cc hrss/hrss_test.cc impl_dispatch_test.cc @@ -204,746 +184,6 @@ index cdb5ddca1..9dcb7a566 100644 lhash/lhash_test.cc obj/obj_test.cc pem/pem_test.cc -diff --git a/src/crypto/kyber/fips202.c b/src/crypto/kyber/fips202.c -new file mode 100644 -index 000000000..9713a4f7e ---- /dev/null -+++ b/src/crypto/kyber/fips202.c -@@ -0,0 +1,699 @@ -+/* Based on the public domain implementation in crypto_hash/keccakc512/simple/ from -+ * http://bench.cr.yp.to/supercop.html by Ronny Van Keer and the public domain "TweetFips202" -+ * implementation from https://twitter.com/tweetfips202 by Gilles Van Assche, Daniel J. Bernstein, -+ * and Peter Schwabe */ -+ -+#include "fips202.h" -+ -+#define NROUNDS 24 -+#define ROL(a, offset) ((a << offset) ^ (a >> (64-offset))) -+ -+/************************************************* -+* Name: load64 -+* -+* Description: Load 8 bytes into uint64_t in little-endian order -+* -+* Arguments: - const uint8_t *x: pointer to input byte array -+* -+* Returns the loaded 64-bit unsigned integer -+**************************************************/ -+static uint64_t load64(const uint8_t x[8]) { -+ unsigned int i; -+ uint64_t r = 0; -+ -+ for(i=0;i<8;i++) -+ r |= (uint64_t)x[i] << 8*i; -+ -+ return r; -+} -+ -+/************************************************* -+* Name: store64 -+* -+* Description: Store a 64-bit integer to array of 8 bytes in little-endian order -+* -+* Arguments: - uint8_t *x: pointer to the output byte array (allocated) -+* - uint64_t u: input 64-bit unsigned integer -+**************************************************/ -+static void store64(uint8_t x[8], uint64_t u) { -+ unsigned int i; -+ -+ for(i=0;i<8;i++) -+ x[i] = u >> 8*i; -+} -+ -+/* Keccak round constants */ -+static const uint64_t KeccakF_RoundConstants[NROUNDS] = { -+ (uint64_t)0x0000000000000001ULL, -+ (uint64_t)0x0000000000008082ULL, -+ (uint64_t)0x800000000000808aULL, -+ (uint64_t)0x8000000080008000ULL, -+ (uint64_t)0x000000000000808bULL, -+ (uint64_t)0x0000000080000001ULL, -+ (uint64_t)0x8000000080008081ULL, -+ (uint64_t)0x8000000000008009ULL, -+ (uint64_t)0x000000000000008aULL, -+ (uint64_t)0x0000000000000088ULL, -+ (uint64_t)0x0000000080008009ULL, -+ (uint64_t)0x000000008000000aULL, -+ (uint64_t)0x000000008000808bULL, -+ (uint64_t)0x800000000000008bULL, -+ (uint64_t)0x8000000000008089ULL, -+ (uint64_t)0x8000000000008003ULL, -+ (uint64_t)0x8000000000008002ULL, -+ (uint64_t)0x8000000000000080ULL, -+ (uint64_t)0x000000000000800aULL, -+ (uint64_t)0x800000008000000aULL, -+ (uint64_t)0x8000000080008081ULL, -+ (uint64_t)0x8000000000008080ULL, -+ (uint64_t)0x0000000080000001ULL, -+ (uint64_t)0x8000000080008008ULL -+}; -+ -+/************************************************* -+* Name: KeccakF1600_StatePermute -+* -+* Description: The Keccak F1600 Permutation -+* -+* Arguments: - uint64_t *state: pointer to input/output Keccak state -+**************************************************/ -+static void KeccakF1600_StatePermute(uint64_t state[25]) -+{ -+ int round; -+ -+ uint64_t Aba, Abe, Abi, Abo, Abu; -+ uint64_t Aga, Age, Agi, Ago, Agu; -+ uint64_t Aka, Ake, Aki, Ako, Aku; -+ uint64_t Ama, Ame, Ami, Amo, Amu; -+ uint64_t Asa, Ase, Asi, Aso, Asu; -+ uint64_t BCa, BCe, BCi, BCo, BCu; -+ uint64_t Da, De, Di, Do, Du; -+ uint64_t Eba, Ebe, Ebi, Ebo, Ebu; -+ uint64_t Ega, Ege, Egi, Ego, Egu; -+ uint64_t Eka, Eke, Eki, Eko, Eku; -+ uint64_t Ema, Eme, Emi, Emo, Emu; -+ uint64_t Esa, Ese, Esi, Eso, Esu; -+ -+ //copyFromState(A, state) -+ Aba = state[ 0]; -+ Abe = state[ 1]; -+ Abi = state[ 2]; -+ Abo = state[ 3]; -+ Abu = state[ 4]; -+ Aga = state[ 5]; -+ Age = state[ 6]; -+ Agi = state[ 7]; -+ Ago = state[ 8]; -+ Agu = state[ 9]; -+ Aka = state[10]; -+ Ake = state[11]; -+ Aki = state[12]; -+ Ako = state[13]; -+ Aku = state[14]; -+ Ama = state[15]; -+ Ame = state[16]; -+ Ami = state[17]; -+ Amo = state[18]; -+ Amu = state[19]; -+ Asa = state[20]; -+ Ase = state[21]; -+ Asi = state[22]; -+ Aso = state[23]; -+ Asu = state[24]; -+ -+ for(round = 0; round < NROUNDS; round += 2) { -+ // prepareTheta -+ BCa = Aba^Aga^Aka^Ama^Asa; -+ BCe = Abe^Age^Ake^Ame^Ase; -+ BCi = Abi^Agi^Aki^Ami^Asi; -+ BCo = Abo^Ago^Ako^Amo^Aso; -+ BCu = Abu^Agu^Aku^Amu^Asu; -+ -+ //thetaRhoPiChiIotaPrepareTheta(round, A, E) -+ Da = BCu^ROL(BCe, 1); -+ De = BCa^ROL(BCi, 1); -+ Di = BCe^ROL(BCo, 1); -+ Do = BCi^ROL(BCu, 1); -+ Du = BCo^ROL(BCa, 1); -+ -+ Aba ^= Da; -+ BCa = Aba; -+ Age ^= De; -+ BCe = ROL(Age, 44); -+ Aki ^= Di; -+ BCi = ROL(Aki, 43); -+ Amo ^= Do; -+ BCo = ROL(Amo, 21); -+ Asu ^= Du; -+ BCu = ROL(Asu, 14); -+ Eba = BCa ^((~BCe)& BCi ); -+ Eba ^= (uint64_t)KeccakF_RoundConstants[round]; -+ Ebe = BCe ^((~BCi)& BCo ); -+ Ebi = BCi ^((~BCo)& BCu ); -+ Ebo = BCo ^((~BCu)& BCa ); -+ Ebu = BCu ^((~BCa)& BCe ); -+ -+ Abo ^= Do; -+ BCa = ROL(Abo, 28); -+ Agu ^= Du; -+ BCe = ROL(Agu, 20); -+ Aka ^= Da; -+ BCi = ROL(Aka, 3); -+ Ame ^= De; -+ BCo = ROL(Ame, 45); -+ Asi ^= Di; -+ BCu = ROL(Asi, 61); -+ Ega = BCa ^((~BCe)& BCi ); -+ Ege = BCe ^((~BCi)& BCo ); -+ Egi = BCi ^((~BCo)& BCu ); -+ Ego = BCo ^((~BCu)& BCa ); -+ Egu = BCu ^((~BCa)& BCe ); -+ -+ Abe ^= De; -+ BCa = ROL(Abe, 1); -+ Agi ^= Di; -+ BCe = ROL(Agi, 6); -+ Ako ^= Do; -+ BCi = ROL(Ako, 25); -+ Amu ^= Du; -+ BCo = ROL(Amu, 8); -+ Asa ^= Da; -+ BCu = ROL(Asa, 18); -+ Eka = BCa ^((~BCe)& BCi ); -+ Eke = BCe ^((~BCi)& BCo ); -+ Eki = BCi ^((~BCo)& BCu ); -+ Eko = BCo ^((~BCu)& BCa ); -+ Eku = BCu ^((~BCa)& BCe ); -+ -+ Abu ^= Du; -+ BCa = ROL(Abu, 27); -+ Aga ^= Da; -+ BCe = ROL(Aga, 36); -+ Ake ^= De; -+ BCi = ROL(Ake, 10); -+ Ami ^= Di; -+ BCo = ROL(Ami, 15); -+ Aso ^= Do; -+ BCu = ROL(Aso, 56); -+ Ema = BCa ^((~BCe)& BCi ); -+ Eme = BCe ^((~BCi)& BCo ); -+ Emi = BCi ^((~BCo)& BCu ); -+ Emo = BCo ^((~BCu)& BCa ); -+ Emu = BCu ^((~BCa)& BCe ); -+ -+ Abi ^= Di; -+ BCa = ROL(Abi, 62); -+ Ago ^= Do; -+ BCe = ROL(Ago, 55); -+ Aku ^= Du; -+ BCi = ROL(Aku, 39); -+ Ama ^= Da; -+ BCo = ROL(Ama, 41); -+ Ase ^= De; -+ BCu = ROL(Ase, 2); -+ Esa = BCa ^((~BCe)& BCi ); -+ Ese = BCe ^((~BCi)& BCo ); -+ Esi = BCi ^((~BCo)& BCu ); -+ Eso = BCo ^((~BCu)& BCa ); -+ Esu = BCu ^((~BCa)& BCe ); -+ -+ // prepareTheta -+ BCa = Eba^Ega^Eka^Ema^Esa; -+ BCe = Ebe^Ege^Eke^Eme^Ese; -+ BCi = Ebi^Egi^Eki^Emi^Esi; -+ BCo = Ebo^Ego^Eko^Emo^Eso; -+ BCu = Ebu^Egu^Eku^Emu^Esu; -+ -+ //thetaRhoPiChiIotaPrepareTheta(round+1, E, A) -+ Da = BCu^ROL(BCe, 1); -+ De = BCa^ROL(BCi, 1); -+ Di = BCe^ROL(BCo, 1); -+ Do = BCi^ROL(BCu, 1); -+ Du = BCo^ROL(BCa, 1); -+ -+ Eba ^= Da; -+ BCa = Eba; -+ Ege ^= De; -+ BCe = ROL(Ege, 44); -+ Eki ^= Di; -+ BCi = ROL(Eki, 43); -+ Emo ^= Do; -+ BCo = ROL(Emo, 21); -+ Esu ^= Du; -+ BCu = ROL(Esu, 14); -+ Aba = BCa ^((~BCe)& BCi ); -+ Aba ^= (uint64_t)KeccakF_RoundConstants[round+1]; -+ Abe = BCe ^((~BCi)& BCo ); -+ Abi = BCi ^((~BCo)& BCu ); -+ Abo = BCo ^((~BCu)& BCa ); -+ Abu = BCu ^((~BCa)& BCe ); -+ -+ Ebo ^= Do; -+ BCa = ROL(Ebo, 28); -+ Egu ^= Du; -+ BCe = ROL(Egu, 20); -+ Eka ^= Da; -+ BCi = ROL(Eka, 3); -+ Eme ^= De; -+ BCo = ROL(Eme, 45); -+ Esi ^= Di; -+ BCu = ROL(Esi, 61); -+ Aga = BCa ^((~BCe)& BCi ); -+ Age = BCe ^((~BCi)& BCo ); -+ Agi = BCi ^((~BCo)& BCu ); -+ Ago = BCo ^((~BCu)& BCa ); -+ Agu = BCu ^((~BCa)& BCe ); -+ -+ Ebe ^= De; -+ BCa = ROL(Ebe, 1); -+ Egi ^= Di; -+ BCe = ROL(Egi, 6); -+ Eko ^= Do; -+ BCi = ROL(Eko, 25); -+ Emu ^= Du; -+ BCo = ROL(Emu, 8); -+ Esa ^= Da; -+ BCu = ROL(Esa, 18); -+ Aka = BCa ^((~BCe)& BCi ); -+ Ake = BCe ^((~BCi)& BCo ); -+ Aki = BCi ^((~BCo)& BCu ); -+ Ako = BCo ^((~BCu)& BCa ); -+ Aku = BCu ^((~BCa)& BCe ); -+ -+ Ebu ^= Du; -+ BCa = ROL(Ebu, 27); -+ Ega ^= Da; -+ BCe = ROL(Ega, 36); -+ Eke ^= De; -+ BCi = ROL(Eke, 10); -+ Emi ^= Di; -+ BCo = ROL(Emi, 15); -+ Eso ^= Do; -+ BCu = ROL(Eso, 56); -+ Ama = BCa ^((~BCe)& BCi ); -+ Ame = BCe ^((~BCi)& BCo ); -+ Ami = BCi ^((~BCo)& BCu ); -+ Amo = BCo ^((~BCu)& BCa ); -+ Amu = BCu ^((~BCa)& BCe ); -+ -+ Ebi ^= Di; -+ BCa = ROL(Ebi, 62); -+ Ego ^= Do; -+ BCe = ROL(Ego, 55); -+ Eku ^= Du; -+ BCi = ROL(Eku, 39); -+ Ema ^= Da; -+ BCo = ROL(Ema, 41); -+ Ese ^= De; -+ BCu = ROL(Ese, 2); -+ Asa = BCa ^((~BCe)& BCi ); -+ Ase = BCe ^((~BCi)& BCo ); -+ Asi = BCi ^((~BCo)& BCu ); -+ Aso = BCo ^((~BCu)& BCa ); -+ Asu = BCu ^((~BCa)& BCe ); -+ } -+ -+ //copyToState(state, A) -+ state[ 0] = Aba; -+ state[ 1] = Abe; -+ state[ 2] = Abi; -+ state[ 3] = Abo; -+ state[ 4] = Abu; -+ state[ 5] = Aga; -+ state[ 6] = Age; -+ state[ 7] = Agi; -+ state[ 8] = Ago; -+ state[ 9] = Agu; -+ state[10] = Aka; -+ state[11] = Ake; -+ state[12] = Aki; -+ state[13] = Ako; -+ state[14] = Aku; -+ state[15] = Ama; -+ state[16] = Ame; -+ state[17] = Ami; -+ state[18] = Amo; -+ state[19] = Amu; -+ state[20] = Asa; -+ state[21] = Ase; -+ state[22] = Asi; -+ state[23] = Aso; -+ state[24] = Asu; -+} -+ -+ -+/************************************************* -+* Name: keccak_squeeze -+* -+* Description: Squeeze step of Keccak. Squeezes arbitratrily many bytes. -+* Modifies the state. Can be called multiple times to keep -+* squeezing, i.e., is incremental. -+* -+* Arguments: - uint8_t *out: pointer to output -+* - size_t outlen: number of bytes to be squeezed (written to out) -+* - uint64_t *s: pointer to input/output Keccak state -+* - unsigned int pos: number of bytes in current block already squeezed -+* - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) -+* -+* Returns new position pos in current block -+**************************************************/ -+static unsigned int keccak_squeeze(uint8_t *out, -+ size_t outlen, -+ uint64_t s[25], -+ unsigned int pos, -+ unsigned int r) -+{ -+ unsigned int i; -+ -+ while(outlen) { -+ if(pos == r) { -+ KeccakF1600_StatePermute(s); -+ pos = 0; -+ } -+ for(i=pos;i < r && i < pos+outlen; i++) -+ *out++ = s[i/8] >> 8*(i%8); -+ outlen -= i-pos; -+ pos = i; -+ } -+ -+ return pos; -+} -+ -+/************************************************* -+* Name: keccak_init -+* -+* Description: Initializes the Keccak state. -+* -+* Arguments: - uint64_t *s: pointer to Keccak state -+**************************************************/ -+static void keccak_init(uint64_t s[25]) -+{ -+ unsigned int i; -+ for(i=0;i<25;i++) -+ s[i] = 0; -+} -+ -+ -+/************************************************* -+* Name: keccak_absorb -+* -+* Description: Absorb step of Keccak; incremental. -+* -+* Arguments: - uint64_t *s: pointer to Keccak state -+* - unsigned int pos: position in current block to be absorbed -+* - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) -+* - const uint8_t *in: pointer to input to be absorbed into s -+* - size_t inlen: length of input in bytes -+* -+* Returns new position pos in current block -+**************************************************/ -+static unsigned int keccak_absorb(uint64_t s[25], -+ unsigned int pos, -+ unsigned int r, -+ const uint8_t *in, -+ size_t inlen) -+{ -+ unsigned int i; -+ -+ while(pos+inlen >= r) { -+ for(i=pos;i= r) { -+ for(i=0;is, SHAKE128_RATE, in, inlen, 0x1F); -+ state->pos = SHAKE128_RATE; -+} -+ -+/************************************************* -+* Name: shake128_squeezeblocks -+* -+* Description: Squeeze step of SHAKE128 XOF. Squeezes full blocks of -+* SHAKE128_RATE bytes each. Can be called multiple times -+* to keep squeezing. Assumes new block has not yet been -+* started (state->pos = SHAKE128_RATE). -+* -+* Arguments: - uint8_t *out: pointer to output blocks -+* - size_t nblocks: number of blocks to be squeezed (written to output) -+* - keccak_state *s: pointer to input/output Keccak state -+**************************************************/ -+void shake128_squeezeblocks(uint8_t *out, size_t nblocks, keccak_state *state) -+{ -+ keccak_squeezeblocks(out, nblocks, state->s, SHAKE128_RATE); -+} -+ -+/************************************************* -+* Name: shake256_squeeze -+* -+* Description: Squeeze step of SHAKE256 XOF. Squeezes arbitraily many -+* bytes. Can be called multiple times to keep squeezing. -+* -+* Arguments: - uint8_t *out: pointer to output blocks -+* - size_t outlen : number of bytes to be squeezed (written to output) -+* - keccak_state *s: pointer to input/output Keccak state -+**************************************************/ -+void shake256_squeeze(uint8_t *out, size_t outlen, keccak_state *state) -+{ -+ state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE256_RATE); -+} -+ -+/************************************************* -+* Name: shake256_init -+* -+* Description: Initilizes Keccak state for use as SHAKE256 XOF -+* -+* Arguments: - keccak_state *state: pointer to (uninitialized) Keccak state -+**************************************************/ -+void shake256_init(keccak_state *state) -+{ -+ keccak_init(state->s); -+ state->pos = 0; -+} -+ -+/************************************************* -+* Name: shake256_absorb -+* -+* Description: Absorb step of the SHAKE256 XOF; incremental. -+* -+* Arguments: - keccak_state *state: pointer to (initialized) output Keccak state -+* - const uint8_t *in: pointer to input to be absorbed into s -+* - size_t inlen: length of input in bytes -+**************************************************/ -+void shake256_absorb(keccak_state *state, const uint8_t *in, size_t inlen) -+{ -+ state->pos = keccak_absorb(state->s, state->pos, SHAKE256_RATE, in, inlen); -+} -+ -+/************************************************* -+* Name: shake256_finalize -+* -+* Description: Finalize absorb step of the SHAKE256 XOF. -+* -+* Arguments: - keccak_state *state: pointer to Keccak state -+**************************************************/ -+void shake256_finalize(keccak_state *state) -+{ -+ keccak_finalize(state->s, state->pos, SHAKE256_RATE, 0x1F); -+ state->pos = SHAKE256_RATE; -+} -+ -+/************************************************* -+* Name: shake256_absorb_once -+* -+* Description: Initialize, absorb into and finalize SHAKE256 XOF; non-incremental. -+* -+* Arguments: - keccak_state *state: pointer to (uninitialized) output Keccak state -+* - const uint8_t *in: pointer to input to be absorbed into s -+* - size_t inlen: length of input in bytes -+**************************************************/ -+void shake256_absorb_once(keccak_state *state, const uint8_t *in, size_t inlen) -+{ -+ keccak_absorb_once(state->s, SHAKE256_RATE, in, inlen, 0x1F); -+ state->pos = SHAKE256_RATE; -+} -+ -+/************************************************* -+* Name: shake256_squeezeblocks -+* -+* Description: Squeeze step of SHAKE256 XOF. Squeezes full blocks of -+* SHAKE256_RATE bytes each. Can be called multiple times -+* to keep squeezing. Assumes next block has not yet been -+* started (state->pos = SHAKE256_RATE). -+* -+* Arguments: - uint8_t *out: pointer to output blocks -+* - size_t nblocks: number of blocks to be squeezed (written to output) -+* - keccak_state *s: pointer to input/output Keccak state -+**************************************************/ -+void shake256_squeezeblocks(uint8_t *out, size_t nblocks, keccak_state *state) -+{ -+ keccak_squeezeblocks(out, nblocks, state->s, SHAKE256_RATE); -+} -+ -+/************************************************* -+* Name: shake256 -+* -+* Description: SHAKE256 XOF with non-incremental API -+* -+* Arguments: - uint8_t *out: pointer to output -+* - size_t outlen: requested output length in bytes -+* - const uint8_t *in: pointer to input -+* - size_t inlen: length of input in bytes -+**************************************************/ -+void shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) -+{ -+ size_t nblocks; -+ keccak_state state; -+ -+ shake256_absorb_once(&state, in, inlen); -+ nblocks = outlen/SHAKE256_RATE; -+ shake256_squeezeblocks(out, nblocks, &state); -+ outlen -= nblocks*SHAKE256_RATE; -+ out += nblocks*SHAKE256_RATE; -+ shake256_squeeze(out, outlen, &state); -+} -+ -+/************************************************* -+* Name: sha3_256 -+* -+* Description: SHA3-256 with non-incremental API -+* -+* Arguments: - uint8_t *h: pointer to output (32 bytes) -+* - const uint8_t *in: pointer to input -+* - size_t inlen: length of input in bytes -+**************************************************/ -+void sha3_256(uint8_t h[32], const uint8_t *in, size_t inlen) -+{ -+ unsigned int i; -+ uint64_t s[25]; -+ -+ keccak_absorb_once(s, SHA3_256_RATE, in, inlen, 0x06); -+ KeccakF1600_StatePermute(s); -+ for(i=0;i<4;i++) -+ store64(h+8*i,s[i]); -+} -+ -+/************************************************* -+* Name: sha3_512 -+* -+* Description: SHA3-512 with non-incremental API -+* -+* Arguments: - uint8_t *h: pointer to output (64 bytes) -+* - const uint8_t *in: pointer to input -+* - size_t inlen: length of input in bytes -+**************************************************/ -+void sha3_512(uint8_t h[64], const uint8_t *in, size_t inlen) -+{ -+ unsigned int i; -+ uint64_t s[25]; -+ -+ keccak_absorb_once(s, SHA3_512_RATE, in, inlen, 0x06); -+ KeccakF1600_StatePermute(s); -+ for(i=0;i<8;i++) -+ store64(h+8*i,s[i]); -+} -+ -+ -diff --git a/src/crypto/kyber/fips202.h b/src/crypto/kyber/fips202.h -new file mode 100644 -index 000000000..7c37570bc ---- /dev/null -+++ b/src/crypto/kyber/fips202.h -@@ -0,0 +1,29 @@ -+#ifndef OPENSSL_HEADER_KYBER_FIPS202_H -+#define OPENSSL_HEADER_KYBER_FIPS202_H -+ -+#include -+#include -+ -+#define SHAKE128_RATE 168 -+#define SHAKE256_RATE 136 -+#define SHA3_256_RATE 136 -+#define SHA3_512_RATE 72 -+ -+typedef struct { -+ uint64_t s[25]; -+ unsigned int pos; -+} keccak_state; -+ -+void shake128_absorb_once(keccak_state *state, const uint8_t *in, size_t inlen); -+void shake128_squeezeblocks(uint8_t *out, size_t nblocks, keccak_state *state); -+void shake256_squeeze(uint8_t *out, size_t outlen, keccak_state *state); -+void shake256_init(keccak_state *state); -+void shake256_absorb(keccak_state *state, const uint8_t *in, size_t inlen); -+void shake256_finalize(keccak_state *state); -+void shake256_absorb_once(keccak_state *state, const uint8_t *in, size_t inlen); -+void shake256_squeezeblocks(uint8_t *out, size_t nblocks, keccak_state *state); -+void shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen); -+void sha3_512(uint8_t h[64], const uint8_t *in, size_t inlen); -+void sha3_256(uint8_t h[32], const uint8_t *in, size_t inlen); -+ -+#endif diff --git a/src/crypto/kyber/internal.h b/src/crypto/kyber/internal.h deleted file mode 100644 index b3bfa86b8..000000000 @@ -1041,122 +281,6 @@ index b3bfa86b8..000000000 -#endif - -#endif // OPENSSL_HEADER_CRYPTO_KYBER_INTERNAL_H -diff --git a/src/crypto/kyber/ipdwing.c b/src/crypto/kyber/ipdwing.c -new file mode 100644 -index 000000000..d55cfefc9 ---- /dev/null -+++ b/src/crypto/kyber/ipdwing.c -@@ -0,0 +1,110 @@ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include "fips202.h" -+#include "kyber.h" -+ -+static const char *label = "\\.//^\\"; -+ -+static void combiner( -+ uint8_t out[32], -+ const uint8_t ss_m[32], -+ const uint8_t ss_x[32], -+ const uint8_t ct_x[32], -+ const uint8_t pk_x[32]) { -+ uint8_t buf[6+32*4]; -+ memcpy(buf, label, 6); -+ memcpy(buf+6, ss_m, 32); -+ memcpy(buf+6+32, ss_x, 32); -+ memcpy(buf+6+32*2, ct_x, 32); -+ memcpy(buf+6+32*3, pk_x, 32); -+ sha3_256(out, buf, 6+32*4); -+} -+ -+void IPDWING_generate_key( -+ struct IPDWING_public_key *out_pub, -+ struct IPDWING_private_key *out_priv, -+ const uint8_t seed[IPDWING_GENERATE_KEY_BYTES]) { -+ KYBER768_generate_key( -+ &out_pub->m, -+ &out_priv->m, -+ seed); -+ memcpy(out_priv->x, seed+64, 32); -+ X25519_public_from_private(out_pub->x, out_priv->x); -+ memcpy(out_priv->xpub, out_pub->x, 32); -+} -+ -+void IPDWING_encap( -+ uint8_t out_ciphertext[IPDWING_CIPHERTEXT_BYTES], -+ uint8_t ss[IPDWING_KEY_BYTES], -+ const struct IPDWING_public_key *in_pub, -+ const uint8_t seed[IPDWING_ENCAP_BYTES]) { -+ -+ uint8_t ss_m[32]; -+ uint8_t ss_x[32]; -+ uint8_t *ct_x = out_ciphertext + KYBER768_CIPHERTEXT_BYTES; -+ const uint8_t *ek_x = seed + 32; -+ X25519_public_from_private(ct_x, ek_x); -+ -+ X25519( -+ ss_x, -+ ek_x, -+ in_pub->x -+ ); -+ -+ KYBER768_encap2( -+ out_ciphertext, -+ ss_m, -+ &in_pub->m, -+ seed, -+ 1 -+ ); -+ -+ combiner(ss, ss_m, ss_x, ct_x, in_pub->x); -+} -+ -+void IPDWING_decap( -+ uint8_t out_shared_key[IPDWING_KEY_BYTES], -+ const struct IPDWING_private_key *in_priv, -+ const uint8_t *ct) { -+ -+ uint8_t ss_m[32]; -+ uint8_t ss_x[32]; -+ const uint8_t *ct_x = ct + KYBER768_CIPHERTEXT_BYTES; -+ -+ KYBER768_decap2( -+ ss_m, -+ &in_priv->m, -+ ct, -+ KYBER768_CIPHERTEXT_BYTES, -+ 1 -+ ); -+ -+ X25519( -+ ss_x, -+ in_priv->x, -+ ct_x -+ ); -+ -+ combiner(out_shared_key, ss_m, ss_x, ct_x, in_priv->xpub); -+} -+ -+void IPDWING_marshal_public_key( -+ uint8_t out[IPDWING_PUBLIC_KEY_BYTES], -+ const struct IPDWING_public_key *in) { -+ KYBER768_marshal_public_key(out, &in->m); -+ memcpy(out + KYBER768_PUBLIC_KEY_BYTES, in->x, 32); -+} -+ -+void IPDWING_parse_public_key( -+ struct IPDWING_public_key *out, -+ const uint8_t in[IPDWING_PUBLIC_KEY_BYTES]) { -+ KYBER768_parse_public_key(&out->m, in); -+ memcpy(out->x, in + KYBER768_PUBLIC_KEY_BYTES, 32); -+} -+ diff --git a/src/crypto/kyber/keccak.c b/src/crypto/kyber/keccak.c deleted file mode 100644 index f1c012d11..000000000 @@ -1368,10 +492,10 @@ index f1c012d11..000000000 - } -} diff --git a/src/crypto/kyber/kyber.c b/src/crypto/kyber/kyber.c -index 776c085f9..5acd45cd9 100644 +index 776c085f9..346d4daec 100644 --- a/src/crypto/kyber/kyber.c +++ b/src/crypto/kyber/kyber.c -@@ -1,833 +1,1706 @@ +@@ -1,833 +1,2252 @@ -/* Copyright (c) 2023, Google Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any @@ -1410,26 +534,21 @@ index 776c085f9..5acd45cd9 100644 +// implementation or https://github.com/cloudflare/circl/tree/main/pke/kyber +// +// - Option to keep A stored in private key. - --#include ++ +#ifndef KYBER_K +#error "Don't compile this file direcly" +#endif --#include --#include -+#include + #include +#include +-#include +-#include +- -#include -#include -+#include -+#include -+#include - -+#include "fips202.h" -+#include "kyber.h" - #include "../internal.h" +- +-#include "../internal.h" -#include "./internal.h" - - @@ -1493,6 +612,9 @@ index 776c085f9..5acd45cd9 100644 - 2099, 561, 2466, 2594, 2804, 1092, 403, 1026, 1143, 2150, 2775, 886, - 1722, 1212, 1874, 1029, 2110, 2935, 885, 2154, -}; ++#include ++#include ++#include -// kInverseNTTRoots = [pow(17, -bitreverse(i), p) for i in range(128)] -static const uint16_t kInverseNTTRoots[128] = { @@ -1589,9 +711,6 @@ index 776c085f9..5acd45cd9 100644 +#define marshal_public_key KYBER_NAMESPACE(marshal_public_key) +#define parse_public_key KYBER_NAMESPACE(parse_public_key) + -+#define decap2 KYBER_NAMESPACE(decap2) -+#define encap2 KYBER_NAMESPACE(encap2) -+ + +// +// params.h @@ -1738,6 +857,30 @@ index 776c085f9..5acd45cd9 100644 +// fips202.h +// + ++#define SHAKE128_RATE 168 ++#define SHAKE256_RATE 136 ++#define SHA3_256_RATE 136 ++#define SHA3_512_RATE 72 ++ ++typedef struct { ++ uint64_t s[25]; ++ unsigned int pos; ++} keccak_state; ++ ++static void shake128_absorb_once(keccak_state *state, const uint8_t *in, size_t inlen); ++static void shake128_squeezeblocks(uint8_t *out, size_t nblocks, keccak_state *state); ++ ++static void shake256_squeeze(uint8_t *out, size_t outlen, keccak_state *state); ++static void shake256_absorb_once(keccak_state *state, const uint8_t *in, size_t inlen); ++static void shake256_squeezeblocks(uint8_t *out, size_t nblocks, keccak_state *state); ++ ++static void shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen); ++static void sha3_256(uint8_t h[32], const uint8_t *in, size_t inlen); ++static void sha3_512(uint8_t h[64], const uint8_t *in, size_t inlen); ++ ++// ++// symmetric.h ++// + +typedef keccak_state xof_state; + @@ -1748,7 +891,6 @@ index 776c085f9..5acd45cd9 100644 + +static void kyber_shake256_prf(uint8_t *out, size_t outlen, const uint8_t key[KYBER_SYMBYTES], uint8_t nonce); + -+ +#define XOF_BLOCKBYTES SHAKE128_RATE + +#define hash_h(OUT, IN, INBYTES) sha3_256(OUT, IN, INBYTES) @@ -1972,15 +1114,6 @@ index 776c085f9..5acd45cd9 100644 +#error "This implementation requires eta1 in {2,3}" +#endif +} -+ -+static void poly_cbd_eta2(poly *r, const uint8_t buf[KYBER_ETA2*KYBER_N/4]) -+{ -+#if KYBER_ETA2 == 2 -+ cbd2(r, buf); -+#else -+#error "This implementation requires eta2 = 2" -+#endif -+} -// In place inverse number theoretic transform of a given scalar, with pairs of -// entries of s->v being interpreted as elements of GF(3329^2). Just as with the @@ -2001,6 +1134,15 @@ index 776c085f9..5acd45cd9 100644 - uint16_t even = s->c[j]; - s->c[j] = reduce_once(odd + even); - s->c[j + offset] = reduce(step_root * (even - odd + kPrime)); ++static void poly_cbd_eta2(poly *r, const uint8_t buf[KYBER_ETA2*KYBER_N/4]) ++{ ++#if KYBER_ETA2 == 2 ++ cbd2(r, buf); ++#else ++#error "This implementation requires eta2 = 2" ++#endif ++} ++ +// +// ntt.c +// @@ -2132,11 +1274,8 @@ index 776c085f9..5acd45cd9 100644 + + for(j = 0; j < 256; j++) + r[j] = fqmul(r[j], f); - } - --static void scalar_add(scalar *lhs, const scalar *rhs) { -- for (int i = 0; i < DEGREE; i++) { -- lhs->c[i] = reduce_once(lhs->c[i] + rhs->c[i]); ++} ++ +/************************************************* +* Name: basemul +* @@ -2155,8 +1294,11 @@ index 776c085f9..5acd45cd9 100644 + r[0] += fqmul(a[0], b[0]); + r[1] = fqmul(a[0], b[1]); + r[1] += fqmul(a[1], b[0]); -+} -+ + } + +-static void scalar_add(scalar *lhs, const scalar *rhs) { +- for (int i = 0; i < DEGREE; i++) { +- lhs->c[i] = reduce_once(lhs->c[i] + rhs->c[i]); +// +// poly.c +// @@ -2174,7 +1316,6 @@ index 776c085f9..5acd45cd9 100644 +{ + unsigned int i,j; + int16_t u; -+ uint32_t d0; + uint8_t t[8]; + +#if (KYBER_POLYCOMPRESSEDBYTES == 128) @@ -2183,11 +1324,7 @@ index 776c085f9..5acd45cd9 100644 + // map to positive standard representatives + u = a->coeffs[8*i+j]; + u += (u >> 15) & KYBER_Q; -+ d0 = u << 4; -+ d0 += 1665; -+ d0 *= 80635; -+ d0 >>= 28; -+ t[j] = d0 & 0xf; ++ t[j] = ((((uint16_t)u << 4) + KYBER_Q/2)/KYBER_Q) & 15; + } + + r[0] = t[0] | (t[1] << 4); @@ -2195,18 +1332,14 @@ index 776c085f9..5acd45cd9 100644 + r[2] = t[4] | (t[5] << 4); + r[3] = t[6] | (t[7] << 4); + r += 4; -+ } + } +#elif (KYBER_POLYCOMPRESSEDBYTES == 160) + for(i=0;icoeffs[8*i+j]; + u += (u >> 15) & KYBER_Q; -+ d0 = u << 5; -+ d0 += 1664; -+ d0 *= 40318; -+ d0 >>= 27; -+ t[j] = d0 & 0x1f; ++ t[j] = ((((uint32_t)u << 5) + KYBER_Q/2)/KYBER_Q) & 31; + } + + r[0] = (t[0] >> 0) | (t[1] << 5); @@ -2215,7 +1348,7 @@ index 776c085f9..5acd45cd9 100644 + r[3] = (t[4] >> 4) | (t[5] << 1) | (t[6] << 6); + r[4] = (t[6] >> 2) | (t[7] << 3); + r += 5; - } ++ } +#else +#error "KYBER_POLYCOMPRESSEDBYTES needs to be in {128, 160}" +#endif @@ -2357,7 +1490,7 @@ index 776c085f9..5acd45cd9 100644 + + for(i=0;i> j)&1); ++ mask = -(int16_t)((msg[i] >> j)&1); + r->coeffs[8*i+j] = mask & ((KYBER_Q+1)/2); } } @@ -2382,17 +1515,14 @@ index 776c085f9..5acd45cd9 100644 +static void poly_tomsg(uint8_t msg[KYBER_INDCPA_MSGBYTES], const poly *a) +{ + unsigned int i,j; -+ uint32_t t; ++ uint16_t t; + + for(i=0;icoeffs[8*i+j]; -+ t <<= 1; -+ t += 1665; -+ t *= 80635; -+ t >>= 28; -+ t &= 1; ++ t += ((int16_t)t >> 15) & KYBER_Q; ++ t = (((t << 1) + KYBER_Q/2)/KYBER_Q) & 1; + msg[i] |= t << j; } } @@ -2671,7 +1801,6 @@ index 776c085f9..5acd45cd9 100644 +static void polyvec_compress(uint8_t r[KYBER_POLYVECCOMPRESSEDBYTES], const polyvec *a) +{ + unsigned int i,j,k; -+ uint64_t d0; + +#if (KYBER_POLYVECCOMPRESSEDBYTES == (KYBER_K * 352)) + uint16_t t[8]; @@ -2680,12 +1809,7 @@ index 776c085f9..5acd45cd9 100644 + for(k=0;k<8;k++) { + t[k] = a->vec[i].coeffs[8*j+k]; + t[k] += ((int16_t)t[k] >> 15) & KYBER_Q; -+ d0 = t[k]; -+ d0 <<= 11; -+ d0 += 1664; -+ d0 *= 645084; -+ d0 >>= 31; -+ t[k] = d0 & 0x7ff; ++ t[k] = ((((uint32_t)t[k] << 11) + KYBER_Q/2)/KYBER_Q) & 0x7ff; } - element_bits_done += chunk_bits; @@ -2711,12 +1835,7 @@ index 776c085f9..5acd45cd9 100644 + for(k=0;k<4;k++) { + t[k] = a->vec[i].coeffs[4*j+k]; + t[k] += ((int16_t)t[k] >> 15) & KYBER_Q; -+ d0 = t[k]; -+ d0 <<= 10; -+ d0 += 1665; -+ d0 *= 1290167; -+ d0 >>= 32; -+ t[k] = d0 & 0x3ff; ++ t[k] = ((((uint32_t)t[k] << 10) + KYBER_Q/2)/ KYBER_Q) & 0x3ff; + } - if (out_byte_bits > 0) { @@ -2807,14 +1926,8 @@ index 776c085f9..5acd45cd9 100644 + unsigned int i; + for(i=0;ivec[i]); - } - --// Encodes an entire vector into 32*|RANK|*|bits| bytes. Note that since 256 --// (DEGREE) is divisible by 8, the individual vector entries will always fill a --// whole number of bytes, so we do not need to worry about bit packing here. --static void vector_encode(uint8_t *out, const vector *a, int bits) { -- for (int i = 0; i < RANK; i++) { -- scalar_encode(out + i * bits * DEGREE / 8, &a->v[i], bits); ++} ++ +/************************************************* +* Name: polyvec_frombytes +* @@ -2830,8 +1943,14 @@ index 776c085f9..5acd45cd9 100644 + unsigned int i; + for(i=0;ivec[i], a+i*KYBER_POLYBYTES); -+} -+ + } + +-// Encodes an entire vector into 32*|RANK|*|bits| bytes. Note that since 256 +-// (DEGREE) is divisible by 8, the individual vector entries will always fill a +-// whole number of bytes, so we do not need to worry about bit packing here. +-static void vector_encode(uint8_t *out, const vector *a, int bits) { +- for (int i = 0; i < RANK; i++) { +- scalar_encode(out + i * bits * DEGREE / 8, &a->v[i], bits); +/************************************************* +* Name: polyvec_ntt +* @@ -3350,28 +2469,35 @@ index 776c085f9..5acd45cd9 100644 - uint8_t public_key_hash[32]; - matrix m; -}; ++// ++// fips202.c ++// ++ ++/* Based on the public domain implementation in crypto_hash/keccakc512/simple/ from ++ * http://bench.cr.yp.to/supercop.html by Ronny Van Keer and the public domain "TweetFips202" ++ * implementation from https://twitter.com/tweetfips202 by Gilles Van Assche, Daniel J. Bernstein, ++ * and Peter Schwabe */ ++ ++#define NROUNDS 24 ++#define ROL(a, offset) ((a << offset) ^ (a >> (64-offset))) ++ +/************************************************* -+* Name: kyber_shake128_absorb ++* Name: load64 +* -+* Description: Absorb step of the SHAKE128 specialized for the Kyber context. ++* Description: Load 8 bytes into uint64_t in little-endian order +* -+* Arguments: - keccak_state *state: pointer to (uninitialized) output Keccak state -+* - const uint8_t *seed: pointer to KYBER_SYMBYTES input to be absorbed into state -+* - uint8_t i: additional byte of input -+* - uint8_t j: additional byte of input ++* Arguments: - const uint8_t *x: pointer to input byte array ++* ++* Returns the loaded 64-bit unsigned integer +**************************************************/ -+void kyber_shake128_absorb(keccak_state *state, -+ const uint8_t seed[KYBER_SYMBYTES], -+ uint8_t x, -+ uint8_t y) -+{ -+ uint8_t extseed[KYBER_SYMBYTES+2]; ++static uint64_t load64(const uint8_t x[8]) { ++ unsigned int i; ++ uint64_t r = 0; + -+ memcpy(extseed, seed, KYBER_SYMBYTES); -+ extseed[KYBER_SYMBYTES+0] = x; -+ extseed[KYBER_SYMBYTES+1] = y; ++ for(i=0;i<8;i++) ++ r |= (uint64_t)x[i] << 8*i; + -+ shake128_absorb_once(state, extseed, sizeof(extseed)); ++ return r; +} -static struct public_key *public_key_from_external( @@ -3382,34 +2508,51 @@ index 776c085f9..5acd45cd9 100644 - "Kyber public key align incorrect"); - return (struct public_key *)external; +/************************************************* -+* Name: kyber_shake256_prf ++* Name: store64 +* -+* Description: Usage of SHAKE256 as a PRF, concatenates secret and public input -+* and then generates outlen bytes of SHAKE256 output ++* Description: Store a 64-bit integer to array of 8 bytes in little-endian order +* -+* Arguments: - uint8_t *out: pointer to output -+* - size_t outlen: number of requested output bytes -+* - const uint8_t *key: pointer to the key (of length KYBER_SYMBYTES) -+* - uint8_t nonce: single-byte nonce (public PRF input) ++* Arguments: - uint8_t *x: pointer to the output byte array (allocated) ++* - uint64_t u: input 64-bit unsigned integer +**************************************************/ -+static void kyber_shake256_prf(uint8_t *out, size_t outlen, const uint8_t key[KYBER_SYMBYTES], uint8_t nonce) -+{ -+ uint8_t extkey[KYBER_SYMBYTES+1]; ++static void store64(uint8_t x[8], uint64_t u) { ++ unsigned int i; + -+ memcpy(extkey, key, KYBER_SYMBYTES); -+ extkey[KYBER_SYMBYTES] = nonce; -+ -+ shake256(out, outlen, extkey, sizeof(extkey)); ++ for(i=0;i<8;i++) ++ x[i] = u >> 8*i; } -struct private_key { - struct public_key pub; - vector s; - uint8_t fo_failure_secret[32]; --}; -+// -+// kem.c -+// ++/* Keccak round constants */ ++static const uint64_t KeccakF_RoundConstants[NROUNDS] = { ++ (uint64_t)0x0000000000000001ULL, ++ (uint64_t)0x0000000000008082ULL, ++ (uint64_t)0x800000000000808aULL, ++ (uint64_t)0x8000000080008000ULL, ++ (uint64_t)0x000000000000808bULL, ++ (uint64_t)0x0000000080000001ULL, ++ (uint64_t)0x8000000080008081ULL, ++ (uint64_t)0x8000000000008009ULL, ++ (uint64_t)0x000000000000008aULL, ++ (uint64_t)0x0000000000000088ULL, ++ (uint64_t)0x0000000080008009ULL, ++ (uint64_t)0x000000008000000aULL, ++ (uint64_t)0x000000008000808bULL, ++ (uint64_t)0x800000000000008bULL, ++ (uint64_t)0x8000000000008089ULL, ++ (uint64_t)0x8000000000008003ULL, ++ (uint64_t)0x8000000000008002ULL, ++ (uint64_t)0x8000000000000080ULL, ++ (uint64_t)0x000000000000800aULL, ++ (uint64_t)0x800000008000000aULL, ++ (uint64_t)0x8000000080008081ULL, ++ (uint64_t)0x8000000000008080ULL, ++ (uint64_t)0x0000000080000001ULL, ++ (uint64_t)0x8000000080008008ULL + }; -static struct private_key *private_key_from_external( - const struct KYBER_private_key *external) { @@ -3439,7 +2582,311 @@ index 776c085f9..5acd45cd9 100644 - vector_encode(vector_output, &pub->t, kLog2Prime); - if (!CBB_add_bytes(out, pub->rho, sizeof(pub->rho))) { - return 0; -- } ++/************************************************* ++* Name: KeccakF1600_StatePermute ++* ++* Description: The Keccak F1600 Permutation ++* ++* Arguments: - uint64_t *state: pointer to input/output Keccak state ++**************************************************/ ++static void KeccakF1600_StatePermute(uint64_t state[25]) ++{ ++ int round; ++ ++ uint64_t Aba, Abe, Abi, Abo, Abu; ++ uint64_t Aga, Age, Agi, Ago, Agu; ++ uint64_t Aka, Ake, Aki, Ako, Aku; ++ uint64_t Ama, Ame, Ami, Amo, Amu; ++ uint64_t Asa, Ase, Asi, Aso, Asu; ++ uint64_t BCa, BCe, BCi, BCo, BCu; ++ uint64_t Da, De, Di, Do, Du; ++ uint64_t Eba, Ebe, Ebi, Ebo, Ebu; ++ uint64_t Ega, Ege, Egi, Ego, Egu; ++ uint64_t Eka, Eke, Eki, Eko, Eku; ++ uint64_t Ema, Eme, Emi, Emo, Emu; ++ uint64_t Esa, Ese, Esi, Eso, Esu; ++ ++ //copyFromState(A, state) ++ Aba = state[ 0]; ++ Abe = state[ 1]; ++ Abi = state[ 2]; ++ Abo = state[ 3]; ++ Abu = state[ 4]; ++ Aga = state[ 5]; ++ Age = state[ 6]; ++ Agi = state[ 7]; ++ Ago = state[ 8]; ++ Agu = state[ 9]; ++ Aka = state[10]; ++ Ake = state[11]; ++ Aki = state[12]; ++ Ako = state[13]; ++ Aku = state[14]; ++ Ama = state[15]; ++ Ame = state[16]; ++ Ami = state[17]; ++ Amo = state[18]; ++ Amu = state[19]; ++ Asa = state[20]; ++ Ase = state[21]; ++ Asi = state[22]; ++ Aso = state[23]; ++ Asu = state[24]; ++ ++ for(round = 0; round < NROUNDS; round += 2) { ++ // prepareTheta ++ BCa = Aba^Aga^Aka^Ama^Asa; ++ BCe = Abe^Age^Ake^Ame^Ase; ++ BCi = Abi^Agi^Aki^Ami^Asi; ++ BCo = Abo^Ago^Ako^Amo^Aso; ++ BCu = Abu^Agu^Aku^Amu^Asu; ++ ++ //thetaRhoPiChiIotaPrepareTheta(round, A, E) ++ Da = BCu^ROL(BCe, 1); ++ De = BCa^ROL(BCi, 1); ++ Di = BCe^ROL(BCo, 1); ++ Do = BCi^ROL(BCu, 1); ++ Du = BCo^ROL(BCa, 1); ++ ++ Aba ^= Da; ++ BCa = Aba; ++ Age ^= De; ++ BCe = ROL(Age, 44); ++ Aki ^= Di; ++ BCi = ROL(Aki, 43); ++ Amo ^= Do; ++ BCo = ROL(Amo, 21); ++ Asu ^= Du; ++ BCu = ROL(Asu, 14); ++ Eba = BCa ^((~BCe)& BCi ); ++ Eba ^= (uint64_t)KeccakF_RoundConstants[round]; ++ Ebe = BCe ^((~BCi)& BCo ); ++ Ebi = BCi ^((~BCo)& BCu ); ++ Ebo = BCo ^((~BCu)& BCa ); ++ Ebu = BCu ^((~BCa)& BCe ); ++ ++ Abo ^= Do; ++ BCa = ROL(Abo, 28); ++ Agu ^= Du; ++ BCe = ROL(Agu, 20); ++ Aka ^= Da; ++ BCi = ROL(Aka, 3); ++ Ame ^= De; ++ BCo = ROL(Ame, 45); ++ Asi ^= Di; ++ BCu = ROL(Asi, 61); ++ Ega = BCa ^((~BCe)& BCi ); ++ Ege = BCe ^((~BCi)& BCo ); ++ Egi = BCi ^((~BCo)& BCu ); ++ Ego = BCo ^((~BCu)& BCa ); ++ Egu = BCu ^((~BCa)& BCe ); ++ ++ Abe ^= De; ++ BCa = ROL(Abe, 1); ++ Agi ^= Di; ++ BCe = ROL(Agi, 6); ++ Ako ^= Do; ++ BCi = ROL(Ako, 25); ++ Amu ^= Du; ++ BCo = ROL(Amu, 8); ++ Asa ^= Da; ++ BCu = ROL(Asa, 18); ++ Eka = BCa ^((~BCe)& BCi ); ++ Eke = BCe ^((~BCi)& BCo ); ++ Eki = BCi ^((~BCo)& BCu ); ++ Eko = BCo ^((~BCu)& BCa ); ++ Eku = BCu ^((~BCa)& BCe ); ++ ++ Abu ^= Du; ++ BCa = ROL(Abu, 27); ++ Aga ^= Da; ++ BCe = ROL(Aga, 36); ++ Ake ^= De; ++ BCi = ROL(Ake, 10); ++ Ami ^= Di; ++ BCo = ROL(Ami, 15); ++ Aso ^= Do; ++ BCu = ROL(Aso, 56); ++ Ema = BCa ^((~BCe)& BCi ); ++ Eme = BCe ^((~BCi)& BCo ); ++ Emi = BCi ^((~BCo)& BCu ); ++ Emo = BCo ^((~BCu)& BCa ); ++ Emu = BCu ^((~BCa)& BCe ); ++ ++ Abi ^= Di; ++ BCa = ROL(Abi, 62); ++ Ago ^= Do; ++ BCe = ROL(Ago, 55); ++ Aku ^= Du; ++ BCi = ROL(Aku, 39); ++ Ama ^= Da; ++ BCo = ROL(Ama, 41); ++ Ase ^= De; ++ BCu = ROL(Ase, 2); ++ Esa = BCa ^((~BCe)& BCi ); ++ Ese = BCe ^((~BCi)& BCo ); ++ Esi = BCi ^((~BCo)& BCu ); ++ Eso = BCo ^((~BCu)& BCa ); ++ Esu = BCu ^((~BCa)& BCe ); ++ ++ // prepareTheta ++ BCa = Eba^Ega^Eka^Ema^Esa; ++ BCe = Ebe^Ege^Eke^Eme^Ese; ++ BCi = Ebi^Egi^Eki^Emi^Esi; ++ BCo = Ebo^Ego^Eko^Emo^Eso; ++ BCu = Ebu^Egu^Eku^Emu^Esu; ++ ++ //thetaRhoPiChiIotaPrepareTheta(round+1, E, A) ++ Da = BCu^ROL(BCe, 1); ++ De = BCa^ROL(BCi, 1); ++ Di = BCe^ROL(BCo, 1); ++ Do = BCi^ROL(BCu, 1); ++ Du = BCo^ROL(BCa, 1); ++ ++ Eba ^= Da; ++ BCa = Eba; ++ Ege ^= De; ++ BCe = ROL(Ege, 44); ++ Eki ^= Di; ++ BCi = ROL(Eki, 43); ++ Emo ^= Do; ++ BCo = ROL(Emo, 21); ++ Esu ^= Du; ++ BCu = ROL(Esu, 14); ++ Aba = BCa ^((~BCe)& BCi ); ++ Aba ^= (uint64_t)KeccakF_RoundConstants[round+1]; ++ Abe = BCe ^((~BCi)& BCo ); ++ Abi = BCi ^((~BCo)& BCu ); ++ Abo = BCo ^((~BCu)& BCa ); ++ Abu = BCu ^((~BCa)& BCe ); ++ ++ Ebo ^= Do; ++ BCa = ROL(Ebo, 28); ++ Egu ^= Du; ++ BCe = ROL(Egu, 20); ++ Eka ^= Da; ++ BCi = ROL(Eka, 3); ++ Eme ^= De; ++ BCo = ROL(Eme, 45); ++ Esi ^= Di; ++ BCu = ROL(Esi, 61); ++ Aga = BCa ^((~BCe)& BCi ); ++ Age = BCe ^((~BCi)& BCo ); ++ Agi = BCi ^((~BCo)& BCu ); ++ Ago = BCo ^((~BCu)& BCa ); ++ Agu = BCu ^((~BCa)& BCe ); ++ ++ Ebe ^= De; ++ BCa = ROL(Ebe, 1); ++ Egi ^= Di; ++ BCe = ROL(Egi, 6); ++ Eko ^= Do; ++ BCi = ROL(Eko, 25); ++ Emu ^= Du; ++ BCo = ROL(Emu, 8); ++ Esa ^= Da; ++ BCu = ROL(Esa, 18); ++ Aka = BCa ^((~BCe)& BCi ); ++ Ake = BCe ^((~BCi)& BCo ); ++ Aki = BCi ^((~BCo)& BCu ); ++ Ako = BCo ^((~BCu)& BCa ); ++ Aku = BCu ^((~BCa)& BCe ); ++ ++ Ebu ^= Du; ++ BCa = ROL(Ebu, 27); ++ Ega ^= Da; ++ BCe = ROL(Ega, 36); ++ Eke ^= De; ++ BCi = ROL(Eke, 10); ++ Emi ^= Di; ++ BCo = ROL(Emi, 15); ++ Eso ^= Do; ++ BCu = ROL(Eso, 56); ++ Ama = BCa ^((~BCe)& BCi ); ++ Ame = BCe ^((~BCi)& BCo ); ++ Ami = BCi ^((~BCo)& BCu ); ++ Amo = BCo ^((~BCu)& BCa ); ++ Amu = BCu ^((~BCa)& BCe ); ++ ++ Ebi ^= Di; ++ BCa = ROL(Ebi, 62); ++ Ego ^= Do; ++ BCe = ROL(Ego, 55); ++ Eku ^= Du; ++ BCi = ROL(Eku, 39); ++ Ema ^= Da; ++ BCo = ROL(Ema, 41); ++ Ese ^= De; ++ BCu = ROL(Ese, 2); ++ Asa = BCa ^((~BCe)& BCi ); ++ Ase = BCe ^((~BCi)& BCo ); ++ Asi = BCi ^((~BCo)& BCu ); ++ Aso = BCo ^((~BCu)& BCa ); ++ Asu = BCu ^((~BCa)& BCe ); ++ } ++ ++ //copyToState(state, A) ++ state[ 0] = Aba; ++ state[ 1] = Abe; ++ state[ 2] = Abi; ++ state[ 3] = Abo; ++ state[ 4] = Abu; ++ state[ 5] = Aga; ++ state[ 6] = Age; ++ state[ 7] = Agi; ++ state[ 8] = Ago; ++ state[ 9] = Agu; ++ state[10] = Aka; ++ state[11] = Ake; ++ state[12] = Aki; ++ state[13] = Ako; ++ state[14] = Aku; ++ state[15] = Ama; ++ state[16] = Ame; ++ state[17] = Ami; ++ state[18] = Amo; ++ state[19] = Amu; ++ state[20] = Asa; ++ state[21] = Ase; ++ state[22] = Asi; ++ state[23] = Aso; ++ state[24] = Asu; ++} ++ ++ ++/************************************************* ++* Name: keccak_squeeze ++* ++* Description: Squeeze step of Keccak. Squeezes arbitratrily many bytes. ++* Modifies the state. Can be called multiple times to keep ++* squeezing, i.e., is incremental. ++* ++* Arguments: - uint8_t *out: pointer to output ++* - size_t outlen: number of bytes to be squeezed (written to out) ++* - uint64_t *s: pointer to input/output Keccak state ++* - unsigned int pos: number of bytes in current block already squeezed ++* - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) ++* ++* Returns new position pos in current block ++**************************************************/ ++static unsigned int keccak_squeeze(uint8_t *out, ++ size_t outlen, ++ uint64_t s[25], ++ unsigned int pos, ++ unsigned int r) ++{ ++ unsigned int i; ++ ++ while(outlen) { ++ if(pos == r) { ++ KeccakF1600_StatePermute(s); ++ pos = 0; ++ } ++ for(i=pos;i < r && i < pos+outlen; i++) ++ *out++ = s[i/8] >> 8*(i%8); ++ outlen -= i-pos; ++ pos = i; + } - return 1; -} - @@ -3470,42 +2917,40 @@ index 776c085f9..5acd45cd9 100644 - CBB_init_fixed(&cbb, out_encoded_public_key, KYBER_PUBLIC_KEY_BYTES); - if (!kyber_marshal_public_key(&cbb, &priv->pub)) { - abort(); -+// Modified crypto_kem_keypair to BoringSSL style API -+void generate_key(struct public_key *out_pub, struct private_key *out_priv, -+ const uint8_t seed[KYBER_GENERATE_KEY_BYTES]) -+{ -+ size_t i; -+ uint8_t* pk = &out_pub->opaque[0]; -+ uint8_t* sk = &out_priv->opaque[0]; + -+ indcpa_keypair(pk, sk, seed); -+ for(i=0;iopaque[0]; -+ uint8_t *ct = out_ciphertext; -+ -+ uint8_t buf[2*KYBER_SYMBYTES]; -+ /* Will contain key, coins */ -+ uint8_t kr[2*KYBER_SYMBYTES]; ++ unsigned int i; + -+ memcpy(buf, seed, KYBER_SYMBYTES); ++ for(i=0;i<25;i++) ++ s[i] = 0; + -+ if (ipd == 0) { -+ /* Don't release system RNG output */ -+ hash_h(buf, buf, KYBER_SYMBYTES); ++ while(inlen >= r) { ++ for(i=0;ipub.public_key_hash, sizeof(priv->pub.public_key_hash), @@ -3638,20 +3083,39 @@ index 776c085f9..5acd45cd9 100644 - for (int i = 0; i < 32; i++) { - input[i] = constant_time_select_8(mask, prekey_and_randomness[i], - priv->fo_failure_secret[i]); -+ /* Multitarget countermeasure for coins + contributory KEM */ -+ hash_h(buf+KYBER_SYMBYTES, pk, KYBER_PUBLICKEYBYTES); -+ hash_g(kr, buf, 2*KYBER_SYMBYTES); ++ for(i=0;is, SHAKE128_RATE, in, inlen, 0x1F); ++ state->pos = SHAKE128_RATE; } -// kyber_parse_public_key_no_hash parses |in| into |pub| but doesn't calculate @@ -3678,39 +3150,25 @@ index 776c085f9..5acd45cd9 100644 - !vector_decode(&pub->t, CBS_data(&t_bytes), kLog2Prime) || - !CBS_copy_bytes(in, pub->rho, sizeof(pub->rho))) { - return 0; -+// Internal version that allows us to select between initial public draft -+// (when ipd=1) and round3 kyber (ipd=0). -+void decap2(uint8_t out_shared_key[KYBER_SSBYTES], -+ const struct private_key *in_priv, -+ const uint8_t *ct, size_t ciphertext_len, int ipd) -+{ -+ uint8_t *ss = out_shared_key; -+ const uint8_t *sk = &in_priv->opaque[0]; -+ -+ size_t i; -+ int fail = 1; -+ uint8_t buf[2*KYBER_SYMBYTES]; -+ /* Will contain key, coins */ -+ uint8_t kr[2*KYBER_SYMBYTES]; -+ uint8_t cmp[KYBER_CIPHERTEXTBYTES]; -+ const uint8_t *pk = sk+KYBER_INDCPA_SECRETKEYBYTES; -+ -+ if (ciphertext_len == KYBER_CIPHERTEXTBYTES) { -+ indcpa_dec(buf, ct, sk); -+ -+ /* Multitarget countermeasure for coins + contributory KEM */ -+ for(i=0;im, pub->rho); - return 1; --} ++/************************************************* ++* Name: shake128_squeezeblocks ++* ++* Description: Squeeze step of SHAKE128 XOF. Squeezes full blocks of ++* SHAKE128_RATE bytes each. Can be called multiple times ++* to keep squeezing. Assumes new block has not yet been ++* started (state->pos = SHAKE128_RATE). ++* ++* Arguments: - uint8_t *out: pointer to output blocks ++* - size_t nblocks: number of blocks to be squeezed (written to output) ++* - keccak_state *s: pointer to input/output Keccak state ++**************************************************/ ++static void shake128_squeezeblocks(uint8_t *out, size_t nblocks, keccak_state *state) ++{ ++ keccak_squeezeblocks(out, nblocks, state->s, SHAKE128_RATE); + } -int KYBER_parse_public_key(struct KYBER_public_key *public_key, CBS *in) { - struct public_key *pub = public_key_from_external(public_key); @@ -3718,36 +3176,23 @@ index 776c085f9..5acd45cd9 100644 - if (!kyber_parse_public_key_no_hash(pub, in) || // - CBS_len(in) != 0) { - return 0; -+ if (ipd == 1) { -+ /* Compute shared secret in case of rejection: ss2 = PRF(z || c). */ -+ uint8_t ss2[KYBER_SYMBYTES]; -+ keccak_state ks; -+ shake256_init(&ks); -+ shake256_absorb( -+ &ks, -+ sk + KYBER_SECRETKEYBYTES - KYBER_SYMBYTES, -+ KYBER_SYMBYTES -+ ); -+ shake256_absorb(&ks, ct, ciphertext_len); -+ shake256_finalize(&ks); -+ shake256_squeeze(ss2, KYBER_SYMBYTES, &ks); -+ -+ /* Set ss2 to the real shared secret if c = c' */ -+ cmov(ss2, kr, KYBER_SYMBYTES, 1-fail); -+ memcpy(ss, ss2, KYBER_SYMBYTES); -+ } else { -+ /* overwrite coins in kr with H(c) */ -+ hash_h(kr+KYBER_SYMBYTES, ct, ciphertext_len); -+ -+ /* Overwrite pre-k with z on re-encryption failure */ -+ cmov(kr, sk+KYBER_SECRETKEYBYTES-KYBER_SYMBYTES, KYBER_SYMBYTES, fail); -+ -+ /* hash concatenation of pre-k and H(c) to k */ -+ kdf(ss, kr, 2*KYBER_SYMBYTES); - } +- } - BORINGSSL_keccak(pub->public_key_hash, sizeof(pub->public_key_hash), - CBS_data(&orig_in), CBS_len(&orig_in), boringssl_sha3_256); - return 1; ++/************************************************* ++* Name: shake256_squeeze ++* ++* Description: Squeeze step of SHAKE256 XOF. Squeezes arbitraily many ++* bytes. Can be called multiple times to keep squeezing. ++* ++* Arguments: - uint8_t *out: pointer to output blocks ++* - size_t outlen : number of bytes to be squeezed (written to output) ++* - keccak_state *s: pointer to input/output Keccak state ++**************************************************/ ++static void shake256_squeeze(uint8_t *out, size_t outlen, keccak_state *state) ++{ ++ state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE256_RATE); } -int KYBER_marshal_private_key(CBB *out, @@ -3782,15 +3227,240 @@ index 776c085f9..5acd45cd9 100644 - sizeof(priv->fo_failure_secret)) || - CBS_len(in) != 0) { - return 0; -- } -- return 1; ++/************************************************* ++* Name: shake256_absorb_once ++* ++* Description: Initialize, absorb into and finalize SHAKE256 XOF; non-incremental. ++* ++* Arguments: - keccak_state *state: pointer to (uninitialized) output Keccak state ++* - const uint8_t *in: pointer to input to be absorbed into s ++* - size_t inlen: length of input in bytes ++**************************************************/ ++static void shake256_absorb_once(keccak_state *state, const uint8_t *in, size_t inlen) ++{ ++ keccak_absorb_once(state->s, SHAKE256_RATE, in, inlen, 0x1F); ++ state->pos = SHAKE256_RATE; ++} ++ ++/************************************************* ++* Name: shake256_squeezeblocks ++* ++* Description: Squeeze step of SHAKE256 XOF. Squeezes full blocks of ++* SHAKE256_RATE bytes each. Can be called multiple times ++* to keep squeezing. Assumes next block has not yet been ++* started (state->pos = SHAKE256_RATE). ++* ++* Arguments: - uint8_t *out: pointer to output blocks ++* - size_t nblocks: number of blocks to be squeezed (written to output) ++* - keccak_state *s: pointer to input/output Keccak state ++**************************************************/ ++static void shake256_squeezeblocks(uint8_t *out, size_t nblocks, keccak_state *state) ++{ ++ keccak_squeezeblocks(out, nblocks, state->s, SHAKE256_RATE); ++} ++ ++/************************************************* ++* Name: shake256 ++* ++* Description: SHAKE256 XOF with non-incremental API ++* ++* Arguments: - uint8_t *out: pointer to output ++* - size_t outlen: requested output length in bytes ++* - const uint8_t *in: pointer to input ++* - size_t inlen: length of input in bytes ++**************************************************/ ++static void shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) ++{ ++ size_t nblocks; ++ keccak_state state; ++ ++ shake256_absorb_once(&state, in, inlen); ++ nblocks = outlen/SHAKE256_RATE; ++ shake256_squeezeblocks(out, nblocks, &state); ++ outlen -= nblocks*SHAKE256_RATE; ++ out += nblocks*SHAKE256_RATE; ++ shake256_squeeze(out, outlen, &state); ++} ++ ++/************************************************* ++* Name: sha3_256 ++* ++* Description: SHA3-256 with non-incremental API ++* ++* Arguments: - uint8_t *h: pointer to output (32 bytes) ++* - const uint8_t *in: pointer to input ++* - size_t inlen: length of input in bytes ++**************************************************/ ++static void sha3_256(uint8_t h[32], const uint8_t *in, size_t inlen) ++{ ++ unsigned int i; ++ uint64_t s[25]; ++ ++ keccak_absorb_once(s, SHA3_256_RATE, in, inlen, 0x06); ++ KeccakF1600_StatePermute(s); ++ for(i=0;i<4;i++) ++ store64(h+8*i,s[i]); ++} ++ ++/************************************************* ++* Name: sha3_512 ++* ++* Description: SHA3-512 with non-incremental API ++* ++* Arguments: - uint8_t *h: pointer to output (64 bytes) ++* - const uint8_t *in: pointer to input ++* - size_t inlen: length of input in bytes ++**************************************************/ ++static void sha3_512(uint8_t h[64], const uint8_t *in, size_t inlen) ++{ ++ unsigned int i; ++ uint64_t s[25]; ++ ++ keccak_absorb_once(s, SHA3_512_RATE, in, inlen, 0x06); ++ KeccakF1600_StatePermute(s); ++ for(i=0;i<8;i++) ++ store64(h+8*i,s[i]); ++} ++ ++// ++// symmetric-shake.c ++// ++ ++/************************************************* ++* Name: kyber_shake128_absorb ++* ++* Description: Absorb step of the SHAKE128 specialized for the Kyber context. ++* ++* Arguments: - keccak_state *state: pointer to (uninitialized) output Keccak state ++* - const uint8_t *seed: pointer to KYBER_SYMBYTES input to be absorbed into state ++* - uint8_t i: additional byte of input ++* - uint8_t j: additional byte of input ++**************************************************/ ++static void kyber_shake128_absorb(keccak_state *state, ++ const uint8_t seed[KYBER_SYMBYTES], ++ uint8_t x, ++ uint8_t y) ++{ ++ uint8_t extseed[KYBER_SYMBYTES+2]; ++ ++ memcpy(extseed, seed, KYBER_SYMBYTES); ++ extseed[KYBER_SYMBYTES+0] = x; ++ extseed[KYBER_SYMBYTES+1] = y; ++ ++ shake128_absorb_once(state, extseed, sizeof(extseed)); ++} ++ ++/************************************************* ++* Name: kyber_shake256_prf ++* ++* Description: Usage of SHAKE256 as a PRF, concatenates secret and public input ++* and then generates outlen bytes of SHAKE256 output ++* ++* Arguments: - uint8_t *out: pointer to output ++* - size_t outlen: number of requested output bytes ++* - const uint8_t *key: pointer to the key (of length KYBER_SYMBYTES) ++* - uint8_t nonce: single-byte nonce (public PRF input) ++**************************************************/ ++static void kyber_shake256_prf(uint8_t *out, size_t outlen, const uint8_t key[KYBER_SYMBYTES], uint8_t nonce) ++{ ++ uint8_t extkey[KYBER_SYMBYTES+1]; ++ ++ memcpy(extkey, key, KYBER_SYMBYTES); ++ extkey[KYBER_SYMBYTES] = nonce; ++ ++ shake256(out, outlen, extkey, sizeof(extkey)); ++} ++ ++// ++// kem.c ++// ++ ++// Modified crypto_kem_keypair to BoringSSL style API ++void generate_key(struct public_key *out_pub, struct private_key *out_priv, ++ const uint8_t seed[KYBER_GENERATE_KEY_BYTES]) ++{ ++ size_t i; ++ uint8_t* pk = &out_pub->opaque[0]; ++ uint8_t* sk = &out_priv->opaque[0]; ++ ++ indcpa_keypair(pk, sk, seed); ++ for(i=0;iopaque[0]; ++ uint8_t *ct = out_ciphertext; ++ ++ uint8_t buf[2*KYBER_SYMBYTES]; ++ /* Will contain key, coins */ ++ uint8_t kr[2*KYBER_SYMBYTES]; ++ ++ memcpy(buf, seed, KYBER_SYMBYTES); ++ /* Don't release system RNG output */ ++ hash_h(buf, buf, KYBER_SYMBYTES); ++ ++ /* Multitarget countermeasure for coins + contributory KEM */ ++ hash_h(buf+KYBER_SYMBYTES, pk, KYBER_PUBLICKEYBYTES); ++ hash_g(kr, buf, 2*KYBER_SYMBYTES); ++ ++ /* coins are in kr+KYBER_SYMBYTES */ ++ indcpa_enc(ct, buf, pk, kr+KYBER_SYMBYTES); ++ ++ /* overwrite coins in kr with H(c) */ ++ hash_h(kr+KYBER_SYMBYTES, ct, KYBER_CIPHERTEXTBYTES); ++ /* hash concatenation of pre-k and H(c) to k */ ++ kdf(ss, kr, 2*KYBER_SYMBYTES); ++} ++ +// Modified crypto_kem_decap to BoringSSL style API +void decap(uint8_t out_shared_key[KYBER_SSBYTES], + const struct private_key *in_priv, -+ const uint8_t *ct, size_t ciphertext_len) { -+ decap2(out_shared_key, in_priv, ct, ciphertext_len, 0); -+} ++ const uint8_t *ct, size_t ciphertext_len) ++{ ++ uint8_t *ss = out_shared_key; ++ const uint8_t *sk = &in_priv->opaque[0]; + ++ size_t i; ++ int fail = 1; ++ uint8_t buf[2*KYBER_SYMBYTES]; ++ /* Will contain key, coins */ ++ uint8_t kr[2*KYBER_SYMBYTES]; ++ uint8_t cmp[KYBER_CIPHERTEXTBYTES]; ++ const uint8_t *pk = sk+KYBER_INDCPA_SECRETKEYBYTES; ++ ++ if (ciphertext_len == KYBER_CIPHERTEXTBYTES) { ++ indcpa_dec(buf, ct, sk); ++ ++ /* Multitarget countermeasure for coins + contributory KEM */ ++ for(i=0;iopaque, in, KYBER_PUBLICKEYBYTES); } -diff --git a/src/crypto/kyber/kyber.h b/src/crypto/kyber/kyber.h -new file mode 100644 -index 000000000..16e47d582 ---- /dev/null -+++ b/src/crypto/kyber/kyber.h -@@ -0,0 +1,29 @@ -+#ifndef OPENSSL_HEADER_KYBER_KYBER_H -+#define OPENSSL_HEADER_KYBER_KYBER_H -+ -+#include -+ -+#include -+#include -+ -+void KYBER512_encap2(uint8_t out_ciphertext[KYBER512_CIPHERTEXT_BYTES], -+ uint8_t ss[KYBER_KEY_BYTES], -+ const struct KYBER512_public_key *in_pub, -+ const uint8_t seed[KYBER_ENCAP_BYTES], -+ int ipd); -+ -+void KYBER512_decap2(uint8_t out_shared_key[KYBER_KEY_BYTES], -+ const struct KYBER512_private_key *in_priv, -+ const uint8_t *ct, size_t ciphertext_len, int ipd); -+ -+void KYBER768_encap2(uint8_t out_ciphertext[KYBER768_CIPHERTEXT_BYTES], -+ uint8_t ss[KYBER_KEY_BYTES], -+ const struct KYBER768_public_key *in_pub, -+ const uint8_t seed[KYBER_ENCAP_BYTES], -+ int ipd); -+ -+void KYBER768_decap2(uint8_t out_shared_key[KYBER_KEY_BYTES], -+ const struct KYBER768_private_key *in_priv, -+ const uint8_t *ct, size_t ciphertext_len, int ipd); -+ -+#endif diff --git a/src/crypto/kyber/kyber512.c b/src/crypto/kyber/kyber512.c new file mode 100644 index 000000000..21eed11a2 @@ -4093,7 +3728,7 @@ index eb76b5bd7..000000000 - FileTestGTest("crypto/kyber/kyber_tests.txt", KyberFileTest); -} diff --git a/src/crypto/obj/obj_dat.h b/src/crypto/obj/obj_dat.h -index 654b3c08e..0d3d9f24f 100644 +index 654b3c08e..06f80f971 100644 --- a/src/crypto/obj/obj_dat.h +++ b/src/crypto/obj/obj_dat.h @@ -57,7 +57,7 @@ @@ -4101,11 +3736,11 @@ index 654b3c08e..0d3d9f24f 100644 -#define NUM_NID 965 -+#define NUM_NID 969 ++#define NUM_NID 968 static const uint8_t kObjectData[] = { /* NID_rsadsi */ -@@ -8784,6 +8784,13 @@ static const ASN1_OBJECT kObjects[NUM_NID] = { +@@ -8784,6 +8784,12 @@ static const ASN1_OBJECT kObjects[NUM_NID] = { {"HKDF", "hkdf", NID_hkdf, 0, NULL, 0}, {"X25519Kyber768Draft00", "X25519Kyber768Draft00", NID_X25519Kyber768Draft00, 0, NULL, 0}, @@ -4115,19 +3750,10 @@ index 654b3c08e..0d3d9f24f 100644 + NULL, 0}, + {"X25519Kyber768Draft00Old", "X25519Kyber768Draft00Old", + NID_X25519Kyber768Draft00Old, 0, NULL, 0}, -+ {"IPDWing", "IPDWing", NID_IPDWing, 0, NULL, 0}, }; static const uint16_t kNIDsInShortNameOrder[] = { -@@ -8889,6 +8896,7 @@ static const uint16_t kNIDsInShortNameOrder[] = { - 35 /* IDEA-CFB */, - 36 /* IDEA-ECB */, - 46 /* IDEA-OFB */, -+ 968 /* IPDWing */, - 181 /* ISO */, - 183 /* ISO-US */, - 645 /* ITU-T */, -@@ -8916,6 +8924,7 @@ static const uint16_t kNIDsInShortNameOrder[] = { +@@ -8916,6 +8922,7 @@ static const uint16_t kNIDsInShortNameOrder[] = { 18 /* OU */, 749 /* Oakley-EC2N-3 */, 750 /* Oakley-EC2N-4 */, @@ -4135,7 +3761,7 @@ index 654b3c08e..0d3d9f24f 100644 9 /* PBE-MD2-DES */, 168 /* PBE-MD2-RC2-64 */, 10 /* PBE-MD5-DES */, -@@ -8982,7 +8991,9 @@ static const uint16_t kNIDsInShortNameOrder[] = { +@@ -8982,7 +8989,9 @@ static const uint16_t kNIDsInShortNameOrder[] = { 458 /* UID */, 0 /* UNDEF */, 948 /* X25519 */, @@ -4145,15 +3771,7 @@ index 654b3c08e..0d3d9f24f 100644 961 /* X448 */, 11 /* X500 */, 378 /* X500algorithms */, -@@ -9787,6 +9798,7 @@ static const uint16_t kNIDsInLongNameOrder[] = { - 431 /* Hold Instruction None */, - 433 /* Hold Instruction Reject */, - 634 /* ICC or token signature */, -+ 968 /* IPDWing */, - 294 /* IPSec End System */, - 295 /* IPSec Tunnel */, - 296 /* IPSec User */, -@@ -9829,6 +9841,7 @@ static const uint16_t kNIDsInLongNameOrder[] = { +@@ -9829,6 +9838,7 @@ static const uint16_t kNIDsInLongNameOrder[] = { 366 /* OCSP Nonce */, 371 /* OCSP Service Locator */, 180 /* OCSP Signing */, @@ -4161,7 +3779,7 @@ index 654b3c08e..0d3d9f24f 100644 161 /* PBES2 */, 69 /* PBKDF2 */, 162 /* PBMAC1 */, -@@ -9853,7 +9866,9 @@ static const uint16_t kNIDsInLongNameOrder[] = { +@@ -9853,7 +9863,9 @@ static const uint16_t kNIDsInLongNameOrder[] = { 133 /* Time Stamping */, 375 /* Trust Root */, 948 /* X25519 */, @@ -4172,22 +3790,21 @@ index 654b3c08e..0d3d9f24f 100644 12 /* X509 */, 402 /* X509v3 AC Targeting */, diff --git a/src/crypto/obj/obj_mac.num b/src/crypto/obj/obj_mac.num -index a0519acee..019770f16 100644 +index a0519acee..caeb5eaed 100644 --- a/src/crypto/obj/obj_mac.num +++ b/src/crypto/obj/obj_mac.num -@@ -952,3 +952,7 @@ X448 961 +@@ -952,3 +952,6 @@ X448 961 sha512_256 962 hkdf 963 X25519Kyber768Draft00 964 +X25519Kyber512Draft00 965 +P256Kyber768Draft00 966 +X25519Kyber768Draft00Old 967 -+IPDWing 968 diff --git a/src/crypto/obj/objects.txt b/src/crypto/obj/objects.txt -index 3ad32ea3d..475d278df 100644 +index 3ad32ea3d..aa1404d83 100644 --- a/src/crypto/obj/objects.txt +++ b/src/crypto/obj/objects.txt -@@ -1332,8 +1332,12 @@ secg-scheme 14 3 : dhSinglePass-cofactorDH-sha512kdf-scheme +@@ -1332,8 +1332,11 @@ secg-scheme 14 3 : dhSinglePass-cofactorDH-sha512kdf-scheme : dh-std-kdf : dh-cofactor-kdf @@ -4197,12 +3814,11 @@ index 3ad32ea3d..475d278df 100644 : X25519Kyber768Draft00 + : P256Kyber768Draft00 + : X25519Kyber768Draft00Old -+ : IPDWing # See RFC 8410. 1 3 101 110 : X25519 diff --git a/src/include/openssl/kyber.h b/src/include/openssl/kyber.h -index cafae9d17..1c889a075 100644 +index cafae9d17..074ac5906 100644 --- a/src/include/openssl/kyber.h +++ b/src/include/openssl/kyber.h @@ -1,17 +1,3 @@ @@ -4223,23 +3839,20 @@ index cafae9d17..1c889a075 100644 #ifndef OPENSSL_HEADER_KYBER_H #define OPENSSL_HEADER_KYBER_H -@@ -21,105 +7,157 @@ +@@ -21,105 +7,100 @@ extern "C" { #endif -- --// Kyber768. +#define KYBER512_PUBLIC_KEY_BYTES 800 +#define KYBER512_CIPHERTEXT_BYTES 768 +#define KYBER512_PRIVATE_KEY_BYTES 1632 +#define KYBER768_PUBLIC_KEY_BYTES 1184 +#define KYBER768_CIPHERTEXT_BYTES 1088 +#define KYBER768_PRIVATE_KEY_BYTES 2400 -+#define IPDWING_PUBLIC_KEY_BYTES 1216 -+#define IPDWING_CIPHERTEXT_BYTES 1120 -+#define IPDWING_PRIVATE_KEY_BYTES 2464 - +-// Kyber768. +- +- -// KYBER_public_key contains a Kyber768 public key. The contents of this -// object should never leave the address space since the format is unstable. -struct KYBER_public_key { @@ -4261,10 +3874,11 @@ index cafae9d17..1c889a075 100644 +struct KYBER768_private_key { + uint8_t opaque[KYBER768_PRIVATE_KEY_BYTES]; +}; -+struct IPDWING_private_key { -+ struct KYBER768_private_key m; -+ uint8_t x[32]; -+ uint8_t xpub[32]; ++struct KYBER512_public_key { ++ uint8_t opaque[KYBER512_PUBLIC_KEY_BYTES]; ++}; ++struct KYBER768_public_key { ++ uint8_t opaque[KYBER768_PUBLIC_KEY_BYTES]; }; -// KYBER_PUBLIC_KEY_BYTES is the number of bytes in an encoded Kyber768 public @@ -4343,39 +3957,18 @@ index cafae9d17..1c889a075 100644 -// there are trailing bytes in |in|. -OPENSSL_EXPORT int KYBER_parse_private_key( - struct KYBER_private_key *out_private_key, CBS *in); -+struct KYBER512_public_key { -+ uint8_t opaque[KYBER512_PUBLIC_KEY_BYTES]; -+}; -+struct KYBER768_public_key { -+ uint8_t opaque[KYBER768_PUBLIC_KEY_BYTES]; -+}; -+struct IPDWING_public_key { -+ struct KYBER768_public_key m; -+ uint8_t x[32]; -+}; - +- +// KYBER_GENERATE_KEY_BYTES is the number of bytes of entropy needed to +// generate a keypair. +#define KYBER_GENERATE_KEY_BYTES 64 + -+// IPDWING_GENERATE_KEY_BYTES is the number of bytes of entropy needed to -+// generate a keypair. -+#define IPDWING_GENERATE_KEY_BYTES 96 -+ +// KYBER_ENCAP_BYTES is the number of bytes of entropy needed to encapsulate a +// session key. +#define KYBER_ENCAP_BYTES 32 + -+// IPDWING_ENCAP_BYTES is the number of bytes of entropy needed to encapsulate a -+// session key. -+#define IPDWING_ENCAP_BYTES 64 -+ +// KYBER_KEY_BYTES is the number of bytes in a shared key. +#define KYBER_KEY_BYTES 32 + -+// IPDWING_KEY_BYTES is the number of bytes in a shared key. -+#define IPDWING_KEY_BYTES 32 -+ +// KYBER512_generate_key is a deterministic function that outputs a public and +// private key based on the given entropy. +OPENSSL_EXPORT void KYBER512_generate_key( @@ -4388,12 +3981,6 @@ index cafae9d17..1c889a075 100644 + struct KYBER768_public_key *out_pub, struct KYBER768_private_key *out_priv, + const uint8_t input[KYBER_GENERATE_KEY_BYTES]); + -+// IPDWING_generate_key is a deterministic function that outputs a public and -+// private key based on the given entropy. -+OPENSSL_EXPORT void IPDWING_generate_key( -+ struct IPDWING_public_key *out_pub, struct IPDWING_private_key *out_priv, -+ const uint8_t input[IPDWING_GENERATE_KEY_BYTES]); -+ +// KYBER512_encap is a deterministic function the generates and encrypts a random +// session key from the given entropy, writing those values to |out_shared_key| +// and |out_ciphertext|, respectively. @@ -4410,14 +3997,6 @@ index cafae9d17..1c889a075 100644 + const struct KYBER768_public_key *in_pub, + const uint8_t in[KYBER_ENCAP_BYTES]); + -+// IPDWING_encap is a deterministic function the generates and encrypts a random -+// session key from the given entropy, writing those values to |out_shared_key| -+// and |out_ciphertext|, respectively. -+OPENSSL_EXPORT void IPDWING_encap(uint8_t out_ciphertext[IPDWING_CIPHERTEXT_BYTES], -+ uint8_t out_shared_key[IPDWING_KEY_BYTES], -+ const struct IPDWING_public_key *in_pub, -+ const uint8_t in[IPDWING_ENCAP_BYTES]); -+ +// KYBER_decap decrypts a session key from |ciphertext_len| bytes of +// |ciphertext|. If the ciphertext is valid, the decrypted key is written to +// |out_shared_key|. Otherwise a key dervied from |ciphertext| and a secret key (kept @@ -4428,7 +4007,7 @@ index cafae9d17..1c889a075 100644 + const struct KYBER512_private_key *in_priv, + const uint8_t *ciphertext, size_t ciphertext_len); + -+// KYBER768_decap decrypts a session key from |ciphertext_len| bytes of ++// KYBER_decap decrypts a session key from |ciphertext_len| bytes of +// |ciphertext|. If the ciphertext is valid, the decrypted key is written to +// |out_shared_key|. Otherwise a key dervied from |ciphertext| and a secret key (kept +// in |in_priv|) is written. If the ciphertext is the wrong length then it will @@ -4438,16 +4017,6 @@ index cafae9d17..1c889a075 100644 + const struct KYBER768_private_key *in_priv, + const uint8_t *ciphertext, size_t ciphertext_len); + -+// IPDWING_decap decrypts a session key from IPDWING_CIPHERTEXT_BYTES bytes of -+// |ciphertext|. If the ciphertext is valid, the decrypted key is written to -+// |out_shared_key|. Otherwise a key dervied from |ciphertext| and a secret key (kept -+// in |in_priv|) is written. If the ciphertext is the wrong length then it will -+// leak which was done via side-channels. Otherwise it should perform either -+// action in constant-time. -+OPENSSL_EXPORT void IPDWING_decap(uint8_t out_shared_key[KYBER_KEY_BYTES], -+ const struct IPDWING_private_key *in_priv, -+ const uint8_t *ciphertext); -+ +// KYBER512_marshal_public_key serialises |in_pub| to |out|. +OPENSSL_EXPORT void KYBER512_marshal_public_key( + uint8_t out[KYBER512_PUBLIC_KEY_BYTES], const struct KYBER512_public_key *in_pub); @@ -4456,10 +4025,6 @@ index cafae9d17..1c889a075 100644 +OPENSSL_EXPORT void KYBER768_marshal_public_key( + uint8_t out[KYBER768_PUBLIC_KEY_BYTES], const struct KYBER768_public_key *in_pub); + -+// IPDWING_marshal_public_key serialises |in_pub| to |out|. -+OPENSSL_EXPORT void IPDWING_marshal_public_key( -+ uint8_t out[IPDWING_PUBLIC_KEY_BYTES], const struct IPDWING_public_key *in_pub); -+ +// KYBER512_parse_public_key sets |*out| to the public-key encoded in |in|. +OPENSSL_EXPORT void KYBER512_parse_public_key( + struct KYBER512_public_key *out, const uint8_t in[KYBER512_PUBLIC_KEY_BYTES]); @@ -4467,18 +4032,14 @@ index cafae9d17..1c889a075 100644 +// KYBER768_parse_public_key sets |*out| to the public-key encoded in |in|. +OPENSSL_EXPORT void KYBER768_parse_public_key( + struct KYBER768_public_key *out, const uint8_t in[KYBER768_PUBLIC_KEY_BYTES]); -+ -+// IPDWING_parse_public_key sets |*out| to the public-key encoded in |in|. -+OPENSSL_EXPORT void IPDWING_parse_public_key( -+ struct IPDWING_public_key *out, const uint8_t in[IPDWING_PUBLIC_KEY_BYTES]); #if defined(__cplusplus) } // extern C diff --git a/src/include/openssl/nid.h b/src/include/openssl/nid.h -index 4dd8841b1..09912d8bb 100644 +index 4dd8841b1..8237efb74 100644 --- a/src/include/openssl/nid.h +++ b/src/include/openssl/nid.h -@@ -4255,6 +4255,18 @@ extern "C" { +@@ -4255,6 +4255,15 @@ extern "C" { #define SN_X25519Kyber768Draft00 "X25519Kyber768Draft00" #define NID_X25519Kyber768Draft00 964 @@ -4490,25 +4051,21 @@ index 4dd8841b1..09912d8bb 100644 + +#define SN_X25519Kyber768Draft00Old "X25519Kyber768Draft00Old" +#define NID_X25519Kyber768Draft00Old 967 -+ -+#define SN_IPDWing "IPDWing" -+#define NID_IPDWing 968 + #if defined(__cplusplus) } /* extern C */ diff --git a/src/include/openssl/ssl.h b/src/include/openssl/ssl.h -index 53aa9b453..3091c6849 100644 +index 53aa9b453..8233ad210 100644 --- a/src/include/openssl/ssl.h +++ b/src/include/openssl/ssl.h -@@ -2378,6 +2378,10 @@ OPENSSL_EXPORT int SSL_set1_curves_list(SSL *ssl, const char *curves); +@@ -2378,6 +2378,9 @@ OPENSSL_EXPORT int SSL_set1_curves_list(SSL *ssl, const char *curves); #define SSL_CURVE_SECP521R1 25 #define SSL_CURVE_X25519 29 #define SSL_CURVE_X25519_KYBER768_DRAFT00 0x6399 +#define SSL_CURVE_X25519_KYBER512_DRAFT00 0xfe30 +#define SSL_CURVE_X25519_KYBER768_DRAFT00_OLD 0xfe31 +#define SSL_CURVE_P256_KYBER768_DRAFT00 0xfe32 -+#define SSL_CURVE_IPDWING 0xfe41 // SSL_get_curve_id returns the ID of the curve used by |ssl|'s most recently // completed handshake or 0 if not applicable. @@ -4526,36 +4083,40 @@ index 5c7e881bf..3c0770cf3 100644 crypto/pkcs8/test/no_encryption.p12 crypto/pkcs8/test/nss.p12 diff --git a/src/ssl/extensions.cc b/src/ssl/extensions.cc -index 5ee280221..cf165df1f 100644 +index 5ee280221..0a706c411 100644 --- a/src/ssl/extensions.cc +++ b/src/ssl/extensions.cc -@@ -207,6 +207,10 @@ static bool tls1_check_duplicate_extensions(const CBS *cbs) { +@@ -207,6 +207,9 @@ static bool tls1_check_duplicate_extensions(const CBS *cbs) { static bool is_post_quantum_group(uint16_t id) { switch (id) { case SSL_CURVE_X25519_KYBER768_DRAFT00: + case SSL_CURVE_X25519_KYBER768_DRAFT00_OLD: + case SSL_CURVE_X25519_KYBER512_DRAFT00: + case SSL_CURVE_P256_KYBER768_DRAFT00: -+ case SSL_CURVE_IPDWING: return true; default: return false; diff --git a/src/ssl/ssl_key_share.cc b/src/ssl/ssl_key_share.cc -index 09a9ad380..d9d3b9032 100644 +index 09a9ad380..f7d2226e3 100644 --- a/src/ssl/ssl_key_share.cc +++ b/src/ssl/ssl_key_share.cc -@@ -193,63 +193,384 @@ class X25519KeyShare : public SSLKeyShare { +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -193,63 +194,384 @@ class X25519KeyShare : public SSLKeyShare { uint8_t private_key_[32]; }; -class X25519Kyber768KeyShare : public SSLKeyShare { +class P256Kyber768Draft00KeyShare : public SSLKeyShare { - public: -- X25519Kyber768KeyShare() {} ++ public: + P256Kyber768Draft00KeyShare() {} - -- uint16_t GroupID() const override { -- return SSL_CURVE_X25519_KYBER768_DRAFT00; ++ + uint16_t GroupID() const override { return SSL_CURVE_P256_KYBER768_DRAFT00; } + + bool Generate(CBB *out) override { @@ -4605,8 +4166,8 @@ index 09a9ad380..d9d3b9032 100644 + } + + return true; - } - ++ } ++ + bool Encap(CBB *out_public_key, Array *out_secret, + uint8_t *out_alert, Span peer_key) override { + assert(!p256_private_key_); @@ -4769,7 +4330,8 @@ index 09a9ad380..d9d3b9032 100644 +}; + +class X25519Kyber768Draft00KeyShare : public SSLKeyShare { -+ public: + public: +- X25519Kyber768KeyShare() {} + X25519Kyber768Draft00KeyShare(uint16_t group_id) : group_id_(group_id) { + assert(group_id == SSL_CURVE_X25519_KYBER768_DRAFT00 + || group_id == SSL_CURVE_X25519_KYBER768_DRAFT00_OLD); @@ -4777,12 +4339,10 @@ index 09a9ad380..d9d3b9032 100644 + + uint16_t GroupID() const override { return group_id_; } + - bool Generate(CBB *out) override { - uint8_t x25519_public_key[32]; - X25519_keypair(x25519_public_key, x25519_private_key_); - -- uint8_t kyber_public_key[KYBER_PUBLIC_KEY_BYTES]; -- KYBER_generate_key(kyber_public_key, &kyber_private_key_); ++ bool Generate(CBB *out) override { ++ uint8_t x25519_public_key[32]; ++ X25519_keypair(x25519_public_key, x25519_private_key_); ++ + uint8_t kyber_entropy[KYBER_GENERATE_KEY_BYTES]; + KYBER768_public_key kyber_public_key; + RAND_bytes(kyber_entropy, sizeof(kyber_entropy)); @@ -4790,19 +4350,16 @@ index 09a9ad380..d9d3b9032 100644 + + uint8_t kyber_public_key_bytes[KYBER768_PUBLIC_KEY_BYTES]; + KYBER768_marshal_public_key(kyber_public_key_bytes, &kyber_public_key); - - if (!CBB_add_bytes(out, x25519_public_key, sizeof(x25519_public_key)) || -- !CBB_add_bytes(out, kyber_public_key, sizeof(kyber_public_key))) { ++ ++ if (!CBB_add_bytes(out, x25519_public_key, sizeof(x25519_public_key)) || + !CBB_add_bytes(out, kyber_public_key_bytes, + sizeof(kyber_public_key_bytes))) { - return false; - } - - return true; - } - -- bool Encap(CBB *out_ciphertext, Array *out_secret, -- uint8_t *out_alert, Span peer_key) override { ++ return false; ++ } ++ ++ return true; ++ } ++ + bool Encap(CBB *out_public_key, Array *out_secret, + uint8_t *out_alert, Span peer_key) override { + Array secret; @@ -4863,11 +4420,13 @@ index 09a9ad380..d9d3b9032 100644 + + KYBER768_decap(secret.data() + 32, &kyber_private_key_, + peer_key.data() + 32, peer_key.size() - 32); -+ + +- uint16_t GroupID() const override { +- return SSL_CURVE_X25519_KYBER768_DRAFT00; + *out_secret = std::move(secret); + return true; -+ } -+ + } + + private: + uint8_t x25519_private_key_[32]; + KYBER768_private_key kyber_private_key_; @@ -4880,10 +4439,12 @@ index 09a9ad380..d9d3b9032 100644 + + uint16_t GroupID() const override { return SSL_CURVE_X25519_KYBER512_DRAFT00; } + -+ bool Generate(CBB *out) override { -+ uint8_t x25519_public_key[32]; -+ X25519_keypair(x25519_public_key, x25519_private_key_); -+ + bool Generate(CBB *out) override { + uint8_t x25519_public_key[32]; + X25519_keypair(x25519_public_key, x25519_private_key_); + +- uint8_t kyber_public_key[KYBER_PUBLIC_KEY_BYTES]; +- KYBER_generate_key(kyber_public_key, &kyber_private_key_); + uint8_t kyber_entropy[KYBER_GENERATE_KEY_BYTES]; + KYBER512_public_key kyber_public_key; + RAND_bytes(kyber_entropy, sizeof(kyber_entropy)); @@ -4891,16 +4452,19 @@ index 09a9ad380..d9d3b9032 100644 + + uint8_t kyber_public_key_bytes[KYBER512_PUBLIC_KEY_BYTES]; + KYBER512_marshal_public_key(kyber_public_key_bytes, &kyber_public_key); -+ -+ if (!CBB_add_bytes(out, x25519_public_key, sizeof(x25519_public_key)) || + + if (!CBB_add_bytes(out, x25519_public_key, sizeof(x25519_public_key)) || +- !CBB_add_bytes(out, kyber_public_key, sizeof(kyber_public_key))) { + !CBB_add_bytes(out, kyber_public_key_bytes, + sizeof(kyber_public_key_bytes))) { -+ return false; -+ } -+ -+ return true; -+ } -+ + return false; + } + + return true; + } + +- bool Encap(CBB *out_ciphertext, Array *out_secret, +- uint8_t *out_alert, Span peer_key) override { + bool Encap(CBB *out_public_key, Array *out_secret, + uint8_t *out_alert, Span peer_key) override { Array secret; @@ -4957,7 +4521,7 @@ index 09a9ad380..d9d3b9032 100644 return false; } -@@ -258,30 +579,111 @@ class X25519Kyber768KeyShare : public SSLKeyShare { +@@ -258,30 +580,32 @@ class X25519Kyber768KeyShare : public SSLKeyShare { } bool Decap(Array *out_secret, uint8_t *out_alert, @@ -4994,89 +4558,10 @@ index 09a9ad380..d9d3b9032 100644 uint8_t x25519_private_key_[32]; - KYBER_private_key kyber_private_key_; + KYBER512_private_key kyber_private_key_; -+}; -+ -+class IPDWingKeyShare : public SSLKeyShare { -+ public: -+ IPDWingKeyShare() {} -+ -+ uint16_t GroupID() const override { return SSL_CURVE_IPDWING; } -+ -+ bool Generate(CBB *out) override { -+ uint8_t entropy[IPDWING_GENERATE_KEY_BYTES]; -+ IPDWING_public_key public_key; -+ RAND_bytes(entropy, sizeof(entropy)); -+ IPDWING_generate_key(&public_key, &private_key_, entropy); -+ -+ uint8_t public_key_bytes[IPDWING_PUBLIC_KEY_BYTES]; -+ IPDWING_marshal_public_key(public_key_bytes, &public_key); -+ -+ if(!CBB_add_bytes(out, public_key_bytes, sizeof(public_key_bytes))) { -+ return false; -+ } -+ -+ return true; -+ } -+ -+ bool Encap(CBB *out_public_key, Array *out_secret, -+ uint8_t *out_alert, Span peer_key) override { -+ Array secret; -+ *out_alert = SSL_AD_INTERNAL_ERROR; -+ if (!secret.Init(IPDWING_KEY_BYTES)) { -+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); -+ return false; -+ } -+ -+ IPDWING_public_key peer_public_key; -+ if (peer_key.size() != IPDWING_PUBLIC_KEY_BYTES) { -+ *out_alert = SSL_AD_DECODE_ERROR; -+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); -+ return false; -+ } -+ -+ IPDWING_parse_public_key(&peer_public_key, peer_key.data()); -+ -+ uint8_t ciphertext[IPDWING_CIPHERTEXT_BYTES]; -+ uint8_t entropy[IPDWING_ENCAP_BYTES]; -+ RAND_bytes(entropy, sizeof(entropy)); -+ -+ IPDWING_encap(ciphertext, secret.data(), &peer_public_key, entropy); -+ if(!CBB_add_bytes(out_public_key, ciphertext, sizeof(ciphertext))) { -+ return false; -+ } -+ -+ *out_secret = std::move(secret); -+ return true; -+ } -+ -+ bool Decap(Array *out_secret, uint8_t *out_alert, -+ Span peer_key) override { -+ *out_alert = SSL_AD_INTERNAL_ERROR; -+ -+ Array secret; -+ if (!secret.Init(IPDWING_KEY_BYTES)) { -+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); -+ return false; -+ } -+ -+ if (peer_key.size() != IPDWING_CIPHERTEXT_BYTES) { -+ *out_alert = SSL_AD_DECODE_ERROR; -+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); -+ return false; -+ } -+ -+ IPDWING_decap(secret.data(), &private_key_, peer_key.data()); -+ -+ *out_secret = std::move(secret); -+ return true; -+ } -+ -+ private: -+ IPDWING_private_key private_key_; }; constexpr NamedGroup kNamedGroups[] = { -@@ -290,8 +692,15 @@ constexpr NamedGroup kNamedGroups[] = { +@@ -290,8 +614,14 @@ constexpr NamedGroup kNamedGroups[] = { {NID_secp384r1, SSL_CURVE_SECP384R1, "P-384", "secp384r1"}, {NID_secp521r1, SSL_CURVE_SECP521R1, "P-521", "secp521r1"}, {NID_X25519, SSL_CURVE_X25519, "X25519", "x25519"}, @@ -5088,12 +4573,11 @@ index 09a9ad380..d9d3b9032 100644 + {NID_X25519Kyber768Draft00Old, SSL_CURVE_X25519_KYBER768_DRAFT00_OLD, + "X25519Kyber768Draft00Old", "Xyber768D00Old"}, + {NID_P256Kyber768Draft00, SSL_CURVE_P256_KYBER768_DRAFT00, -+ "P256Kyber768Draft00", "P256Kyber768D00"}, -+ {NID_IPDWing, SSL_CURVE_IPDWING, "IPDWing", ""} ++ "P256Kyber768Draft00", "P256Kyber768D00"} }; } // namespace -@@ -312,8 +721,18 @@ UniquePtr SSLKeyShare::Create(uint16_t group_id) { +@@ -312,8 +642,16 @@ UniquePtr SSLKeyShare::Create(uint16_t group_id) { return MakeUnique(NID_secp521r1, SSL_CURVE_SECP521R1); case SSL_CURVE_X25519: return MakeUnique(); @@ -5108,8 +4592,6 @@ index 09a9ad380..d9d3b9032 100644 + group_id)); + case SSL_CURVE_P256_KYBER768_DRAFT00: + return UniquePtr(New()); -+ case SSL_CURVE_IPDWING: -+ return UniquePtr(New()); default: return nullptr; } @@ -5127,10 +4609,10 @@ index 838761af5..9eb201d37 100644 static const uint16_t kSigAlgs[] = { SSL_SIGN_RSA_PKCS1_SHA256, diff --git a/src/ssl/ssl_test.cc b/src/ssl/ssl_test.cc -index ef43a9e98..bb79509ea 100644 +index ef43a9e98..9756fd2a0 100644 --- a/src/ssl/ssl_test.cc +++ b/src/ssl/ssl_test.cc -@@ -409,7 +409,34 @@ static const CurveTest kCurveTests[] = { +@@ -409,7 +409,30 @@ static const CurveTest kCurveTests[] = { "P-256:X25519Kyber768Draft00", { SSL_CURVE_SECP256R1, SSL_CURVE_X25519_KYBER768_DRAFT00 }, }, @@ -5144,10 +4626,6 @@ index ef43a9e98..bb79509ea 100644 + { SSL_CURVE_X25519_KYBER768_DRAFT00 }, + }, + { -+ "IPDWing", -+ { SSL_CURVE_IPDWING }, -+ }, -+ { + "Xyber768D00:Xyber768D00Old", + { SSL_CURVE_X25519_KYBER768_DRAFT00, SSL_CURVE_X25519_KYBER768_DRAFT00_OLD }, + }, @@ -5354,5 +4832,5 @@ index 5b0205953..831875514 100644 !SpeedTrustToken("TrustToken-Exp1-Batch1", TRUST_TOKEN_experiment_v1(), 1, selected) || -- -2.45.2 +2.41.0 diff --git a/boring/src/lib.rs b/boring/src/lib.rs index 4d477a72..6b3ade0f 100644 --- a/boring/src/lib.rs +++ b/boring/src/lib.rs @@ -83,10 +83,6 @@ //! boxes. //! - `P256Kyber768Draft00`. Similar again to `X25519Kyber768Draft00`, but uses P256 as classical //! part. It uses a non-standard codepoint. Not recommended. -//! - `IPDWing`. A preliminary version of -//! [X-Wing](https://datatracker.ietf.org/doc/draft-connolly-cfrg-xwing-kem/02/). -//! Similar to `X25519Kyber768Draft00Old`, but uses a newer (but not yet final) version of Kyber -//! called ML-KEM-ipd. Not recommended. //! //! Presently all these key agreements are deployed by Cloudflare, but we do not guarantee continued //! support for them. diff --git a/boring/src/ssl/mod.rs b/boring/src/ssl/mod.rs index 6a9361e1..277002b7 100644 --- a/boring/src/ssl/mod.rs +++ b/boring/src/ssl/mod.rs @@ -723,9 +723,6 @@ impl SslCurve { #[cfg(feature = "pq-experimental")] pub const P256_KYBER768_DRAFT00: SslCurve = SslCurve(ffi::SSL_CURVE_P256_KYBER768_DRAFT00 as _); - #[cfg(feature = "pq-experimental")] - pub const IPD_WING: SslCurve = SslCurve(ffi::SSL_CURVE_IPDWING); - /// Returns the curve name /// /// This corresponds to [`SSL_get_curve_name`] @@ -768,8 +765,6 @@ impl SslCurve { ffi::SSL_CURVE_X25519_KYBER512_DRAFT00 => Some(ffi::NID_X25519Kyber512Draft00), #[cfg(feature = "pq-experimental")] ffi::SSL_CURVE_P256_KYBER768_DRAFT00 => Some(ffi::NID_P256Kyber768Draft00), - #[cfg(feature = "pq-experimental")] - ffi::SSL_CURVE_IPDWING => Some(ffi::NID_IPDWing), _ => None, } }