From dddcd3bfa91452fe2dc5a466c85f46dfe8e8cf77 Mon Sep 17 00:00:00 2001 From: Rene Meusel Date: Fri, 29 Sep 2023 12:04:04 +0200 Subject: [PATCH 1/5] FIX: how to regenerate oid_maps.cpp/x509_dn_ub.cpp --- src/build-data/oids.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/build-data/oids.txt b/src/build-data/oids.txt index 2e1922faaf2..f59df0d5d8f 100644 --- a/src/build-data/oids.txt +++ b/src/build-data/oids.txt @@ -1,5 +1,5 @@ -# Regenerate with ./src/scripts/oids.py oids > src/lib/asn1/oid_maps.cpp -# AND ./src/scripts/oids.py dn_ub > src/lib/x509/x509_dn_ub.cpp +# Regenerate with ./src/scripts/dev_tools/oids.py oids > src/lib/asn1/oid_maps.cpp +# AND ./src/scripts/dev_tools/oids.py dn_ub > src/lib/x509/x509_dn_ub.cpp # (if you modified something under [dn] # Public key types From fac04ab1044d8d9273098169ce079f97b032fe25 Mon Sep 17 00:00:00 2001 From: Amos Treiber Date: Mon, 9 Oct 2023 11:52:00 +0200 Subject: [PATCH 2/5] Add subscript operator to strong type --- src/lib/utils/strong_type.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/lib/utils/strong_type.h b/src/lib/utils/strong_type.h index dda41492da6..a1fb4544115 100644 --- a/src/lib/utils/strong_type.h +++ b/src/lib/utils/strong_type.h @@ -137,6 +137,12 @@ class Strong_Adapter : public Strong_Base { { this->get().resize(size); } + + decltype(auto) operator[](size_type i) const noexcept(noexcept(this->get().operator[](i))) { + return this->get()[i]; + } + + decltype(auto) operator[](size_type i) noexcept(noexcept(this->get().operator[](i))) { return this->get()[i]; } }; } // namespace detail @@ -572,6 +578,8 @@ class StrongSpan { decltype(auto) end() const noexcept(noexcept(this->m_span.end())) { return this->m_span.end(); } + decltype(auto) operator[](typename underlying_span::size_type i) const noexcept { return this->m_span[i]; } + private: underlying_span m_span; }; From 21b52d30ff467c02e122ef5f97126a995dd4292c Mon Sep 17 00:00:00 2001 From: Amos Treiber Date: Tue, 1 Aug 2023 13:57:54 +0200 Subject: [PATCH 3/5] Implement FrodoKEM and eFrodoKEM according to ISO 20230314 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Integrated into CLI benchmarking tool and X.509 tests Co-Authored-By: René Meusel --- doc/api_ref/pubkey.rst | 8 +- doc/dev_ref/oids.rst | 18 + src/build-data/oids.txt | 14 + src/cli/speed.cpp | 47 +- src/lib/asn1/oid_maps.cpp | 26 +- .../frodokem/frodokem/frodo_shake_generator.h | 40 + src/lib/pubkey/frodokem/frodokem/info.txt | 12 + .../frodokem_aes/frodo_aes_generator.h | 56 + src/lib/pubkey/frodokem/frodokem_aes/info.txt | 12 + .../frodokem_common/frodo_constants.cpp | 102 + .../frodokem_common/frodo_constants.h | 103 + .../frodokem/frodokem_common/frodo_matrix.cpp | 494 +++++ .../frodokem/frodokem_common/frodo_matrix.h | 143 ++ .../frodokem/frodokem_common/frodo_mode.cpp | 111 + .../frodokem/frodokem_common/frodo_mode.h | 89 + .../frodokem/frodokem_common/frodo_types.h | 60 + .../frodokem/frodokem_common/frodokem.cpp | 381 ++++ .../frodokem/frodokem_common/frodokem.h | 107 + .../pubkey/frodokem/frodokem_common/info.txt | 26 + src/lib/pubkey/pk_algs.cpp | 23 + src/scripts/dev_tools/gen_frodo_kat.py | 131 ++ src/tests/data/pubkey/frodokem_kat.vec | 1814 +++++++++++++++++ src/tests/test_frodokem.cpp | 176 ++ src/tests/unit_x509.cpp | 6 +- 24 files changed, 3993 insertions(+), 6 deletions(-) create mode 100644 src/lib/pubkey/frodokem/frodokem/frodo_shake_generator.h create mode 100644 src/lib/pubkey/frodokem/frodokem/info.txt create mode 100644 src/lib/pubkey/frodokem/frodokem_aes/frodo_aes_generator.h create mode 100644 src/lib/pubkey/frodokem/frodokem_aes/info.txt create mode 100644 src/lib/pubkey/frodokem/frodokem_common/frodo_constants.cpp create mode 100644 src/lib/pubkey/frodokem/frodokem_common/frodo_constants.h create mode 100644 src/lib/pubkey/frodokem/frodokem_common/frodo_matrix.cpp create mode 100644 src/lib/pubkey/frodokem/frodokem_common/frodo_matrix.h create mode 100644 src/lib/pubkey/frodokem/frodokem_common/frodo_mode.cpp create mode 100644 src/lib/pubkey/frodokem/frodokem_common/frodo_mode.h create mode 100644 src/lib/pubkey/frodokem/frodokem_common/frodo_types.h create mode 100644 src/lib/pubkey/frodokem/frodokem_common/frodokem.cpp create mode 100644 src/lib/pubkey/frodokem/frodokem_common/frodokem.h create mode 100644 src/lib/pubkey/frodokem/frodokem_common/info.txt create mode 100644 src/scripts/dev_tools/gen_frodo_kat.py create mode 100644 src/tests/data/pubkey/frodokem_kat.vec create mode 100644 src/tests/test_frodokem.cpp diff --git a/doc/api_ref/pubkey.rst b/doc/api_ref/pubkey.rst index e2e8d43e632..88f31c4c9d5 100644 --- a/doc/api_ref/pubkey.rst +++ b/doc/api_ref/pubkey.rst @@ -97,7 +97,7 @@ Post-quantum secure signature scheme based on lattice problems. Kyber ~~~~~~~~~~~ -Post-quantum key encapsulation scheme based on lattices. +Post-quantum key encapsulation scheme based on (structured) lattices. .. note:: @@ -131,6 +131,11 @@ security of a hash function. Unlike XMSS, it is a stateless signature scheme, meaning that the private key does not change with each signature. It has high security but very long signatures and high runtime. +FrodoKEM +~~~~~~~~ + +A post-quantum secure key encapsulation scheme based on (unstructured) lattices. + McEliece ~~~~~~~~~~ @@ -1121,6 +1126,7 @@ Botan implements the following KEM schemes: 1. RSA #. Kyber +#. FrodoKEM #. McEliece .. _kyber_example: diff --git a/doc/dev_ref/oids.rst b/doc/dev_ref/oids.rst index f8ea9446a8e..47683e9fc60 100644 --- a/doc/dev_ref/oids.rst +++ b/doc/dev_ref/oids.rst @@ -15,6 +15,24 @@ Values currently assigned are:: -- { publicKey 5 } previously used for XMSS draft 6 gost-3410-with-sha256 OBJECT IDENTIFIER ::= { publicKey 6 1 } + frodokem-shake OBJECT IDENTIFIER ::= { publicKey 14 } + efrodokem-shake OBJECT IDENTIFIER ::= { publicKey 16 } + frodokem-aes OBJECT IDENTIFIER ::= { publicKey 15 } + efrodokem-aes OBJECT IDENTIFIER ::= { publicKey 17 } + + frodokem-640-shake OBJECT_IDENTIFIER : { frodokem-shake 1 } + frodokem-976-shake OBJECT_IDENTIFIER : { frodokem-shake 2 } + frodokem-1344-shake OBJECT_IDENTIFIER : { frodokem-shake 3 } + frodokem-640-aes OBJECT_IDENTIFIER : { frodokem-aes 1 } + frodokem-976-aes OBJECT_IDENTIFIER : { frodokem-aes 2 } + frodokem-1344-aes OBJECT_IDENTIFIER : { frodokem-aes 3 } + efrodokem-640-shake OBJECT_IDENTIFIER : { efrodokem-shake 1 } + efrodokem-976-shake OBJECT_IDENTIFIER : { efrodokem-shake 2 } + efrodokem-1344-shake OBJECT_IDENTIFIER : { efrodokem-shake 3 } + efrodokem-640-aes OBJECT_IDENTIFIER : { efrodokem-aes 1 } + efrodokem-976-aes OBJECT_IDENTIFIER : { efrodokem-aes 2 } + efrodokem-1344-aes OBJECT_IDENTIFIER : { efrodokem-aes 3 } + kyber OBJECT IDENTIFIER ::= { publicKey 7 } kyber-90s OBJECT IDENTIFIER ::= { publicKey 11 } diff --git a/src/build-data/oids.txt b/src/build-data/oids.txt index f59df0d5d8f..b3146f4d5fb 100644 --- a/src/build-data/oids.txt +++ b/src/build-data/oids.txt @@ -13,6 +13,20 @@ 1.3.101.110 = Curve25519 1.3.101.112 = Ed25519 +# FrodoKEM OIDs are currently in Botan's private arc +1.3.6.1.4.1.25258.1.14.1 = FrodoKEM-640-SHAKE +1.3.6.1.4.1.25258.1.14.2 = FrodoKEM-976-SHAKE +1.3.6.1.4.1.25258.1.14.3 = FrodoKEM-1344-SHAKE +1.3.6.1.4.1.25258.1.15.1 = FrodoKEM-640-AES +1.3.6.1.4.1.25258.1.15.2 = FrodoKEM-976-AES +1.3.6.1.4.1.25258.1.15.3 = FrodoKEM-1344-AES +1.3.6.1.4.1.25258.1.16.1 = eFrodoKEM-640-SHAKE +1.3.6.1.4.1.25258.1.16.2 = eFrodoKEM-976-SHAKE +1.3.6.1.4.1.25258.1.16.3 = eFrodoKEM-1344-SHAKE +1.3.6.1.4.1.25258.1.17.1 = eFrodoKEM-640-AES +1.3.6.1.4.1.25258.1.17.2 = eFrodoKEM-976-AES +1.3.6.1.4.1.25258.1.17.3 = eFrodoKEM-1344-AES + # Kyber OIDs are currently in Botan's private arc 1.3.6.1.4.1.25258.1.7.1 = Kyber-512-r3 1.3.6.1.4.1.25258.1.7.2 = Kyber-768-r3 diff --git a/src/cli/speed.cpp b/src/cli/speed.cpp index 2bb6c226201..746adfada0c 100644 --- a/src/cli/speed.cpp +++ b/src/cli/speed.cpp @@ -128,6 +128,10 @@ #include #endif +#if defined(BOTAN_HAS_FRODOKEM) + #include +#endif + #if defined(BOTAN_HAS_ECDSA) #include #endif @@ -404,7 +408,8 @@ class Speed final : public Command { "Curve25519", "McEliece", "Kyber", - "SPHINCS+" + "SPHINCS+", + "FrodoKEM" }; // clang-format on } @@ -614,6 +619,11 @@ class Speed final : public Command { bench_sphincs_plus(provider, msec); } #endif +#if defined(BOTAN_HAS_FRODOKEM) + else if(algo == "FrodoKEM") { + bench_frodokem(provider, msec); + } +#endif #if defined(BOTAN_HAS_SCRYPT) else if(algo == "scrypt") { bench_scrypt(provider, msec); @@ -2037,6 +2047,41 @@ class Speed final : public Command { } #endif +#if defined(BOTAN_HAS_FRODOKEM) + void bench_frodokem(const std::string& provider, std::chrono::milliseconds msec) { + std::vector frodo_modes{ + Botan::FrodoKEMMode::FrodoKEM640_SHAKE, + Botan::FrodoKEMMode::FrodoKEM976_SHAKE, + Botan::FrodoKEMMode::FrodoKEM1344_SHAKE, + Botan::FrodoKEMMode::eFrodoKEM640_SHAKE, + Botan::FrodoKEMMode::eFrodoKEM976_SHAKE, + Botan::FrodoKEMMode::eFrodoKEM1344_SHAKE, + Botan::FrodoKEMMode::FrodoKEM640_AES, + Botan::FrodoKEMMode::FrodoKEM976_AES, + Botan::FrodoKEMMode::FrodoKEM1344_AES, + Botan::FrodoKEMMode::eFrodoKEM640_AES, + Botan::FrodoKEMMode::eFrodoKEM976_AES, + Botan::FrodoKEMMode::eFrodoKEM1344_AES, + }; + + for(auto modet : frodo_modes) { + if(!modet.is_available()) { + continue; + } + + Botan::FrodoKEMMode mode(modet); + + auto keygen_timer = make_timer(mode.to_string(), provider, "keygen"); + + auto key = keygen_timer->run([&] { return Botan::FrodoKEM_PrivateKey(rng(), mode); }); + + record_result(keygen_timer); + + bench_pk_kem(key, mode.to_string(), provider, "KDF2(SHA-256)", msec); + } + } +#endif + #if defined(BOTAN_HAS_XMSS_RFC8391) void bench_xmss(const std::string& provider, std::chrono::milliseconds msec) { /* diff --git a/src/lib/asn1/oid_maps.cpp b/src/lib/asn1/oid_maps.cpp index a2fab4b0f96..d879c2fe6f3 100644 --- a/src/lib/asn1/oid_maps.cpp +++ b/src/lib/asn1/oid_maps.cpp @@ -1,7 +1,7 @@ /* * OID maps * -* This file was automatically generated by src/scripts/dev_tools/gen_oids.py on 2023-05-30 +* This file was automatically generated by ./src/scripts/dev_tools/gen_oids.py on 2023-11-02 * * All manual edits to this file will be lost. Edit the script * then regenerate this source file. @@ -162,6 +162,18 @@ std::unordered_map OID_Map::load_oid2str_map() { {"1.3.6.1.4.1.25258.1.12.3.4", "SphincsPlus-haraka-192f-r3.1"}, {"1.3.6.1.4.1.25258.1.12.3.5", "SphincsPlus-haraka-256s-r3.1"}, {"1.3.6.1.4.1.25258.1.12.3.6", "SphincsPlus-haraka-256f-r3.1"}, + {"1.3.6.1.4.1.25258.1.14.1", "FrodoKEM-640-SHAKE"}, + {"1.3.6.1.4.1.25258.1.14.2", "FrodoKEM-976-SHAKE"}, + {"1.3.6.1.4.1.25258.1.14.3", "FrodoKEM-1344-SHAKE"}, + {"1.3.6.1.4.1.25258.1.15.1", "FrodoKEM-640-AES"}, + {"1.3.6.1.4.1.25258.1.15.2", "FrodoKEM-976-AES"}, + {"1.3.6.1.4.1.25258.1.15.3", "FrodoKEM-1344-AES"}, + {"1.3.6.1.4.1.25258.1.16.1", "eFrodoKEM-640-SHAKE"}, + {"1.3.6.1.4.1.25258.1.16.2", "eFrodoKEM-976-SHAKE"}, + {"1.3.6.1.4.1.25258.1.16.3", "eFrodoKEM-1344-SHAKE"}, + {"1.3.6.1.4.1.25258.1.17.1", "eFrodoKEM-640-AES"}, + {"1.3.6.1.4.1.25258.1.17.2", "eFrodoKEM-976-AES"}, + {"1.3.6.1.4.1.25258.1.17.3", "eFrodoKEM-1344-AES"}, {"1.3.6.1.4.1.25258.1.3", "McEliece"}, {"1.3.6.1.4.1.25258.1.5", "XMSS-draft6"}, {"1.3.6.1.4.1.25258.1.6.1", "GOST-34.10-2012-256/SHA-256"}, @@ -367,6 +379,12 @@ std::unordered_map OID_Map::load_str2oid_map() { {"ECKCDSA/SHA-256", OID({1, 2, 410, 200004, 1, 100, 4, 5})}, {"Ed25519", OID({1, 3, 101, 112})}, {"ElGamal", OID({1, 3, 6, 1, 4, 1, 3029, 1, 2, 1})}, + {"FrodoKEM-1344-AES", OID({1, 3, 6, 1, 4, 1, 25258, 1, 15, 3})}, + {"FrodoKEM-1344-SHAKE", OID({1, 3, 6, 1, 4, 1, 25258, 1, 14, 3})}, + {"FrodoKEM-640-AES", OID({1, 3, 6, 1, 4, 1, 25258, 1, 15, 1})}, + {"FrodoKEM-640-SHAKE", OID({1, 3, 6, 1, 4, 1, 25258, 1, 14, 1})}, + {"FrodoKEM-976-AES", OID({1, 3, 6, 1, 4, 1, 25258, 1, 15, 2})}, + {"FrodoKEM-976-SHAKE", OID({1, 3, 6, 1, 4, 1, 25258, 1, 14, 2})}, {"GOST-34.10", OID({1, 2, 643, 2, 2, 19})}, {"GOST-34.10-2012-256", OID({1, 2, 643, 7, 1, 1, 1, 1})}, {"GOST-34.10-2012-256/SHA-256", OID({1, 3, 6, 1, 4, 1, 25258, 1, 6, 1})}, @@ -540,6 +558,12 @@ std::unordered_map OID_Map::load_str2oid_map() { {"brainpool320r1", OID({1, 3, 36, 3, 3, 2, 8, 1, 1, 9})}, {"brainpool384r1", OID({1, 3, 36, 3, 3, 2, 8, 1, 1, 11})}, {"brainpool512r1", OID({1, 3, 36, 3, 3, 2, 8, 1, 1, 13})}, + {"eFrodoKEM-1344-AES", OID({1, 3, 6, 1, 4, 1, 25258, 1, 17, 3})}, + {"eFrodoKEM-1344-SHAKE", OID({1, 3, 6, 1, 4, 1, 25258, 1, 16, 3})}, + {"eFrodoKEM-640-AES", OID({1, 3, 6, 1, 4, 1, 25258, 1, 17, 1})}, + {"eFrodoKEM-640-SHAKE", OID({1, 3, 6, 1, 4, 1, 25258, 1, 16, 1})}, + {"eFrodoKEM-976-AES", OID({1, 3, 6, 1, 4, 1, 25258, 1, 17, 2})}, + {"eFrodoKEM-976-SHAKE", OID({1, 3, 6, 1, 4, 1, 25258, 1, 16, 2})}, {"frp256v1", OID({1, 2, 250, 1, 223, 101, 256, 1})}, {"gost_256A", OID({1, 2, 643, 7, 1, 2, 1, 1, 1})}, {"gost_256B", OID({1, 2, 643, 7, 1, 2, 1, 1, 2})}, diff --git a/src/lib/pubkey/frodokem/frodokem/frodo_shake_generator.h b/src/lib/pubkey/frodokem/frodokem/frodo_shake_generator.h new file mode 100644 index 00000000000..819f0bbdd7c --- /dev/null +++ b/src/lib/pubkey/frodokem/frodokem/frodo_shake_generator.h @@ -0,0 +1,40 @@ +/* + * FrodoKEM matrix generator based on SHAKE + * + * The Fellowship of the FrodoKEM: + * (C) 2023 Jack Lloyd + * 2023 René Meusel, Amos Treiber - Rohde & Schwarz Cybersecurity + * + * Botan is released under the Simplified BSD License (see license.txt) + */ + +#ifndef BOTAN_FRODOKEM_SHAKE_GENERATOR_H_ +#define BOTAN_FRODOKEM_SHAKE_GENERATOR_H_ + +#include +#include +#include +#include + +#include + +namespace Botan { + +inline auto create_shake_row_generator(const FrodoKEMConstants& constants, StrongSpan seed_a) { + BOTAN_ASSERT_NOMSG(constants.mode().is_shake()); + + return [xof = SHAKE_128_XOF(), a = FrodoSeedA(seed_a)](std::span out, uint16_t i) mutable { + xof.clear(); + // TODO: update that once #3707 is merged + // potentially add a new method: std::array as_le(uintXX_t) + std::array le; + store_le(i, le.data()); + xof.update(le); + xof.update(a); + xof.output(out); + }; +} + +} // namespace Botan + +#endif diff --git a/src/lib/pubkey/frodokem/frodokem/info.txt b/src/lib/pubkey/frodokem/frodokem/info.txt new file mode 100644 index 00000000000..9012457a3da --- /dev/null +++ b/src/lib/pubkey/frodokem/frodokem/info.txt @@ -0,0 +1,12 @@ + +FRODOKEM_SHAKE -> 20231114 + + + +name -> "FrodoKEM" + + + +shake_xof +frodokem_common + diff --git a/src/lib/pubkey/frodokem/frodokem_aes/frodo_aes_generator.h b/src/lib/pubkey/frodokem/frodokem_aes/frodo_aes_generator.h new file mode 100644 index 00000000000..d7d269854a4 --- /dev/null +++ b/src/lib/pubkey/frodokem/frodokem_aes/frodo_aes_generator.h @@ -0,0 +1,56 @@ +/* + * FrodoKEM matrix generator based on AES + * + * The Fellowship of the FrodoKEM: + * (C) 2023 Jack Lloyd + * 2023 René Meusel, Amos Treiber - Rohde & Schwarz Cybersecurity + * + * Botan is released under the Simplified BSD License (see license.txt) + */ + +#ifndef BOTAN_FRODOKEM_AES_GENERATOR_H_ +#define BOTAN_FRODOKEM_AES_GENERATOR_H_ + +#include +#include +#include +#include +#include + +#include +#include + +namespace Botan { + +inline auto create_aes_row_generator(const FrodoKEMConstants& constants, StrongSpan seed_a) { + BOTAN_ASSERT_NOMSG(constants.mode().is_aes()); + + auto setup_aes = [](StrongSpan seed) { + AES_128 aes; + aes.set_key(seed); + return aes; + }; + + return [n = constants.n(), aes = setup_aes(seed_a)](std::span out, uint16_t i) { + BufferStuffer out_bs(out); + + for(size_t j = 0; j < n; j += 8) { + // set up the to-be-encrypted 'b' value in the out variable + // for in-place encryption of the block cipher + auto out_coefs = out_bs.next(aes.block_size()); + + // b = i || j || 0000... + store_le(static_cast(i), out_coefs.data()); + store_le(static_cast(j), out_coefs.data() + sizeof(uint16_t)); + for(size_t ii = 4; ii < out_coefs.size(); ++ii) { + out_coefs[ii] = 0; + } + + aes.encrypt(out_coefs); + } + }; +} + +} // namespace Botan + +#endif diff --git a/src/lib/pubkey/frodokem/frodokem_aes/info.txt b/src/lib/pubkey/frodokem/frodokem_aes/info.txt new file mode 100644 index 00000000000..a96ba3df431 --- /dev/null +++ b/src/lib/pubkey/frodokem/frodokem_aes/info.txt @@ -0,0 +1,12 @@ + +FRODOKEM_AES -> 20231103 + + + +name -> "FrodoKEM (AES)" + + + +aes +frodokem_common + diff --git a/src/lib/pubkey/frodokem/frodokem_common/frodo_constants.cpp b/src/lib/pubkey/frodokem/frodokem_common/frodo_constants.cpp new file mode 100644 index 00000000000..08ca2de6102 --- /dev/null +++ b/src/lib/pubkey/frodokem/frodokem_common/frodo_constants.cpp @@ -0,0 +1,102 @@ +/* + * FrodoKEM modes and constants + * + * The Fellowship of the FrodoKEM: + * (C) 2023 Jack Lloyd + * 2023 René Meusel, Amos Treiber - Rohde & Schwarz Cybersecurity + * + * Botan is released under the Simplified BSD License (see license.txt) + */ + +#include + +#include + +namespace Botan { + +FrodoKEMConstants::FrodoKEMConstants(FrodoKEMMode mode) : m_mode(mode), m_len_a(128), m_n_bar(8) { + BOTAN_ASSERT(m_mode.is_available(), "Mode is not available."); + + if(mode.is_ephemeral()) { + m_len_salt = 0; + } + + switch(mode.mode()) { + case FrodoKEMMode::FrodoKEM640_SHAKE: + case FrodoKEMMode::FrodoKEM640_AES: + case FrodoKEMMode::eFrodoKEM640_SHAKE: + case FrodoKEMMode::eFrodoKEM640_AES: + m_nist_strength = 128; + m_d = 15; + m_n = 640; + m_b = 2; + if(mode.is_static()) { + m_len_salt = 256; + m_len_se = 256; + } else if(mode.is_ephemeral()) { + m_len_se = 128; + } else { + BOTAN_ASSERT_UNREACHABLE(); + } + + m_cdf_table = {4643, 13363, 20579, 25843, 29227, 31145, 32103, 32525, 32689, 32745, 32762, 32766, 32767}; + + m_shake = "SHAKE-128"; + break; + + case FrodoKEMMode::FrodoKEM976_SHAKE: + case FrodoKEMMode::FrodoKEM976_AES: + case FrodoKEMMode::eFrodoKEM976_SHAKE: + case FrodoKEMMode::eFrodoKEM976_AES: + m_nist_strength = 192; + m_d = 16; + m_n = 976; + m_b = 3; + if(mode.is_static()) { + m_len_salt = 384; + m_len_se = 384; + } else if(mode.is_ephemeral()) { + m_len_se = 192; + } else { + BOTAN_ASSERT_UNREACHABLE(); + } + + m_cdf_table = {5638, 15915, 23689, 28571, 31116, 32217, 32613, 32731, 32760, 32766, 32767}; + + m_shake = "SHAKE-256"; + break; + + case FrodoKEMMode::FrodoKEM1344_SHAKE: + case FrodoKEMMode::FrodoKEM1344_AES: + case FrodoKEMMode::eFrodoKEM1344_SHAKE: + case FrodoKEMMode::eFrodoKEM1344_AES: + m_nist_strength = 256; + m_d = 16; + m_n = 1344; + m_b = 4; + if(mode.is_static()) { + m_len_salt = 512; + m_len_se = 512; + } else if(mode.is_ephemeral()) { + m_len_se = 256; + } else { + BOTAN_ASSERT_UNREACHABLE(); + } + + m_cdf_table = {9142, 23462, 30338, 32361, 32725, 32765, 32767}; + + m_shake = "SHAKE-256"; + break; + } + + m_shake_xof = XOF::create_or_throw(m_shake); +} + +FrodoKEMConstants::~FrodoKEMConstants() = default; + +XOF& FrodoKEMConstants::SHAKE_XOF() const { + m_shake_xof->clear(); + return *m_shake_xof; +} + +} // namespace Botan diff --git a/src/lib/pubkey/frodokem/frodokem_common/frodo_constants.h b/src/lib/pubkey/frodokem/frodokem_common/frodo_constants.h new file mode 100644 index 00000000000..8ecf11fe285 --- /dev/null +++ b/src/lib/pubkey/frodokem/frodokem_common/frodo_constants.h @@ -0,0 +1,103 @@ +/* + * FrodoKEM constants + * + * The Fellowship of the FrodoKEM: + * (C) 2023 Jack Lloyd + * 2023 René Meusel, Amos Treiber - Rohde & Schwarz Cybersecurity + * + * Botan is released under the Simplified BSD License (see license.txt) + */ + +#ifndef BOTAN_FRODOKEM_CONSTANTS_H_ +#define BOTAN_FRODOKEM_CONSTANTS_H_ + +#include +#include + +#include +#include +#include + +namespace Botan { + +class XOF; + +class BOTAN_TEST_API FrodoKEMConstants { + public: + FrodoKEMConstants(FrodoKEMMode mode); + + ~FrodoKEMConstants(); + + FrodoKEMConstants(const FrodoKEMConstants& other) : FrodoKEMConstants(other.m_mode) {} + + FrodoKEMConstants(FrodoKEMConstants&& other) = default; + FrodoKEMConstants& operator=(const FrodoKEMConstants& other) = delete; + FrodoKEMConstants& operator=(FrodoKEMConstants&& other) = default; + + FrodoKEMMode mode() const { return m_mode; } + + size_t cdf_table_len() const { return m_cdf_table.size(); } + + uint16_t cdf_table_at(size_t i) const { return m_cdf_table.at(i); } + + size_t estimated_strength() const { return m_nist_strength; } + + size_t n() const { return m_n; } + + size_t b() const { return m_b; } // extracted bits + + size_t d() const { return m_d; } // D = logq + + size_t n_bar() const { return m_n_bar; } + + size_t len_a_bytes() const { return m_len_a / 8; } // len of seed_a in bytes + + size_t len_se_bytes() const { return m_len_se / 8; } + + size_t len_sec_bytes() const { return m_nist_strength / 8; } + + size_t len_salt_bytes() const { return m_len_salt / 8; } + + size_t len_ct_bytes() const { + return (m_d * m_n * m_n_bar + m_d * m_n_bar * m_n_bar + m_len_salt) / 8; + } // Ciphertext length in bytes + + size_t len_public_key_bytes() const { return (m_len_a + (m_d * m_n * m_n_bar)) / 8; } + + size_t len_private_key_bytes() const { + return (m_nist_strength + m_len_a + (m_d * m_n * m_n_bar) + (m_n_bar * m_n * 16) + m_nist_strength) / 8; + } + + size_t len_packed_b_bytes() const { return (m_d * m_n * m_n_bar) / 8; } + + size_t len_packed_c_bytes() const { return (m_d * m_n_bar * m_n_bar) / 8; } + + FrodoDomainSeparator encapsulation_domain_separator() const { return FrodoDomainSeparator({0x96}); } + + FrodoDomainSeparator keygen_domain_separator() const { return FrodoDomainSeparator({0x5F}); } + + // TODO: those aren't actually const. We worked around some constness + // issues when playing with the XOFs that are residing in this class. + XOF& SHAKE_XOF() const; + + private: + FrodoKEMMode m_mode; + size_t m_nist_strength; + size_t m_len_salt; + size_t m_len_se; + size_t m_len_a; + size_t m_b; + size_t m_n; + size_t m_n_bar; + size_t m_d; + + std::vector m_cdf_table; // Distribution table T_chi + + mutable std::unique_ptr m_shake_xof; + + std::string m_shake; +}; + +} // namespace Botan + +#endif diff --git a/src/lib/pubkey/frodokem/frodokem_common/frodo_matrix.cpp b/src/lib/pubkey/frodokem/frodokem_common/frodo_matrix.cpp new file mode 100644 index 00000000000..fae19ea5e24 --- /dev/null +++ b/src/lib/pubkey/frodokem/frodokem_common/frodo_matrix.cpp @@ -0,0 +1,494 @@ +/* + * FrodoKEM matrix logic + * Based on the MIT licensed reference implementation by the designers + * (https://github.com/microsoft/PQCrypto-LWEKE/tree/master/src) + * + * The Fellowship of the FrodoKEM: + * (C) 2023 Jack Lloyd + * 2023 René Meusel, Amos Treiber - Rohde & Schwarz Cybersecurity + * + * Botan is released under the Simplified BSD License (see license.txt) + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOTAN_HAS_FRODOKEM_AES) + #include +#endif + +#if defined(BOTAN_HAS_FRODOKEM_SHAKE) + #include +#endif + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +secure_vector make_elements_vector(const FrodoMatrix::Dimensions& dimensions) { + return secure_vector(static_cast(std::get<0>(dimensions)) * std::get<1>(dimensions)); +} + +std::function out, uint16_t i)> make_row_generator(const FrodoKEMConstants& constants, + StrongSpan seed_a) { +#if defined(BOTAN_HAS_FRODOKEM_AES) + if(constants.mode().is_aes()) { + return create_aes_row_generator(constants, seed_a); + } +#endif + +#if defined(BOTAN_HAS_FRODOKEM_SHAKE) + if(constants.mode().is_shake()) { + return create_shake_row_generator(constants, seed_a); + } +#endif + + // If we don't have AES in this build, the instantiation of the FrodoKEM instance + // is blocked upstream already. Hence, assert is save here. + BOTAN_ASSERT_UNREACHABLE(); +} + +} // namespace + +FrodoMatrix FrodoMatrix::sample(const FrodoKEMConstants& constants, + const Dimensions& dimensions, + StrongSpan r) { + BOTAN_ASSERT_NOMSG(r.size() % 2 == 0); + const auto n = r.size() / 2; + + auto elements = make_elements_vector(dimensions); + BOTAN_ASSERT_NOMSG(n == elements.size()); + + load_le(elements.data(), r.data(), n); + + for(size_t i = 0; i < n; ++i) { + uint32_t sample = 0; // Avoid integral promotion + uint16_t prnd = elements.at(i) >> 1; // Drop the least significant bit + uint16_t sign = elements.at(i) & 0x1; // Pick the least significant bit + + // No need to compare with the last value. + for(size_t j = 0; j < constants.cdf_table_len() - 1; ++j) { + // Constant time comparison: 1 if CDF_TABLE[j] < s, 0 otherwise. + sample += CT::Mask::is_lt(constants.cdf_table_at(j), prnd).if_set_return(1); + } + // Assuming that sign is either 0 or 1, flips sample iff sign = 1 + elements.at(i) = static_cast((-sign) ^ sample) + sign; + } + + return FrodoMatrix(dimensions, std::move(elements)); +} + +std::function FrodoMatrix::make_sample_generator( + const FrodoKEMConstants& constants, Botan::XOF& shake) { + return [&constants, &shake](const FrodoMatrix::Dimensions& dimensions) mutable { + return sample(constants, + dimensions, + shake.output(sizeof(uint16_t) * std::get<0>(dimensions) * std::get<1>(dimensions))); + }; +} + +FrodoMatrix::FrodoMatrix(Dimensions dims) : + m_dim1(std::get<0>(dims)), m_dim2(std::get<1>(dims)), m_elements(make_elements_vector(dims)) {} + +FrodoMatrix FrodoMatrix::mul_add_as_plus_e(const FrodoKEMConstants& constants, + const FrodoMatrix& s, + const FrodoMatrix& e, + StrongSpan seed_a) { + BOTAN_ASSERT(std::get<0>(e.dimensions()) == std::get<1>(s.dimensions()) && + std::get<1>(e.dimensions()) == std::get<0>(s.dimensions()), + "FrodoMatrix dimension mismatch of E and S"); + BOTAN_ASSERT(std::get<0>(e.dimensions()) == constants.n() && std::get<1>(e.dimensions()) == constants.n_bar(), + "FrodoMatrix dimension mismatch of new matrix dimensions and E"); + + auto elements = make_elements_vector(e.dimensions()); + auto row_generator = make_row_generator(constants, seed_a); + + /* + We perform 4 invocations of SHAKE128 per iteration to obtain n 16-bit values per invocation. + a_row_data contains the 16-bit values of the current 4 rows. a_row_data_bytes represents the corresponding bytes. + */ + std::vector a_row_data(4 * constants.n(), 0); + // TODO: maybe use std::as_bytes() instead + // (take extra care, as it produces a std::span) + std::span a_row_data_bytes(reinterpret_cast(a_row_data.data()), + sizeof(uint16_t) * a_row_data.size()); + + for(size_t i = 0; i < constants.n(); i += 4) { + auto a_row = BufferStuffer(a_row_data_bytes); + + // Do 4 invocations to fill 4 rows + row_generator(a_row.next(constants.n() * sizeof(uint16_t)), static_cast(i + 0)); + row_generator(a_row.next(constants.n() * sizeof(uint16_t)), static_cast(i + 1)); + row_generator(a_row.next(constants.n() * sizeof(uint16_t)), static_cast(i + 2)); + row_generator(a_row.next(constants.n() * sizeof(uint16_t)), static_cast(i + 3)); + + // Use generated bytes to fill 16-bit data + load_le(a_row_data.data(), a_row_data_bytes.data(), 4 * constants.n()); + + for(size_t k = 0; k < constants.n_bar(); ++k) { + std::array sum = {0}; + for(size_t j = 0; j < constants.n(); ++j) { // Matrix-vector multiplication + // Note: we use uint32_t for `sp` to avoid an integral promotion to `int` + // when multiplying `sp` with other row values. Otherwise we might + // suffer from undefined behaviour due to a signed integer overflow. + // See: https://learn.microsoft.com/en-us/cpp/cpp/standard-conversions#integral-promotions + const uint32_t sp = s.elements_at(k * constants.n() + j); + + // Go through four lines with same sp + sum.at(0) += static_cast(a_row_data.at(0 * constants.n() + j) * sp); + sum.at(1) += static_cast(a_row_data.at(1 * constants.n() + j) * sp); + sum.at(2) += static_cast(a_row_data.at(2 * constants.n() + j) * sp); + sum.at(3) += static_cast(a_row_data.at(3 * constants.n() + j) * sp); + } + elements.at((i + 0) * constants.n_bar() + k) = e.elements_at((i + 0) * constants.n_bar() + k) + sum.at(0); + elements.at((i + 3) * constants.n_bar() + k) = e.elements_at((i + 3) * constants.n_bar() + k) + sum.at(3); + elements.at((i + 2) * constants.n_bar() + k) = e.elements_at((i + 2) * constants.n_bar() + k) + sum.at(2); + elements.at((i + 1) * constants.n_bar() + k) = e.elements_at((i + 1) * constants.n_bar() + k) + sum.at(1); + } + } + + return FrodoMatrix(e.dimensions(), std::move(elements)); +} + +FrodoMatrix FrodoMatrix::mul_add_sa_plus_e(const FrodoKEMConstants& constants, + const FrodoMatrix& s, + const FrodoMatrix& e, + StrongSpan seed_a) { + BOTAN_ASSERT(std::get<0>(e.dimensions()) == std::get<0>(s.dimensions()) && + std::get<1>(e.dimensions()) == std::get<1>(s.dimensions()), + "FrodoMatrix dimension mismatch of E and S"); + BOTAN_ASSERT(std::get<0>(e.dimensions()) == constants.n_bar() && std::get<1>(e.dimensions()) == constants.n(), + "FrodoMatrix dimension mismatch of new matrix dimensions and E"); + + auto elements = e.m_elements; + auto row_generator = make_row_generator(constants, seed_a); + + /* + We perform 8 invocations of SHAKE128 per iteration to obtain n 16-bit values per invocation. + a_row_data contains the 16-bit values of the current 8 rows. a_row_data_bytes represents the corresponding bytes. + */ + std::vector a_row_data(8 * constants.n(), 0); + // TODO: maybe use std::as_bytes() + std::span a_row_data_bytes(reinterpret_cast(a_row_data.data()), + sizeof(uint16_t) * a_row_data.size()); + + // Start matrix multiplication + for(size_t i = 0; i < constants.n(); i += 8) { + auto a_row = BufferStuffer(a_row_data_bytes); + + // Do 8 invocations to fill 8 rows + row_generator(a_row.next(sizeof(uint16_t) * constants.n()), static_cast(i + 0)); + row_generator(a_row.next(sizeof(uint16_t) * constants.n()), static_cast(i + 1)); + row_generator(a_row.next(sizeof(uint16_t) * constants.n()), static_cast(i + 2)); + row_generator(a_row.next(sizeof(uint16_t) * constants.n()), static_cast(i + 3)); + row_generator(a_row.next(sizeof(uint16_t) * constants.n()), static_cast(i + 4)); + row_generator(a_row.next(sizeof(uint16_t) * constants.n()), static_cast(i + 5)); + row_generator(a_row.next(sizeof(uint16_t) * constants.n()), static_cast(i + 6)); + row_generator(a_row.next(sizeof(uint16_t) * constants.n()), static_cast(i + 7)); + + // Use generated bytes to fill 16-bit data + load_le(a_row_data.data(), a_row_data_bytes.data(), 8 * constants.n()); + + for(size_t j = 0; j < constants.n_bar(); ++j) { + uint16_t sum = 0; + std::array sp; + for(size_t p = 0; p < 8; ++p) { + sp[p] = s.elements_at(j * constants.n() + i + p); + } + for(size_t q = 0; q < constants.n(); ++q) { + sum = elements.at(j * constants.n() + q); + for(size_t p = 0; p < 8; ++p) { + sum += static_cast(sp[p] * a_row_data.at(p * constants.n() + q)); + } + elements.at(j * constants.n() + q) = sum; + } + } + } + + return FrodoMatrix(e.dimensions(), std::move(elements)); +} + +FrodoMatrix FrodoMatrix::mul_add_sb_plus_e(const FrodoKEMConstants& constants, + const FrodoMatrix& b, + const FrodoMatrix& s, + const FrodoMatrix& e) { + BOTAN_ASSERT(std::get<0>(b.dimensions()) == std::get<1>(s.dimensions()) && + std::get<1>(b.dimensions()) == std::get<0>(s.dimensions()), + "FrodoMatrix dimension mismatch of B and S"); + BOTAN_ASSERT(std::get<0>(b.dimensions()) == constants.n() && std::get<1>(b.dimensions()) == constants.n_bar(), + "FrodoMatrix dimension mismatch of B"); + BOTAN_ASSERT(std::get<0>(e.dimensions()) == constants.n_bar() && std::get<1>(e.dimensions()) == constants.n_bar(), + "FrodoMatrix dimension mismatch of E"); + + auto elements = make_elements_vector(e.dimensions()); + + for(size_t k = 0; k < constants.n_bar(); ++k) { + for(size_t i = 0; i < constants.n_bar(); ++i) { + elements.at(k * constants.n_bar() + i) = e.elements_at(k * constants.n_bar() + i); + for(size_t j = 0; j < constants.n(); ++j) { + elements.at(k * constants.n_bar() + i) += static_cast( + static_cast(s.elements_at(k * constants.n() + j)) * + b.elements_at(j * constants.n_bar() + i)); + } + } + } + + return FrodoMatrix(e.dimensions(), std::move(elements)); +} + +FrodoMatrix FrodoMatrix::encode(const FrodoKEMConstants& constants, StrongSpan in) { + const uint64_t mask = (uint64_t(1) << constants.b()) - 1; + + const auto dimensions = std::make_tuple(constants.n_bar(), constants.n_bar()); + auto elements = make_elements_vector(dimensions); + + BOTAN_ASSERT_NOMSG(in.size() * 8 == constants.n_bar() * constants.n_bar() * constants.b()); + + size_t pos = 0; + for(size_t i = 0; i < (constants.n_bar() * constants.n_bar()) / 8; ++i) { + uint64_t temp = 0; + for(size_t j = 0; j < constants.b(); ++j) { + temp |= static_cast(in[i * constants.b() + j]) << (8 * j); + } + for(size_t j = 0; j < 8; ++j) { + elements.at(pos++) = static_cast((temp & mask) << (constants.d() - constants.b())); // k*2^(D-B) + temp >>= constants.b(); + } + } + + return FrodoMatrix(dimensions, std::move(elements)); +} + +FrodoMatrix FrodoMatrix::add(const FrodoKEMConstants& constants, const FrodoMatrix& a, const FrodoMatrix& b) { + // Addition is defined for n_bar x n_bar matrices only + BOTAN_ASSERT_NOMSG(a.dimensions() == b.dimensions()); + BOTAN_ASSERT_NOMSG(std::get<0>(a.dimensions()) == constants.n_bar() && + std::get<1>(a.dimensions()) == constants.n_bar()); + + auto elements = make_elements_vector(a.dimensions()); + + for(size_t i = 0; i < constants.n_bar() * constants.n_bar(); ++i) { + elements.at(i) = a.elements_at(i) + b.elements_at(i); + } + + return FrodoMatrix(a.dimensions(), std::move(elements)); +} + +FrodoMatrix FrodoMatrix::sub(const FrodoKEMConstants& constants, const FrodoMatrix& a, const FrodoMatrix& b) { + // Subtraction is defined for n_bar x n_bar matrices only + BOTAN_ASSERT_NOMSG(a.dimensions() == b.dimensions()); + BOTAN_ASSERT_NOMSG(std::get<0>(a.dimensions()) == constants.n_bar() && + std::get<1>(a.dimensions()) == constants.n_bar()); + + auto elements = make_elements_vector(a.dimensions()); + + for(size_t i = 0; i < constants.n_bar() * constants.n_bar(); ++i) { + elements.at(i) = a.elements_at(i) - b.elements_at(i); + } + + return FrodoMatrix(a.dimensions(), std::move(elements)); +} + +CT::Mask FrodoMatrix::constant_time_compare(const FrodoMatrix& other) const { + BOTAN_ASSERT_NOMSG(dimensions() == other.dimensions()); + // TODO: Possibly use range-based comparison after #3715 is merged + return CT::is_equal(reinterpret_cast(m_elements.data()), + reinterpret_cast(other.m_elements.data()), + sizeof(decltype(m_elements)::value_type) * m_elements.size()); +} + +FrodoMatrix FrodoMatrix::mul_bs(const FrodoKEMConstants& constants, const FrodoMatrix& b, const FrodoMatrix& s) { + Dimensions dimensions = {constants.n_bar(), constants.n_bar()}; + auto elements = make_elements_vector(dimensions); + + for(size_t i = 0; i < constants.n_bar(); ++i) { + for(size_t j = 0; j < constants.n_bar(); ++j) { + auto& current = elements.at(i * constants.n_bar() + j); + current = 0; + for(size_t k = 0; k < constants.n(); ++k) { + current += static_cast( + static_cast(b.elements_at(i * constants.n() + k)) * + s.elements_at(j * constants.n() + + k)); //Since the input is s^T, we multiply the i-th row of b with the j-th row of s^t + } + } + } + + return FrodoMatrix(dimensions, std::move(elements)); +} + +void FrodoMatrix::pack(const FrodoKEMConstants& constants, StrongSpan out) const { + const size_t outlen = packed_size(constants); + BOTAN_ASSERT_NOMSG(out.size() == outlen); + + size_t i = 0; // whole bytes already filled in + size_t j = 0; // whole uint16_t already copied + uint16_t w = 0; // the leftover, not yet copied + uint8_t bits = 0; // the number of lsb in w + + while(i < outlen && (j < element_count() || ((j == element_count()) && (bits > 0)))) { + /* + in: | | |********|********| + ^ + j + w : | ****| + ^ + bits + out:|**|**|**|**|**|**|**|**|* | + ^^ + ib + */ + uint8_t b = 0; // bits in out[i] already filled in + while(b < 8) { + const uint8_t nbits = std::min(static_cast(8 - b), bits); + const uint16_t mask = static_cast(1 << nbits) - 1; + const auto t = static_cast((w >> (bits - nbits)) & mask); // the bits to copy from w to out + out[i] = out[i] + static_cast(t << (8 - b - nbits)); + b += nbits; + bits -= nbits; + + if(bits == 0) { + if(j < element_count()) { + w = m_elements.at(j); + bits = static_cast(constants.d()); + j++; + } else { + break; // the input vector is exhausted + } + } + } + if(b == 8) { // out[i] is filled in + i++; + } + } +} + +FrodoSerializedMatrix FrodoMatrix::serialize() const { + FrodoSerializedMatrix out(2 * m_elements.size()); + + for(unsigned int i = 0; i < m_elements.size(); ++i) { + store_le(m_elements.at(i), out.data() + 2 * i); + } + + return out; +} + +FrodoPlaintext FrodoMatrix::decode(const FrodoKEMConstants& constants) const { + const size_t nwords = (constants.n_bar() * constants.n_bar()) / 8; + uint16_t temp; + uint16_t maskex = static_cast(1 << constants.b()) - 1; + uint16_t maskq = static_cast(1 << constants.d()) - 1; + + uint64_t templong; + + FrodoPlaintext out(nwords * constants.b()); + + size_t index = 0; + for(size_t i = 0; i < nwords; i++) { + templong = 0; + for(size_t j = 0; j < 8; j++) { + temp = static_cast(((m_elements.at(index) & maskq) + (1 << (constants.d() - constants.b() - 1))) >> + (constants.d() - constants.b())); + templong |= static_cast(temp & maskex) << (constants.b() * j); + index++; + } + for(size_t j = 0; j < constants.b(); j++) { + out[i * constants.b() + j] = (templong >> (8 * j)) & 0xFF; + } + } + + return out; +} + +FrodoMatrix FrodoMatrix::unpack(const FrodoKEMConstants& constants, + const Dimensions& dimensions, + StrongSpan packed_bytes) { + const uint8_t lsb = static_cast(constants.d()); + const size_t inlen = packed_bytes.size(); + const size_t outlen = static_cast(std::get<0>(dimensions)) * std::get<1>(dimensions); + + BOTAN_ASSERT_NOMSG(inlen == ceil_tobytes(outlen * lsb)); + + auto elements = make_elements_vector(dimensions); + + size_t i = 0; // whole uint16_t already filled in + size_t j = 0; // whole bytes already copied + uint8_t w = 0; // the leftover, not yet copied + uint8_t bits = 0; // the number of lsb bits of w + + while(i < outlen && (j < inlen || ((j == inlen) && (bits > 0)))) { + /* + in: | | | | | | |**|**|... + ^ + j + w : | *| + ^ + bits + out:| *****| *****| *** | |... + ^ ^ + i b + */ + uint8_t b = 0; // bits in out[i] already filled in + while(b < lsb) { + const uint8_t nbits = std::min(static_cast(lsb - b), bits); + uint16_t mask = static_cast(1 << nbits) - 1; + uint8_t t = (w >> (bits - nbits)) & mask; // the bits to copy from w to out + + elements.at(i) = elements.at(i) + static_cast(t << (lsb - b - nbits)); + b += nbits; + bits -= nbits; + w &= static_cast(~(mask << bits)); // not strictly necessary; mostly for debugging + + if(bits == 0) { + if(j < inlen) { + w = packed_bytes[j]; + bits = 8; + j++; + } else { + break; // the input vector is exhausted + } + } + } + if(b == lsb) { // out[i] is filled in + i++; + } + } + + return FrodoMatrix(dimensions, std::move(elements)); +} + +FrodoMatrix FrodoMatrix::deserialize(const Dimensions& dimensions, StrongSpan bytes) { + auto elements = make_elements_vector(dimensions); + BOTAN_ASSERT_NOMSG(elements.size() * 2 == bytes.size()); + load_le(elements.data(), bytes.data(), elements.size()); + return FrodoMatrix(dimensions, std::move(elements)); +} + +void FrodoMatrix::reduce(const FrodoKEMConstants& constants) { + // Reduction is inherent if D is 16, because we use uint16_t in m_elements + if(constants.d() < sizeof(decltype(m_elements)::value_type) * 8) { + const uint16_t mask = static_cast(1 << constants.d()) - 1; + for(auto& elem : m_elements) { + elem = elem & mask; // mod q + } + } +} + +} // namespace Botan diff --git a/src/lib/pubkey/frodokem/frodokem_common/frodo_matrix.h b/src/lib/pubkey/frodokem/frodokem_common/frodo_matrix.h new file mode 100644 index 00000000000..46aaa4f9927 --- /dev/null +++ b/src/lib/pubkey/frodokem/frodokem_common/frodo_matrix.h @@ -0,0 +1,143 @@ +/* + * FrodoKEM matrix logic + * Based on the MIT licensed reference implementation by the designers + * (https://github.com/microsoft/PQCrypto-LWEKE/tree/master/src) + * + * The Fellowship of the FrodoKEM: + * (C) 2023 Jack Lloyd + * 2023 René Meusel, Amos Treiber - Rohde & Schwarz Cybersecurity + * + * Botan is released under the Simplified BSD License (see license.txt) + */ + +#ifndef BOTAN_FRODOKEM_MATRIX_H_ +#define BOTAN_FRODOKEM_MATRIX_H_ + +#include +#include +#include + +#include +#include +#include +#include + +namespace Botan { + +class FrodoMatrix { + public: + using Dimensions = std::tuple; + + explicit FrodoMatrix(Dimensions dims); + + uint16_t elements_at(size_t i) const { return m_elements.at(i); } + + size_t packed_size(const FrodoKEMConstants& constants) const { + const size_t lsb = constants.d(); + const size_t inlen = element_count(); + BOTAN_ASSERT_NOMSG((lsb * inlen) % 8 == 0); + return lsb * inlen / 8; // in bytes + } + + FrodoPackedMatrix pack(const FrodoKEMConstants& constants) const { + FrodoPackedMatrix out(packed_size(constants)); + pack(constants, out); + return out; + } + + // Pack m_elements into a output buffer, copying lsb = D = log2 q bits from each input element. + // Section 7.3 of spec + void pack(const FrodoKEMConstants& constants, StrongSpan out) const; + + FrodoSerializedMatrix serialize() const; + + FrodoPlaintext decode(const FrodoKEMConstants& constants) const; + + // Unpack the input FrodoPackedMatrix into the 16 bit m_elements vector, copying d bits + // for each output element from input. outlen must be at least ceil(inlen * 8 / d). + // m_elements is allocated here. + static FrodoMatrix unpack(const FrodoKEMConstants& constants, + const Dimensions& dimensions, + StrongSpan packed_bytes); + + static FrodoMatrix deserialize(const Dimensions& dimensions, StrongSpan bytes); + + static FrodoMatrix encode(const FrodoKEMConstants& constants, + StrongSpan in); // Section 7.2 of spec + + // Creates a matrix with n samples from the noise distribution which requires 16 bits to sample. + // The distribution is specified by its CDF. + // Input: pseudo-random values (2*n bytes) passed in r. + // Section 7.5 of spec + static FrodoMatrix sample(const FrodoKEMConstants& constants, + const Dimensions& dimensions, + StrongSpan r); + + // Helper function that calls FrodoMatrix::sample on initially provided consts and shake XOF. + // The output function calls shake.output at each invocation. + static std::function make_sample_generator( + const FrodoKEMConstants& constants, Botan::XOF& shake); + + // Generate-and-multiply: generate matrix A (N x N) row-wise, multiply by s on the right. + // Inputs: s^T (N_BAR x N), e (N x N_BAR), seed for matrix A + // Output: The elements of the FrodoMatrix will correspond to A*s + e (N x N_BAR). + static FrodoMatrix mul_add_as_plus_e(const FrodoKEMConstants& constants, + const FrodoMatrix& s, + const FrodoMatrix& e, + StrongSpan seed_a); + + // Generate-and-multiply: generate matrix A (N x N) column-wise, multiply by s' on the left. + // Inputs: s', e' (N_BAR x N) + // Output: out = s'*A + e' (N_BAR x N) + // The matrix multiplication uses the row-wise blocking and packing (RWCF) approach described in: J.W. Bos, M. Ofner, J. Renes, + // T. Schneider, C. van Vredendaal, "The Matrix Reloaded: Multiplication Strategies in FrodoKEM". https://eprint.iacr.org/2021/711 + static FrodoMatrix mul_add_sa_plus_e(const FrodoKEMConstants& constants, + const FrodoMatrix& s, + const FrodoMatrix& e, + StrongSpan seed_a); + + // Multiply by s on the left + // Inputs: b (N x N_BAR), s (N_BAR x N), e (N_BAR x N_BAR) + // Output: out = s*b + e (N_BAR x N_BAR). The existing elements are overwritten and a self reference is returned. + static FrodoMatrix mul_add_sb_plus_e(const FrodoKEMConstants& constants, + const FrodoMatrix& b, + const FrodoMatrix& s, + const FrodoMatrix& e); + + // Multiply by s on the right + // Inputs: b (N_BAR x N), s^T (N_BAR x N) + // Output: out = b*s (N_BAR x N_BAR) + static FrodoMatrix mul_bs(const FrodoKEMConstants& constants, const FrodoMatrix& b_p, const FrodoMatrix& s); + + // Add a and b + // Inputs: a, b (N_BAR x N_BAR) + // Output: c = a + b + static FrodoMatrix add(const FrodoKEMConstants& constants, const FrodoMatrix& a, const FrodoMatrix& b); + + // Subtract a and b + // Inputs: a, b (N_BAR x N_BAR) + // Output: c = a - b + static FrodoMatrix sub(const FrodoKEMConstants& constants, const FrodoMatrix& a, const FrodoMatrix& b); + + Dimensions dimensions() const { return {m_dim1, m_dim2}; } + + CT::Mask constant_time_compare(const FrodoMatrix& other) const; + + size_t element_count() const { return m_elements.size(); } + + void reduce(const FrodoKEMConstants& constants); + + private: + FrodoMatrix(const Dimensions& dimensions, secure_vector elements) : + m_dim1(std::get<0>(dimensions)), m_dim2(std::get<1>(dimensions)), m_elements(std::move(elements)) {} + + private: + size_t m_dim1; + size_t m_dim2; + + secure_vector m_elements; +}; + +} // namespace Botan + +#endif diff --git a/src/lib/pubkey/frodokem/frodokem_common/frodo_mode.cpp b/src/lib/pubkey/frodokem/frodokem_common/frodo_mode.cpp new file mode 100644 index 00000000000..ad4d7e4465a --- /dev/null +++ b/src/lib/pubkey/frodokem/frodokem_common/frodo_mode.cpp @@ -0,0 +1,111 @@ +/* + * FrodoKEM modes and constants + * + * The Fellowship of the FrodoKEM: + * (C) 2023 Jack Lloyd + * 2023 René Meusel, Amos Treiber - Rohde & Schwarz Cybersecurity + * + * Botan is released under the Simplified BSD License (see license.txt) + */ + +#include + +#include +#include +#include + +#include +#include +#include + +namespace Botan { + +namespace { + +FrodoKEMMode::Mode FrodoKEM_mode_from_string(std::string_view str) { + if(str == "FrodoKEM-640-SHAKE") { + return FrodoKEMMode::FrodoKEM640_SHAKE; + } + if(str == "FrodoKEM-976-SHAKE") { + return FrodoKEMMode::FrodoKEM976_SHAKE; + } + if(str == "FrodoKEM-1344-SHAKE") { + return FrodoKEMMode::FrodoKEM1344_SHAKE; + } + if(str == "eFrodoKEM-640-SHAKE") { + return FrodoKEMMode::eFrodoKEM640_SHAKE; + } + if(str == "eFrodoKEM-976-SHAKE") { + return FrodoKEMMode::eFrodoKEM976_SHAKE; + } + if(str == "eFrodoKEM-1344-SHAKE") { + return FrodoKEMMode::eFrodoKEM1344_SHAKE; + } + + if(str == "FrodoKEM-640-AES") { + return FrodoKEMMode::FrodoKEM640_AES; + } + if(str == "FrodoKEM-976-AES") { + return FrodoKEMMode::FrodoKEM976_AES; + } + if(str == "FrodoKEM-1344-AES") { + return FrodoKEMMode::FrodoKEM1344_AES; + } + if(str == "eFrodoKEM-640-AES") { + return FrodoKEMMode::eFrodoKEM640_AES; + } + if(str == "eFrodoKEM-976-AES") { + return FrodoKEMMode::eFrodoKEM976_AES; + } + if(str == "eFrodoKEM-1344-AES") { + return FrodoKEMMode::eFrodoKEM1344_AES; + } + + throw Invalid_Argument(fmt("'{}' is not a valid FrodoKEM mode name", str)); +} + +} // anonymous namespace + +FrodoKEMMode::FrodoKEMMode(Mode mode) : m_mode(mode) {} + +FrodoKEMMode::FrodoKEMMode(const OID& oid) : m_mode(FrodoKEM_mode_from_string(oid.to_formatted_string())) {} + +FrodoKEMMode::FrodoKEMMode(std::string_view str) : m_mode(FrodoKEM_mode_from_string(str)) {} + +OID FrodoKEMMode::object_identifier() const { + return OID::from_string(to_string()); +} + +std::string FrodoKEMMode::to_string() const { + switch(m_mode) { + case FrodoKEM640_SHAKE: + return "FrodoKEM-640-SHAKE"; + case FrodoKEM976_SHAKE: + return "FrodoKEM-976-SHAKE"; + case FrodoKEM1344_SHAKE: + return "FrodoKEM-1344-SHAKE"; + case eFrodoKEM640_SHAKE: + return "eFrodoKEM-640-SHAKE"; + case eFrodoKEM976_SHAKE: + return "eFrodoKEM-976-SHAKE"; + case eFrodoKEM1344_SHAKE: + return "eFrodoKEM-1344-SHAKE"; + + case FrodoKEM640_AES: + return "FrodoKEM-640-AES"; + case FrodoKEM976_AES: + return "FrodoKEM-976-AES"; + case FrodoKEM1344_AES: + return "FrodoKEM-1344-AES"; + case eFrodoKEM640_AES: + return "eFrodoKEM-640-AES"; + case eFrodoKEM976_AES: + return "eFrodoKEM-976-AES"; + case eFrodoKEM1344_AES: + return "eFrodoKEM-1344-AES"; + } + + BOTAN_ASSERT_UNREACHABLE(); +} + +} // namespace Botan diff --git a/src/lib/pubkey/frodokem/frodokem_common/frodo_mode.h b/src/lib/pubkey/frodokem/frodokem_common/frodo_mode.h new file mode 100644 index 00000000000..aa22890d012 --- /dev/null +++ b/src/lib/pubkey/frodokem/frodokem_common/frodo_mode.h @@ -0,0 +1,89 @@ +/* + * FrodoKEM modes and constants + * + * The Fellowship of the FrodoKEM: + * (C) 2023 Jack Lloyd + * 2023 René Meusel, Amos Treiber - Rohde & Schwarz Cybersecurity + * + * Botan is released under the Simplified BSD License (see license.txt) + */ + +#ifndef BOTAN_FRODOKEM_MODE_H_ +#define BOTAN_FRODOKEM_MODE_H_ + +#include + +#include + +namespace Botan { + +class BOTAN_PUBLIC_API(3, 3) FrodoKEMMode { + public: + enum Mode { + FrodoKEM640_SHAKE, + FrodoKEM976_SHAKE, + FrodoKEM1344_SHAKE, + eFrodoKEM640_SHAKE, + eFrodoKEM976_SHAKE, + eFrodoKEM1344_SHAKE, + FrodoKEM640_AES, + FrodoKEM976_AES, + FrodoKEM1344_AES, + eFrodoKEM640_AES, + eFrodoKEM976_AES, + eFrodoKEM1344_AES + }; + + FrodoKEMMode(Mode mode); + explicit FrodoKEMMode(const OID& oid); + explicit FrodoKEMMode(std::string_view str); + + OID object_identifier() const; + std::string to_string() const; + + Mode mode() const { return m_mode; } + + bool is_ephemeral() const { + return m_mode == eFrodoKEM640_SHAKE || m_mode == eFrodoKEM976_SHAKE || m_mode == eFrodoKEM1344_SHAKE || + m_mode == eFrodoKEM640_AES || m_mode == eFrodoKEM976_AES || m_mode == eFrodoKEM1344_AES; + } + + bool is_static() const { + return m_mode == FrodoKEM640_SHAKE || m_mode == FrodoKEM976_SHAKE || m_mode == FrodoKEM1344_SHAKE || + m_mode == FrodoKEM640_AES || m_mode == FrodoKEM976_AES || m_mode == FrodoKEM1344_AES; + } + + bool is_shake() const { + return m_mode == eFrodoKEM640_SHAKE || m_mode == eFrodoKEM976_SHAKE || m_mode == eFrodoKEM1344_SHAKE || + m_mode == FrodoKEM640_SHAKE || m_mode == FrodoKEM976_SHAKE || m_mode == FrodoKEM1344_SHAKE; + } + + bool is_aes() const { + return m_mode == eFrodoKEM640_AES || m_mode == eFrodoKEM976_AES || m_mode == eFrodoKEM1344_AES || + m_mode == FrodoKEM640_AES || m_mode == FrodoKEM976_AES || m_mode == FrodoKEM1344_AES; + } + + bool is_available() const { + return +#if defined(BOTAN_HAS_FRODOKEM_AES) + is_aes() || +#endif + +#if defined(BOTAN_HAS_FRODOKEM_SHAKE) + is_shake() || +#endif + + false; + } + + bool operator==(const FrodoKEMMode& other) const { return m_mode == other.m_mode; } + + bool operator!=(const FrodoKEMMode& other) const { return !(*this == other); } + + private: + Mode m_mode; +}; + +} // namespace Botan + +#endif diff --git a/src/lib/pubkey/frodokem/frodokem_common/frodo_types.h b/src/lib/pubkey/frodokem/frodokem_common/frodo_types.h new file mode 100644 index 00000000000..2ed26402638 --- /dev/null +++ b/src/lib/pubkey/frodokem/frodokem_common/frodo_types.h @@ -0,0 +1,60 @@ +/* + * FrodoKEM modes and constants + * + * The Fellowship of the FrodoKEM: + * (C) 2023 Jack Lloyd + * 2023 René Meusel, Amos Treiber - Rohde & Schwarz Cybersecurity + * + * Botan is released under the Simplified BSD License (see license.txt) + */ + +#ifndef BOTAN_FRODOKEM_TYPES_H_ +#define BOTAN_FRODOKEM_TYPES_H_ + +#include +#include + +#include +#include + +namespace Botan { + +// Bytes of seed_a +using FrodoSeedA = Strong, struct FrodoSeedA_>; + +// Bytes of s +using FrodoSeedS = Strong, struct FrodoSeedS_>; + +// Bytes of seed_se +using FrodoSeedSE = Strong, struct FrodoSeedSE_>; + +// Bytes of z +using FrodoSeedZ = Strong, struct FrodoSeedZ_>; + +// Bytes of an r^(i) +using FrodoSampleR = Strong, struct FrodoSampleR_>; + +// Bytes of pkh +using FrodoPublicKeyHash = Strong, struct FrodoPublicKeyHash_>; + +// Bytes of a packed Matrix +using FrodoPackedMatrix = Strong, struct FrodoPackedMatrix_>; + +// Bytes of a serialized Matrix +using FrodoSerializedMatrix = Strong, struct FrodoSerializedMatrix_>; + +// Constant byte 0x5F/0x96 given to SHAKE for domain separation +using FrodoDomainSeparator = Strong, struct FrodoDoaminSeparator_>; + +// Bytes of u/u' +using FrodoPlaintext = Strong, struct FrodoPlaintext_>; + +// Bytes of salt +using FrodoSalt = Strong, struct FrodoSalt_>; + +// Bytes of k/k' aka intermediate shared secret in FO transform +using FrodoIntermediateSharedSecret = Strong, struct FrodoIntermediateSharedSecret_>; + +} // namespace Botan + +#endif diff --git a/src/lib/pubkey/frodokem/frodokem_common/frodokem.cpp b/src/lib/pubkey/frodokem/frodokem_common/frodokem.cpp new file mode 100644 index 00000000000..b46420b2495 --- /dev/null +++ b/src/lib/pubkey/frodokem/frodokem_common/frodokem.cpp @@ -0,0 +1,381 @@ +/* + * FrodoKEM implemenation + * Based on the MIT licensed reference implementation by the designers + * (https://github.com/microsoft/PQCrypto-LWEKE/tree/master/src) + * + * The Fellowship of the FrodoKEM: + * (C) 2023 Jack Lloyd + * 2023 René Meusel, Amos Treiber - Rohde & Schwarz Cybersecurity + * + * Botan is released under the Simplified BSD License (see license.txt) + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace Botan { + +class FrodoKEM_PublicKeyInternal { + public: + FrodoKEM_PublicKeyInternal(FrodoKEMConstants constants, FrodoSeedA seed_a, FrodoMatrix b) : + m_constants(std::move(constants)), m_seed_a(std::move(seed_a)), m_b(std::move(b)) { + auto& shake = m_constants.SHAKE_XOF(); + shake.update(serialize()); + m_hash = shake.output(m_constants.len_sec_bytes()); + } + + const FrodoKEMConstants& constants() const { return m_constants; } + + const FrodoSeedA& seed_a() const { return m_seed_a; } + + const FrodoMatrix& b() const { return m_b; } + + const FrodoPublicKeyHash& hash() const { return m_hash; } + + std::vector serialize() const { + return concat_as>(seed_a(), b().pack(m_constants)); + } + + private: + FrodoKEMConstants m_constants; + FrodoSeedA m_seed_a; + FrodoMatrix m_b; + FrodoPublicKeyHash m_hash; +}; + +class FrodoKEM_PrivateKeyInternal { + public: + FrodoKEM_PrivateKeyInternal(FrodoSeedS s, FrodoMatrix s_trans) : + m_s(std::move(s)), m_s_trans(std::move(s_trans)) {} + + const FrodoSeedS& s() const { return m_s; } + + const FrodoMatrix& s_trans() const { return m_s_trans; } + + private: + FrodoSeedS m_s; + FrodoMatrix m_s_trans; +}; + +// +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// + +class Frodo_KEM_Encryptor final : public PK_Ops::KEM_Encryption_with_KDF { + public: + Frodo_KEM_Encryptor(std::shared_ptr key, std::string_view kdf) : + KEM_Encryption_with_KDF(kdf), m_public_key(std::move(key)) {} + + size_t raw_kem_shared_key_length() const override { return m_public_key->constants().len_sec_bytes(); } + + size_t encapsulated_key_length() const override { return m_public_key->constants().len_ct_bytes(); } + + void raw_kem_encrypt(std::span out_encapsulated_key, + std::span out_shared_key, + RandomNumberGenerator& rng) override { + const auto& consts = m_public_key->constants(); + auto& shake = consts.SHAKE_XOF(); + auto sample_generator = FrodoMatrix::make_sample_generator(consts, shake); + + BufferStuffer out_ct_bs(out_encapsulated_key); + + auto c_1 = out_ct_bs.next(consts.len_packed_b_bytes()); + auto c_2 = out_ct_bs.next(consts.len_packed_c_bytes()); + auto salt = out_ct_bs.next(consts.len_salt_bytes()); + + BOTAN_ASSERT_NOMSG(out_ct_bs.full()); + + const auto u = rng.random_vec(consts.len_sec_bytes()); + rng.randomize(salt); + + shake.update(m_public_key->hash()); + shake.update(u); + shake.update(salt); + const auto seed_se = shake.output(consts.len_se_bytes()); + const auto k = shake.output(consts.len_sec_bytes()); + shake.clear(); + + shake.update(consts.encapsulation_domain_separator()); + shake.update(seed_se); + + const auto s_p = sample_generator(std::tuple(consts.n_bar(), consts.n())); + + const auto e_p = sample_generator(std::tuple(consts.n_bar(), consts.n())); + + const auto b_p = FrodoMatrix::mul_add_sa_plus_e(consts, s_p, e_p, m_public_key->seed_a()); + + b_p.pack(consts, c_1); + + const auto e_pp = sample_generator(std::tuple(consts.n_bar(), consts.n_bar())); + shake.clear(); + + const auto v = FrodoMatrix::mul_add_sb_plus_e(consts, m_public_key->b(), s_p, e_pp); + + const auto encoded = FrodoMatrix::encode(consts, u); + + const auto c = FrodoMatrix::add(consts, v, encoded); + + c.pack(consts, c_2); + + shake.update(out_encapsulated_key); + shake.update(k); + shake.output(out_shared_key); + } + + private: + std::shared_ptr m_public_key; +}; + +class Frodo_KEM_Decryptor final : public PK_Ops::KEM_Decryption_with_KDF { + public: + Frodo_KEM_Decryptor(std::shared_ptr public_key, + std::shared_ptr private_key, + std::string_view kdf) : + KEM_Decryption_with_KDF(kdf), m_public_key(std::move(public_key)), m_private_key(std::move(private_key)) {} + + size_t raw_kem_shared_key_length() const override { return m_public_key->constants().len_sec_bytes(); } + + size_t encapsulated_key_length() const override { return m_public_key->constants().len_ct_bytes(); } + + void raw_kem_decrypt(std::span out_shared_key, std::span encapsulated_key) override { + const auto& consts = m_public_key->constants(); + auto& shake = consts.SHAKE_XOF(); + auto sample_generator = FrodoMatrix::make_sample_generator(consts, shake); + + if(encapsulated_key.size() != consts.len_ct_bytes()) { + throw Invalid_Argument("FrodoKEM ciphertext does not have the correct byte count"); + } + + BufferSlicer ct_bs(encapsulated_key); + auto c_1 = ct_bs.take(consts.len_packed_b_bytes()); + auto c_2 = ct_bs.take(consts.len_packed_c_bytes()); + auto salt = ct_bs.take(consts.len_salt_bytes()); + BOTAN_ASSERT_NOMSG(ct_bs.empty()); + + const auto b_p = FrodoMatrix::unpack(consts, {consts.n_bar(), consts.n()}, c_1); + const auto c = FrodoMatrix::unpack(consts, {consts.n_bar(), consts.n_bar()}, c_2); + + const auto w = FrodoMatrix::mul_bs(consts, b_p, m_private_key->s_trans()); + const auto m = FrodoMatrix::sub(consts, c, w); + + const auto seed_u_p = m.decode(consts); + + shake.update(m_public_key->hash()); + shake.update(seed_u_p); + shake.update(salt); + + const auto seed_se_p = shake.output(consts.len_se_bytes()); + const auto k_p = shake.output(consts.len_sec_bytes()); + shake.clear(); + + shake.update(consts.encapsulation_domain_separator()); + shake.update(seed_se_p); + const auto s_p = sample_generator(std::tuple(consts.n_bar(), consts.n())); + + const auto e_p = sample_generator(std::tuple(consts.n_bar(), consts.n())); + + auto b_pp = FrodoMatrix::mul_add_sa_plus_e(consts, s_p, e_p, m_public_key->seed_a()); + + const auto e_pp = sample_generator(std::tuple(consts.n_bar(), consts.n_bar())); + shake.clear(); + + const auto v = FrodoMatrix::mul_add_sb_plus_e(consts, m_public_key->b(), s_p, e_pp); + + const auto encoded = FrodoMatrix::encode(consts, seed_u_p); + auto c_p = FrodoMatrix::add(consts, v, encoded); + + // b_p and c are unpacked values that are reduced by definition. + // b_pp and c_p are calculated values that need the reduction for + // an unambiguous comparison that is required next. + b_pp.reduce(consts); + c_p.reduce(consts); + + // The spec concats the matrices b_p and c (b_pp and c_p respectively) + // and performs a single CT comparison. For convenience we compare the + // matrices individually in CT and CT-&& the resulting masks. + const auto cmp = b_p.constant_time_compare(b_pp) & c.constant_time_compare(c_p); + + std::vector k_bar(consts.len_sec_bytes(), 0); + CT::conditional_copy_mem(cmp, k_bar.data(), k_p.data(), m_private_key->s().data(), consts.len_sec_bytes()); + + shake.update(encapsulated_key); + shake.update(k_bar); + shake.output(out_shared_key); + } + + private: + std::shared_ptr m_public_key; + std::shared_ptr m_private_key; +}; + +// +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// + +FrodoKEM_PublicKey::FrodoKEM_PublicKey(std::span pub_key, FrodoKEMMode mode) { + FrodoKEMConstants consts(mode); + if(pub_key.size() != consts.len_public_key_bytes()) { + throw Invalid_Argument("FrodoKEM public key does not have the correct byte count"); + } + + BufferSlicer pk_bs(pub_key); + auto seed_a = pk_bs.copy(consts.len_a_bytes()); + const auto packed_b = pk_bs.take(consts.d() * consts.n() * consts.n_bar() / 8); + BOTAN_ASSERT_NOMSG(pk_bs.empty()); + + auto b = FrodoMatrix::unpack(consts, std::tuple(consts.n(), consts.n_bar()), packed_b); + + m_public = std::make_shared(std::move(consts), std::move(seed_a), std::move(b)); +} + +FrodoKEM_PublicKey::FrodoKEM_PublicKey(const AlgorithmIdentifier& alg_id, std::span key_bits) : + FrodoKEM_PublicKey(key_bits, FrodoKEMMode(alg_id.oid())) {} + +FrodoKEM_PublicKey::FrodoKEM_PublicKey(const FrodoKEM_PublicKey& other) { + m_public = std::make_shared( + other.m_public->constants(), other.m_public->seed_a(), other.m_public->b()); +} + +FrodoKEM_PublicKey& FrodoKEM_PublicKey::operator=(const FrodoKEM_PublicKey& other) { + if(this != &other) { + m_public = std::make_shared( + other.m_public->constants(), other.m_public->seed_a(), other.m_public->b()); + } + return *this; +} + +AlgorithmIdentifier FrodoKEM_PublicKey::algorithm_identifier() const { + return AlgorithmIdentifier(object_identifier(), AlgorithmIdentifier::USE_EMPTY_PARAM); +} + +OID FrodoKEM_PublicKey::object_identifier() const { + return m_public->constants().mode().object_identifier(); +} + +size_t FrodoKEM_PublicKey::key_length() const { + return m_public->constants().n(); +} + +size_t FrodoKEM_PublicKey::estimated_strength() const { + return m_public->constants().estimated_strength(); +} + +std::vector FrodoKEM_PublicKey::public_key_bits() const { + return concat_as>(m_public->seed_a(), m_public->b().pack(m_public->constants())); +} + +bool FrodoKEM_PublicKey::check_key(RandomNumberGenerator&, bool) const { + return true; +} + +std::unique_ptr FrodoKEM_PublicKey::generate_another(RandomNumberGenerator& rng) const { + return std::make_unique(rng, m_public->constants().mode()); +} + +std::unique_ptr FrodoKEM_PublicKey::create_kem_encryption_op(std::string_view params, + std::string_view provider) const { + if(provider.empty() || provider == "base") { + return std::make_unique(m_public, params); + } + throw Provider_Not_Found(algo_name(), provider); +} + +// +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// + +FrodoKEM_PrivateKey::FrodoKEM_PrivateKey(RandomNumberGenerator& rng, FrodoKEMMode mode) { + FrodoKEMConstants consts(mode); + auto& shake = consts.SHAKE_XOF(); + auto sample_generator = FrodoMatrix::make_sample_generator(consts, shake); + + auto s = rng.random_vec(consts.len_sec_bytes()); + const auto seed_se = rng.random_vec(consts.len_se_bytes()); + const auto z = rng.random_vec(consts.len_a_bytes()); + + shake.update(z); + auto seed_a = shake.output(consts.len_a_bytes()); + shake.clear(); + + shake.update(consts.keygen_domain_separator()); + shake.update(seed_se); + + auto s_trans = sample_generator(std::tuple(consts.n_bar(), consts.n())); + auto e = sample_generator(std::tuple(consts.n(), consts.n_bar())); + + auto b = FrodoMatrix::mul_add_as_plus_e(consts, s_trans, e, seed_a); + + m_public = std::make_shared(std::move(consts), std::move(seed_a), std::move(b)); + m_private = std::make_shared(std::move(s), std::move(s_trans)); +} + +FrodoKEM_PrivateKey::FrodoKEM_PrivateKey(std::span sk, FrodoKEMMode mode) { + FrodoKEMConstants consts(mode); + + if(sk.size() != consts.len_private_key_bytes()) { + throw Invalid_Argument("FrodoKEM private key does not have the correct byte count"); + } + + BufferSlicer sk_bs(sk); + auto s = sk_bs.copy(consts.len_sec_bytes()); + auto seed_a = sk_bs.copy(consts.len_a_bytes()); + const auto packed_b = sk_bs.take(consts.d() * consts.n() * consts.n_bar() / 8); + const auto s_trans_bytes = sk_bs.take(consts.n_bar() * consts.n() * 2); + const auto pkh = sk_bs.copy(consts.len_sec_bytes()); + BOTAN_ASSERT_NOMSG(sk_bs.empty()); + + auto b = FrodoMatrix::unpack(consts, std::tuple(consts.n(), consts.n_bar()), packed_b); + auto s_trans = FrodoMatrix::deserialize({consts.n_bar(), consts.n()}, s_trans_bytes); + + m_public = std::make_shared(std::move(consts), std::move(seed_a), std::move(b)); + m_private = std::make_shared(std::move(s), std::move(s_trans)); + + BOTAN_STATE_CHECK(pkh == m_public->hash()); +} + +FrodoKEM_PrivateKey::FrodoKEM_PrivateKey(const AlgorithmIdentifier& alg_id, std::span key_bits) : + FrodoKEM_PrivateKey(key_bits, FrodoKEMMode(alg_id.oid())) {} + +std::unique_ptr FrodoKEM_PrivateKey::public_key() const { + return std::make_unique(*this); +} + +secure_vector FrodoKEM_PrivateKey::private_key_bits() const { + return raw_private_key_bits(); // TODO: check if we need to do something else here +} + +secure_vector FrodoKEM_PrivateKey::raw_private_key_bits() const { + return concat_as>(m_private->s(), + m_public->seed_a(), + m_public->b().pack(m_public->constants()), + m_private->s_trans().serialize(), + m_public->hash()); +} + +std::unique_ptr FrodoKEM_PrivateKey::create_kem_decryption_op(RandomNumberGenerator& rng, + std::string_view params, + std::string_view provider) const { + BOTAN_UNUSED(rng); + if(provider.empty() || provider == "base") { + return std::make_unique(m_public, m_private, params); + } + throw Provider_Not_Found(algo_name(), provider); +} + +} // namespace Botan diff --git a/src/lib/pubkey/frodokem/frodokem_common/frodokem.h b/src/lib/pubkey/frodokem/frodokem_common/frodokem.h new file mode 100644 index 00000000000..d34c3effaa0 --- /dev/null +++ b/src/lib/pubkey/frodokem/frodokem_common/frodokem.h @@ -0,0 +1,107 @@ +/* + * FrodoKEM implementation + * Based on the MIT licensed reference implementation by the designers + * (https://github.com/microsoft/PQCrypto-LWEKE/tree/master/src) + * + * The Fellowship of the FrodoKEM: + * (C) 2023 Jack Lloyd + * 2023 René Meusel, Amos Treiber - Rohde & Schwarz Cybersecurity + * + * Botan is released under the Simplified BSD License (see license.txt) + */ + +#ifndef BOTAN_FRODOKEM_H_ +#define BOTAN_FRODOKEM_H_ + +#include +#include + +#include +#include + +namespace Botan { + +class FrodoKEM_PublicKeyInternal; +class FrodoKEM_PrivateKeyInternal; + +/** + * FrodoKEM is an unstructured lattice-based post-quantum secure KEM. It is a + * round 3 candidate in NIST's PQC competition but was eventually not considered + * for standardization by NIST. Nevertheless, it is endorsed by the German + * Federal Office for Information Security for its conservative security + * assumptions and is being standardized as an ISO standard. + */ +class BOTAN_PUBLIC_API(3, 3) FrodoKEM_PublicKey : public virtual Public_Key { + public: + FrodoKEM_PublicKey(std::span pub_key, FrodoKEMMode mode); + + FrodoKEM_PublicKey(const AlgorithmIdentifier& alg_id, std::span key_bits); + + FrodoKEM_PublicKey(const FrodoKEM_PublicKey& other); + FrodoKEM_PublicKey& operator=(const FrodoKEM_PublicKey& other); + FrodoKEM_PublicKey(FrodoKEM_PublicKey&&) = default; + FrodoKEM_PublicKey& operator=(FrodoKEM_PublicKey&&) = default; + + ~FrodoKEM_PublicKey() override = default; + + std::string algo_name() const override { return "FrodoKEM"; } + + AlgorithmIdentifier algorithm_identifier() const override; + + OID object_identifier() const override; + + size_t key_length() const override; + + size_t estimated_strength() const override; + + std::vector public_key_bits() const override; + + bool check_key(RandomNumberGenerator&, bool) const override; + + bool supports_operation(PublicKeyOperation op) const override { + return (op == PublicKeyOperation::KeyEncapsulation); + } + + std::unique_ptr generate_another(RandomNumberGenerator& rng) const final; + + std::unique_ptr create_kem_encryption_op(std::string_view params, + std::string_view provider) const override; + + protected: + FrodoKEM_PublicKey() = default; + + protected: + std::shared_ptr m_public; // NOLINT(misc-non-private-member-variables-in-classes) +}; + +BOTAN_DIAGNOSTIC_PUSH +BOTAN_DIAGNOSTIC_IGNORE_INHERITED_VIA_DOMINANCE + +class BOTAN_PUBLIC_API(3, 3) FrodoKEM_PrivateKey final : public virtual FrodoKEM_PublicKey, + public virtual Private_Key { + public: + FrodoKEM_PrivateKey(RandomNumberGenerator& rng, FrodoKEMMode mode); + + FrodoKEM_PrivateKey(std::span sk, FrodoKEMMode mode); + + FrodoKEM_PrivateKey(const AlgorithmIdentifier& alg_id, std::span key_bits); + + std::unique_ptr public_key() const override; + + secure_vector private_key_bits() const override; + + secure_vector raw_private_key_bits() const override; + + std::unique_ptr create_kem_decryption_op(RandomNumberGenerator& rng, + std::string_view params, + std::string_view provider) const override; + + private: + std::shared_ptr m_private; +}; + +BOTAN_DIAGNOSTIC_POP + +} // namespace Botan + +#endif diff --git a/src/lib/pubkey/frodokem/frodokem_common/info.txt b/src/lib/pubkey/frodokem/frodokem_common/info.txt new file mode 100644 index 00000000000..36c623413ed --- /dev/null +++ b/src/lib/pubkey/frodokem/frodokem_common/info.txt @@ -0,0 +1,26 @@ + +FRODOKEM -> 20230801 + + + +name -> "FrodoKEM (common)" +brief -> "Base implementation of FrodoKEM" +type -> "Internal" + + + +pubkey +rng +shake_xof + + + +frodokem.h +frodo_mode.h + + + +frodo_constants.h +frodo_matrix.h +frodo_types.h + diff --git a/src/lib/pubkey/pk_algs.cpp b/src/lib/pubkey/pk_algs.cpp index 69cd2971e45..4f62db6150d 100644 --- a/src/lib/pubkey/pk_algs.cpp +++ b/src/lib/pubkey/pk_algs.cpp @@ -66,6 +66,10 @@ #include #endif +#if defined(BOTAN_HAS_FRODOKEM) + #include +#endif + #if defined(BOTAN_HAS_KYBER) || defined(BOTAN_HAS_KYBER_90S) #include #endif @@ -112,6 +116,12 @@ std::unique_ptr load_public_key(const AlgorithmIdentifier& alg_id, } #endif +#if defined(BOTAN_HAS_FRODOKEM) + if(alg_name == "FrodoKEM" || alg_name.starts_with("FrodoKEM-") || alg_name.starts_with("eFrodoKEM-")) { + return std::make_unique(alg_id, key_bits); + } +#endif + #if defined(BOTAN_HAS_KYBER) || defined(BOTAN_HAS_KYBER_90S) if(alg_name == "Kyber" || alg_name.starts_with("Kyber-")) { return std::make_unique(alg_id, key_bits); @@ -241,6 +251,12 @@ std::unique_ptr load_private_key(const AlgorithmIdentifier& alg_id, } #endif +#if defined(BOTAN_HAS_FRODOKEM) + if(alg_name == "FrodoKEM" || alg_name.starts_with("FrodoKEM-") || alg_name.starts_with("eFrodoKEM-")) { + return std::make_unique(alg_id, key_bits); + } +#endif + #if defined(BOTAN_HAS_KYBER) || defined(BOTAN_HAS_KYBER_90S) if(alg_name == "Kyber" || alg_name.starts_with("Kyber-")) { return std::make_unique(alg_id, key_bits); @@ -398,6 +414,13 @@ std::unique_ptr create_private_key(std::string_view alg_name, } #endif +#if defined(BOTAN_HAS_FRODOKEM) + if(alg_name == "FrodoKEM") { + const auto mode = params.empty() ? FrodoKEMMode::FrodoKEM976_SHAKE : FrodoKEMMode(params); + return std::make_unique(rng, mode); + } +#endif + #if defined(BOTAN_HAS_KYBER) || defined(BOTAN_HAS_KYBER_90S) if(alg_name == "Kyber") { const auto mode = [&]() -> KyberMode { diff --git a/src/scripts/dev_tools/gen_frodo_kat.py b/src/scripts/dev_tools/gen_frodo_kat.py new file mode 100644 index 00000000000..07fe494bf45 --- /dev/null +++ b/src/scripts/dev_tools/gen_frodo_kat.py @@ -0,0 +1,131 @@ +#!/usr/bin/env python3 + +# +# Strips the KAT harness in the FrodoKEM reference implementation down +# to a less space consuming version. This script was used to generate +# `src/tests/data/pubkey/frodokem_kat.vec` test data from the *.rsp files in +# the reference implemenation repository. +# +# See here: https://github.com/microsoft/PQCrypto-LWEKE/tree/master/KAT +# +# (C) 2023 Jack Lloyd +# (C) 2023 René Meusel, Amos Treiber - Rohde & Schwarz Cybersecurity +# +# Botan is released under the Simplified BSD License (see license.txt) +# + +import sys +import hashlib +import binascii +import os + +class KatReader: + def __init__(self, file): + self.file = file + self.last_mlen = None + + def next_value(self): + while True: + line = self.file.readline() + + if line == "": + return (None, None) + + if line.startswith('#') or line == "\n": + continue + + key, val = line.strip().split(' = ') + + return (key, val) + + def read_kats(self): + kat = {} + + while True: + key, val = self.next_value() + + if key == None: + return # eof + + if key not in ['count', 'seed', 'pk', 'sk', 'ct', 'ss']: + raise Exception("Unknown key %s" % (key)) + + if key == 'count': + kat[key] = int(val) + else: + kat[key] = val + + if key == 'ss': + yield kat + kat = {} + +def shake_256_16(v): + # v is assumed to be hex + h = hashlib.shake_256() + h.update(binascii.unhexlify(v)) + return h.hexdigest(16) + +def compress_kat(kat): + first = kat['count'] == 0 + del kat['count'] + + # rename keys + kat['Seed'] = kat.pop('seed') + kat['SS'] = kat.pop('ss') + kat['PK'] = shake_256_16(kat.pop('pk')) + kat['SK'] = shake_256_16(kat.pop('sk')) + kat['CT'] = shake_256_16(kat.pop('ct')) + + return kat + +def map_mode(mode, is_ephemeral = False): + out = None + if mode == "PQCkemKAT_19888": + out = "eFrodoKEM-640-AES" + if mode == "PQCkemKAT_19888_shake": + out = "eFrodoKEM-640-SHAKE" + if mode == "PQCkemKAT_31296": + out = "eFrodoKEM-976-AES" + if mode == "PQCkemKAT_31296_shake": + out = "eFrodoKEM-976-SHAKE" + if mode == "PQCkemKAT_43088": + out = "eFrodoKEM-1344-AES" + if mode == "PQCkemKAT_43088_shake": + out = "eFrodoKEM-1344-SHAKE" + + if out is None: + raise Exception('Unknown FrodoKEM mode', mode) + + if is_ephemeral: + return out + else: + return out[1:] # remove 'e' to obtain 'FrodoKEM' + +def main(args = None): + """Set True for eFrodo, otherwise the non-ephemeral variant is assumed. + Necessary because the files have the same name for either variant.""" + is_ephemeral = False + + if args is None: + args = sys.argv + + with open('src/tests/data/pubkey/frodokem_kat.vec', 'w') as output: + print("# This file was auto-generated from the reference implemention's KATs", file=output) + print("# See src/scripts/dev_tools/gen_frodo_kat.py\n", file=output) + + for file in args[1:]: + mode = map_mode(os.path.basename(os.path.splitext(file)[0]), is_ephemeral) + + reader = KatReader(open(file)) + + print(f"[{mode}]", file=output) + + for kat in list(reader.read_kats())[:25]: + kat = compress_kat(kat) + + for key in kat.keys(): + print(key, '=', kat[key], file=output) + print("", file=output) + +if __name__ == '__main__': + sys.exit(main()) diff --git a/src/tests/data/pubkey/frodokem_kat.vec b/src/tests/data/pubkey/frodokem_kat.vec new file mode 100644 index 00000000000..e0049071e7c --- /dev/null +++ b/src/tests/data/pubkey/frodokem_kat.vec @@ -0,0 +1,1814 @@ +# This file was auto-generated from the reference implemention's KATs +# See src/scripts/dev_tools/gen_frodo_kat.py + +[eFrodoKEM-640-AES] +Seed = 061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1 +SS = 9F54377D452090F3631E45B9399A2892 +PK = b9b8397ff0789080b5b41b7d5aff1df0 +SK = 6448206859a3462c66a3631a783ba935 +CT = 91d6f48b4cc54be5d187353eb2d4ba95 + +Seed = D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556AC81ADDE6AEEB4A5A875C3BFCADFA958F +SS = BB2DBA7517585B7F88A66E3A94F3B939 +PK = 39e86a93213c9842bfc3a5f40257644e +SK = 91b40978b51fdb73c6a8c7529499c6f0 +CT = 6dcae4f7f17b69cf554ac11307814825 + +Seed = 64335BF29E5DE62842C941766BA129B0643B5E7121CA26CFC190EC7DC3543830557FDD5C03CF123A456D48EFEA43C868 +SS = 6498C010E54C19CBE9FC780B0615E2A3 +PK = ccff6ea24068540e19a2bd19c852d740 +SK = 14fd9348ae4461dac2144602a1254d1f +CT = cd4ea0084d355aad54135395903a9234 + +Seed = 225D5CE2CEAC61930A07503FB59F7C2F936A3E075481DA3CA299A80F8C5DF9223A073E7B90E02EBF98CA2227EBA38C1A +SS = D15C1F9A058E2F1754B4EE5790F235E7 +PK = 08b71e78239ecbf73a47877073db54b1 +SK = f29118e9d8696bd0540b069e3d61d6b4 +CT = a393f983a1a09ddacc1635a710e8862e + +Seed = EDC76E7C1523E3862552133FEA4D2AB05C69FB54A9354F0846456A2A407E071DF4650EC0E0A5666A52CD09462DBC51F9 +SS = C0F11C349CD1204D650C2680A16DBFD8 +PK = 2615c065c854a1a2cc9e0f743c9bdbea +SK = 1b64766cc149fb680cc974cddd8142d2 +CT = 544fba761c39533d4b56a579602f367d + +Seed = AA93649193C2C5985ACF8F9E6AC50C36AE16A2526D7C684F7A3BB4ABCD7B6FF790E82BADCE89BC7380D66251F97AAAAA +SS = A374CC2EC33BC2538F5D59A95CE7C5FC +PK = 5ad326d441594e9da28b37d8f58331b1 +SK = 762e736330fdff5e6072ebc2540cd188 +CT = 746aec674174a23b1d45c37178a790c8 + +Seed = 2E014DC7C2696B9F6D4AF555CBA4B931B34863FF60E2341D4FDFE472FEF2FE2C33E0813FC5CAFDE4E30277FE522A9049 +SS = 68ACE2699B9DF0F028840E100DF8A60B +PK = e0c1b04954211b39ef9968a60a43f28b +SK = b3e8c03589969bf1555de7849dae1eb7 +CT = feaab406207437612ebf5d71eeef5945 + +Seed = AEFB28FDD34E0AB403A703B535296E3A545CA479C1D8148E2D501B3C8DD8B1034BD986F13F1A7B4671BE769359FD2AAB +SS = 600141459234027328E123AEB678CEE7 +PK = 6dc66a079fd0101ea9f15d3b26f49a34 +SK = d061286ae1ae09851cb0c7b709e7feb8 +CT = 34353132a7ac435c98a9b689a5cc8886 + +Seed = CBE5161E8DE02DDA7DE204AEB0FBB4CA81344BA8C30FE357A4664E5D2988A03B64184D7DC69F8D367550E5FEA0876D41 +SS = 4BB6DD65401689BEDAD5758E85D202B1 +PK = 6b378cec01b54d4751d82f28e16f71a4 +SK = 0d3877fea8485551b5dc4fa9396539bd +CT = a57d42fe0593800aeb691c74d154f5ad + +Seed = B4663A7A9883386A2AE4CBD93787E247BF26087E3826D1B8DBEB679E49C0BB286E114F0E9F42F61F63DEC42B4F974846 +SS = 5B10E1CC2BAF6B14987E95924FBCA806 +PK = ace4fa70f938eb7c10deec4d0c1cdbea +SK = dca1facfe62631f4307cf924a3f3e95f +CT = abe2a4e286038ad0bc25c4d1525b2b35 + +Seed = 980D0BA7C8F8B23D0E948A6029FF2659810EA1360064663A8994D0333C8543EE5FF5D6D5C9ACF446E61DC464F792B9D3 +SS = 098F66268297E43EFF04ABE2117DF74B +PK = b8ad4ac3789b3db1f1154d3b39526e66 +SK = 28af7eb9a044a819b791b7e0e112019b +CT = c528faa52355c74805315cbb7264fe37 + +Seed = 6C029462CA42ED520F10A579F52687101105E0B90C6E7BFA582A4C112B579D5AD0A0ABD38F72ABCFDCAAF5893A112BDC +SS = 3436A9C42920951A2658BBCDDAFDD8AE +PK = 2c0f4e580ddedb4b9660ae3353efefdd +SK = bccbae2df5fa092f649b94eb1158b3c1 +CT = a4133f0ee7ab8c7c8ec91c2cff88a958 + +Seed = DB00120937570D62331F4C3F19A10465231EFF46465CDEE336A0D46AA1E7493DF80F18617F9FFD0476CF7784A403EF4F +SS = 53C4F327A98349383F0DB1613D6B4111 +PK = a25c25cdfeec1f7d1a9fc7e8d86f7043 +SK = d13b43596faf92b3f60e27b9a41208c6 +CT = 24c838cc9aeace72ccfc67726fc20748 + +Seed = BD26C0B9A33E3B9B4C5D7EA32D5BD1FC371015BE163C86F584E49BFD5362C8D8341161CD1308115B2A03B7E5EADDD418 +SS = B1C5E83532EFBC0F40D56707FDF785DD +PK = 108d34fc96803903e7ced42e0bb8406a +SK = fcb3c52a9ebb312614cf9a5d93e30764 +CT = 44ce1eb29f9ce92c6bb9d0a72cea1202 + +Seed = E2819EF86853BCA1B9DEE7EE1C1619988964F9A913E635AACF0D96CA6E0300D084329DABD8F149E24176D22757404260 +SS = 82444DD43BAEA0F87624FA092EA2D913 +PK = c0eb3669b2bca646755689ff651b689f +SK = 63182bd84abd1a3a4b5222b393b5fe9d +CT = 1aa5c2dd4f3ca9c9fd44c460c847d1ef + +Seed = 669C4EF8A051CE201DA65FC4BC34D398EC1F806276FC5D987AD71D93BC12DC8F107B58BE6E8422A0795C88CB9A0E7488 +SS = 21AC63A7D58C081C0C1BC46B52C7EEDD +PK = 3eaa85415c139f77f3021f8244c87840 +SK = 4fb9df2e294e9612f81ee1662660fe44 +CT = 8dad9b9654d9d91050b0d25d8ffaaebe + +Seed = 9DEBCCFE818F6B5204DB4EA09C03EC9A19DCF1629C1527685B8A29776BB1DAAEC45F8ABF8F0ADC9A8C8BD6E2DF6D8048 +SS = EE2EEEA80455B4E6FACF12827F8FDE3B +PK = a150c519b9f0a8a71cb4362cdc41ac5d +SK = ec924a290c9176573577862489fb4bb1 +CT = 0edaf37e08f065229ba9f230a7e79c51 + +Seed = 8098AE7A92C10F707D405F7DEA02C2EFBEF44EFA132BA8AEFE81BD45E543ECEC74F10920AE48A40B0653D63532517F2A +SS = FC9A72B165DC801CBCD2B567ED917345 +PK = 1474bc97c2404ed28ce6a8bb2512b538 +SK = 94aedef85678f8305986647f11992249 +CT = 536b480c89635b286b218eff1289b95f + +Seed = D5F23808871544E9C1D6EACE2028362B48E225312F77663E9F78CAFEB512B908CD9E25875D61A16EC615F4B8FF826856 +SS = B334AF75BC43F6B5E3F71C5EA8B60B6A +PK = 07c6838a18fdf743d1095124075fbb7c +SK = 54ce5d2df64d8387c79f95fba9e2e991 +CT = 52dfa45993cc71b946c4c7c4ed015f29 + +Seed = 822CB47BE2266E182F34546924D753A5E3369011047E6950B00BC392F8FEC19EA87C26D8021D377DF86DC76C24C5F827 +SS = 84E17364F894F2BD26F4CD46E7D699DC +PK = 827e018971328fc707a0df0ce68cc055 +SK = f851432173aee1cad0138cba46c34c5a +CT = c66833dd7207fba99e3ccaa94603698f + +Seed = 81401DB81138D6874E91B7C11D59596E4ACE543F5A3471B6FB00999221765FEC3CA057ABE20F03B2D59003375FD71FE8 +SS = 19EBC195FDA1434EEBB3911B0355D412 +PK = 51ce750d603f8f46c9af88e75a3cc12d +SK = ff6304028453d746faa3b3591b59ffe5 +CT = 10101b923e1156a9b438a6bfdd2c0c9e + +Seed = 30B5DE5B73681EC08AAA03F6F2D2169525D25F4042A5E3695A20A52CA54927B85F8BB948FC21DF7DEFC3910B28674994 +SS = 4ABE85DBB4306305249D2340C77924E1 +PK = 11dfe5c524f5c37e7ce3f93ec97a9f78 +SK = 1ce34f0c378ef4c6b88a8c74f60a63c1 +CT = c05f8b3344ab638015edafd6ac2a5a14 + +Seed = E335DF8FC0D890588C3E305AC92C7160FF199E07C85760A828933750E3FED8C83B0DBE802234481ECF890A32D7A2884F +SS = 68F973F15F8502567B9DA63759A0D8CB +PK = dd933b6f696c4475dba3670c7debcc2c +SK = 4cc72aa8a35bb982e8fe0c58b20e6fb3 +CT = a6286e28db327eca002ce30677ec808f + +Seed = FBEA1BC2C379F4F8FDCB0DE260D31CDB064C9EA9B1D6DFBE91B3692ADD1D34DEC9C9FFAE7BF5E72ED2743BA3F9F2E43D +SS = 970584834D7E96A8F12B4F387C91F156 +PK = 5a3f823c86abf53356395d83c33c6296 +SK = c273a39183c353609542b9cbaa264393 +CT = 271a1b4fced9e7da805b2a3caafc3d6c + +Seed = 7E87FB886BC3C7C9FC12569F465D2ECD12532E76CC27C65644C8D3DD603B0CB2D036C5974E675058F271D5C82AD7A813 +SS = 636BE561391CE5FA660D501E2DD8A697 +PK = 2b9575d1b738a9c1c8a406a30b494330 +SK = 40bc8a84c318e805231e32566485201f +CT = 49449c97f8e3bc32c28f602e3f4c2759 + +[eFrodoKEM-640-SHAKE] +Seed = 061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1 +SS = 729780FC51657E21357F03A338116569 +PK = dde5a8fc21db35be36a43a986dc512b7 +SK = c496eaf839737128973ff4f4a5d86a39 +CT = fb0066835f4939182f5d0d0945566bea + +Seed = D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556AC81ADDE6AEEB4A5A875C3BFCADFA958F +SS = 9D8377188B7CF0B3499171B594C773D8 +PK = 11a5b9260cf5504dc1f8f5ae2644739a +SK = 6e096a96e33c3fadf59e2d88044ff40b +CT = 53e950f0ca1c0285168c7a4164f14297 + +Seed = 64335BF29E5DE62842C941766BA129B0643B5E7121CA26CFC190EC7DC3543830557FDD5C03CF123A456D48EFEA43C868 +SS = 72D63F620C623C7D1005621FBF6E8A56 +PK = 274f54e6bd0a037d6d102cc726640fc4 +SK = cfcddd8e3b156e27f5c4cc75fa7e3097 +CT = fad389d85bb5e1d8821b5d906c14b600 + +Seed = 225D5CE2CEAC61930A07503FB59F7C2F936A3E075481DA3CA299A80F8C5DF9223A073E7B90E02EBF98CA2227EBA38C1A +SS = 7DD5EE7A95EB8918FC5205C820E4BAC8 +PK = d10dc14437fb7a7a12d76606e64d9300 +SK = c4e8eb93f7a1c4eafa75ce9a30126ee4 +CT = e053923f78b84f5b56d03d172dcd74e2 + +Seed = EDC76E7C1523E3862552133FEA4D2AB05C69FB54A9354F0846456A2A407E071DF4650EC0E0A5666A52CD09462DBC51F9 +SS = AB32096B44E2497ED7F7E80840D21834 +PK = 65e2af1f6fb85f759b96cb1d543bdaa2 +SK = e6f1ca59a34ac512263b7e945189903c +CT = 89e32c7d96883b0987ec7f42cf7a9df1 + +Seed = AA93649193C2C5985ACF8F9E6AC50C36AE16A2526D7C684F7A3BB4ABCD7B6FF790E82BADCE89BC7380D66251F97AAAAA +SS = F9DD418400F74D8DD232F06C19EA0791 +PK = 9fb43603222bddcdde7bbb1b9c2b8637 +SK = ab3c5eae9e435a3d0cd9bf5d2f698fd2 +CT = 8cbfbea61adb695e07df7809ce2b20be + +Seed = 2E014DC7C2696B9F6D4AF555CBA4B931B34863FF60E2341D4FDFE472FEF2FE2C33E0813FC5CAFDE4E30277FE522A9049 +SS = 83634479611C881A6CFB117EF2CB7ACE +PK = 141c0f20995dadb9b180bde686f1540e +SK = 6729b287c1b1aac0935cad5b58446a35 +CT = b008cb0faa08796d55e562c4ade463b4 + +Seed = AEFB28FDD34E0AB403A703B535296E3A545CA479C1D8148E2D501B3C8DD8B1034BD986F13F1A7B4671BE769359FD2AAB +SS = 11B4C4877DB1798EC32998854DF70CE5 +PK = 6531691ae1907d33f7813032f6952c33 +SK = 6f03b5674db4d0e3c445730e89427a83 +CT = 7fd53f41873230ad62ceb542dc4b27bb + +Seed = CBE5161E8DE02DDA7DE204AEB0FBB4CA81344BA8C30FE357A4664E5D2988A03B64184D7DC69F8D367550E5FEA0876D41 +SS = 630334993F6974C657516C9E27196549 +PK = 5e723cfb237cdbdac29e5e65bfdfd00e +SK = f45ad010e6472be26dcdacd348efd005 +CT = 22860624631d2383383441f3853ef201 + +Seed = B4663A7A9883386A2AE4CBD93787E247BF26087E3826D1B8DBEB679E49C0BB286E114F0E9F42F61F63DEC42B4F974846 +SS = D2E3E10044428633A642DC6DC830CB34 +PK = 3e0e56f199c2259df8c92bc7807405d9 +SK = 00faf025b1519595464d3ba289a23da5 +CT = bbb110240ace88547578f3046bd0b4ce + +Seed = 980D0BA7C8F8B23D0E948A6029FF2659810EA1360064663A8994D0333C8543EE5FF5D6D5C9ACF446E61DC464F792B9D3 +SS = 68B6256D62CDB01D8A8904E64B821FA0 +PK = 4c4af840514fbc761ad937d75b0eee13 +SK = c9cee07d38000bc4b1ed2b2b2d66e990 +CT = dba033432af3875872a994ee3920da1d + +Seed = 6C029462CA42ED520F10A579F52687101105E0B90C6E7BFA582A4C112B579D5AD0A0ABD38F72ABCFDCAAF5893A112BDC +SS = 3BF42CD771D3E5FF4613E667D80AA995 +PK = 2bb9d9e9df8d8eddeecd1228d3dc5f8f +SK = d4c0346bbafae5d5a1341e05f2aed76f +CT = ba4fbcdc43e286d30a24ecb17eebbd07 + +Seed = DB00120937570D62331F4C3F19A10465231EFF46465CDEE336A0D46AA1E7493DF80F18617F9FFD0476CF7784A403EF4F +SS = A7D96D957A70CCE570E2C250D365A385 +PK = eebd119f44681536e5b716165d50149f +SK = 04b44942fda00209b764d002a9643a47 +CT = 2e1b810c322ee3e66d3653f7490a9481 + +Seed = BD26C0B9A33E3B9B4C5D7EA32D5BD1FC371015BE163C86F584E49BFD5362C8D8341161CD1308115B2A03B7E5EADDD418 +SS = 5BC496A2CCEB161E2BEC67EBF387E903 +PK = 452dda899029be140578e387b0355e5d +SK = 6a6c0366b06392dbd3c7d2b0db96abc0 +CT = 51c3f3111ba40105247aa804d72cc5b8 + +Seed = E2819EF86853BCA1B9DEE7EE1C1619988964F9A913E635AACF0D96CA6E0300D084329DABD8F149E24176D22757404260 +SS = DD44BCA5543471F2169097E3A336E35E +PK = 0e7a549cea40cf1c271ece89ba2a694f +SK = 52659b8199ef4514e98856139d783012 +CT = 2d40866003e75e128121ee8db27c8c3c + +Seed = 669C4EF8A051CE201DA65FC4BC34D398EC1F806276FC5D987AD71D93BC12DC8F107B58BE6E8422A0795C88CB9A0E7488 +SS = D0A5A2AA5AEC02B686F036F00D3E2918 +PK = a40028745585d20e60e882377a760d1e +SK = 6987733183fe2babb36204083071c553 +CT = a3a91d5f110ba9477215012b0531697a + +Seed = 9DEBCCFE818F6B5204DB4EA09C03EC9A19DCF1629C1527685B8A29776BB1DAAEC45F8ABF8F0ADC9A8C8BD6E2DF6D8048 +SS = 41CF13FD3423D2953DED0B60CC273303 +PK = e73dc6f9dce0e2dddac68d0f45a651cc +SK = 9dfc0de99e8d53705d7bfc19ce411606 +CT = d93c096ca88fb5725a806084c118051c + +Seed = 8098AE7A92C10F707D405F7DEA02C2EFBEF44EFA132BA8AEFE81BD45E543ECEC74F10920AE48A40B0653D63532517F2A +SS = D97BF1DEA8AC16F0A24507C76EA6971F +PK = 090f17580d52447f09f826c59e09a016 +SK = 9a8ae84dff81f768411907829329e077 +CT = 87906757159de29a5125d5e0b7c81c40 + +Seed = D5F23808871544E9C1D6EACE2028362B48E225312F77663E9F78CAFEB512B908CD9E25875D61A16EC615F4B8FF826856 +SS = 74879751B347AF107B6E9DE0D6F24C73 +PK = e78393baf4f5aa180cc1bb9e081a1cf4 +SK = eec12c1bee62354a294878711e353e80 +CT = a1846da8eac26148cdf4a544b6476062 + +Seed = 822CB47BE2266E182F34546924D753A5E3369011047E6950B00BC392F8FEC19EA87C26D8021D377DF86DC76C24C5F827 +SS = A096F83952F0A877F8D7A61B951567D2 +PK = 8c36517af04d79c067d40d5152b237bc +SK = a25fc1e3dc06c69c29b74ec67188bd9c +CT = 5b15edb8331a25f8aa260ebb16bb9124 + +Seed = 81401DB81138D6874E91B7C11D59596E4ACE543F5A3471B6FB00999221765FEC3CA057ABE20F03B2D59003375FD71FE8 +SS = 194EB021E71392CD40DC0415DFE75A57 +PK = 1d771c2104c15e46e23f823d887aba1d +SK = c91943d8d2189718a0396dbafce66179 +CT = b2a5c6cda3251f0b01b1d2317d6b2db1 + +Seed = 30B5DE5B73681EC08AAA03F6F2D2169525D25F4042A5E3695A20A52CA54927B85F8BB948FC21DF7DEFC3910B28674994 +SS = FCE060F0EFD323DC532212609E0A1D55 +PK = 58367a8a54bd149b8793baba8fafcfc5 +SK = d38d345685575e875b35970ef93d3b5b +CT = 28e0f3f1e1c460cb3a54738690e26ffd + +Seed = E335DF8FC0D890588C3E305AC92C7160FF199E07C85760A828933750E3FED8C83B0DBE802234481ECF890A32D7A2884F +SS = 7D26F7B1FA676266C922604F17241032 +PK = 2321c0cf6c4f94bb2bf3652ff51586d8 +SK = 502d339392f231ea720b12b0ae9dd2cd +CT = b84f22562c18417115a14040a70ccf5e + +Seed = FBEA1BC2C379F4F8FDCB0DE260D31CDB064C9EA9B1D6DFBE91B3692ADD1D34DEC9C9FFAE7BF5E72ED2743BA3F9F2E43D +SS = 4ED34648750240C38E8EBA9972537D8A +PK = a220b424df1abab324cc8c2039c0cdfb +SK = b7b424ca46623e26fa79d155ccfef16d +CT = 56e5c8f9cae65d6ea0f35bfb2b2bf68e + +Seed = 7E87FB886BC3C7C9FC12569F465D2ECD12532E76CC27C65644C8D3DD603B0CB2D036C5974E675058F271D5C82AD7A813 +SS = 44894068B3A3813BBB3D40367A451AFF +PK = 25974f9baa410399b3a813426b3b4345 +SK = d7c99c82a3bfc10bad8923829f7f5dac +CT = 3077d0633c3f0bd24baa497ce91e51b2 + +[eFrodoKEM-976-AES] +Seed = 061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1 +SS = 594DE84473B3408E35F6C4D1F2F2EC3B56D2DDA96FA23496 +PK = a3e045c8228a29a68fdc47d9834b1832 +SK = 4ded00e6a7b08e0cec81304a3937dd0c +CT = d9e2240d5580a25e7fc53545dbd20535 + +Seed = D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556AC81ADDE6AEEB4A5A875C3BFCADFA958F +SS = AA303E873ED6DD7EF9EA61667C893EB05135B4004DD08E18 +PK = fa27f91f6ca053adbafc408c97f51016 +SK = 1c774865fc284e0264fc66428be438d2 +CT = 560e172bfadb8d5c2cc18bfa4cc6ed27 + +Seed = 64335BF29E5DE62842C941766BA129B0643B5E7121CA26CFC190EC7DC3543830557FDD5C03CF123A456D48EFEA43C868 +SS = E12C64E111788ADFB3EB57B6D165D3A294C560D417085E3D +PK = aba6eec113533ffa2c8607b0894312d6 +SK = 0d4381392f82a10ed49c27a8ea6c200c +CT = 5cca78c6ec52770837070104056add49 + +Seed = 225D5CE2CEAC61930A07503FB59F7C2F936A3E075481DA3CA299A80F8C5DF9223A073E7B90E02EBF98CA2227EBA38C1A +SS = E7E58F55555C892ECD63034E45EB689E3B38685F0DD3BF5C +PK = 6c24233a7ff8384e645da5bc7a4cebe7 +SK = 2f5a05b1f7b284b8a41659f3d009de05 +CT = 379417e6a821b90fcdd8a313023474be + +Seed = EDC76E7C1523E3862552133FEA4D2AB05C69FB54A9354F0846456A2A407E071DF4650EC0E0A5666A52CD09462DBC51F9 +SS = 8E140160B927E3BD62F5DFF66CFFC82E76862E832D6DB5C6 +PK = e8504293283a4f4ec6f77ca4ff42d40e +SK = 3b34f7adbc5fb4f9f250eb2343741c16 +CT = c52f8d5afe9b2d97b0bf81b9bd5c80b2 + +Seed = AA93649193C2C5985ACF8F9E6AC50C36AE16A2526D7C684F7A3BB4ABCD7B6FF790E82BADCE89BC7380D66251F97AAAAA +SS = B99BD8E1254BFAAC1C47017E3C0D8D43D861F359911CF0F7 +PK = e26902cc4a342ee1fba5189ebcb37a51 +SK = 7a4d15331518973221b6e46d418bef75 +CT = c81f2d9ea0d7150f6abc13e15afebc10 + +Seed = 2E014DC7C2696B9F6D4AF555CBA4B931B34863FF60E2341D4FDFE472FEF2FE2C33E0813FC5CAFDE4E30277FE522A9049 +SS = 84F6FB0BE7F89536412BB667E98311A8C0B45478C6C9D95B +PK = bf00beecf445dc6612acff28185d35cf +SK = eb66519635a05d55ee1daf9cfef0c76f +CT = ad4d31454bbee6554213c2af696b02e0 + +Seed = AEFB28FDD34E0AB403A703B535296E3A545CA479C1D8148E2D501B3C8DD8B1034BD986F13F1A7B4671BE769359FD2AAB +SS = DCD04F3F85D5D3576CF40E50A8F7BC6B76FD4033CAE57C16 +PK = 5b50a3f04d9895e5c15f992918245712 +SK = e33bb0f29323c1fb699dd182b77448fc +CT = 958330976f80bb9685e45a9c79e5715f + +Seed = CBE5161E8DE02DDA7DE204AEB0FBB4CA81344BA8C30FE357A4664E5D2988A03B64184D7DC69F8D367550E5FEA0876D41 +SS = E320DA10918B9F41E052BB949F4BA4CEB8A92FF53B24AC2F +PK = 92c2796b1aa2a2897d51f982c19da9ed +SK = cda602a93a11325b5ea20a562a50b027 +CT = 32842c23e86b6fd59db8ff00abb9babd + +Seed = B4663A7A9883386A2AE4CBD93787E247BF26087E3826D1B8DBEB679E49C0BB286E114F0E9F42F61F63DEC42B4F974846 +SS = 4191FE26F8F3F146D61466D50223226BBA46FDFB8979A7C2 +PK = 682071d27fa870b25e7ce562e1e788b9 +SK = 3b5d3053780019201c76b5f74a126e26 +CT = 6f82fbd46763f54dea1f4c10b5be5ec3 + +Seed = 980D0BA7C8F8B23D0E948A6029FF2659810EA1360064663A8994D0333C8543EE5FF5D6D5C9ACF446E61DC464F792B9D3 +SS = 937ADBC5FCD44FECB91036FAA007BD6BDA11D04531389C61 +PK = ec64e9c60272ad1b209c4e5ec211b8a0 +SK = f7470e69e267b2ffbbc9ca12f8371b90 +CT = 198fa82ec8998fde5c5c1ca8f2d60754 + +Seed = 6C029462CA42ED520F10A579F52687101105E0B90C6E7BFA582A4C112B579D5AD0A0ABD38F72ABCFDCAAF5893A112BDC +SS = 1EBB2FD370EE1E46C76EC364E8B41E7CCD230C4C29C1A506 +PK = bb26eee0be00e22317fb5ac990842eb9 +SK = 2a1474ecc52cfdb02e0ad58660ad738b +CT = 6fe5a81b1436ae5a3bc0908901d59dc1 + +Seed = DB00120937570D62331F4C3F19A10465231EFF46465CDEE336A0D46AA1E7493DF80F18617F9FFD0476CF7784A403EF4F +SS = 568C2C81070F370454FF4FF6791E79912C1B7575DB5F3B85 +PK = d60c9211b3cdd1b258951682437816d8 +SK = fc4955f2661db8d3e490fdc7324eab58 +CT = d10bf488a328668662470cfcfd326204 + +Seed = BD26C0B9A33E3B9B4C5D7EA32D5BD1FC371015BE163C86F584E49BFD5362C8D8341161CD1308115B2A03B7E5EADDD418 +SS = FA5C6CAE809DDEE45675D73E2938034DD3B33195507FD9F9 +PK = ee36a9a2624a53debf44f965034c3623 +SK = 4efda3a0daea897ff491bd1172664c4c +CT = c6cab48f4db3891292c0413d033566e8 + +Seed = E2819EF86853BCA1B9DEE7EE1C1619988964F9A913E635AACF0D96CA6E0300D084329DABD8F149E24176D22757404260 +SS = 96776BD079A19BB61039E647145B1E772F15F23385D2AF18 +PK = 92e6c6c90d216fc8f4029e8c4840f95c +SK = 68530e04ecc0a13d380d3b724319cc23 +CT = 2a6d7458acf1fa8de09d61e757d3eb12 + +Seed = 669C4EF8A051CE201DA65FC4BC34D398EC1F806276FC5D987AD71D93BC12DC8F107B58BE6E8422A0795C88CB9A0E7488 +SS = 1FB44EE61BF997AE51337EA357567CB75BF0CA640E9ED914 +PK = 98fae89ea7f8a025bb0c83728684b797 +SK = 761784c7bd923b3feff6c0d6de8e9bfd +CT = 04c9854c4b236c89bd29553f323e8525 + +Seed = 9DEBCCFE818F6B5204DB4EA09C03EC9A19DCF1629C1527685B8A29776BB1DAAEC45F8ABF8F0ADC9A8C8BD6E2DF6D8048 +SS = C63F80BE3F17DFA49C1418D643B53A3F2B79B3709414A7B5 +PK = 63e8e7cc2861ad031695be053873e263 +SK = dca62baf6d4c23b02bab83b4fc9975b1 +CT = 43ae310cae3eeb3afe395306048d604c + +Seed = 8098AE7A92C10F707D405F7DEA02C2EFBEF44EFA132BA8AEFE81BD45E543ECEC74F10920AE48A40B0653D63532517F2A +SS = AA290E1E83A990F944744CD01C131140E7968F1D15715F73 +PK = f3e083f287e638e0c34891ef24fb56d7 +SK = 0556b850c19aec255913b253ec826bcc +CT = e95c3d363d48cd7ef2db69bbe3023125 + +Seed = D5F23808871544E9C1D6EACE2028362B48E225312F77663E9F78CAFEB512B908CD9E25875D61A16EC615F4B8FF826856 +SS = 7A0DD9BAD7B79D92AD014A066BA3B7EB2AB9F778EE35C917 +PK = d99be9746469273224c93c096ed30c46 +SK = 5f3f3f9708eb72d70c85d5362d23ae6f +CT = cadfc5bcfb0a48e12ca4a19f643ffa47 + +Seed = 822CB47BE2266E182F34546924D753A5E3369011047E6950B00BC392F8FEC19EA87C26D8021D377DF86DC76C24C5F827 +SS = 9E6E806C848AFE409210E717242CD1CC12791724D40CF317 +PK = 618776baa1d7f2fbadc6b2fbe7fad25c +SK = da7113c05fab2e6ebecb865ec4636623 +CT = 30c893be49541ff2f11073a77df6ea8c + +Seed = 81401DB81138D6874E91B7C11D59596E4ACE543F5A3471B6FB00999221765FEC3CA057ABE20F03B2D59003375FD71FE8 +SS = C8EC930640D4E6296BB3FF473942F9193362754EB470ED5D +PK = 30b8c7e24b65e090adfea886e2fc63b3 +SK = 52157e659aacab781db2813cff689730 +CT = fcf7cd1aa51b93b20bf00fddd37c6a67 + +Seed = 30B5DE5B73681EC08AAA03F6F2D2169525D25F4042A5E3695A20A52CA54927B85F8BB948FC21DF7DEFC3910B28674994 +SS = 025A62B3126B569842AA078276EEE1582C7BF0AD90863DA5 +PK = c04b29b5b83f5888f8af766c20a5ab17 +SK = 2b9d2531506383fb1fd68bc9d9cdbfe5 +CT = fe3e15aab7343d0b9e17dca678ebb3db + +Seed = E335DF8FC0D890588C3E305AC92C7160FF199E07C85760A828933750E3FED8C83B0DBE802234481ECF890A32D7A2884F +SS = A8AE449F0FCD939546A43015568D16EF0D1033B0F06D9AEB +PK = 3ea3235373bb648ea8e0d77b39c7eca3 +SK = f57f99e50d524a2807c5507150a8bb51 +CT = a890f407eba7c1f3a027fede2794c9cd + +Seed = FBEA1BC2C379F4F8FDCB0DE260D31CDB064C9EA9B1D6DFBE91B3692ADD1D34DEC9C9FFAE7BF5E72ED2743BA3F9F2E43D +SS = 2FE7B0C910179AAE6F7971D5211149D71CDE8CBFAB3F4BB5 +PK = 273226ebda4bbd51fabb5d0c0869504e +SK = d64765326f1768c2708a8144ad1ad232 +CT = 6a194a1f8d6b97661b9b9247367c01c6 + +Seed = 7E87FB886BC3C7C9FC12569F465D2ECD12532E76CC27C65644C8D3DD603B0CB2D036C5974E675058F271D5C82AD7A813 +SS = 9ECDA4E4BCBF349CD56F2BCF03CAF48F1F043C82745EF83F +PK = 3a5f72d24b5a685b2e7d5d566004d3fb +SK = fad7f9965eaf326b1137196373caf29d +CT = 2c55b123a357575f5c0c840b98dbb53a + +[eFrodoKEM-976-SHAKE] +Seed = 061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1 +SS = A98165539A4AAD979023D67B435D316F007C86EEAFDB63C7 +PK = e95760ceec6f6c7d33c287f6b6b04e97 +SK = d1a966bcc94f16a12f259ebf2a3e953a +CT = 1de54140203034aecff44e720b6a6d91 + +Seed = D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556AC81ADDE6AEEB4A5A875C3BFCADFA958F +SS = A096BD2B6A731D97B2FC51110C30D6328A13B577EC5510C5 +PK = e59bcc4a73c6eee24bf1ee60977dffb5 +SK = 35b7fcd7e64923a2572e0b366b974e59 +CT = 0e02cf2fdebe7bc5c566b33b56036eae + +Seed = 64335BF29E5DE62842C941766BA129B0643B5E7121CA26CFC190EC7DC3543830557FDD5C03CF123A456D48EFEA43C868 +SS = F8B6AD07670DE6BF61A51352FD5988360BA4054B5EACC8A9 +PK = 34a58818a8f562825a758ccba9463662 +SK = 243bab593856ade796a704c3e69fb79c +CT = a0b662e2cb60e1900642e081490d0ceb + +Seed = 225D5CE2CEAC61930A07503FB59F7C2F936A3E075481DA3CA299A80F8C5DF9223A073E7B90E02EBF98CA2227EBA38C1A +SS = FDBEE405409B9D6AFFB6D561360905C58DCE6F6D05B33AB6 +PK = 975655b9e333379de2029e5fa4a172a8 +SK = d13aca695ba26cde117cc17222da432d +CT = 6e478c01ac1147a7d9250863e731e771 + +Seed = EDC76E7C1523E3862552133FEA4D2AB05C69FB54A9354F0846456A2A407E071DF4650EC0E0A5666A52CD09462DBC51F9 +SS = 4F309BBE0B8210DE99B9B195B017E1B31C107390FFF1BCCA +PK = 026f87b0f4f58c621cb048fb26c3e607 +SK = b6d4cfc9fc72a170f21af958885bf3d9 +CT = 138ef1247653572d8f55e6c71ceaa50c + +Seed = AA93649193C2C5985ACF8F9E6AC50C36AE16A2526D7C684F7A3BB4ABCD7B6FF790E82BADCE89BC7380D66251F97AAAAA +SS = F07A3FBDCF0C3C8259A0E113F5E01761D04654A924778AF6 +PK = 75f18cfa885cb51b0a228240899fc15a +SK = c3541003ca0074dd83a8d647ea15f11c +CT = 61c80397bf610b0733da981003b352f1 + +Seed = 2E014DC7C2696B9F6D4AF555CBA4B931B34863FF60E2341D4FDFE472FEF2FE2C33E0813FC5CAFDE4E30277FE522A9049 +SS = C5202FAD7AA48F00DB1387E939F3B715F7A6D2A90E9AFD75 +PK = 8ba6a1b3c54b04f92360d98ae6a9ffc7 +SK = 747401cdc779eef96d1a2ac46c5b25e8 +CT = 3bf7799e5457fb1b8970aba51ece4588 + +Seed = AEFB28FDD34E0AB403A703B535296E3A545CA479C1D8148E2D501B3C8DD8B1034BD986F13F1A7B4671BE769359FD2AAB +SS = 25A549F71B2CD5EBA53C8A27A1CC90614B4D91694958B724 +PK = 890af8681909e9ca241ed0e2b1ad5111 +SK = 6f9e1037624b7edbd7c7236e1546e3ff +CT = 60ffd1483c76ac57ea64890593b7a927 + +Seed = CBE5161E8DE02DDA7DE204AEB0FBB4CA81344BA8C30FE357A4664E5D2988A03B64184D7DC69F8D367550E5FEA0876D41 +SS = 6312B6766A110BA360F0CDDEC7BC5EEBEF9CC06F3F045F77 +PK = 16b3aa0782262044a90328d3c3bb497d +SK = b25d2056b83038e72fa387c4552aff9c +CT = 70b09111d939e81b40507a057f898ad1 + +Seed = B4663A7A9883386A2AE4CBD93787E247BF26087E3826D1B8DBEB679E49C0BB286E114F0E9F42F61F63DEC42B4F974846 +SS = 0FCDD7AA8142195D7855850E6E7EC116E84561A340422AC0 +PK = 854e89913ac87d3ec5e80d99eab50138 +SK = 29a3d33b62f45286ba9ea797e2d2d6d9 +CT = 9c625387e2ff198d4320e4c466fbf906 + +Seed = 980D0BA7C8F8B23D0E948A6029FF2659810EA1360064663A8994D0333C8543EE5FF5D6D5C9ACF446E61DC464F792B9D3 +SS = 848EA850A873B2440417DA87E875D96968F35CDECE3F8FF0 +PK = 3c50b54073fc07bd25bd4cf2acaa20ba +SK = 72c3642df508bf24ee9fed73f59dc616 +CT = c8b413ee854161a3062cda30f77d0557 + +Seed = 6C029462CA42ED520F10A579F52687101105E0B90C6E7BFA582A4C112B579D5AD0A0ABD38F72ABCFDCAAF5893A112BDC +SS = D2CB92220B5E8EAAA5D603C4944C9EA983F081355E2F26B9 +PK = b81dc6c73b605677b60f2573e08c3240 +SK = d6cc4e824733e9f8f633dd6022fedf08 +CT = df2443f30d053861d629300e25533182 + +Seed = DB00120937570D62331F4C3F19A10465231EFF46465CDEE336A0D46AA1E7493DF80F18617F9FFD0476CF7784A403EF4F +SS = BE31A1AF9BA16B5AF5848501AD88181092B072E97983F86C +PK = 5a0b049b38fdc8c5525e6b1cd4350fa9 +SK = 647c2884350e3f7564ba7b4008b35c85 +CT = 398d670b35ec615f2e59eba60bc593f3 + +Seed = BD26C0B9A33E3B9B4C5D7EA32D5BD1FC371015BE163C86F584E49BFD5362C8D8341161CD1308115B2A03B7E5EADDD418 +SS = B9DBBE506DBF70F87C32BBFE4982443610A997B383D5645C +PK = 3b8ccb3e539b44a658332b0f0d83c0e4 +SK = 915eed754db5926832435ac72c1e8f21 +CT = ca0e656e0e664317eafe9978a14743a7 + +Seed = E2819EF86853BCA1B9DEE7EE1C1619988964F9A913E635AACF0D96CA6E0300D084329DABD8F149E24176D22757404260 +SS = DF90CE5452A7337F5497E68599BED2B941EE5C5EC2AF921C +PK = 9c6e3908c5ab2f28e397b6e5b8d52a1a +SK = 840106359756dc4142640e9a647fef55 +CT = ab1707a7eca53fa8c23f6122c382be03 + +Seed = 669C4EF8A051CE201DA65FC4BC34D398EC1F806276FC5D987AD71D93BC12DC8F107B58BE6E8422A0795C88CB9A0E7488 +SS = 694B3EFF9D5D7894CB8A1998763137F0B940DB56A340C936 +PK = e3ade951bfe1b409aa1ff58079644147 +SK = 79ce2c7621807c2592fa57a85439cbf5 +CT = 1dfc59f93172e0d6ea24ad134159a79f + +Seed = 9DEBCCFE818F6B5204DB4EA09C03EC9A19DCF1629C1527685B8A29776BB1DAAEC45F8ABF8F0ADC9A8C8BD6E2DF6D8048 +SS = 08C4D7CB077A4E840B1F28BEAC823BD91AE5843AD8A8C593 +PK = 594699f44b3e647f1167d805e8bc43ce +SK = b43d083b601c58a5dcbb82bbdcb34b84 +CT = 524412ef67c9fa919c3ba903401594cc + +Seed = 8098AE7A92C10F707D405F7DEA02C2EFBEF44EFA132BA8AEFE81BD45E543ECEC74F10920AE48A40B0653D63532517F2A +SS = 33087DECB17868FA7F8B7B579482F797821331442B929AAD +PK = becfa86d015f166732113c208b432b7b +SK = f94c01a016f711a1785683c50c071578 +CT = cbef4a77d6c1543e640c637ecb9fd3fd + +Seed = D5F23808871544E9C1D6EACE2028362B48E225312F77663E9F78CAFEB512B908CD9E25875D61A16EC615F4B8FF826856 +SS = 2CB01647029EBE6A80145A8EE763B9E06B8726008B78B2EA +PK = af6dcc79388af7ded210a41cec1eea59 +SK = 2b955da86a8d4e1f8efd5926121d054c +CT = 1afc9f92a3c85783267702caf3e44340 + +Seed = 822CB47BE2266E182F34546924D753A5E3369011047E6950B00BC392F8FEC19EA87C26D8021D377DF86DC76C24C5F827 +SS = 11395C3652221E52B992A2A7DD6D6E1CF30787D1E5FB8DA6 +PK = 0cf9be2d016af8ca358b130ea86e3a54 +SK = e868554a473a23a0f4f6872092ca6091 +CT = f4038046537d4406486791da31c53e86 + +Seed = 81401DB81138D6874E91B7C11D59596E4ACE543F5A3471B6FB00999221765FEC3CA057ABE20F03B2D59003375FD71FE8 +SS = 24DA2EBD04EE0F5145A6FB41945DB94AEE3AC93A2339D53F +PK = 4dd7ff26af87dfc5de8bcb8cfbdb570d +SK = d21833e2048c61a693636cb70897f15e +CT = e51ba6d90d6a2dce05529c5f6c9e7a39 + +Seed = 30B5DE5B73681EC08AAA03F6F2D2169525D25F4042A5E3695A20A52CA54927B85F8BB948FC21DF7DEFC3910B28674994 +SS = 68CD03373F3A451A6A5E601AB1654DB428D78CEB7565A924 +PK = 630440bd934793497ddeb8c6a443bbba +SK = 6a02aac613f8d8097cdacc95dcc87be4 +CT = 92afdfcac45e715816392c3db34db175 + +Seed = E335DF8FC0D890588C3E305AC92C7160FF199E07C85760A828933750E3FED8C83B0DBE802234481ECF890A32D7A2884F +SS = 118698B7DEE2AE7BB9A05A2015B2971D4CDFBA1DC2D16B03 +PK = 8ae4b9bab4666a8f7b9074f6935e99bf +SK = 4093b135df3104458d56be8736892f09 +CT = 60cea6ff0bd742d6bc42ff7ab20e29fe + +Seed = FBEA1BC2C379F4F8FDCB0DE260D31CDB064C9EA9B1D6DFBE91B3692ADD1D34DEC9C9FFAE7BF5E72ED2743BA3F9F2E43D +SS = B5FB1C1B9D1DB3B368D40A175D664D584A981F4CE016F6E4 +PK = 069f7176145824c5a2845922dcd6fb2f +SK = 2a8ab4425e129eecfd8f367b3955d64a +CT = fbdb29c7a1c6af627e6d6ae5f5a297d2 + +Seed = 7E87FB886BC3C7C9FC12569F465D2ECD12532E76CC27C65644C8D3DD603B0CB2D036C5974E675058F271D5C82AD7A813 +SS = 6F4019879DA2462942896AD9427144D933C33843EA04C94E +PK = 44a8b1658d4bbf9833670d04c73b8678 +SK = d19669c73ceb6c65fdea51e7c8b769b2 +CT = 5788a131fcc331fa75668569e4d094b8 + +[eFrodoKEM-1344-AES] +Seed = 061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1 +SS = B243FE6D7C9B3829252D5AEC090A4709F5E396FDEFE4EF1AA4AE6C9498CBCE15 +PK = 4c893613c93652f6597b1c7cbc9ea79f +SK = dc0c54c66f4c84b0cbbdee777f0110a9 +CT = 230dc1b6227fc3c6dba8386046a69a23 + +Seed = D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556AC81ADDE6AEEB4A5A875C3BFCADFA958F +SS = AC476D7B8A09F8EC1C9022D1D7D723FDD546C946E4DDC978FA2ED413D9F8A6C9 +PK = 1312cc1bd69793b3b3d63abb6b8eeccf +SK = 9362fb4ba04c64bd46f7d985be368c6c +CT = 8d565431d8a57b030174ccc2ae57d785 + +Seed = 64335BF29E5DE62842C941766BA129B0643B5E7121CA26CFC190EC7DC3543830557FDD5C03CF123A456D48EFEA43C868 +SS = 278B1C72ED7EEE897E090771C79C58708927ADABCC63D5788D4BFA0EDD578485 +PK = 18a6e71293ccce4110f920dcb28efb30 +SK = 3e06d86f8acf4be9f986e1b69eccc1e2 +CT = 69ff149dcd5533dc6a43dfa853866486 + +Seed = 225D5CE2CEAC61930A07503FB59F7C2F936A3E075481DA3CA299A80F8C5DF9223A073E7B90E02EBF98CA2227EBA38C1A +SS = 3C8C23707BD077158F33B6ED1EC95D636930BD1DBBB7949E3031EA94A0EB9025 +PK = 7d57c053eb1093bb5b3e88b069db3e54 +SK = f944704649b8d2401d5f858ea0671e4e +CT = b501e3aa858ad4273d3cafdef906131f + +Seed = EDC76E7C1523E3862552133FEA4D2AB05C69FB54A9354F0846456A2A407E071DF4650EC0E0A5666A52CD09462DBC51F9 +SS = D79C5836F1F1B13A536BF7A9E1E1AE3416CF838C20E226EC110647470818CAE8 +PK = 39524c9ff1ac59a2e9f7441e8b053cae +SK = fe3a3034e76b2fca292dc688f53e2323 +CT = 95a890d4734e420b99513d6ac6752f79 + +Seed = AA93649193C2C5985ACF8F9E6AC50C36AE16A2526D7C684F7A3BB4ABCD7B6FF790E82BADCE89BC7380D66251F97AAAAA +SS = E156C33AB4A07A4BD7431BEF77DD61BD3AC5CCF44EF2791193D03C641813371A +PK = 713376c78883e0b8ebf9926348e217c1 +SK = fcf9a010a3eaa0b17fcc45b12b26e2d1 +CT = 57059c74de66fbdf34767d38c982ea56 + +Seed = 2E014DC7C2696B9F6D4AF555CBA4B931B34863FF60E2341D4FDFE472FEF2FE2C33E0813FC5CAFDE4E30277FE522A9049 +SS = EDAA8D335A1924A63D8D7023C2992EB87B29F636372C568BA25723D90AE08E89 +PK = b7b2ab17507872d114f751a78daca06c +SK = ec6e64cf691058f09b2a6b39c5dfc961 +CT = 92cf0f58d4a57a27d5a8953dd36e753e + +Seed = AEFB28FDD34E0AB403A703B535296E3A545CA479C1D8148E2D501B3C8DD8B1034BD986F13F1A7B4671BE769359FD2AAB +SS = 38C537ACF4627473F19C9231F4FF42DEAFA16D8B18AB722AE3861AE796868C47 +PK = 1218b70bfd2199bcc218118d3f213d1a +SK = ee2043ebdcf0d393136518672863ef85 +CT = c86292a05b13c08c45396f52edef8d73 + +Seed = CBE5161E8DE02DDA7DE204AEB0FBB4CA81344BA8C30FE357A4664E5D2988A03B64184D7DC69F8D367550E5FEA0876D41 +SS = E45FA47942974EACF57F94C7E3098DDFB6DD0DD2D04311E2576D6E048F065898 +PK = 60d7e956bbf8c368b4386ef8d20f6300 +SK = 08bb666bed5d4fe19939c0423465bd25 +CT = 9d2221ec3e30e22d0733431fabc49d98 + +Seed = B4663A7A9883386A2AE4CBD93787E247BF26087E3826D1B8DBEB679E49C0BB286E114F0E9F42F61F63DEC42B4F974846 +SS = 64A42D476E731ADEAA76DFEB40D55340883554E6CCD9CF2AEB7FE76C64EED5FF +PK = fd464203f23ac18db354d47609dfe5dd +SK = 59e513162f211a993b45f59ad2eef1e5 +CT = 6a21cd98a7f8129345dedba36b3553ef + +Seed = 980D0BA7C8F8B23D0E948A6029FF2659810EA1360064663A8994D0333C8543EE5FF5D6D5C9ACF446E61DC464F792B9D3 +SS = 4061E2C5B0D8394D9E349F393E3ADCAA2D24EE3299465C7A98A47D526AD75E7E +PK = fb5ce84f361e66de1be0c568458d4ad5 +SK = 5a9ea01f0ad9815d1afb057c05274c08 +CT = 4c5ae9265c1b4101e2120bc034ca1833 + +Seed = 6C029462CA42ED520F10A579F52687101105E0B90C6E7BFA582A4C112B579D5AD0A0ABD38F72ABCFDCAAF5893A112BDC +SS = 61649230A07344FC6296831FCAA7F89A85CB9A399235B5D61B65DA9314E15596 +PK = 5a5e9880e507bd754a7782aae1ccf075 +SK = 489c03ba4bd75376d48b68d2abda45d7 +CT = a3140ac327c7429b6a918a3540a0fcaa + +Seed = DB00120937570D62331F4C3F19A10465231EFF46465CDEE336A0D46AA1E7493DF80F18617F9FFD0476CF7784A403EF4F +SS = D27E5950861F21865862B62E3F3260D4ED0668E93C4EF24A226BB969FBDD72D5 +PK = cd78673934503ca5d70b71b4a81e9b9e +SK = 5d73b4bb29c4f94bebf84103f436f0cf +CT = d97c6f2947204e5be81c07bd2c06216d + +Seed = BD26C0B9A33E3B9B4C5D7EA32D5BD1FC371015BE163C86F584E49BFD5362C8D8341161CD1308115B2A03B7E5EADDD418 +SS = 9835A646229C7A3287C71682D2E1C1C3BE74D57AD09C5F2D3764BB766C52AFB3 +PK = f0095c5f32ee24a1786c4afbee24e067 +SK = a518deee63f4cce67dbddd4f9d6437bf +CT = 74905076a467aa98d51e784bdf272cd8 + +Seed = E2819EF86853BCA1B9DEE7EE1C1619988964F9A913E635AACF0D96CA6E0300D084329DABD8F149E24176D22757404260 +SS = A4218CF1E68187BB62C5A3BCB379B113E7A2F2917AAD87666951955A430F62D3 +PK = f75a362f27893bffa8d72d6b39c7ef96 +SK = 6fc977376ae347b9aa49dae46a8deb74 +CT = 399af3fd86baec4ce606ca637a5c8dc0 + +Seed = 669C4EF8A051CE201DA65FC4BC34D398EC1F806276FC5D987AD71D93BC12DC8F107B58BE6E8422A0795C88CB9A0E7488 +SS = 2A2D01DBD581FB855480736CAD0DF2B9CE48209D29A794A73EB6C12C5EA8E58F +PK = 6c625e424d0360a610ee732f79a6a126 +SK = 196b44739e547935233dafe7367862cd +CT = a6d37ae7018ece481d3d610821cfed4c + +Seed = 9DEBCCFE818F6B5204DB4EA09C03EC9A19DCF1629C1527685B8A29776BB1DAAEC45F8ABF8F0ADC9A8C8BD6E2DF6D8048 +SS = D20DC16A0171F56F26F5E2C03EFB98120018B6E0ED30F00CA02B1F398DA6B2EC +PK = 9c2e28a5f032d0b1f41ab516185a6b1e +SK = f45269c599051ac53571c92111996b51 +CT = 355206c6a9177457d4c2f013bbd2a639 + +Seed = 8098AE7A92C10F707D405F7DEA02C2EFBEF44EFA132BA8AEFE81BD45E543ECEC74F10920AE48A40B0653D63532517F2A +SS = D65E506A180DD370043B302CE4E937C016F33011C21AF9ECFFFAD1488DA69E22 +PK = 091ee67ee67da42f656c5395744ae97a +SK = 97d3bf42274cf77c04ab58e7ca3b4af7 +CT = e5554e760a85544fdbd33712d2ff17e6 + +Seed = D5F23808871544E9C1D6EACE2028362B48E225312F77663E9F78CAFEB512B908CD9E25875D61A16EC615F4B8FF826856 +SS = D6197DD4FD8D3C6C12EE83F72FC21890D2C2B0436E181B0E843D73081FB07452 +PK = 8d79c69df61453df8a0b21ec67a964ac +SK = a02cdd144021b9a5d739f1099a496fbd +CT = b04f1d256e57f8f1fc3b4a23482b7b3d + +Seed = 822CB47BE2266E182F34546924D753A5E3369011047E6950B00BC392F8FEC19EA87C26D8021D377DF86DC76C24C5F827 +SS = 92C65EAE10B4F8CF7A2DA124174004B910A5EBF13D78BD4CC6759541F0CD18D4 +PK = dfc13779192dde17fe4838b7a2b5b505 +SK = 69249805ba295367011ef8335ec21783 +CT = 803345b4edb6205a74ac7321adcd118d + +Seed = 81401DB81138D6874E91B7C11D59596E4ACE543F5A3471B6FB00999221765FEC3CA057ABE20F03B2D59003375FD71FE8 +SS = E7DB957F63CB22C4AA15BB7C87AF3F8622E290E734ABE6256260C5C23F53DB0E +PK = 6cf71d98aa8160cd492787fe0bd914d5 +SK = 044e343e7ab8ecb8f7f99d11dadbb744 +CT = 1750d8c626931f965a623cbe63a2fa73 + +Seed = 30B5DE5B73681EC08AAA03F6F2D2169525D25F4042A5E3695A20A52CA54927B85F8BB948FC21DF7DEFC3910B28674994 +SS = BEBED176064BF57FE03DEC7A3E888B0AE990758C1FD0740987300AC0A69441F2 +PK = 20656980b736b55bf3701e6f1787ca75 +SK = 62422b790bad009fbbbff1c4acdc96f2 +CT = 1afc776b7c3f8b16e0e021e84ee8dcd3 + +Seed = E335DF8FC0D890588C3E305AC92C7160FF199E07C85760A828933750E3FED8C83B0DBE802234481ECF890A32D7A2884F +SS = F29EC7F8E2DE3D44EB78DC1BF0AE96B54CEDEA1CC7987765D8C536407B8D42AA +PK = 0b25225f311476f229f802bfc7617879 +SK = 23e4f31a967fb191d9fd32cd07152ec0 +CT = d9caf3fd6a1f38742a12a76338367284 + +Seed = FBEA1BC2C379F4F8FDCB0DE260D31CDB064C9EA9B1D6DFBE91B3692ADD1D34DEC9C9FFAE7BF5E72ED2743BA3F9F2E43D +SS = ADD145A994832FFB1BE003AB02CCE3BB6EFC7D8BAB4613A6F0CC89C585A18BA3 +PK = cdf3cc1bbf70cd27d5ff307952c9144a +SK = 4e449fc1747714561bc7886d7ee8f6bc +CT = 44b997dddf85a3efff3a7863aece6a94 + +Seed = 7E87FB886BC3C7C9FC12569F465D2ECD12532E76CC27C65644C8D3DD603B0CB2D036C5974E675058F271D5C82AD7A813 +SS = 068DBDD08ED68F6B1AE51969E4D31BD2EDDECF4ADBB895BD92C3F44B8AB1D819 +PK = 24ce094774c5b3f9aceeda211761d073 +SK = 30e8a9c6a21b2cdecd4257308f3205fb +CT = de2a651030e9b3f23e84e60bccc839a0 + +[eFrodoKEM-1344-SHAKE] +Seed = 061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1 +SS = 6D69DF1A90968EABADA69CD30EC6813A4406309DAC174429A0120852BF826460 +PK = 3888d1ae429f0abc85756f8e14b3f659 +SK = 1076715135993cebdea9b383c66de6ef +CT = ec6a9010e644d934c80b6809faf0e99b + +Seed = D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556AC81ADDE6AEEB4A5A875C3BFCADFA958F +SS = 28D0AACDF5375797B4D7D010EADE8583F7CF10916B3009E66DAD9ED27AB1A523 +PK = 048fa3b3aee3a3ccaf51b9436e3fe37f +SK = 3fc155ecccf4d76322bfab995d065667 +CT = 597eab05012fe0daf84c7f7f24bd381e + +Seed = 64335BF29E5DE62842C941766BA129B0643B5E7121CA26CFC190EC7DC3543830557FDD5C03CF123A456D48EFEA43C868 +SS = CD8F284F9E888CDAF4D7C7FF7497FAC785129E31FDF1B36CF40F537EB1653CE1 +PK = f48977af4b8a0c601bd5d87688c3cdff +SK = f63541a7d3c50e4b162c024719723933 +CT = c779031540f1ac22f8943dac81e907ca + +Seed = 225D5CE2CEAC61930A07503FB59F7C2F936A3E075481DA3CA299A80F8C5DF9223A073E7B90E02EBF98CA2227EBA38C1A +SS = F95C9572AD2632C8A0A4DD4E8CDB2C37AB423159E84E3B08111538459B7113A7 +PK = cc1b6217d83b9fe174ef84d4dad89ae2 +SK = 517f7ed456c48f4132154db990bd98c3 +CT = 3a8ef04882c22b4575358f5723555fbe + +Seed = EDC76E7C1523E3862552133FEA4D2AB05C69FB54A9354F0846456A2A407E071DF4650EC0E0A5666A52CD09462DBC51F9 +SS = 859535FD01FAC70865A16F99FDAFC6E895FF7363B4A46DBC96837E260B8BA8E8 +PK = 760449791dac7b5424b90c987cd68896 +SK = 80c354cebe3b848d081576d300e6ec2c +CT = 9d8cbb44e11a0def2394ce357f1f6912 + +Seed = AA93649193C2C5985ACF8F9E6AC50C36AE16A2526D7C684F7A3BB4ABCD7B6FF790E82BADCE89BC7380D66251F97AAAAA +SS = CE89528A4B9A0315DCC47ECE692F673DFB7AAEFF181B0509E148D1E6C0E6352E +PK = c9a6e2bc093cb6c6bea56151344548d6 +SK = c8b7a5064de2c6aac82bfb7db3eca37b +CT = 016d9f1036743a2ac15d745e1470b31d + +Seed = 2E014DC7C2696B9F6D4AF555CBA4B931B34863FF60E2341D4FDFE472FEF2FE2C33E0813FC5CAFDE4E30277FE522A9049 +SS = 27ED5B0FF3488594D4E550F4D1760D64D4FCFED543D6AC2753BEF050B87CA3CF +PK = 76a4283c240df535754fa17d6d189ee1 +SK = eca6f37247094d2ef20435c12a9528a0 +CT = 0f22c942055d60690d4592751859ae77 + +Seed = AEFB28FDD34E0AB403A703B535296E3A545CA479C1D8148E2D501B3C8DD8B1034BD986F13F1A7B4671BE769359FD2AAB +SS = 93DE67CF6DE1F52B710F6E35F125E60D888775FD96C412B683B2917107375C1B +PK = 066618229086ebc483e0f0e39135039e +SK = abfce2e506b97fcd0e5986a7fe0e9008 +CT = 3e7bac57b45476a0f66f910ecdd3ba23 + +Seed = CBE5161E8DE02DDA7DE204AEB0FBB4CA81344BA8C30FE357A4664E5D2988A03B64184D7DC69F8D367550E5FEA0876D41 +SS = F4207EB36B291787CF252B07D510E5D1FF960DFBF94EE01406A1032547AA281F +PK = ee7a0a7937b3c87016eaa78bf9533730 +SK = 4286e8e02fbca2e89a6e9aade7209790 +CT = 3d2055f9b4c01118106b7765717e0b65 + +Seed = B4663A7A9883386A2AE4CBD93787E247BF26087E3826D1B8DBEB679E49C0BB286E114F0E9F42F61F63DEC42B4F974846 +SS = 1583A2BE9C6B07C46401A12E98CB1EC525C29D321DF356E4504F276DECD77BAF +PK = c6da6f5abcd68f242049de5663a9f367 +SK = c673d4fdf4c3c33941c592941a79d647 +CT = 7638d65f9e6624d0868e136f2804ed5f + +Seed = 980D0BA7C8F8B23D0E948A6029FF2659810EA1360064663A8994D0333C8543EE5FF5D6D5C9ACF446E61DC464F792B9D3 +SS = A8EAD131B4AB70D7447878B86D7CAE105787E9E7097BB9ECAEBE93327674AD7D +PK = bdd9eee5482992fb7a927a28a3bcdb55 +SK = 6b2a1e9d68854708eaf7d9d07f39eb2b +CT = fd7f5af8fc547118a54190615e23296e + +Seed = 6C029462CA42ED520F10A579F52687101105E0B90C6E7BFA582A4C112B579D5AD0A0ABD38F72ABCFDCAAF5893A112BDC +SS = 8D9ECC592AD3978ECC5F754C6DDEADD79619739C681120E894160ECC49A8297D +PK = 591dbe5d7642a94a78247fd1ef607f37 +SK = 2cd68301f1cbbff465d9c00d218e1262 +CT = 4326b243e760638d15ab74632b525c07 + +Seed = DB00120937570D62331F4C3F19A10465231EFF46465CDEE336A0D46AA1E7493DF80F18617F9FFD0476CF7784A403EF4F +SS = FAA19D723AC5176F12053B62F0B3B573E04845EBDD909987CA2AD6BB50EE9D46 +PK = 96a725d19e9bdeb39d29f006fd91d7ed +SK = 41c5e43b07ef1b628556a580791d2388 +CT = 3d2af731ef83dd8a9e50796674b2a091 + +Seed = BD26C0B9A33E3B9B4C5D7EA32D5BD1FC371015BE163C86F584E49BFD5362C8D8341161CD1308115B2A03B7E5EADDD418 +SS = D2634F36CF6470779BBF0E3743BF44B4798C52FAFAE4FE0EB7DCB244E8AC0C3D +PK = efc6cca75e88a47f24da6270e4ccfde7 +SK = a4c1ad17bd11a11f4af56010837921ac +CT = 379461277cb290806287a45482e2952b + +Seed = E2819EF86853BCA1B9DEE7EE1C1619988964F9A913E635AACF0D96CA6E0300D084329DABD8F149E24176D22757404260 +SS = 8D9BCEDF424B5427E598A025BB4A39A4B3CDB2710D6B721A981C704728941E61 +PK = 06e69693794dfd7503fc6e4b2815e9e8 +SK = 4dc07f7006ec2aaa0cff607f29e32f6c +CT = 053046f13fa31e0d75e6e6acbb9dadeb + +Seed = 669C4EF8A051CE201DA65FC4BC34D398EC1F806276FC5D987AD71D93BC12DC8F107B58BE6E8422A0795C88CB9A0E7488 +SS = 79AC0BBC40C89939E6D8AE21CCAEB50CF7E1461A2612E85819AE73001C281773 +PK = d61115e35ca9d39a096d345a7ead3651 +SK = 5bc7fe4512fe43485a19a8d2d02e8ee0 +CT = 29562a266848fc6c1834f80422484d44 + +Seed = 9DEBCCFE818F6B5204DB4EA09C03EC9A19DCF1629C1527685B8A29776BB1DAAEC45F8ABF8F0ADC9A8C8BD6E2DF6D8048 +SS = C03FF247350BA9C2E8875752C25851058EF3DD4BD14E635B049AF7E8E60DA113 +PK = 9877a210da36a8e8a569029c74359cd0 +SK = 500d08a051d3fc35cf1a9d3050a158ae +CT = 5cc3656ee5fccfd071c33bccdd5411d1 + +Seed = 8098AE7A92C10F707D405F7DEA02C2EFBEF44EFA132BA8AEFE81BD45E543ECEC74F10920AE48A40B0653D63532517F2A +SS = 00F4FEBB9CE29F50E33207877DAF8AB04370873A7D4B69D3666E9301DAE41CDD +PK = 89f3bd94dea3d07cc0a1c5b92f850af6 +SK = cca02f030bf36d95e4e323a0aad3f8fe +CT = 7baf01ce2599ccb2edbea228bc8f100e + +Seed = D5F23808871544E9C1D6EACE2028362B48E225312F77663E9F78CAFEB512B908CD9E25875D61A16EC615F4B8FF826856 +SS = 89E7D1C53217873F442C41245A79AE3FB547DBC4E10F48BD044CD111DDA93A3B +PK = dc68c17c75a6cd0bc343f372b1d385ab +SK = fb2ac4aba9ddcee80fba716f89cf3f42 +CT = 8a1f86e92caf572fac3a8cc64f945607 + +Seed = 822CB47BE2266E182F34546924D753A5E3369011047E6950B00BC392F8FEC19EA87C26D8021D377DF86DC76C24C5F827 +SS = 625D04AA99446E05AB3E9EEB8D4BC07D56545E1D172121A741B9A2F4638A9ABB +PK = e017c46067ee1f31b67921f45b809d12 +SK = 63fd4a97aeeac2e991a4c7a46a4fe21f +CT = 19e17f9ec0a7e219ca396ad2ef3705b7 + +Seed = 81401DB81138D6874E91B7C11D59596E4ACE543F5A3471B6FB00999221765FEC3CA057ABE20F03B2D59003375FD71FE8 +SS = 269A8C6DB0F23894BA934E067C15C3604D5EC5442D549AA4291D2A8C7690E2B3 +PK = 02cd89fdb90156ccf3c3556686c422c6 +SK = dd3f4f600f5f7e2ed2409778d55437d2 +CT = 2e05120b16218eb071d634be2b879c16 + +Seed = 30B5DE5B73681EC08AAA03F6F2D2169525D25F4042A5E3695A20A52CA54927B85F8BB948FC21DF7DEFC3910B28674994 +SS = B5910FBA9AAFD765944CC281CF0BFFA41B2D2EF379BE7CF8036B2A6ECF8B03E8 +PK = e73697241b1a960f6b85acc180be896c +SK = 697e11ef6215bbdfa47e14bbb47f24d2 +CT = 0d099420352edb36d8c873da2826d6f4 + +Seed = E335DF8FC0D890588C3E305AC92C7160FF199E07C85760A828933750E3FED8C83B0DBE802234481ECF890A32D7A2884F +SS = 35499F3354A2AC39ABFDC564B3BB02A74FCB31871F96586B0634407B3198BD97 +PK = c7b22e2cb982e18241d4d8e243c26d9b +SK = e965da116e1cdb6cfff70a894f02b41d +CT = 696760df2dbf5915115dc72654034512 + +Seed = FBEA1BC2C379F4F8FDCB0DE260D31CDB064C9EA9B1D6DFBE91B3692ADD1D34DEC9C9FFAE7BF5E72ED2743BA3F9F2E43D +SS = 7EEC23815862F4B3D1AA2CFE64AEE23D29184C9790562F9546364D540F65E069 +PK = 681d063018bb5b9c5c2d3077316ad288 +SK = 53d966e46f275c014af958c9cc82231f +CT = 5b12967bd55036136dda4c2e71c14888 + +Seed = 7E87FB886BC3C7C9FC12569F465D2ECD12532E76CC27C65644C8D3DD603B0CB2D036C5974E675058F271D5C82AD7A813 +SS = CC9843627DAEFE6448D2087E69CED94AEDD014FDC0BB9F0266AC9A655347E253 +PK = 144fd00449c618dcf687e8f4e52dee62 +SK = 0e62d193e261bd84334eef3dd085148c +CT = bdaadf1cfc7c9d35b016e4e68cf18aa7 + +[FrodoKEM-640-AES] +Seed = 061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1 +SS = EE5BA8CEBB0B41E9030CA1FBC3BEADB9 +PK = ce7e9105f68c90174262112506c8424f +SK = 899beef8683a11baf301852fe37199ca +CT = 73e8b989c2a2bc36c224fb67da07969f + +Seed = D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556AC81ADDE6AEEB4A5A875C3BFCADFA958F +SS = 42EE40211952277A40D6AC097897EBEE +PK = a259b174f72f067a0a8fd5ba87fc7d4d +SK = 013e59a07908000faabe1847a5166fb4 +CT = 5e66cccf7520b221706cba827b7f5f68 + +Seed = 64335BF29E5DE62842C941766BA129B0643B5E7121CA26CFC190EC7DC3543830557FDD5C03CF123A456D48EFEA43C868 +SS = C7B2206217C56A6B2F8C9EF540A33968 +PK = d7b7797c60e80e3940265b792721a011 +SK = 0b39255e75e27ae010505beab60ec343 +CT = c924423987eb8a2ee2acece2ac36b736 + +Seed = 225D5CE2CEAC61930A07503FB59F7C2F936A3E075481DA3CA299A80F8C5DF9223A073E7B90E02EBF98CA2227EBA38C1A +SS = 2819759ED0117878C9578866DDCDAC26 +PK = 8e4eb6585a8538b276cf594caa75fb77 +SK = 07e28d4e18937add508b147447eafce6 +CT = 70a8b3d6a390fff840c28ae9e9905714 + +Seed = EDC76E7C1523E3862552133FEA4D2AB05C69FB54A9354F0846456A2A407E071DF4650EC0E0A5666A52CD09462DBC51F9 +SS = A526263B342472A024163E7A4B7D1950 +PK = fe9fbf66a287eabbcc178dac5972b384 +SK = 114912c9a46475b11b80329e662970b0 +CT = feefd6b3e0a8d57b6ef7bfded570b68c + +Seed = AA93649193C2C5985ACF8F9E6AC50C36AE16A2526D7C684F7A3BB4ABCD7B6FF790E82BADCE89BC7380D66251F97AAAAA +SS = E963C593FF794CA3B7CC0D245B600B53 +PK = 088a96acccecd796fbc25e8ec8094cb1 +SK = 0cd6470885f06f3854f6862ed9476671 +CT = 8bd17b4b3e0688fed258e381fc6a4785 + +Seed = 2E014DC7C2696B9F6D4AF555CBA4B931B34863FF60E2341D4FDFE472FEF2FE2C33E0813FC5CAFDE4E30277FE522A9049 +SS = 330D0DB20BB00B4A0BF7CA3CED193595 +PK = ce08686d791d1ac8af90439ea782e3d3 +SK = c541165b146b08e3ffc536b7bf9cacf8 +CT = 6955335454678e715fc6f24a0a447f20 + +Seed = AEFB28FDD34E0AB403A703B535296E3A545CA479C1D8148E2D501B3C8DD8B1034BD986F13F1A7B4671BE769359FD2AAB +SS = 1FCDFF4DE67E90AB355B3C9170B8C27B +PK = efb6a7c4025b201af01d66c49c8ab9cd +SK = 96f21ca599a395f5b4e3f795e8c8e1fe +CT = 653e4928aa6f5d0bf91e78c466c03962 + +Seed = CBE5161E8DE02DDA7DE204AEB0FBB4CA81344BA8C30FE357A4664E5D2988A03B64184D7DC69F8D367550E5FEA0876D41 +SS = 4CA46DECBCC84B85380A78B2C4DBEC53 +PK = bb8d9e9441935eb5b7d98dff91e91c7d +SK = e643d2efc454db6abfb120febd3e847e +CT = f75a109f17ea0d9819c362ad6fcbcb9f + +Seed = B4663A7A9883386A2AE4CBD93787E247BF26087E3826D1B8DBEB679E49C0BB286E114F0E9F42F61F63DEC42B4F974846 +SS = 207212870F8F1C16E0FA30024FFC4CD1 +PK = 28ba6775fccd5131ab4ebb43c9b65e8d +SK = 95bbee0edb3bde99fa5b1d6ebe61aa81 +CT = dbe04fd1b44ca3f78d2265e2848cefc5 + +Seed = 980D0BA7C8F8B23D0E948A6029FF2659810EA1360064663A8994D0333C8543EE5FF5D6D5C9ACF446E61DC464F792B9D3 +SS = 645D7176086F9448E00B2343BF0C15CB +PK = 8f03fcce4d7bd9e2c5e99df621f5e8ec +SK = 0bc55f06a39612d4eccb2ab1a29b4620 +CT = f71ad9d829cc2b4ae2cebd85770e0f57 + +Seed = 6C029462CA42ED520F10A579F52687101105E0B90C6E7BFA582A4C112B579D5AD0A0ABD38F72ABCFDCAAF5893A112BDC +SS = A8B34D75DAADBD24FDC41FC80AC2E084 +PK = 6a2aa2a49f9d739d861e7121d1f543fd +SK = a96422ad65ea9550527d59dcab516868 +CT = 0432da221303a615cf81bca3cfcaf46f + +Seed = DB00120937570D62331F4C3F19A10465231EFF46465CDEE336A0D46AA1E7493DF80F18617F9FFD0476CF7784A403EF4F +SS = 612E9091E1D0EA670DA719F0DA9D6A71 +PK = cbf609da6c36a246389c6f6b330cbfe3 +SK = d2d62d4bdb6506b8423fc77376168db5 +CT = 4dc7e159b82a6b212c2f94ea25d8bdc9 + +Seed = BD26C0B9A33E3B9B4C5D7EA32D5BD1FC371015BE163C86F584E49BFD5362C8D8341161CD1308115B2A03B7E5EADDD418 +SS = 693686D3D7431536B14D94E5E10A4F58 +PK = 97ef06d0502b77b0e9334d6d2d5c5534 +SK = c5d29c093da8b5a16ac7dcca3455e5da +CT = 2eccebf62c7c6b79d99a143a3bfd4707 + +Seed = E2819EF86853BCA1B9DEE7EE1C1619988964F9A913E635AACF0D96CA6E0300D084329DABD8F149E24176D22757404260 +SS = DC355A7581AF97B4D24C56997E17D25A +PK = 6fe1a2a0f56b545d68d621c6eefa901f +SK = c1005151b3f00c1ceac401cc6d95573b +CT = 6098c4e1aaf42b8c58f72ff336c1efed + +Seed = 669C4EF8A051CE201DA65FC4BC34D398EC1F806276FC5D987AD71D93BC12DC8F107B58BE6E8422A0795C88CB9A0E7488 +SS = 9F1DEA344D4F2C0843EE668312B47C7E +PK = 5fe8d2545ad5c8ba259135446d7cbb0b +SK = 7ac0a452250d9a8339395aa89ec75c88 +CT = 56deb9edbfb5f47568118bf576ed4a83 + +Seed = 9DEBCCFE818F6B5204DB4EA09C03EC9A19DCF1629C1527685B8A29776BB1DAAEC45F8ABF8F0ADC9A8C8BD6E2DF6D8048 +SS = AF4B7F1AB8C3BBD1F64C5FFC4B5FFB46 +PK = be2cc8663f3bbcec3e0e9c1a08dc4b9c +SK = 1ad61009375fc0b0582235776852386a +CT = aeb07d0e5202b1258dedf355196fb027 + +Seed = 8098AE7A92C10F707D405F7DEA02C2EFBEF44EFA132BA8AEFE81BD45E543ECEC74F10920AE48A40B0653D63532517F2A +SS = 24F068F4BC26ACD02468160496891A43 +PK = 91184416096f43e2fa546ae252261629 +SK = 5607ed8974457467ffee7db6ab7573e8 +CT = ce8388c5b36727ed6fba8e842eb7d722 + +Seed = D5F23808871544E9C1D6EACE2028362B48E225312F77663E9F78CAFEB512B908CD9E25875D61A16EC615F4B8FF826856 +SS = 8E7FCF0F10077759642D1D3EB75F12B2 +PK = d05548aaaba224772e443d0b222542bf +SK = b575d347292ec38acd6bf19e3ad426a6 +CT = 62ac37b3411f56d280670e6cdf3f48f3 + +Seed = 822CB47BE2266E182F34546924D753A5E3369011047E6950B00BC392F8FEC19EA87C26D8021D377DF86DC76C24C5F827 +SS = CC73683BF37EA6EEB191600C0E40D676 +PK = b2c18ef8a57a25731233f67e8463bcfb +SK = bf73949ce719029868b328246ceb5751 +CT = 2a788fb93ce067816ccf86401eccf083 + +Seed = 81401DB81138D6874E91B7C11D59596E4ACE543F5A3471B6FB00999221765FEC3CA057ABE20F03B2D59003375FD71FE8 +SS = 760D2BCCD452CFD1BBE2DF4AB7E4A411 +PK = e176ec6b693970452b2d83de00a7f405 +SK = 3c268440e1cf336db1728090efd6331e +CT = 0e000beefc20e2c7887bfe1f1240ab03 + +Seed = 30B5DE5B73681EC08AAA03F6F2D2169525D25F4042A5E3695A20A52CA54927B85F8BB948FC21DF7DEFC3910B28674994 +SS = ECEBEC557EDE65CAA88F930C33C9432C +PK = c96188f7b0366483a5869747b02db5c2 +SK = dbd0b026778d4f87e1c41c8c73d99c5c +CT = c25644db2ea7118715165e669cd6871a + +Seed = E335DF8FC0D890588C3E305AC92C7160FF199E07C85760A828933750E3FED8C83B0DBE802234481ECF890A32D7A2884F +SS = B39EA23C0F7EA8CB855035E76A846399 +PK = 6c24adf630bfcd0b985fedf62ecc8c63 +SK = f47d1b212f648fea30dc6ef7de82efb3 +CT = fae07d12d71d5f203e7299d1a29aaa16 + +Seed = FBEA1BC2C379F4F8FDCB0DE260D31CDB064C9EA9B1D6DFBE91B3692ADD1D34DEC9C9FFAE7BF5E72ED2743BA3F9F2E43D +SS = C4F4D563ABB89B489C6E948DDE84C602 +PK = ac5b709a1f7a86ad3d8656c736e9ec49 +SK = 032fc6cde968db3e5883856e7a7ef643 +CT = 3d95293388489a9b2459b45069646549 + +Seed = 7E87FB886BC3C7C9FC12569F465D2ECD12532E76CC27C65644C8D3DD603B0CB2D036C5974E675058F271D5C82AD7A813 +SS = 78472AB746FAB555605A59F4213BA93C +PK = 65934706a4bdea302a76cdd389a7e474 +SK = 8e1959618124aaf74c79af15cf334dca +CT = 20ab22a868c6bcdd3150932b17a1bc05 + +[FrodoKEM-640-SHAKE] +Seed = 061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1 +SS = 2ED42CE7D5DBFB115F2E2BDCB650B3FA +PK = ac4ef8be0e87b9086abced017ebc9bfb +SK = b76534f69ba98cc1fc051d31992fc9ce +CT = f5e2b6ae2ef9ad6f43876a000780c221 + +Seed = D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556AC81ADDE6AEEB4A5A875C3BFCADFA958F +SS = B666E2057AA667943D296982B73BC0D6 +PK = 7286f26c786d04955eb0b9c1e6a6f0ae +SK = 962e582b2bb287d7ab10a7d3fbbb7634 +CT = 9d7bba5b30f309b6b8b8b2b54814c2b1 + +Seed = 64335BF29E5DE62842C941766BA129B0643B5E7121CA26CFC190EC7DC3543830557FDD5C03CF123A456D48EFEA43C868 +SS = CB68B07DD28534B5A2926332D7E6CBEF +PK = a22fd95d39fae6b8c21c5fbb13f028f9 +SK = 18830da892e22ccda6897ddb23e17124 +CT = a2fc5d4e08f2da1f31ff85b0923b4b14 + +Seed = 225D5CE2CEAC61930A07503FB59F7C2F936A3E075481DA3CA299A80F8C5DF9223A073E7B90E02EBF98CA2227EBA38C1A +SS = 4E0A573FAEF65792833F533326DA1F34 +PK = 2ea7d6f7f1e53eceadbfe38d21c6bea3 +SK = 6f2dc5f8aef4e9bfc0ad162bba7ead2a +CT = 19656ac4f7a8d2acd3d27c77da0cba1f + +Seed = EDC76E7C1523E3862552133FEA4D2AB05C69FB54A9354F0846456A2A407E071DF4650EC0E0A5666A52CD09462DBC51F9 +SS = B550C1BE6444146475CD31E41F847877 +PK = 0722b8be6fd9f1c0b2e07e315f2c7426 +SK = 49e7e077378925ef997b17abf52dd086 +CT = 15d34c18701930882ff0b3257a26a09f + +Seed = AA93649193C2C5985ACF8F9E6AC50C36AE16A2526D7C684F7A3BB4ABCD7B6FF790E82BADCE89BC7380D66251F97AAAAA +SS = 4733328FE2C13A25078AB62AB0AB8F64 +PK = 475660e89af49106abc96355f79ec214 +SK = f6d0ecaa17ec4aaa106694c7966f6ff3 +CT = 4463613bf1549275c41ab8d7ea849c1b + +Seed = 2E014DC7C2696B9F6D4AF555CBA4B931B34863FF60E2341D4FDFE472FEF2FE2C33E0813FC5CAFDE4E30277FE522A9049 +SS = AB0C67652A8490705FBFA8F821B4E528 +PK = c088ccb3d5898ecdd52c3b8f989c85d5 +SK = 4a8b6eddf5c0dd2b9a89f8e000609d62 +CT = ddc980f3c975093bdc63693a59242dfa + +Seed = AEFB28FDD34E0AB403A703B535296E3A545CA479C1D8148E2D501B3C8DD8B1034BD986F13F1A7B4671BE769359FD2AAB +SS = 37691D50A713442E0EFE5B2B2D834A61 +PK = 6a9a45b44a9853c8a6fd4aa721c2366f +SK = 64123945b30f720153f3d49851c3fa96 +CT = 25bf3a4f82f376c41410320466a00ba2 + +Seed = CBE5161E8DE02DDA7DE204AEB0FBB4CA81344BA8C30FE357A4664E5D2988A03B64184D7DC69F8D367550E5FEA0876D41 +SS = D7B31D81616AD1B69412A4D9019DA275 +PK = 9ddbc9979d6f2080d68f834a47a9d89a +SK = a874bb206727b7c27558de0c072de5cd +CT = f914f968bf270b897cf0db1dc0a4b6bf + +Seed = B4663A7A9883386A2AE4CBD93787E247BF26087E3826D1B8DBEB679E49C0BB286E114F0E9F42F61F63DEC42B4F974846 +SS = 23BFACF85D72B9A262D5A92EC2435CA5 +PK = 1acf0f389e018f9c103310582af3175f +SK = 77a31c78bebe6a329c1ab8d85393b4df +CT = 017cdfce4a7769a4d044263465f5f86c + +Seed = 980D0BA7C8F8B23D0E948A6029FF2659810EA1360064663A8994D0333C8543EE5FF5D6D5C9ACF446E61DC464F792B9D3 +SS = 3EEF707BAC00653B415A998E45911B88 +PK = b7fd042aada7aba1445227b635925dfc +SK = 1d76ec0fce7a8e87adbe0731ca8c3299 +CT = 070cde91feeb790f0a9609da491e50b4 + +Seed = 6C029462CA42ED520F10A579F52687101105E0B90C6E7BFA582A4C112B579D5AD0A0ABD38F72ABCFDCAAF5893A112BDC +SS = 420B29381DD5CFD81AB36EF603A78C15 +PK = c55f0bc844add3c6e85358f75897d368 +SK = d5d81c827eff8fdf3bb726029caa78c0 +CT = e252d5bad72d537d95fe8904e85aabcf + +Seed = DB00120937570D62331F4C3F19A10465231EFF46465CDEE336A0D46AA1E7493DF80F18617F9FFD0476CF7784A403EF4F +SS = 6E6D281AA79367A64DC4E512E9DDF38A +PK = fd9d34877cf4714aa5bb205e25588298 +SK = e32d3290c7122443845337be6bcbfab2 +CT = 84d2b7ce58f66a8050f69bcc3be8419b + +Seed = BD26C0B9A33E3B9B4C5D7EA32D5BD1FC371015BE163C86F584E49BFD5362C8D8341161CD1308115B2A03B7E5EADDD418 +SS = CF822942001C4270B6DF81D5975EBDE7 +PK = da63dedc2fce0ec8c6d4cf9be72fe153 +SK = 778dd8883788ca2116e07ba98d7bce84 +CT = 4f8625b694d9500007f53b6592104b6e + +Seed = E2819EF86853BCA1B9DEE7EE1C1619988964F9A913E635AACF0D96CA6E0300D084329DABD8F149E24176D22757404260 +SS = FBEAAD7FE459A0E2A68EEC367AE04116 +PK = 1228e3981adfec2e9f8ef82731f63667 +SK = 2439733665a100b90f3d872ed584d824 +CT = 8ce9273869112f8a2521b74fae083387 + +Seed = 669C4EF8A051CE201DA65FC4BC34D398EC1F806276FC5D987AD71D93BC12DC8F107B58BE6E8422A0795C88CB9A0E7488 +SS = F82C5804C61862FD09DC633C0FAE5B40 +PK = 5e3371ffd162e7315d6567fdf1b6a98c +SK = 164c6bf0e7f16be5ba1d993d088fa217 +CT = 8ace7046699410704d9d7d3f84ded38a + +Seed = 9DEBCCFE818F6B5204DB4EA09C03EC9A19DCF1629C1527685B8A29776BB1DAAEC45F8ABF8F0ADC9A8C8BD6E2DF6D8048 +SS = A801254302E38D90B5F50E20F0B4B1D2 +PK = 6cdbfcf244c9abb188dbcbcf00f2c5f5 +SK = db599439dfd7d16df1a4c0fdd7de3f39 +CT = c4bd9e77991b668462d14bf8af316f0b + +Seed = 8098AE7A92C10F707D405F7DEA02C2EFBEF44EFA132BA8AEFE81BD45E543ECEC74F10920AE48A40B0653D63532517F2A +SS = 2FF57A7651C9B026FE317F099EDAF160 +PK = 2b55e73d34ead9800096c3398d4dfb0b +SK = 0487d6bf893de544e98fcbf9c5ae6ff9 +CT = d5521bf387ae94ab7c2a167ba1b05185 + +Seed = D5F23808871544E9C1D6EACE2028362B48E225312F77663E9F78CAFEB512B908CD9E25875D61A16EC615F4B8FF826856 +SS = 42EFB5CDC06079F15FB870E2AC1AC274 +PK = 1b229dd322498cbf6c34159273c1b988 +SK = 99855fd0e7be0f694f0ea6b3a8bca77b +CT = 302e1cbc1e4ffe4e207dbc72d0be3113 + +Seed = 822CB47BE2266E182F34546924D753A5E3369011047E6950B00BC392F8FEC19EA87C26D8021D377DF86DC76C24C5F827 +SS = 7CEE90123B7F542B7B9E74ED50C22DB5 +PK = b1c4ef90d2498e3e12a7b23d276a3328 +SK = 0a92d2abbfe6e012f7a67e8603ba00ce +CT = 16f81eeceb20ab89e1bd52d7c160124d + +Seed = 81401DB81138D6874E91B7C11D59596E4ACE543F5A3471B6FB00999221765FEC3CA057ABE20F03B2D59003375FD71FE8 +SS = CD74B1093981273E240352733348428F +PK = 68eb43448e10ddd580e52e3f84f11bc6 +SK = 54764d1e3de8d344563a80ac9d1ed33d +CT = 3fcaabb4683435a246cc0dc4fc79a18e + +Seed = 30B5DE5B73681EC08AAA03F6F2D2169525D25F4042A5E3695A20A52CA54927B85F8BB948FC21DF7DEFC3910B28674994 +SS = 6F97389D442ACEF7431CDD5C989FAB99 +PK = 7b96a6210963bd1667f76d2da0f54ee0 +SK = 7a202311cec191a4eb7103fd47060a9d +CT = 3651609bc9652b3c7a00887c90fa4ef0 + +Seed = E335DF8FC0D890588C3E305AC92C7160FF199E07C85760A828933750E3FED8C83B0DBE802234481ECF890A32D7A2884F +SS = 7B338E860F4C7ADBD3FCDFB2DB16C362 +PK = b3f30417d2eb2ad1691c939280e11965 +SK = 43218f3a54bfc71e4d770e7c6b75e2b0 +CT = 9ccce71038887a20c8f882d379cf67dd + +Seed = FBEA1BC2C379F4F8FDCB0DE260D31CDB064C9EA9B1D6DFBE91B3692ADD1D34DEC9C9FFAE7BF5E72ED2743BA3F9F2E43D +SS = 78E8326BABDF0182BB1FB0AD39AF46DC +PK = 4b5546ee231a9ba06e6c3e4350897bdc +SK = 372a682378cbfc96eb3c5f64dedad8bd +CT = f4403af2474694d2fac27887978c5813 + +Seed = 7E87FB886BC3C7C9FC12569F465D2ECD12532E76CC27C65644C8D3DD603B0CB2D036C5974E675058F271D5C82AD7A813 +SS = 2DC963F1C61640832B1FBD37C23D44AD +PK = 9c5fda8ff8bfe06c34c61fbf7649a0bc +SK = 4e17113ad6ea792e8b6200dbc46a9ddc +CT = 4ba570977fafcae19ff352afe107cae3 + +[FrodoKEM-976-AES] +Seed = 061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1 +SS = D9388D1B0F97C5DB5F9B4A7E99427CFE90E3E10C5C569D02 +PK = dc172ba8f3da1eb147f8146285eca044 +SK = 27bce0d79a16cda4fdfaa4c7e1dc6911 +CT = 8d95c22acb4133bc0e0088eca7d9443b + +Seed = D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556AC81ADDE6AEEB4A5A875C3BFCADFA958F +SS = B21B6EA682420DF2278018C85504711467A6E2CA36438869 +PK = b3024021b08201b25a5b37359d13edbc +SK = fa796979ea8114b5680994d4de791f00 +CT = 9a82fa9641631d50ab641ccd2cfdb226 + +Seed = 64335BF29E5DE62842C941766BA129B0643B5E7121CA26CFC190EC7DC3543830557FDD5C03CF123A456D48EFEA43C868 +SS = 800F0B850F6884E0373B25F3AEE81627228126EF9DC3985A +PK = 925d21d3abd7fc19f5a8ecd5390d071c +SK = e2581f7657eeffb5487485e2b12b3291 +CT = 5e5a309d479b8216c0707128d21239e9 + +Seed = 225D5CE2CEAC61930A07503FB59F7C2F936A3E075481DA3CA299A80F8C5DF9223A073E7B90E02EBF98CA2227EBA38C1A +SS = 7462330FCF20924EE9066E8C2EAE671701477F983DAC2A86 +PK = cb3ad537e885b6aab3df6cc40ce3b99e +SK = 932fd8f63bbd5da5093f11958495cfd0 +CT = 26bec60958dcff70f3232aa6b98b02b1 + +Seed = EDC76E7C1523E3862552133FEA4D2AB05C69FB54A9354F0846456A2A407E071DF4650EC0E0A5666A52CD09462DBC51F9 +SS = 9081C935D5E801499D4F104C7C904490DF1C0F730195E949 +PK = 2ef410198244898f8870aab9cb5136aa +SK = 78ffcdc3f52e3115047bf8fa22e5a19d +CT = 79bd40c86a05ca196c8e25c58a2e36bb + +Seed = AA93649193C2C5985ACF8F9E6AC50C36AE16A2526D7C684F7A3BB4ABCD7B6FF790E82BADCE89BC7380D66251F97AAAAA +SS = 113A610B0F36F42A1898CBC100D8394D0CD1287C17633123 +PK = b6ace6c23d27c1e2c35fe48b32b68cee +SK = 6206b19c736dcc4777390dacb368e12d +CT = efcad660a7ef6ab26b5cddbe899301e3 + +Seed = 2E014DC7C2696B9F6D4AF555CBA4B931B34863FF60E2341D4FDFE472FEF2FE2C33E0813FC5CAFDE4E30277FE522A9049 +SS = DC61C2FD9A64C9DA2584DDCA98D57D4057692DE13FCD550B +PK = 97d163df2a85b2fc70a2ec28adb6d5fa +SK = 119ffe4edd8128eb498cf16abb7ec1c4 +CT = bb7eb6091c6eddd998ddbaa143a1bfce + +Seed = AEFB28FDD34E0AB403A703B535296E3A545CA479C1D8148E2D501B3C8DD8B1034BD986F13F1A7B4671BE769359FD2AAB +SS = 76C14A4F1E94587F5AEDC64528125487E696D0BECDC6AD05 +PK = d1601aeb5e1f3961e293ba57bc7e46de +SK = e8967ba8a634fc6286972af517e6bd0c +CT = 416cbf7b34e8cf5ef6954e88386c1192 + +Seed = CBE5161E8DE02DDA7DE204AEB0FBB4CA81344BA8C30FE357A4664E5D2988A03B64184D7DC69F8D367550E5FEA0876D41 +SS = 82FE447FA6F04E941532C875950926DCC83C40ACAC264F46 +PK = d5802c25ecb78346a7db7bbdcdeabc63 +SK = 1efd0eb0bdb13ba26fa93166f41f9aee +CT = c0f54e68c3ce578cd5433130f4adbcbd + +Seed = B4663A7A9883386A2AE4CBD93787E247BF26087E3826D1B8DBEB679E49C0BB286E114F0E9F42F61F63DEC42B4F974846 +SS = 584CE3A32ADEF5BF907608C338306B0CB0691CFFF7F47D87 +PK = f094b597a7ebfa1e71b28815e5a87a59 +SK = 74e9ad345c663651a4ec0597cd4bc38a +CT = fdcdacd4045eb767a51d6a540b3585df + +Seed = 980D0BA7C8F8B23D0E948A6029FF2659810EA1360064663A8994D0333C8543EE5FF5D6D5C9ACF446E61DC464F792B9D3 +SS = 307D316FF1C4C76790C6FAC2E82DDFCB3C91524E0930F13D +PK = ffdcdd504816ec88cdf137f8dbffdd8f +SK = c2bdca353f07f83ff871c4dbb13a16e9 +CT = 82ecee439195b30592e9b46d9cd9cf20 + +Seed = 6C029462CA42ED520F10A579F52687101105E0B90C6E7BFA582A4C112B579D5AD0A0ABD38F72ABCFDCAAF5893A112BDC +SS = 56027D10228F322F087C6C5DF9CA66AD9A2F524488EEEE9E +PK = 47c93fd135197d9a08c18a360b3e59d4 +SK = caf56d37d8f63a3d6410989d2d300477 +CT = 0da8665f8740f1a4bdbc1ee6b6c9c8e3 + +Seed = DB00120937570D62331F4C3F19A10465231EFF46465CDEE336A0D46AA1E7493DF80F18617F9FFD0476CF7784A403EF4F +SS = 9F1CA49BBCC42DBF5D848A6F51F4F995AE236B06E4A48A33 +PK = 0fb5b747b3376c21824c7f3db4c2d10e +SK = a8a8f9a135a9031815ce0b5377e61130 +CT = 6a6b429e3a82afcee1ce02fcdb4fb45f + +Seed = BD26C0B9A33E3B9B4C5D7EA32D5BD1FC371015BE163C86F584E49BFD5362C8D8341161CD1308115B2A03B7E5EADDD418 +SS = 4C3818BCDF5702E4A4D617ADE2A46C3DBB373DF654490E97 +PK = 6e83b00ac9c350628d171eb7bba4494a +SK = 08e849f148514784a1da590c62c6fecc +CT = 219618cded39d8c1e928d19e12c301df + +Seed = E2819EF86853BCA1B9DEE7EE1C1619988964F9A913E635AACF0D96CA6E0300D084329DABD8F149E24176D22757404260 +SS = 1515D0ED1E556C3961024D25EAC47B7036FDE813E5551BD4 +PK = 1e6a8c7a4d5fbacc46cbda1349a4b464 +SK = fcc0cc78411dcc6dcd5f0ae190675d20 +CT = 92784a77ea888e5505dbf913476a4233 + +Seed = 669C4EF8A051CE201DA65FC4BC34D398EC1F806276FC5D987AD71D93BC12DC8F107B58BE6E8422A0795C88CB9A0E7488 +SS = B1768E131D1A6445A1FFFF405E7705BC0032071939CD044A +PK = 169695d93156d41e2f5655f32f4297ee +SK = e194766a9961c0a5ec7d9907606784c7 +CT = 42d150b6942588a1710c49bd75f9e562 + +Seed = 9DEBCCFE818F6B5204DB4EA09C03EC9A19DCF1629C1527685B8A29776BB1DAAEC45F8ABF8F0ADC9A8C8BD6E2DF6D8048 +SS = 8BF315961CD6F6774BB9E4E2DD2481C0F01C12720141393D +PK = ce001ca03be73f97809f605f5e857176 +SK = 789298f1c95c7d94cee341262c9b53f1 +CT = 6a3836d447e43f027453a55b03d2a0cc + +Seed = 8098AE7A92C10F707D405F7DEA02C2EFBEF44EFA132BA8AEFE81BD45E543ECEC74F10920AE48A40B0653D63532517F2A +SS = A38C0889E212A6FAB384A887EEA59F3A1A953C7946B453CE +PK = 51c4912225de629e22bd9d0339060a36 +SK = 65f2fb7745522c1f98a2ae96e5c9ba6f +CT = 3668b1af35e42aa8248d040b9251ffb5 + +Seed = D5F23808871544E9C1D6EACE2028362B48E225312F77663E9F78CAFEB512B908CD9E25875D61A16EC615F4B8FF826856 +SS = A03EC42CE9F9631D9FF07FBA9ED319482D236FA9B07B1FC7 +PK = 67f0d4c947d6af3859168aae648c9a7f +SK = 10ec9dd56f555ab7219617826905fa00 +CT = aeece175c059a92a4aab2b890b327d67 + +Seed = 822CB47BE2266E182F34546924D753A5E3369011047E6950B00BC392F8FEC19EA87C26D8021D377DF86DC76C24C5F827 +SS = BC6FFA023EC6742D334E6B9C2B689F608050C300712F04C8 +PK = d24e740f5058ea723c33622b7b09f1c9 +SK = f0820a4f3d49cfc562784b3dac17c902 +CT = 5b905ce2e938c83be09db8e28bff00f1 + +Seed = 81401DB81138D6874E91B7C11D59596E4ACE543F5A3471B6FB00999221765FEC3CA057ABE20F03B2D59003375FD71FE8 +SS = 365F5700A9635204FB31DBE5EF77B5A4F2BB4398F912121A +PK = eb9f052c3458744bd727f7a2fd8baa27 +SK = 6a5286c7cd5d9f4bfe15d0f9520f3b78 +CT = 2b85106144cb5000124e7cab6ac611a7 + +Seed = 30B5DE5B73681EC08AAA03F6F2D2169525D25F4042A5E3695A20A52CA54927B85F8BB948FC21DF7DEFC3910B28674994 +SS = 2CFE117CCDB9F3B18D8CEE049176F4704AB481DF539D8E1E +PK = 2d850ac470cf872e574878ef8c19c5db +SK = 2ffb2d8ebb14c30942fd9bc4f39358d0 +CT = 621266f9aa7fb5bf5eafa259b30bf36d + +Seed = E335DF8FC0D890588C3E305AC92C7160FF199E07C85760A828933750E3FED8C83B0DBE802234481ECF890A32D7A2884F +SS = 8F58FCBCBD024555559B15E7E9688008A15CF975B897D116 +PK = 37bce4424bef83cb012e53be4f92ca65 +SK = 5fce3ffa45da5abba88d478841790355 +CT = 21b5f850434067da1ca4832ecad11f1f + +Seed = FBEA1BC2C379F4F8FDCB0DE260D31CDB064C9EA9B1D6DFBE91B3692ADD1D34DEC9C9FFAE7BF5E72ED2743BA3F9F2E43D +SS = 10CF33559803971CDCC3123C2DEB8BEF3BAB294E37064FF8 +PK = d2b200ccf4d5d025a4d3ca6c8e07017a +SK = 9aedb13ee9ea0e3897b730d468054117 +CT = 5faabd149305b3a6a2b4fd952971657e + +Seed = 7E87FB886BC3C7C9FC12569F465D2ECD12532E76CC27C65644C8D3DD603B0CB2D036C5974E675058F271D5C82AD7A813 +SS = EE2140E605305A4EC811D9C559B12524F9B0BC8C783FCD8A +PK = 112ca7d8e3a6711d72783fef16e10e8b +SK = d0b8bf37460cc180132647df71612f31 +CT = ebe2ccaebb1ef5e91d84c1c6b0875235 + +[FrodoKEM-976-SHAKE] +Seed = 061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1 +SS = 5B6E5A69A3D5F8E75EEA3A6E95595ED0278DA55B8B373142 +PK = 9b1f7a8d8a66043eda842896a37250af +SK = 0b238848077eae9a2c4408c7e331b407 +CT = 62a29bf0b5fc38dd8042b33c83324fc6 + +Seed = D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556AC81ADDE6AEEB4A5A875C3BFCADFA958F +SS = 42955E28B1A8B344BB274B50F579724F18D343C77254E5C1 +PK = c7ec28429e636ac53f255aaac56f443f +SK = 9263410b23a88288ca942ada371740d3 +CT = fd1f1f0254846495bee9188371bcb575 + +Seed = 64335BF29E5DE62842C941766BA129B0643B5E7121CA26CFC190EC7DC3543830557FDD5C03CF123A456D48EFEA43C868 +SS = 51C991E2A4A25B9B6CFC14EE318C2C83ACC74121764254F0 +PK = c24018da926f98dae2481cdf0a7e6ddc +SK = 63ae4c990a088800f72de82863c740d5 +CT = 80e91edb16869e1b3fa63c09abf7db23 + +Seed = 225D5CE2CEAC61930A07503FB59F7C2F936A3E075481DA3CA299A80F8C5DF9223A073E7B90E02EBF98CA2227EBA38C1A +SS = 2EF8DB6996F182C991FA87B21EF605B4355E064BF748F21D +PK = e1e528f1517ba2be4d1884d1d4e6b998 +SK = 6d2732caf3da7fd2bd3c648b5ce7ec93 +CT = 226403bf89c877e5eb49f2c1f70902f2 + +Seed = EDC76E7C1523E3862552133FEA4D2AB05C69FB54A9354F0846456A2A407E071DF4650EC0E0A5666A52CD09462DBC51F9 +SS = 93337A11A870091750504F47C5E86A9A3C950F4A948D9CFC +PK = 2a5bee40dfc563d18e6a6931bb882e01 +SK = ae082d89428932c4d80e47275b8d3fe8 +CT = 8098ad3cf2b689fd21a8aee8581fa97d + +Seed = AA93649193C2C5985ACF8F9E6AC50C36AE16A2526D7C684F7A3BB4ABCD7B6FF790E82BADCE89BC7380D66251F97AAAAA +SS = 65E85A8A4898135EA87D209C5CD8573EEB8D5899E2E94D4F +PK = 4223dce0792b0ab802f3a1df3523da32 +SK = 27e66e3fac35b89ac62ecf9577e1660a +CT = 4a300f55402233af968c81c0f773ac01 + +Seed = 2E014DC7C2696B9F6D4AF555CBA4B931B34863FF60E2341D4FDFE472FEF2FE2C33E0813FC5CAFDE4E30277FE522A9049 +SS = 4965F3F0402F975E9F11A716C932BA359D19118568904E41 +PK = d969fb8b900f9b51e295e203d2efe8f6 +SK = 07e6e9ca650cc018b9b932f235be423e +CT = 1e61ca9c0433e9a8d90edbfad5964d5a + +Seed = AEFB28FDD34E0AB403A703B535296E3A545CA479C1D8148E2D501B3C8DD8B1034BD986F13F1A7B4671BE769359FD2AAB +SS = 00B0A20E60A16AF2B86683479133847DA0B7D4D9EA9ADB00 +PK = 6b8d5ed69c24588dadfa3ea6bca22d5e +SK = 682a1971b4cff80d498075a66306252d +CT = 6c1fbe2915751c8c493b936e65297d92 + +Seed = CBE5161E8DE02DDA7DE204AEB0FBB4CA81344BA8C30FE357A4664E5D2988A03B64184D7DC69F8D367550E5FEA0876D41 +SS = CE8E76B068DE5C3737FDEC377B30191C8DF3701ECFD941C1 +PK = 912714069c28e74cb2706a33371a2446 +SK = c0ce6de84ace140a40aafc0c805c51f6 +CT = ebcc1498fc9c8be5e198aaca1446258b + +Seed = B4663A7A9883386A2AE4CBD93787E247BF26087E3826D1B8DBEB679E49C0BB286E114F0E9F42F61F63DEC42B4F974846 +SS = 7CD1B98A4D9476E71568DFEA1594B887C6319807EC0A0C27 +PK = 00ceb816a61cac0f994debe01075cdbc +SK = d8950eb6b927076fd15fbb692e704854 +CT = fe233306ea320329689edf4607397a92 + +Seed = 980D0BA7C8F8B23D0E948A6029FF2659810EA1360064663A8994D0333C8543EE5FF5D6D5C9ACF446E61DC464F792B9D3 +SS = DA50B703B4F16568714A49D86C6C54F9DF56377129DBB54D +PK = 8562eee63d69097596031d0aeb7b1448 +SK = c867ee651ad8c41cab7276cadbc0bf7b +CT = 03eee200374609ffdc41e82c491556c3 + +Seed = 6C029462CA42ED520F10A579F52687101105E0B90C6E7BFA582A4C112B579D5AD0A0ABD38F72ABCFDCAAF5893A112BDC +SS = 9C6EB6F271C88CBB4BE0B0CD6CC024F14FDE346636A29827 +PK = f89f2787e9490da9e2b75e81fd4a2cfd +SK = 5ee5d35c59d008aa4b82a21454882cfa +CT = 799d167b40a5f6b2559486805aeeca1f + +Seed = DB00120937570D62331F4C3F19A10465231EFF46465CDEE336A0D46AA1E7493DF80F18617F9FFD0476CF7784A403EF4F +SS = 3EA709B25F07DE29240A7BE78D6F2508E14C43E2D9E50638 +PK = 494cce93eaa0d91dcad8b9c4263de9b3 +SK = 8cf8dca3f1cdacfc763b6ec0bbc18c5f +CT = c9abe6b5def98edb739e71743e22f4cb + +Seed = BD26C0B9A33E3B9B4C5D7EA32D5BD1FC371015BE163C86F584E49BFD5362C8D8341161CD1308115B2A03B7E5EADDD418 +SS = EF0DD5F7F2677A56C892C8D2A751D6CC6ED798454347DB25 +PK = 7627ae92abc5906d8d9372ae80bb1aee +SK = a8bdb79b18ab723c695a9e4246811d96 +CT = 388e4ed1f6e71e4dffd9a0950e8c3b4d + +Seed = E2819EF86853BCA1B9DEE7EE1C1619988964F9A913E635AACF0D96CA6E0300D084329DABD8F149E24176D22757404260 +SS = FCE15A661C044BC3F39A190CF4A296611A262286B4AFE78E +PK = e566570a3129c120088e4d3c2e7b9d88 +SK = c30d4498bda8bb7d1152fe470e2226c4 +CT = 9321e3554850bc4fbcfd13c3a5ea7ced + +Seed = 669C4EF8A051CE201DA65FC4BC34D398EC1F806276FC5D987AD71D93BC12DC8F107B58BE6E8422A0795C88CB9A0E7488 +SS = 6FB2A1357F6C92CAD3E034169FFDCA0CEC69F5155789E3D3 +PK = d25f9a7623a7c8ba6cf06cb1013d8812 +SK = f1e2e69d28268616498da734dbf9f840 +CT = cc066109a154f5d0dedbdda0e0791c1e + +Seed = 9DEBCCFE818F6B5204DB4EA09C03EC9A19DCF1629C1527685B8A29776BB1DAAEC45F8ABF8F0ADC9A8C8BD6E2DF6D8048 +SS = 7EDABFB5E0041715569F9593B70BE0FCA8A1B31BED422221 +PK = 5e5cc14079c6ceb080f85a982a156f23 +SK = a446e53c771808e41fd3fced10ebbfb0 +CT = 73aaaa85489b8138e4ea116409fce8a1 + +Seed = 8098AE7A92C10F707D405F7DEA02C2EFBEF44EFA132BA8AEFE81BD45E543ECEC74F10920AE48A40B0653D63532517F2A +SS = F772BE6D7CD80CAC48DB97615AC7E20D3E826A4B08E1F1CE +PK = 23e6e66f33d3619eb9bde4fd578aef55 +SK = 8a79059479b08d971286bd06d25c9b1a +CT = 4abf3be385050b5872a1d91a071a6ddb + +Seed = D5F23808871544E9C1D6EACE2028362B48E225312F77663E9F78CAFEB512B908CD9E25875D61A16EC615F4B8FF826856 +SS = D5672EBD43F1DF8C7F0A2A00BDFDAAB77BC7FEC928650AD8 +PK = 5e857095a4705201054c1576965cd201 +SK = add11e92a0087383f4c08d1f61790486 +CT = 799ba2f9c67c3d843cd9704058c8e459 + +Seed = 822CB47BE2266E182F34546924D753A5E3369011047E6950B00BC392F8FEC19EA87C26D8021D377DF86DC76C24C5F827 +SS = C56EBEF08C60309A60C83F537A4E4BFB13798B84C0F4AF88 +PK = 2ab64849a7a896d159c2e3a265f12398 +SK = d3ad882f3c9070e86dbd545956e11c09 +CT = f0c93c452add3af4c974ed1b9aedaa61 + +Seed = 81401DB81138D6874E91B7C11D59596E4ACE543F5A3471B6FB00999221765FEC3CA057ABE20F03B2D59003375FD71FE8 +SS = A993B1F760D53E316129332ECC3385E6992D2D551D4966CE +PK = 473b5166363f7bd835fe233c935dc2c2 +SK = 8874a9bd3c2be0fce50b81bbf4776808 +CT = 4bbf67f35e6f6d5242755475d1515fc7 + +Seed = 30B5DE5B73681EC08AAA03F6F2D2169525D25F4042A5E3695A20A52CA54927B85F8BB948FC21DF7DEFC3910B28674994 +SS = 46916114A823EFE32E523F576B6EBD5A15C430E8F88028BF +PK = bc6772973d7d5fcf478439f0a5e98322 +SK = 492fdda0e8b162c1c3af8f383818515a +CT = cdd4e4f25fed35af3e954263cf1d3ed8 + +Seed = E335DF8FC0D890588C3E305AC92C7160FF199E07C85760A828933750E3FED8C83B0DBE802234481ECF890A32D7A2884F +SS = B39FB7BDA422FCA8F27AFB958C29150856562FB98A43A2CB +PK = 2cfe1b3be5c3e56d208efe7abf8e35f2 +SK = b98cefa0649912399ce0c4fa349cda53 +CT = 3dc4ef3accc737de287d60a7b4108278 + +Seed = FBEA1BC2C379F4F8FDCB0DE260D31CDB064C9EA9B1D6DFBE91B3692ADD1D34DEC9C9FFAE7BF5E72ED2743BA3F9F2E43D +SS = 5439C231FF1ACF601819928D3979DE94E40004E2A9B9F8E0 +PK = 95d930170b63a6a54c96aceeb25c0d0b +SK = 09c66b257ad2b24ab869fb7cb6bc75ff +CT = d54dfaebdc91978428c1ed280f12dad0 + +Seed = 7E87FB886BC3C7C9FC12569F465D2ECD12532E76CC27C65644C8D3DD603B0CB2D036C5974E675058F271D5C82AD7A813 +SS = 141DC63C78EC271B066A3B83236AC44B0E5B129B8CC89C91 +PK = 4bbe18a25af34884d6e587a12c40c6a4 +SK = bd991345fd9f93ef61cf67d0f9d4261e +CT = 63be38b154611aa21aa717e7a57b2643 + +[FrodoKEM-1344-AES] +Seed = 061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1 +SS = 376955161273FC667F3FEAE5EC98681820DBD759971BB0A2D2BEC4510F557E83 +PK = 1f214cad1e168a4d7839668c3d12ad5e +SK = ebdd074ceed3e42d9f420e55285a541b +CT = c6efcea412fd5cc9c7279e1abca7e7b5 + +Seed = D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556AC81ADDE6AEEB4A5A875C3BFCADFA958F +SS = 0CF8924412EDED85A8BCE13953517164AB02C975D38A38FEA4A13B504FF49BA1 +PK = 5cf213fb9867c25a590c94ead4aa02dc +SK = 58d7e763bb8b0a9a7777c93ca7518780 +CT = eef6c692104937e8a93c28f6caf61922 + +Seed = 64335BF29E5DE62842C941766BA129B0643B5E7121CA26CFC190EC7DC3543830557FDD5C03CF123A456D48EFEA43C868 +SS = 38A009A0CE0BB5AC7F22C2EA38B2DEE485FFC3AEC6E030249565EB2CD5E601D6 +PK = ad13f54ab3d3e65e29a779f1ea7eab3d +SK = 528fecb48df4336bc77addf8b58068e3 +CT = 65769bbfbdd6a24734879082d0ce15f7 + +Seed = 225D5CE2CEAC61930A07503FB59F7C2F936A3E075481DA3CA299A80F8C5DF9223A073E7B90E02EBF98CA2227EBA38C1A +SS = 5132B5D557642CF8CAE37452422657046FD9CB9F76CD19716FC4020B977BAB74 +PK = bfd529237dee7f6e26ca6741e5a34f0b +SK = 9e4b3901dd61c4ecd9ab4b69330dd79f +CT = a7f5b3bb54ab44bf3a3f27af12a4091d + +Seed = EDC76E7C1523E3862552133FEA4D2AB05C69FB54A9354F0846456A2A407E071DF4650EC0E0A5666A52CD09462DBC51F9 +SS = 706E6B819FAB44CF99BBF14132181D20EDA94521D8858A7AE6E5246CEA2EAC25 +PK = f5c669c5bd8840cf390ae7fe6e64938a +SK = 6eae3d4c64c08290f7f5deda27b85566 +CT = 4e0bd1d1bfb5792d6c77a9a39b057912 + +Seed = AA93649193C2C5985ACF8F9E6AC50C36AE16A2526D7C684F7A3BB4ABCD7B6FF790E82BADCE89BC7380D66251F97AAAAA +SS = 8BEEC9306C70982AA2B582E9FD96034503FD85ADC805EC3B237295AE71D70442 +PK = d87bd98041a7e6acae7aaeda5bbcde53 +SK = bf964deef67bd81ced678a20ead3fda9 +CT = e68693d0bc0b1d2a15895b545dd3c666 + +Seed = 2E014DC7C2696B9F6D4AF555CBA4B931B34863FF60E2341D4FDFE472FEF2FE2C33E0813FC5CAFDE4E30277FE522A9049 +SS = F1B772B9C31F9B7FF9CD65A51F27A0904F24D60E60A4A9BE28C585FA64FC3DCF +PK = f64e6eb2f6a95d5de6d6af950ae93304 +SK = bcd9ae713b74edcf7562824c75d7bc6d +CT = fc5ab7949d6cd1d8cb134098b98ea8ab + +Seed = AEFB28FDD34E0AB403A703B535296E3A545CA479C1D8148E2D501B3C8DD8B1034BD986F13F1A7B4671BE769359FD2AAB +SS = 6B2DCCF814078B9155A6E0A91346CEF857C85FC3CD5D46CD46E88C309EECDB99 +PK = 9c7af66f22cd28b94e2d4cb2c991dfe6 +SK = 83e7099f4319e7d44e73f875e8093747 +CT = e4f98400d4f8dd91265a316fedfd5f5b + +Seed = CBE5161E8DE02DDA7DE204AEB0FBB4CA81344BA8C30FE357A4664E5D2988A03B64184D7DC69F8D367550E5FEA0876D41 +SS = 448D33F6750E3074586890555F53A67F6423540E7167355C3388B663D31935E5 +PK = 9193f88a6b0f4e3e6d2607b597e5ff08 +SK = d35e5c47ce3a6228664bdb82dcb6a6df +CT = 3c72470c39fe62745a80e20ff9cf090a + +Seed = B4663A7A9883386A2AE4CBD93787E247BF26087E3826D1B8DBEB679E49C0BB286E114F0E9F42F61F63DEC42B4F974846 +SS = 552AA0B119B63AF474BC2D1802B4DFA85C9B73FCC9C541F76C6E0AF892A669E9 +PK = ccb08f1cdf0f63c04c24240cae68ff5a +SK = 60d89e7e8b98944e8f61623433cc6d68 +CT = a8ed39e825cf621e9d0fd03828d981fa + +Seed = 980D0BA7C8F8B23D0E948A6029FF2659810EA1360064663A8994D0333C8543EE5FF5D6D5C9ACF446E61DC464F792B9D3 +SS = CE916A65E2495CDE57BEE87C26934A4A8DE8E030801C1740C36B2AAB326B7214 +PK = b64a51f129537ca5fb017d85aad44324 +SK = 3f4e9539f1e259ee513a1f0bfa97a139 +CT = d6315fad5b3e7886cded1de91c09a6b6 + +Seed = 6C029462CA42ED520F10A579F52687101105E0B90C6E7BFA582A4C112B579D5AD0A0ABD38F72ABCFDCAAF5893A112BDC +SS = B1B07A7410BDE4AF44863BEE8B431301C6DE2A23111F1D53380873341C1DBEEF +PK = bfd4b3d668a83ad6d159eb39ec5729f7 +SK = dfd02fd449eb3559a47833a30d53bba7 +CT = e3667c901c4af2cfa2b1323ab209bdf1 + +Seed = DB00120937570D62331F4C3F19A10465231EFF46465CDEE336A0D46AA1E7493DF80F18617F9FFD0476CF7784A403EF4F +SS = 67786EFDC538AD78A21C4C25CE6E21B17EBF46BF8DB70C9EB896CBE3B76B3254 +PK = cc9c88804136fee29c5ff5985174da6d +SK = 620990090a59f515679268a118fe9722 +CT = efb3b6157271fc9a7573aaf12708982a + +Seed = BD26C0B9A33E3B9B4C5D7EA32D5BD1FC371015BE163C86F584E49BFD5362C8D8341161CD1308115B2A03B7E5EADDD418 +SS = 30E5C225451F71C62D6D76715C5712C7DD13E8E9780D80FD5325AC052000E14B +PK = d89097f65b97e0e12b888538609fe64c +SK = 10798597820aa21250364423cc817e84 +CT = 515e0a93836729f8d702489839eb532a + +Seed = E2819EF86853BCA1B9DEE7EE1C1619988964F9A913E635AACF0D96CA6E0300D084329DABD8F149E24176D22757404260 +SS = 1F85A7E3C8D59BE37953B2AE9ED8E3C35210D4705FB26E72A4AAB9A76CB413E3 +PK = 1aa1e614639904b2e27ef98a59a42585 +SK = 94b3d81d263e9b9c0a77a3a76f2fbc47 +CT = 905ca1c7fbc73453b7539db8d4914c81 + +Seed = 669C4EF8A051CE201DA65FC4BC34D398EC1F806276FC5D987AD71D93BC12DC8F107B58BE6E8422A0795C88CB9A0E7488 +SS = 9FEC12039B0874680EC7A41EE40A0954903B03A8361AE9933773B9077EFE5163 +PK = 05a7e3f93b10bb7d09bbfff858b01099 +SK = 05626ad28bdc7508093548166a4c0978 +CT = db6de7b5399fd07b2302d16f913def89 + +Seed = 9DEBCCFE818F6B5204DB4EA09C03EC9A19DCF1629C1527685B8A29776BB1DAAEC45F8ABF8F0ADC9A8C8BD6E2DF6D8048 +SS = F58B8DD866667BA0080B6723613B356FC4A8B7B77CE3960374AAFB9BE647F7B7 +PK = 271bd5abde4f1e40afaee375856a0ad4 +SK = 4b031260d130aa46b8df2a86b413ade2 +CT = d244c0f9b27dabaa9231124b74b41810 + +Seed = 8098AE7A92C10F707D405F7DEA02C2EFBEF44EFA132BA8AEFE81BD45E543ECEC74F10920AE48A40B0653D63532517F2A +SS = 2BF61C580F1A577BB1CD30EABB85939ACFB139479E5A36AD9DCDE190D7D7A821 +PK = 81112f74d3f849bed132cb2c70ce72e7 +SK = 3b0aa95ef9168e566004227bc2d883e1 +CT = 7d378c4a9ba3dbc5014834941d45b4f4 + +Seed = D5F23808871544E9C1D6EACE2028362B48E225312F77663E9F78CAFEB512B908CD9E25875D61A16EC615F4B8FF826856 +SS = C005F3B4A8EE43257083F4171F018E09559AE586C40043633E267DACD647191E +PK = 5b3683d0e8718f3f8ddd9018eaa70478 +SK = 82db00316b79e59854044b4680e2d8c8 +CT = 9e459596f5b6600b0b11d92136d75386 + +Seed = 822CB47BE2266E182F34546924D753A5E3369011047E6950B00BC392F8FEC19EA87C26D8021D377DF86DC76C24C5F827 +SS = C52908BB1C68554CEEAAB0079EEE0FF23B74000D05ACDD00754F64651703E826 +PK = 0b96ba4a770bb9c7ca15a6ec50cb2f00 +SK = d64185c62452ff91b386d129850c1861 +CT = 479f174a4ceb4b15014e2d24dfea66b6 + +Seed = 81401DB81138D6874E91B7C11D59596E4ACE543F5A3471B6FB00999221765FEC3CA057ABE20F03B2D59003375FD71FE8 +SS = 7F4936FDD7876784F35DD50A2AA5EC8497E070E1C458229991172F702754948C +PK = 3d470dccc56931fe00c17add425ba191 +SK = a684440a7cf2dbe9ec6693e893d4ab57 +CT = 32bbebdb35075498789d5331bc2176c3 + +Seed = 30B5DE5B73681EC08AAA03F6F2D2169525D25F4042A5E3695A20A52CA54927B85F8BB948FC21DF7DEFC3910B28674994 +SS = F23F5C1152C0C4B985F647213FF96AE439E4F289F98D77B68865EBD08BE599F0 +PK = 44cf55e20134c7c1cecfcb8b24c11d8d +SK = f0e5ff55a321b5ea88c1b430308689b5 +CT = ad3ac5c4da3dc90042f456dbc7b1e5c0 + +Seed = E335DF8FC0D890588C3E305AC92C7160FF199E07C85760A828933750E3FED8C83B0DBE802234481ECF890A32D7A2884F +SS = 38141DBB43320FA70A6139EBC2088930A56311956EA5F02E0EC1B3D77174C41C +PK = aa09a622092b547de4145176f56b4e70 +SK = f716a7f908f316bd2c88b1a8d5e260a6 +CT = f5f392b244c1be99acb1da4c9ecfcd53 + +Seed = FBEA1BC2C379F4F8FDCB0DE260D31CDB064C9EA9B1D6DFBE91B3692ADD1D34DEC9C9FFAE7BF5E72ED2743BA3F9F2E43D +SS = 187EEFD2F4AAC108CC0AC4C88A470CB25775028EB27FDD5FF330CDB26910C360 +PK = d207cb8b6ad60cbce60477e8c7546027 +SK = 0d34df9c8415cd19c0a3c3762dbc00d4 +CT = fa270538c86e1a707055e58c1d391478 + +Seed = 7E87FB886BC3C7C9FC12569F465D2ECD12532E76CC27C65644C8D3DD603B0CB2D036C5974E675058F271D5C82AD7A813 +SS = 5D3E888167936DEF99EDEEF3E2139F55081CCB22A0A5F1A3D5867AA9925BCC0E +PK = a3fa3c41e405ae1a338eaad0ec145e02 +SK = 631c4248d85d382fd670f8e9fdca9784 +CT = 4263bbdf3d4258a001a95806415c72e8 + +[FrodoKEM-1344-SHAKE] +Seed = 061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1 +SS = 8D20F971464DF19E0561BDD385AFD0E2EF0CE212EFD45A632F5D2C64F3D66AAC +PK = 3a3673875d692016275e7b0bf922ba96 +SK = 3f11528eb8ec1377aa36c195b7d4a2fd +CT = 32e139a39e3889da406ec72344089ffe + +Seed = D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556AC81ADDE6AEEB4A5A875C3BFCADFA958F +SS = BCFFFCDB9CF17FEC81D3F6012784E6F47F52E08040DBBBB5CF0EEAE9ED9E1CC8 +PK = 336ce4eded796ad501b9996859fb0ee2 +SK = 79e0a0c0f832d9af9c0dc736cbe813c0 +CT = 688cef9b663edce1ff650749d27cee52 + +Seed = 64335BF29E5DE62842C941766BA129B0643B5E7121CA26CFC190EC7DC3543830557FDD5C03CF123A456D48EFEA43C868 +SS = 245490A558F3A9F83B6DD0BA3B5B4A5772EE92FE5F21FEF17C1BC3439D89C37D +PK = cd0966ccbeaf1564a6bcbe87a1b9c885 +SK = c5d7d8d5357f86ffcd6fe1c4fb8c9166 +CT = b472fa77c6e4e6e901c565927deef5e8 + +Seed = 225D5CE2CEAC61930A07503FB59F7C2F936A3E075481DA3CA299A80F8C5DF9223A073E7B90E02EBF98CA2227EBA38C1A +SS = 9C4FE368FFC4044E75904573FE3C86B64F80664787A6BF497D0B334BF34A6F8A +PK = 97b287235880b805a1b02dc1289113dd +SK = 2855953aebee0429e077f8e0963a644d +CT = a2976d4362f65e947944b96bc2daa79c + +Seed = EDC76E7C1523E3862552133FEA4D2AB05C69FB54A9354F0846456A2A407E071DF4650EC0E0A5666A52CD09462DBC51F9 +SS = 7545A20AA1426198C7FDB7C7B454E702356FD8E6F7796CF6B1D3C90B14C8D4DC +PK = 29897f2fb518e7aed03bff565c4197fa +SK = 4a6b5c4a6195a9305caa4870a767b387 +CT = 05037037ed1e5c25be8b081497e15511 + +Seed = AA93649193C2C5985ACF8F9E6AC50C36AE16A2526D7C684F7A3BB4ABCD7B6FF790E82BADCE89BC7380D66251F97AAAAA +SS = 2E2CFBD57D10E681F8139A311C5AFAB1F204594843A474830E8F9E031BEB3476 +PK = 887033fd267d7706253d145e9476ba9e +SK = 099efee13ca489b27eb8f8de78fb5a86 +CT = 6d5eb2005f43fe403d1a280a3a463e70 + +Seed = 2E014DC7C2696B9F6D4AF555CBA4B931B34863FF60E2341D4FDFE472FEF2FE2C33E0813FC5CAFDE4E30277FE522A9049 +SS = BE83969F52410AD57105FDFD9D288F78FDE8080F738947254D1157E4BB7CBE50 +PK = 3df94ea9a0c557375fa351b8d36d00ab +SK = 5da91a0896c77622115f92104a49d787 +CT = 89a2ea8cd685f79b27ed634c987c80d3 + +Seed = AEFB28FDD34E0AB403A703B535296E3A545CA479C1D8148E2D501B3C8DD8B1034BD986F13F1A7B4671BE769359FD2AAB +SS = 78B02CD951AE07108155C06CAFFE8706D40042516B6F31A7874576420D09C8D8 +PK = 5ef13bdf7f1b4d0e0d46012cdf7f240a +SK = 792d1d78f9b9ea485931e7c03aa94863 +CT = 955653f6042539ecda7fe0013982b6f2 + +Seed = CBE5161E8DE02DDA7DE204AEB0FBB4CA81344BA8C30FE357A4664E5D2988A03B64184D7DC69F8D367550E5FEA0876D41 +SS = 1907CEAA7172D9790E47F4A9BA019680CA2313C9DD75B200C3C1AA14A145E2BE +PK = 8f4c88f29b49c7b25fd136efc812c1e6 +SK = 276240124a5ec23d9501ce1ae38f8ade +CT = 37a0052cfdf6d156af9fe023d4cc5cfc + +Seed = B4663A7A9883386A2AE4CBD93787E247BF26087E3826D1B8DBEB679E49C0BB286E114F0E9F42F61F63DEC42B4F974846 +SS = 21994734011C19E6083CF4551CA77F9037F6925C29F311B250D9B927E39AA513 +PK = 6a94764cb373b1584f9f8dbc3fa3e06d +SK = 63417835f39979f400013abfa2656eb9 +CT = b33cf923ff49f4f2a79d1ca65009edf0 + +Seed = 980D0BA7C8F8B23D0E948A6029FF2659810EA1360064663A8994D0333C8543EE5FF5D6D5C9ACF446E61DC464F792B9D3 +SS = E6BD12D43BD50CA1941D2FBD2355A71DA22CA663528F32B17C7C1966AEFC9461 +PK = 717ee1b192c8440a9898508ed81818f6 +SK = 913637d682451b6f0b5b5517c9850aba +CT = 19bb7ab19b96692d02b48fc6e0002484 + +Seed = 6C029462CA42ED520F10A579F52687101105E0B90C6E7BFA582A4C112B579D5AD0A0ABD38F72ABCFDCAAF5893A112BDC +SS = 001DE6901036955D1FEBD96FCF64EFC4878E5D6FDF640FF72DBB3770A1DE1414 +PK = 46e1da2f2628da67cec1a71899807a01 +SK = a1ce53edacddfa24b2fea0aa7c283dae +CT = eea018d7128241711b236be7a4a4c02e + +Seed = DB00120937570D62331F4C3F19A10465231EFF46465CDEE336A0D46AA1E7493DF80F18617F9FFD0476CF7784A403EF4F +SS = 767DE1188DDBB48C63B4FBA81DD86CA0795541FF11DC235A133C2A2A3D9F7AA4 +PK = da59faf6863188488c6e3e369c2adf17 +SK = 370f3f0b35591fc158bd054540c10b1a +CT = 95c544979538adc5c260950ea4c253fa + +Seed = BD26C0B9A33E3B9B4C5D7EA32D5BD1FC371015BE163C86F584E49BFD5362C8D8341161CD1308115B2A03B7E5EADDD418 +SS = BD6434B3A940E712E376A0BDE17CBCAE4B4D357AAB07EABE022FB4899830164B +PK = 9498837d5826b582eefd03b0d5c3a3ba +SK = f60cb3d718ec531ef69148373442fe9b +CT = 77c86ae51bb8ee4a082317fea768a3dc + +Seed = E2819EF86853BCA1B9DEE7EE1C1619988964F9A913E635AACF0D96CA6E0300D084329DABD8F149E24176D22757404260 +SS = C82ACDD89787D291E54B53D2E7197DA34C1ADD75766D3577F911C61256692B4F +PK = af9395b4a7bab3c42229ba5363873099 +SK = baf43e5367ac1b6703ac932a3951ae63 +CT = 2434a4a8162efde48eca03e51d444b44 + +Seed = 669C4EF8A051CE201DA65FC4BC34D398EC1F806276FC5D987AD71D93BC12DC8F107B58BE6E8422A0795C88CB9A0E7488 +SS = EE7A865D05FA9D534DFE6FA9DBCC8983EF3EEBF2292621DEAD244DFF175C1AC5 +PK = e4adcffcc19ee94b6a7f1a3640cfb522 +SK = 6b2f023889d8a087610340f4896b3007 +CT = 2cf435aaaa2b98a16e3dc5a397f4508a + +Seed = 9DEBCCFE818F6B5204DB4EA09C03EC9A19DCF1629C1527685B8A29776BB1DAAEC45F8ABF8F0ADC9A8C8BD6E2DF6D8048 +SS = 500E790E7FDFF0C1E601D32E809C2EB1AC83FE47855441C3212108D2D55BB767 +PK = 97a33bdbd7de2f6eff2c7580636bc099 +SK = bd82de2a81e5e0fe73122cad7af3efaf +CT = 11f7f8ea48d04c756e18948cd7d19146 + +Seed = 8098AE7A92C10F707D405F7DEA02C2EFBEF44EFA132BA8AEFE81BD45E543ECEC74F10920AE48A40B0653D63532517F2A +SS = A9F4796268BC5E7B70D89BE958DA08B4EA6AD119B61369ABC967EE1843E5F5D6 +PK = a6887bfa790f079ea8f08eb74a7b0c63 +SK = 6d69b5a13833e7185cc4d015bfc66955 +CT = ad5fc1040a15189122f19fd68bd14484 + +Seed = D5F23808871544E9C1D6EACE2028362B48E225312F77663E9F78CAFEB512B908CD9E25875D61A16EC615F4B8FF826856 +SS = BECDB3430FBF5674299F617167D3426FE2F3E2DC163835C661265CB2DF081898 +PK = dc2a64908e7543a2fe8d2d4740d2d1ae +SK = 438d1c982704021b8143bef7f679341e +CT = 9f2e2eaa3e0db3a740bd8e18951b3766 + +Seed = 822CB47BE2266E182F34546924D753A5E3369011047E6950B00BC392F8FEC19EA87C26D8021D377DF86DC76C24C5F827 +SS = 44556D8198EA98A7E5B7058358B77E80B41A981D7548FE5695411DE0329B4AE9 +PK = 5bed2218b5cd6a283a7262520ded21e8 +SK = 6f32a643ab1d8c371356dc2e2b11507e +CT = 1c61512d2ccc3521998355a4d4be2805 + +Seed = 81401DB81138D6874E91B7C11D59596E4ACE543F5A3471B6FB00999221765FEC3CA057ABE20F03B2D59003375FD71FE8 +SS = 524BC34B77C27C11F0BE4B7CDE196E6ECF815A72F4D9D0C5323F6D53AEF01B21 +PK = 324f9ce46db0f1845f3f7a8a8f03a0cb +SK = fa2244549f09813b22cdc858956fbc49 +CT = 989822ac522f5288aacf3d0d9464900d + +Seed = 30B5DE5B73681EC08AAA03F6F2D2169525D25F4042A5E3695A20A52CA54927B85F8BB948FC21DF7DEFC3910B28674994 +SS = F755284BDE3C60EC1164E04835D5E81B54310AD43462CED3100123FC5835B376 +PK = e5b8a0208f4fcf7353bca18da3bf8f0e +SK = a2f324e67bd1d2a7cc6d0d41f133bb4f +CT = c0695eae86a86f02ce5434a05ae31dcd + +Seed = E335DF8FC0D890588C3E305AC92C7160FF199E07C85760A828933750E3FED8C83B0DBE802234481ECF890A32D7A2884F +SS = E3234D555A90079C9614008B126C9F0FC62EAAD6B244BF3C49D199C90C97857B +PK = bdfdbedce1234421d975f6d012a59016 +SK = 7443d58cd7584dcb1d36063a5cf81262 +CT = e2c788970bf1aa7309e9c714b7b6c454 + +Seed = FBEA1BC2C379F4F8FDCB0DE260D31CDB064C9EA9B1D6DFBE91B3692ADD1D34DEC9C9FFAE7BF5E72ED2743BA3F9F2E43D +SS = 046A5411F12DAA35B932D4E22A4EB210604776E20093F5BF2E1E6ED39036346A +PK = 180c38c970b1e89c83b1a54a431332c4 +SK = c15dfba7c69f25729c00a15980374626 +CT = ae4706199f7fda31d01e164403ff3bd1 + +Seed = 7E87FB886BC3C7C9FC12569F465D2ECD12532E76CC27C65644C8D3DD603B0CB2D036C5974E675058F271D5C82AD7A813 +SS = C77E09656213793D4D62FA6A38D35BA3A82217E684F5EA438EEBFC4F1235515D +PK = 28787ce64d2d43d4cd3c9775daa6ede9 +SK = 57824759c61efd54803f0af0725c4fd5 +CT = 270c75e81f721118ec1d7d78047c2b97 diff --git a/src/tests/test_frodokem.cpp b/src/tests/test_frodokem.cpp new file mode 100644 index 00000000000..f4a023e029d --- /dev/null +++ b/src/tests/test_frodokem.cpp @@ -0,0 +1,176 @@ +/* + * Tests for FrodoKEM ("You SHALL Pass") + * - KAT tests using the KAT vectors from + * https://github.com/microsoft/PQCrypto-LWEKE/tree/master/KAT + * + * (C) 2023 Jack Lloyd + * (C) 2023 René Meusel and Amos Treiber, Rohde & Schwarz Cybersecurity + * + * Botan is released under the Simplified BSD License (see license.txt) + */ + +#include "test_pubkey_pqc.h" +#include "test_rng.h" +#include "tests.h" + +#include +#include + +#if defined(BOTAN_HAS_FRODOKEM) + #include "test_pubkey.h" + + #include + #include + #include + #include + #include +#endif + +namespace Botan_Tests { + +#if defined(BOTAN_HAS_FRODOKEM) + +namespace { +class Frodo_KAT_Tests_Impl { + public: + using public_key_t = Botan::FrodoKEM_PublicKey; + using private_key_t = Botan::FrodoKEM_PrivateKey; + + static constexpr const char* algo_name = "FrodoKEM"; + static constexpr const char* input_file = "pubkey/frodokem_kat.vec"; + + public: + Frodo_KAT_Tests_Impl(std::string_view algo_spec) : m_mode(algo_spec) {} + + decltype(auto) mode() const { return m_mode; } + + bool available() const { return m_mode.is_available(); } + + auto map_value(std::span value) const { + auto xof = Botan::XOF::create_or_throw("SHAKE-256"); + xof->update(value); + return xof->output>(16); + } + + auto rng_for_keygen(Botan::RandomNumberGenerator& rng) const { + Botan::FrodoKEMConstants consts(m_mode); + return Fixed_Output_RNG(rng, consts.len_sec_bytes() + consts.len_se_bytes() + consts.len_a_bytes()); + } + + auto rng_for_encapsulation(Botan::RandomNumberGenerator& rng) const { + Botan::FrodoKEMConstants consts(m_mode); + return Fixed_Output_RNG(rng, consts.len_sec_bytes() + consts.len_salt_bytes()); + } + + private: + Botan::FrodoKEMMode m_mode; +}; + +class Frodo_KAT_Tests : public Botan_Tests::PK_PQC_KEM_KAT_Test {}; + +std::vector test_frodo_roundtrips() { + auto& rng = Test::rng(); + + auto modes = std::vector{Botan::FrodoKEMMode::eFrodoKEM1344_SHAKE, + Botan::FrodoKEMMode::eFrodoKEM976_SHAKE, + Botan::FrodoKEMMode::eFrodoKEM640_SHAKE, + Botan::FrodoKEMMode::FrodoKEM1344_SHAKE, + Botan::FrodoKEMMode::FrodoKEM976_SHAKE, + Botan::FrodoKEMMode::FrodoKEM640_SHAKE, + Botan::FrodoKEMMode::eFrodoKEM1344_AES, + Botan::FrodoKEMMode::eFrodoKEM976_AES, + Botan::FrodoKEMMode::eFrodoKEM640_AES, + Botan::FrodoKEMMode::FrodoKEM1344_AES, + Botan::FrodoKEMMode::FrodoKEM976_AES, + Botan::FrodoKEMMode::FrodoKEM640_AES}; + + auto get_decryption_error_value = [](Botan::FrodoKEMConstants& consts, + std::span encaps_value, + const Botan::FrodoKEM_PrivateKey& sk) { + // Extracts the `S` value from the encoded private key + auto& shake = consts.SHAKE_XOF(); + const auto sk_bytes = sk.raw_private_key_bits(); + auto sk_s = std::span(sk_bytes.data(), consts.len_sec_bytes()); + shake.update(encaps_value); + shake.update(sk_s); + return shake.output(consts.len_sec_bytes()); + }; + + std::vector results; + for(auto mode : modes) { + Botan::FrodoKEMMode m(mode); + if(!m.is_available()) { + continue; + } + Botan::FrodoKEMConstants consts(mode); + Test::Result& result = results.emplace_back("FrodoKEM roundtrip: " + m.to_string()); + + Botan::FrodoKEM_PrivateKey sk1(rng, mode); + Botan::FrodoKEM_PublicKey pk1(sk1.public_key_bits(), mode); + + // Happy case + Botan::PK_KEM_Encryptor enc1(pk1, "Raw"); + const auto enc_res = enc1.encrypt(rng, 0 /* no KDF */); + + result.test_eq("length of shared secret", enc_res.shared_key().size(), enc1.shared_key_length(0)); + result.test_eq("length of ciphertext", enc_res.encapsulated_shared_key().size(), enc1.encapsulated_key_length()); + + Botan::PK_KEM_Decryptor dec1(sk1, rng, "Raw"); + auto ss = dec1.decrypt(enc_res.encapsulated_shared_key(), 0 /* no KDF */); + + result.test_eq("shared secrets match", ss, enc_res.shared_key()); + result.test_eq("length of shared secret (decaps)", ss.size(), dec1.shared_key_length(0)); + + // Decryption failures ("All right then, keep your secrets.") + Botan::FrodoKEM_PrivateKey sk2(rng, mode); + + // Decryption failure: mismatching private key + Botan::PK_KEM_Decryptor dec2(sk2, rng, "Raw"); + auto ss_mismatch = dec2.decrypt(enc_res.encapsulated_shared_key(), 0 /* no KDF */); + result.test_eq("decryption failure sk", + ss_mismatch, + get_decryption_error_value(consts, enc_res.encapsulated_shared_key(), sk2)); + + // Decryption failure: bitflip in encapsulated shared value + const auto mutated_encaps_value = Test::mutate_vec(enc_res.encapsulated_shared_key()); + ss_mismatch = dec2.decrypt(mutated_encaps_value, 0 /* no KDF */); + result.test_eq( + "decryption failure bitflip", ss_mismatch, get_decryption_error_value(consts, mutated_encaps_value, sk2)); + + // Decryption failure: malformed encapsulation value + result.test_throws( + "malformed encapsulation value", "FrodoKEM ciphertext does not have the correct byte count", [&] { + auto short_encaps_value = enc_res.encapsulated_shared_key(); + short_encaps_value.pop_back(); + dec1.decrypt(short_encaps_value, 0); + }); + } + + return results; +} + +class Frodo_Keygen_Tests final : public PK_Key_Generation_Test { + public: + std::vector keygen_params() const override { + return { + #if defined(BOTAN_HAS_FRODOKEM_SHAKE) + "FrodoKEM-640-SHAKE", "FrodoKEM-976-SHAKE", "eFrodoKEM-640-SHAKE", "eFrodoKEM-976-SHAKE", + #endif + #if defined(BOTAN_HAS_FRODOKEM_AES) + "FrodoKEM-640-AES", "FrodoKEM-976-AES", "eFrodoKEM-640-AES", "eFrodoKEM-976-AES", + #endif + }; + } + + std::string algo_name() const override { return "FrodoKEM"; } +}; + +} // namespace + +BOTAN_REGISTER_TEST("frodokem", "frodo_kat_tests", Frodo_KAT_Tests); +BOTAN_REGISTER_TEST_FN("frodokem", "frodo_roundtrips", test_frodo_roundtrips); +BOTAN_REGISTER_TEST("frodokem", "frodo_keygen", Frodo_Keygen_Tests); + +#endif + +} // namespace Botan_Tests diff --git a/src/tests/unit_x509.cpp b/src/tests/unit_x509.cpp index 077e7fb1697..7b96c3802e0 100644 --- a/src/tests/unit_x509.cpp +++ b/src/tests/unit_x509.cpp @@ -1174,8 +1174,8 @@ Test::Result test_valid_constraints(const Botan::Private_Key& key, const std::st result.test_eq("usage acceptable", key_agreement_decipher_only.compatible_with(key), true); result.test_eq("crl sign not permitted", crl_sign.compatible_with(key), false); result.test_eq("sign", sign_everything.compatible_with(key), false); - } else if(pk_algo == "Kyber") { - // Kyber can encrypt and agree + } else if(pk_algo == "Kyber" || pk_algo == "FrodoKEM") { + // KEMs can encrypt and agree result.test_eq("all constraints not permitted", all.compatible_with(key), false); result.test_eq("cert sign not permitted", ca.compatible_with(key), false); result.test_eq("signature not permitted", sign_data.compatible_with(key), false); @@ -1596,7 +1596,7 @@ class X509_Cert_Unit_Tests final : public Test { /* These are algos which cannot sign but can be included in certs */ - const std::vector enc_algos = {"DH", "ECDH", "ElGamal", "Kyber"}; + const std::vector enc_algos = {"DH", "ECDH", "ElGamal", "Kyber", "FrodoKEM"}; for(const std::string& algo : enc_algos) { auto key = make_a_private_key(algo); From 57f46d935560e799af8ce5573d66ad7e679d7b3e Mon Sep 17 00:00:00 2001 From: Amos Treiber Date: Mon, 9 Oct 2023 14:06:01 +0200 Subject: [PATCH 4/5] Support eFrodoKEM in TLS 1.3 (also as hybrid PQ/T) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: René Meusel --- src/lib/tls/tls13_pqc/hybrid_public_key.cpp | 36 ++++++++++ src/lib/tls/tls_algos.cpp | 76 ++++++++++++++++++++- src/lib/tls/tls_algos.h | 46 +++++++++++-- src/lib/tls/tls_callbacks.cpp | 16 +++++ src/scripts/test_cli.py | 14 ++++ 5 files changed, 183 insertions(+), 5 deletions(-) diff --git a/src/lib/tls/tls13_pqc/hybrid_public_key.cpp b/src/lib/tls/tls13_pqc/hybrid_public_key.cpp index e9e46b1c3bf..dc503c0b25a 100644 --- a/src/lib/tls/tls13_pqc/hybrid_public_key.cpp +++ b/src/lib/tls/tls13_pqc/hybrid_public_key.cpp @@ -30,15 +30,33 @@ std::vector> algorithm_specs_for_group(Group return {{"Curve25519", "Curve25519"}, {"Kyber", "Kyber-512-r3"}}; case Group_Params::HYBRID_X25519_KYBER_768_R3_OQS: return {{"Curve25519", "Curve25519"}, {"Kyber", "Kyber-768-r3"}}; + case Group_Params::HYBRID_X25519_eFRODOKEM_640_SHAKE_OQS: + return {{"Curve25519", "Curve25519"}, {"FrodoKEM", "eFrodoKEM-640-SHAKE"}}; + case Group_Params::HYBRID_X25519_eFRODOKEM_640_AES_OQS: + return {{"Curve25519", "Curve25519"}, {"FrodoKEM", "eFrodoKEM-640-AES"}}; case Group_Params::HYBRID_SECP256R1_KYBER_512_R3_OQS: return {{"ECDH", "secp256r1"}, {"Kyber", "Kyber-512-r3"}}; case Group_Params::HYBRID_SECP256R1_KYBER_768_R3_OQS: return {{"ECDH", "secp256r1"}, {"Kyber", "Kyber-768-r3"}}; + case Group_Params::HYBRID_SECP256R1_eFRODOKEM_640_SHAKE_OQS: + return {{"ECDH", "secp256r1"}, {"FrodoKEM", "eFrodoKEM-640-SHAKE"}}; + case Group_Params::HYBRID_SECP256R1_eFRODOKEM_640_AES_OQS: + return {{"ECDH", "secp256r1"}, {"FrodoKEM", "eFrodoKEM-640-AES"}}; + case Group_Params::HYBRID_SECP384R1_KYBER_768_R3_OQS: return {{"ECDH", "secp384r1"}, {"Kyber", "Kyber-768-r3"}}; + case Group_Params::HYBRID_SECP384R1_eFRODOKEM_976_SHAKE_OQS: + return {{"ECDH", "secp384r1"}, {"FrodoKEM", "eFrodoKEM-976-SHAKE"}}; + case Group_Params::HYBRID_SECP384R1_eFRODOKEM_976_AES_OQS: + return {{"ECDH", "secp384r1"}, {"FrodoKEM", "eFrodoKEM-976-AES"}}; + case Group_Params::HYBRID_SECP521R1_KYBER_1024_R3_OQS: return {{"ECDH", "secp521r1"}, {"Kyber", "Kyber-1024-r3"}}; + case Group_Params::HYBRID_SECP521R1_eFRODOKEM_1344_SHAKE_OQS: + return {{"ECDH", "secp521r1"}, {"FrodoKEM", "eFrodoKEM-1344-SHAKE"}}; + case Group_Params::HYBRID_SECP521R1_eFRODOKEM_1344_AES_OQS: + return {{"ECDH", "secp521r1"}, {"FrodoKEM", "eFrodoKEM-1344-AES"}}; default: return {}; @@ -79,13 +97,31 @@ std::vector public_value_lengths_for_group(Group_Params group) { return {32, 800}; case Group_Params::HYBRID_X25519_KYBER_768_R3_OQS: return {32, 1184}; + case Group_Params::HYBRID_X25519_eFRODOKEM_640_SHAKE_OQS: + return {32, 9616}; + case Group_Params::HYBRID_X25519_eFRODOKEM_640_AES_OQS: + return {32, 9616}; case Group_Params::HYBRID_SECP256R1_KYBER_512_R3_OQS: return {32, 800}; case Group_Params::HYBRID_SECP256R1_KYBER_768_R3_OQS: return {32, 1184}; + case Group_Params::HYBRID_SECP256R1_eFRODOKEM_640_SHAKE_OQS: + return {32, 9616}; + case Group_Params::HYBRID_SECP256R1_eFRODOKEM_640_AES_OQS: + return {32, 9616}; + case Group_Params::HYBRID_SECP384R1_KYBER_768_R3_OQS: return {48, 1184}; + case Group_Params::HYBRID_SECP384R1_eFRODOKEM_976_SHAKE_OQS: + return {48, 15632}; + case Group_Params::HYBRID_SECP384R1_eFRODOKEM_976_AES_OQS: + return {48, 15632}; + + case Group_Params::HYBRID_SECP521R1_eFRODOKEM_1344_SHAKE_OQS: + return {66, 21520}; + case Group_Params::HYBRID_SECP521R1_eFRODOKEM_1344_AES_OQS: + return {66, 21520}; case Group_Params::HYBRID_SECP521R1_KYBER_1024_R3_OQS: return {66, 1568}; diff --git a/src/lib/tls/tls_algos.cpp b/src/lib/tls/tls_algos.cpp index 41958402c0a..8623fe35777 100644 --- a/src/lib/tls/tls_algos.cpp +++ b/src/lib/tls/tls_algos.cpp @@ -183,16 +183,40 @@ std::optional Group_Params::from_string(std::string_view group_nam return Group_Params::KYBER_1024_R3_OQS; } + if(group_name == "eFrodoKEM-640-SHAKE") { + return Group_Params::eFRODOKEM_640_SHAKE_OQS; + } + if(group_name == "eFrodoKEM-976-SHAKE") { + return Group_Params::eFRODOKEM_976_SHAKE_OQS; + } + if(group_name == "eFrodoKEM-1344-SHAKE") { + return Group_Params::eFRODOKEM_1344_SHAKE_OQS; + } + if(group_name == "eFrodoKEM-640-AES") { + return Group_Params::eFRODOKEM_640_AES_OQS; + } + if(group_name == "eFrodoKEM-976-AES") { + return Group_Params::eFRODOKEM_976_AES_OQS; + } + if(group_name == "eFrodoKEM-1344-AES") { + return Group_Params::eFRODOKEM_1344_AES_OQS; + } + if(group_name == "x25519/Kyber-512-r3/cloudflare") { return Group_Params::HYBRID_X25519_KYBER_512_R3_CLOUDFLARE; } - if(group_name == "x25519/Kyber-512-r3") { return Group_Params::HYBRID_X25519_KYBER_512_R3_OQS; } if(group_name == "x25519/Kyber-768-r3") { return Group_Params::HYBRID_X25519_KYBER_768_R3_OQS; } + if(group_name == "x25519/eFrodoKEM-640-SHAKE") { + return Group_Params::HYBRID_X25519_eFRODOKEM_640_SHAKE_OQS; + } + if(group_name == "x25519/eFrodoKEM-640-AES") { + return Group_Params::HYBRID_X25519_eFRODOKEM_640_AES_OQS; + } if(group_name == "secp256r1/Kyber-512-r3") { return Group_Params::HYBRID_SECP256R1_KYBER_512_R3_OQS; @@ -200,12 +224,32 @@ std::optional Group_Params::from_string(std::string_view group_nam if(group_name == "secp256r1/Kyber-768-r3") { return Group_Params::HYBRID_SECP256R1_KYBER_768_R3_OQS; } + if(group_name == "secp256r1/eFrodoKEM-640-SHAKE") { + return Group_Params::HYBRID_SECP256R1_eFRODOKEM_640_SHAKE_OQS; + } + if(group_name == "secp256r1/eFrodoKEM-640-AES") { + return Group_Params::HYBRID_SECP256R1_eFRODOKEM_640_AES_OQS; + } + if(group_name == "secp384r1/Kyber-768-r3") { return Group_Params::HYBRID_SECP384R1_KYBER_768_R3_OQS; } + if(group_name == "secp384r1/eFrodoKEM-976-SHAKE") { + return Group_Params::HYBRID_SECP384R1_eFRODOKEM_976_SHAKE_OQS; + } + if(group_name == "secp384r1/eFrodoKEM-976-AES") { + return Group_Params::HYBRID_SECP384R1_eFRODOKEM_976_AES_OQS; + } + if(group_name == "secp521r1/Kyber-1024-r3") { return Group_Params::HYBRID_SECP521R1_KYBER_1024_R3_OQS; } + if(group_name == "secp521r1/eFrodoKEM-1344-SHAKE") { + return Group_Params::HYBRID_SECP521R1_eFRODOKEM_1344_SHAKE_OQS; + } + if(group_name == "secp521r1/eFrodoKEM-1344-AES") { + return Group_Params::HYBRID_SECP521R1_eFRODOKEM_1344_AES_OQS; + } return std::nullopt; } @@ -245,6 +289,36 @@ std::optional Group_Params::to_string() const { case Group_Params::KYBER_1024_R3_OQS: return "Kyber-1024-r3"; + case Group_Params::eFRODOKEM_640_SHAKE_OQS: + return "eFrodoKEM-640-SHAKE"; + case Group_Params::eFRODOKEM_976_SHAKE_OQS: + return "eFrodoKEM-976-SHAKE"; + case Group_Params::eFRODOKEM_1344_SHAKE_OQS: + return "eFrodoKEM-1344-SHAKE"; + case Group_Params::eFRODOKEM_640_AES_OQS: + return "eFrodoKEM-640-AES"; + case Group_Params::eFRODOKEM_976_AES_OQS: + return "eFrodoKEM-976-AES"; + case Group_Params::eFRODOKEM_1344_AES_OQS: + return "eFrodoKEM-1344-AES"; + + case Group_Params::HYBRID_X25519_eFRODOKEM_640_SHAKE_OQS: + return "x25519/eFrodoKEM-640-SHAKE"; + case Group_Params::HYBRID_X25519_eFRODOKEM_640_AES_OQS: + return "x25519/eFrodoKEM-640-AES"; + case Group_Params::HYBRID_SECP256R1_eFRODOKEM_640_SHAKE_OQS: + return "secp256r1/eFrodoKEM-640-SHAKE"; + case Group_Params::HYBRID_SECP256R1_eFRODOKEM_640_AES_OQS: + return "secp256r1/eFrodoKEM-640-AES"; + case Group_Params::HYBRID_SECP384R1_eFRODOKEM_976_SHAKE_OQS: + return "secp384r1/eFrodoKEM-976-SHAKE"; + case Group_Params::HYBRID_SECP384R1_eFRODOKEM_976_AES_OQS: + return "secp384r1/eFrodoKEM-976-AES"; + case Group_Params::HYBRID_SECP521R1_eFRODOKEM_1344_SHAKE_OQS: + return "secp521r1/eFrodoKEM-1344-SHAKE"; + case Group_Params::HYBRID_SECP521R1_eFRODOKEM_1344_AES_OQS: + return "secp521r1/eFrodoKEM-1344-AES"; + case Group_Params::HYBRID_X25519_KYBER_512_R3_CLOUDFLARE: return "x25519/Kyber-512-r3/cloudflare"; diff --git a/src/lib/tls/tls_algos.h b/src/lib/tls/tls_algos.h index a13bf9bca08..3d52f420f66 100644 --- a/src/lib/tls/tls_algos.h +++ b/src/lib/tls/tls_algos.h @@ -103,6 +103,13 @@ enum class Group_Params_Code : uint16_t { KYBER_768_R3_OQS = 0x023C, KYBER_1024_R3_OQS = 0x023D, + eFRODOKEM_640_SHAKE_OQS = 0x0201, + eFRODOKEM_976_SHAKE_OQS = 0x0203, + eFRODOKEM_1344_SHAKE_OQS = 0x0205, + eFRODOKEM_640_AES_OQS = 0x0200, + eFRODOKEM_976_AES_OQS = 0x0202, + eFRODOKEM_1344_AES_OQS = 0x0204, + // Cloudflare code points for hybrid PQC // https://blog.cloudflare.com/post-quantum-for-all/ HYBRID_X25519_KYBER_512_R3_CLOUDFLARE = 0xFE30, @@ -117,8 +124,22 @@ enum class Group_Params_Code : uint16_t { HYBRID_SECP256R1_KYBER_512_R3_OQS = 0x2F3A, HYBRID_SECP256R1_KYBER_768_R3_OQS = 0x639A, + HYBRID_SECP384R1_KYBER_768_R3_OQS = 0x2F3C, + HYBRID_SECP521R1_KYBER_1024_R3_OQS = 0x2F3D, + + HYBRID_X25519_eFRODOKEM_640_SHAKE_OQS = 0x2F81, + HYBRID_X25519_eFRODOKEM_640_AES_OQS = 0x2F80, + + HYBRID_SECP256R1_eFRODOKEM_640_SHAKE_OQS = 0x2F01, + HYBRID_SECP256R1_eFRODOKEM_640_AES_OQS = 0x2F00, + + HYBRID_SECP384R1_eFRODOKEM_976_SHAKE_OQS = 0x2F03, + HYBRID_SECP384R1_eFRODOKEM_976_AES_OQS = 0x2F02, + + HYBRID_SECP521R1_eFRODOKEM_1344_SHAKE_OQS = 0x2F05, + HYBRID_SECP521R1_eFRODOKEM_1344_AES_OQS = 0x2F04, }; class BOTAN_PUBLIC_API(3, 2) Group_Params final { @@ -170,21 +191,38 @@ class BOTAN_PUBLIC_API(3, 2) Group_Params final { m_code == Group_Params_Code::KYBER_1024_R3_OQS; } + constexpr bool is_pure_frodokem() const { + return m_code == Group_Params_Code::eFRODOKEM_640_SHAKE_OQS || + m_code == Group_Params_Code::eFRODOKEM_976_SHAKE_OQS || + m_code == Group_Params_Code::eFRODOKEM_1344_SHAKE_OQS || + m_code == Group_Params_Code::eFRODOKEM_640_AES_OQS || + m_code == Group_Params_Code::eFRODOKEM_976_AES_OQS || + m_code == Group_Params_Code::eFRODOKEM_1344_AES_OQS; + } + constexpr bool is_pure_ecc_group() const { return is_x25519() || is_ecdh_named_curve(); } - constexpr bool is_post_quantum() const { return is_pure_kyber() || is_pqc_hybrid(); } + constexpr bool is_post_quantum() const { return is_pure_kyber() || is_pure_frodokem() || is_pqc_hybrid(); } constexpr bool is_pqc_hybrid() const { - return m_code == Group_Params::HYBRID_X25519_KYBER_512_R3_CLOUDFLARE || + return m_code == Group_Params_Code::HYBRID_X25519_KYBER_512_R3_CLOUDFLARE || m_code == Group_Params_Code::HYBRID_X25519_KYBER_512_R3_OQS || m_code == Group_Params_Code::HYBRID_X25519_KYBER_768_R3_OQS || + m_code == Group_Params_Code::HYBRID_X25519_eFRODOKEM_640_SHAKE_OQS || + m_code == Group_Params_Code::HYBRID_X25519_eFRODOKEM_640_AES_OQS || m_code == Group_Params_Code::HYBRID_SECP256R1_KYBER_512_R3_OQS || m_code == Group_Params_Code::HYBRID_SECP256R1_KYBER_768_R3_OQS || + m_code == Group_Params_Code::HYBRID_SECP256R1_eFRODOKEM_640_SHAKE_OQS || + m_code == Group_Params_Code::HYBRID_SECP256R1_eFRODOKEM_640_AES_OQS || m_code == Group_Params_Code::HYBRID_SECP384R1_KYBER_768_R3_OQS || - m_code == Group_Params_Code::HYBRID_SECP521R1_KYBER_1024_R3_OQS; + m_code == Group_Params_Code::HYBRID_SECP384R1_eFRODOKEM_976_SHAKE_OQS || + m_code == Group_Params_Code::HYBRID_SECP384R1_eFRODOKEM_976_AES_OQS || + m_code == Group_Params_Code::HYBRID_SECP521R1_KYBER_1024_R3_OQS || + m_code == Group_Params_Code::HYBRID_SECP521R1_eFRODOKEM_1344_SHAKE_OQS || + m_code == Group_Params_Code::HYBRID_SECP521R1_eFRODOKEM_1344_AES_OQS; } - constexpr bool is_kem() const { return is_pure_kyber() || is_pqc_hybrid(); } + constexpr bool is_kem() const { return is_pure_kyber() || is_pure_frodokem() || is_pqc_hybrid(); } // Returns std::nullopt if the param has no known name std::optional to_string() const; diff --git a/src/lib/tls/tls_callbacks.cpp b/src/lib/tls/tls_callbacks.cpp index b6c4769e82d..0f89e70894d 100644 --- a/src/lib/tls/tls_callbacks.cpp +++ b/src/lib/tls/tls_callbacks.cpp @@ -30,6 +30,10 @@ #include #endif +#if defined(BOTAN_HAS_FRODOKEM) + #include +#endif + #if defined(BOTAN_HAS_TLS_13_PQC) #include #endif @@ -157,6 +161,12 @@ std::unique_ptr TLS::Callbacks::tls_kem_generate_key(TLS::Group_Par } #endif +#if defined(BOTAN_HAS_FRODOKEM) + if(group.is_pure_frodokem()) { + return std::make_unique(rng, FrodoKEMMode(group.to_string().value())); + } +#endif + #if defined(BOTAN_HAS_TLS_13_PQC) if(group.is_pqc_hybrid()) { return Hybrid_KEM_PrivateKey::generate_from_group(group, rng); @@ -185,6 +195,12 @@ KEM_Encapsulation TLS::Callbacks::tls_kem_encapsulate(TLS::Group_Params group, } #endif +#if defined(BOTAN_HAS_FRODOKEM) + if(group.is_pure_frodokem()) { + return std::make_unique(encoded_public_key, FrodoKEMMode(group.to_string().value())); + } +#endif + throw TLS_Exception(Alert::IllegalParameter, "KEM is not supported"); }(); diff --git a/src/scripts/test_cli.py b/src/scripts/test_cli.py index 62e0641deeb..0f807ccfebe 100755 --- a/src/scripts/test_cli.py +++ b/src/scripts/test_cli.py @@ -1214,6 +1214,20 @@ def get_oqs_ports(): TestConfig("test.openquantumsafe.org", "Kyber-512-r3", port=oqsp['kyber512'], ca=oqs_test_ca), TestConfig("test.openquantumsafe.org", "Kyber-768-r3", port=oqsp['kyber768'], ca=oqs_test_ca), TestConfig("test.openquantumsafe.org", "Kyber-1024-r3", port=oqsp['kyber1024'], ca=oqs_test_ca), + TestConfig("test.openquantumsafe.org", "eFrodoKEM-640-SHAKE", port=oqsp['frodo640shake'], ca=oqs_test_ca), + TestConfig("test.openquantumsafe.org", "eFrodoKEM-976-SHAKE", port=oqsp['frodo976shake'], ca=oqs_test_ca), + TestConfig("test.openquantumsafe.org", "eFrodoKEM-1344-SHAKE", port=oqsp['frodo1344shake'], ca=oqs_test_ca), + TestConfig("test.openquantumsafe.org", "eFrodoKEM-640-AES", port=oqsp['frodo640aes'], ca=oqs_test_ca), + TestConfig("test.openquantumsafe.org", "eFrodoKEM-976-AES", port=oqsp['frodo976aes'], ca=oqs_test_ca), + TestConfig("test.openquantumsafe.org", "eFrodoKEM-1344-AES", port=oqsp['frodo1344aes'], ca=oqs_test_ca), + TestConfig("test.openquantumsafe.org", "x25519/eFrodoKEM-640-SHAKE", port=oqsp['x25519_frodo640shake'], ca=oqs_test_ca), + TestConfig("test.openquantumsafe.org", "x25519/eFrodoKEM-640-AES", port=oqsp['x25519_frodo640aes'], ca=oqs_test_ca), + TestConfig("test.openquantumsafe.org", "secp256r1/eFrodoKEM-640-SHAKE", port=oqsp['p256_frodo640shake'], ca=oqs_test_ca), + TestConfig("test.openquantumsafe.org", "secp256r1/eFrodoKEM-640-AES", port=oqsp['p256_frodo640aes'], ca=oqs_test_ca), + TestConfig("test.openquantumsafe.org", "secp384r1/eFrodoKEM-976-SHAKE", port=oqsp['p384_frodo976shake'], ca=oqs_test_ca), + TestConfig("test.openquantumsafe.org", "secp384r1/eFrodoKEM-976-AES", port=oqsp['p384_frodo976aes'], ca=oqs_test_ca), + TestConfig("test.openquantumsafe.org", "secp521r1/eFrodoKEM-1344-SHAKE", port=oqsp['p521_frodo1344shake'], ca=oqs_test_ca), + TestConfig("test.openquantumsafe.org", "secp521r1/eFrodoKEM-1344-AES", port=oqsp['p521_frodo1344aes'], ca=oqs_test_ca), ] else: logging.info("failed to pull OQS port assignment, skipping OQS...") From c256e53a3e6c1342edc781a99e42639c8b4dfc8a Mon Sep 17 00:00:00 2001 From: Rene Meusel Date: Tue, 2 Jan 2024 10:55:01 +0100 Subject: [PATCH 5/5] address review comments Co-Authored-By: Fabian Albert --- .../frodokem/frodokem_common/frodo_matrix.cpp | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/lib/pubkey/frodokem/frodokem_common/frodo_matrix.cpp b/src/lib/pubkey/frodokem/frodokem_common/frodo_matrix.cpp index fae19ea5e24..f15490654c8 100644 --- a/src/lib/pubkey/frodokem/frodokem_common/frodo_matrix.cpp +++ b/src/lib/pubkey/frodokem/frodokem_common/frodo_matrix.cpp @@ -79,9 +79,9 @@ FrodoMatrix FrodoMatrix::sample(const FrodoKEMConstants& constants, load_le(elements.data(), r.data(), n); for(size_t i = 0; i < n; ++i) { - uint32_t sample = 0; // Avoid integral promotion - uint16_t prnd = elements.at(i) >> 1; // Drop the least significant bit - uint16_t sign = elements.at(i) & 0x1; // Pick the least significant bit + uint32_t sample = 0; // Avoid integral promotion + const uint16_t prnd = elements.at(i) >> 1; // Drop the least significant bit + const uint16_t sign = elements.at(i) & 0x1; // Pick the least significant bit // No need to compare with the last value. for(size_t j = 0; j < constants.cdf_table_len() - 1; ++j) { @@ -323,10 +323,13 @@ FrodoMatrix FrodoMatrix::mul_bs(const FrodoKEMConstants& constants, const FrodoM auto& current = elements.at(i * constants.n_bar() + j); current = 0; for(size_t k = 0; k < constants.n(); ++k) { - current += static_cast( - static_cast(b.elements_at(i * constants.n() + k)) * - s.elements_at(j * constants.n() + - k)); //Since the input is s^T, we multiply the i-th row of b with the j-th row of s^t + // Explicitly store the values in 32-bit variables to avoid integral promotion + const uint32_t b_ink = b.elements_at(i * constants.n() + k); + + // Since the input is s^T, we multiply the i-th row of b with the j-th row of s^t + const uint32_t s_ink = s.elements_at(j * constants.n() + k); + + current += static_cast(b_ink * s_ink); } } } @@ -392,20 +395,18 @@ FrodoSerializedMatrix FrodoMatrix::serialize() const { FrodoPlaintext FrodoMatrix::decode(const FrodoKEMConstants& constants) const { const size_t nwords = (constants.n_bar() * constants.n_bar()) / 8; - uint16_t temp; - uint16_t maskex = static_cast(1 << constants.b()) - 1; - uint16_t maskq = static_cast(1 << constants.d()) - 1; - - uint64_t templong; + const uint16_t maskex = static_cast(1 << constants.b()) - 1; + const uint16_t maskq = static_cast(1 << constants.d()) - 1; FrodoPlaintext out(nwords * constants.b()); size_t index = 0; for(size_t i = 0; i < nwords; i++) { - templong = 0; + uint64_t templong = 0; for(size_t j = 0; j < 8; j++) { - temp = static_cast(((m_elements.at(index) & maskq) + (1 << (constants.d() - constants.b() - 1))) >> - (constants.d() - constants.b())); + const auto temp = + static_cast(((m_elements.at(index) & maskq) + (1 << (constants.d() - constants.b() - 1))) >> + (constants.d() - constants.b())); templong |= static_cast(temp & maskex) << (constants.b() * j); index++; } @@ -448,7 +449,7 @@ FrodoMatrix FrodoMatrix::unpack(const FrodoKEMConstants& constants, uint8_t b = 0; // bits in out[i] already filled in while(b < lsb) { const uint8_t nbits = std::min(static_cast(lsb - b), bits); - uint16_t mask = static_cast(1 << nbits) - 1; + const uint16_t mask = static_cast(1 << nbits) - 1; uint8_t t = (w >> (bits - nbits)) & mask; // the bits to copy from w to out elements.at(i) = elements.at(i) + static_cast(t << (lsb - b - nbits));