Skip to content

Commit

Permalink
extract FrodoKEM AES mode into a submodule
Browse files Browse the repository at this point in the history
  • Loading branch information
reneme committed Nov 3, 2023
1 parent cdcaad5 commit 0694f1d
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 37 deletions.
2 changes: 1 addition & 1 deletion src/lib/pubkey/frodokem/frodo_constants.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
namespace Botan {

FrodoKEMConstants::FrodoKEMConstants(FrodoKEMMode mode) : m_mode(mode), m_len_a(128), m_n_bar(8) {
#if !defined(BOTAN_HAS_AES)
#if !defined(BOTAN_HAS_FRODOKEM_AES)
BOTAN_ARG_CHECK(!mode.is_aes(), "cannot instantiate AES-based FrodoKEM: This build does not support AES");
#endif

Expand Down
33 changes: 6 additions & 27 deletions src/lib/pubkey/frodokem/frodo_matrix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,17 @@
#include <botan/frodokem.h>
#include <botan/hex.h>
#include <botan/mem_ops.h>
#if defined(BOTAN_HAS_AES)
#include <botan/internal/aes.h>
#endif
#include <botan/internal/bit_ops.h>
#include <botan/internal/ct_utils.h>
#include <botan/internal/frodo_constants.h>
#include <botan/internal/loadstor.h>
#include <botan/internal/shake_xof.h>
#include <botan/internal/stl_util.h>

#if defined(BOTAN_HAS_FRODOKEM_AES)
#include <botan/internal/frodo_aes_generator.h>
#endif

#include <array>
#include <cmath>
#include <cstdint>
Expand All @@ -45,31 +46,9 @@ secure_vector<uint16_t> make_elements_vector(const FrodoMatrix::Dimensions& dime

std::function<void(std::span<uint8_t> out, uint16_t i)> make_row_generator(const FrodoKEMConstants& constants,
StrongSpan<const FrodoSeedA> seed_a) {
#if defined(BOTAN_HAS_AES)
#if defined(BOTAN_HAS_FRODOKEM_AES)
if(constants.mode().is_aes()) {
// precondition the block cipher for "seed a" to avoid
// regenerating the AES' key schedule for each matrix row
AES_128 aes;
aes.set_key(seed_a);

return [n = constants.n(), aes](std::span<uint8_t> out, uint16_t i) mutable {
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<uint16_t>(i), out_coefs.data());
store_le(static_cast<uint16_t>(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);
}
};
return create_aes_row_generator(constants, seed_a);
}
#endif

Expand Down
56 changes: 56 additions & 0 deletions src/lib/pubkey/frodokem/frodokem_aes/frodo_aes_generator.h
Original file line number Diff line number Diff line change
@@ -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 <botan/internal/aes.h>
#include <botan/internal/frodo_constants.h>
#include <botan/internal/frodo_types.h>
#include <botan/internal/loadstor.h>
#include <botan/internal/stl_util.h>

#include <functional>
#include <span>

namespace Botan {

inline auto create_aes_row_generator(const FrodoKEMConstants& constants, StrongSpan<const FrodoSeedA> seed_a) {
BOTAN_ASSERT_NOMSG(constants.mode().is_aes());

auto setup_aes = [](StrongSpan<const FrodoSeedA> seed) {
AES_128 aes;
aes.set_key(seed);
return aes;
};

return [n = constants.n(), aes = setup_aes(seed_a)](std::span<uint8_t> 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<uint16_t>(i), out_coefs.data());
store_le(static_cast<uint16_t>(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
11 changes: 11 additions & 0 deletions src/lib/pubkey/frodokem/frodokem_aes/info.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<defines>
FRODOKEM_AES -> 20231103
</defines>

<module_info>
name -> "FrodoKEM-AES"
</module_info>

<requires>
aes
</requires>
25 changes: 16 additions & 9 deletions src/tests/test_frodokem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ namespace Botan_Tests {

namespace {

#if defined(BOTAN_HAS_AES)

Botan::FrodoKEMMode get_mode(std::string_view header) {
if(header == "FrodoKEM-640-SHAKE") {
return Botan::FrodoKEMMode::FrodoKEM640_SHAKE;
Expand Down Expand Up @@ -61,7 +59,7 @@ Botan::FrodoKEMMode get_mode(std::string_view header) {
return Botan::FrodoKEMMode::eFrodoKEM1344_AES;
}

BOTAN_ASSERT_UNREACHABLE();
throw Test_Error(Botan::fmt("Unexpected FrodoKEM mode: {}", header));
}

decltype(auto) shake256_16(std::span<const uint8_t> data) {
Expand All @@ -78,6 +76,19 @@ class Frodo_KAT_Tests final : public Text_Based_Test {
public:
Frodo_KAT_Tests() : Text_Based_Test("pubkey/frodokem_kat.vec", "seed,ss,pk,sk,ct") {}

bool skip_this_test(const std::string& header, const VarMap&) override {
#if !defined(BOTAN_HAS_FRODOKEM_AES)
const auto mode = get_mode(header);
if(mode.is_aes()) {
return true;
}
#else
BOTAN_UNUSED(header);
#endif

return false;
}

Test::Result run_one_test(const std::string& header, const VarMap& vars) override {
Test::Result result(Botan::fmt("FrodoKEM KAT {}", header));

Expand Down Expand Up @@ -118,7 +129,6 @@ class Frodo_KAT_Tests final : public Text_Based_Test {
return result;
}
};
#endif

std::vector<Test::Result> test_frodo_roundtrips() {
auto& rng = Test::rng();
Expand All @@ -127,7 +137,7 @@ std::vector<Test::Result> test_frodo_roundtrips() {
Botan::FrodoKEMMode::eFrodoKEM1344_SHAKE, Botan::FrodoKEMMode::eFrodoKEM976_SHAKE,
Botan::FrodoKEMMode::eFrodoKEM640_SHAKE, Botan::FrodoKEMMode::FrodoKEM1344_SHAKE,
Botan::FrodoKEMMode::FrodoKEM976_SHAKE, Botan::FrodoKEMMode::FrodoKEM640_SHAKE,
#if defined(BOTAN_HAS_AES)
#if defined(BOTAN_HAS_FRODOKEM_AES)
Botan::FrodoKEMMode::eFrodoKEM1344_AES, Botan::FrodoKEMMode::eFrodoKEM976_AES,
Botan::FrodoKEMMode::eFrodoKEM640_AES, Botan::FrodoKEMMode::FrodoKEM1344_AES,
Botan::FrodoKEMMode::FrodoKEM976_AES, Botan::FrodoKEMMode::FrodoKEM640_AES
Expand Down Expand Up @@ -201,7 +211,7 @@ class Frodo_Keygen_Tests final : public PK_Key_Generation_Test {
std::vector<std::string> keygen_params() const override {
return {
"FrodoKEM-640-SHAKE", "FrodoKEM-976-SHAKE", "eFrodoKEM-640-SHAKE", "eFrodoKEM-976-SHAKE",
#if defined(BOTAN_HAS_AES)
#if defined(BOTAN_HAS_FRODOKEM_AES)
"FrodoKEM-640-AES", "FrodoKEM-976-AES", "eFrodoKEM-640-AES", "eFrodoKEM-976-AES",
#endif
};
Expand All @@ -212,10 +222,7 @@ class Frodo_Keygen_Tests final : public PK_Key_Generation_Test {

} // namespace

#if defined(BOTAN_HAS_AES)
BOTAN_REGISTER_TEST("frodokem", "frodo_kat_tests", Frodo_KAT_Tests);
#endif

BOTAN_REGISTER_TEST_FN("frodokem", "frodo_roundtrips", test_frodo_roundtrips);
BOTAN_REGISTER_TEST("frodokem", "frodo_keygen", Frodo_Keygen_Tests);

Expand Down

0 comments on commit 0694f1d

Please sign in to comment.