Skip to content

Commit

Permalink
Separate modules for AES/SHAKE
Browse files Browse the repository at this point in the history
  • Loading branch information
atreiber94 committed Oct 4, 2023
1 parent ad660cc commit 0c1a815
Show file tree
Hide file tree
Showing 19 changed files with 265 additions and 86 deletions.
4 changes: 2 additions & 2 deletions src/cli/speed.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@
#include <botan/sphincsplus.h>
#endif

#if defined(BOTAN_HAS_FRODOKEM)
#if defined(BOTAN_HAS_FRODOKEM_AES) || defined(BOTAN_HAS_FRODOKEM_SHAKE)
#include <botan/frodokem.h>
#endif

Expand Down Expand Up @@ -2047,7 +2047,7 @@ class Speed final : public Command {
}
#endif

#if defined(BOTAN_HAS_FRODOKEM)
#if defined(BOTAN_HAS_FRODOKEM_AES) || defined(BOTAN_HAS_FRODOKEM_SHAKE)
void bench_frodokem(const std::string& provider, std::chrono::milliseconds msec) {
std::vector<Botan::FrodoKEMMode> frodo_modes{
Botan::FrodoKEMMode::FrodoKEM640_SHAKE,
Expand Down
51 changes: 51 additions & 0 deletions src/lib/pubkey/frodokem/frodokem_aes/frodo_expansion_aes.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* FrodoKEM seed expansion w/ AES
* 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 <botan/assert.h>
#include <botan/block_cipher.h>
#include <botan/internal/aes.h>
#include <botan/internal/frodo_constants.h>
#include <botan/internal/frodo_expansion_aes.h>
#include <botan/internal/loadstor.h>
#include <botan/internal/stl_util.h>

namespace Botan {

FrodoRowGenerator frodo_aes_row_generator(const FrodoKEMConstants& constants, StrongSpan<const FrodoSeedA> seed_a) {
BOTAN_ASSERT_NOMSG(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 FrodoRowGenerator([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);
}
});
}

} // namespace Botan
28 changes: 28 additions & 0 deletions src/lib/pubkey/frodokem/frodokem_aes/frodo_expansion_aes.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* FrodoKEM seed expansion w/ AES
* 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_EXPANSION_AES_H_
#define BOTAN_FRODOKEM_EXPANSION_AES_H_

#include <botan/internal/frodo_constants.h>
#include <botan/internal/frodo_types.h>

#include <tuple>
#include <utility>
#include <vector>

namespace Botan {

FrodoRowGenerator frodo_aes_row_generator(const FrodoKEMConstants& constants, StrongSpan<const FrodoSeedA> seed_a);
}

#endif
18 changes: 18 additions & 0 deletions src/lib/pubkey/frodokem/frodokem_aes/info.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<defines>
FRODOKEM_AES -> 20231004
</defines>

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

<requires>
aes
shake_xof
sha3
frodokem_common
</requires>

<header:internal>
frodo_expansion_aes.h
</header:internal>
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,24 @@
*/

#include <botan/assert.h>
#include <botan/block_cipher.h>
#include <botan/frodokem.h>
#include <botan/hex.h>
#include <botan/mem_ops.h>
#include <botan/internal/aes.h>
#include <botan/internal/bit_ops.h>
#include <botan/internal/ct_utils.h>
#include <botan/internal/frodo_constants.h>
#include <botan/internal/frodo_matrix.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_expansion_aes.h>
#endif

#if defined(BOTAN_HAS_FRODOKEM_SHAKE)
#include <botan/internal/frodo_expansion_shake.h>
#endif

#include <array>
#include <cmath>
#include <cstdint>
Expand All @@ -41,47 +46,18 @@ std::vector<uint16_t> make_elements_vector(const FrodoMatrix::Dimensions& dimens
return std::vector<uint16_t>(static_cast<size_t>(std::get<0>(dimensions)) * std::get<1>(dimensions));
}

// TODO: Probably we want to split AES-support into an extra botan module
// For that, this function will need to be refactored.
std::function<void(std::span<uint8_t> out, uint16_t i)> make_row_generator(const FrodoKEMConstants& constants,
StrongSpan<const FrodoSeedA> seed_a) {
FrodoRowGenerator make_row_generator(const FrodoKEMConstants& constants, StrongSpan<const FrodoSeedA> seed_a) {
#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;
}
return frodo_aes_row_generator(constants, seed_a);
}
#endif

aes.encrypt(out_coefs);
}
};
} else if(constants.mode().is_shake()) {
SHAKE_128_XOF xof;
return [xof, a = FrodoSeedA(seed_a)](std::span<uint8_t> out, uint16_t i) mutable {
xof.clear();
// TODO: update that once #3707 is merged
// potentially add a new method: std::array<uint8_t, XX> as_le(uintXX_t)
std::array<uint8_t, 2> le;
store_le(i, le.data());
xof.update(le);
xof.update(a);
xof.output(out);
};
#if defined(BOTAN_HAS_FRODOKEM_SHAKE)
if(constants.mode().is_shake()) {
return frodo_shake_row_generator(constants, seed_a);
}
#endif

BOTAN_ASSERT_UNREACHABLE();
}
Expand Down Expand Up @@ -153,10 +129,10 @@ FrodoMatrix FrodoMatrix::mul_add_as_plus_e(const FrodoKEMConstants& constants,
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<uint16_t>(i + 0));
row_generator(a_row.next(constants.n() * sizeof(uint16_t)), static_cast<uint16_t>(i + 1));
row_generator(a_row.next(constants.n() * sizeof(uint16_t)), static_cast<uint16_t>(i + 2));
row_generator(a_row.next(constants.n() * sizeof(uint16_t)), static_cast<uint16_t>(i + 3));
row_generator.get()(a_row.next(constants.n() * sizeof(uint16_t)), static_cast<uint16_t>(i + 0));
row_generator.get()(a_row.next(constants.n() * sizeof(uint16_t)), static_cast<uint16_t>(i + 1));
row_generator.get()(a_row.next(constants.n() * sizeof(uint16_t)), static_cast<uint16_t>(i + 2));
row_generator.get()(a_row.next(constants.n() * sizeof(uint16_t)), static_cast<uint16_t>(i + 3));

// Use generated bytes to fill 16-bit data
load_le<uint16_t>(a_row_data.data(), a_row_data_bytes.data(), 4 * constants.n());
Expand Down Expand Up @@ -218,14 +194,14 @@ FrodoMatrix FrodoMatrix::mul_add_sa_plus_e(const FrodoKEMConstants& constants,
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<uint16_t>(i + 0));
row_generator(a_row.next(sizeof(uint16_t) * constants.n()), static_cast<uint16_t>(i + 1));
row_generator(a_row.next(sizeof(uint16_t) * constants.n()), static_cast<uint16_t>(i + 2));
row_generator(a_row.next(sizeof(uint16_t) * constants.n()), static_cast<uint16_t>(i + 3));
row_generator(a_row.next(sizeof(uint16_t) * constants.n()), static_cast<uint16_t>(i + 4));
row_generator(a_row.next(sizeof(uint16_t) * constants.n()), static_cast<uint16_t>(i + 5));
row_generator(a_row.next(sizeof(uint16_t) * constants.n()), static_cast<uint16_t>(i + 6));
row_generator(a_row.next(sizeof(uint16_t) * constants.n()), static_cast<uint16_t>(i + 7));
row_generator.get()(a_row.next(sizeof(uint16_t) * constants.n()), static_cast<uint16_t>(i + 0));
row_generator.get()(a_row.next(sizeof(uint16_t) * constants.n()), static_cast<uint16_t>(i + 1));
row_generator.get()(a_row.next(sizeof(uint16_t) * constants.n()), static_cast<uint16_t>(i + 2));
row_generator.get()(a_row.next(sizeof(uint16_t) * constants.n()), static_cast<uint16_t>(i + 3));
row_generator.get()(a_row.next(sizeof(uint16_t) * constants.n()), static_cast<uint16_t>(i + 4));
row_generator.get()(a_row.next(sizeof(uint16_t) * constants.n()), static_cast<uint16_t>(i + 5));
row_generator.get()(a_row.next(sizeof(uint16_t) * constants.n()), static_cast<uint16_t>(i + 6));
row_generator.get()(a_row.next(sizeof(uint16_t) * constants.n()), static_cast<uint16_t>(i + 7));

// Use generated bytes to fill 16-bit data
load_le<uint16_t>(a_row_data.data(), a_row_data_bytes.data(), 8 * constants.n());
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ using FrodoSalt = Strong<std::vector<uint8_t>, struct FrodoSalt_>;
// TODO: Find a better name for this
using FrodoK = Strong<secure_vector<uint8_t>, struct FrodoK_>;

using FrodoRowGenerator = Strong<std::function<void(std::span<uint8_t>, uint16_t)>, struct FrodoRowGenerator_>;

} // namespace Botan

#endif
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
<defines>
FRODOKEM -> 20230801
FRODOKEM_COMMON -> 20230801
</defines>

<module_info>
name -> "FrodoKEM"
name -> "FrodoKEM (common)"
brief -> "Base implementation of FrodoKEM"
type -> "Internal"
</module_info>

<requires>
aes
shake_xof
sha3
</requires>
Expand Down
37 changes: 37 additions & 0 deletions src/lib/pubkey/frodokem/frodokem_shake/frodo_expansion_shake.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* FrodoKEM seed expansion w/ SHAKE
* 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 <botan/assert.h>
#include <botan/internal/frodo_constants.h>
#include <botan/internal/frodo_expansion_shake.h>
#include <botan/internal/loadstor.h>
#include <botan/internal/shake_xof.h>

namespace Botan {

FrodoRowGenerator frodo_shake_row_generator(const FrodoKEMConstants& constants, StrongSpan<const FrodoSeedA> seed_a) {
BOTAN_ASSERT_NOMSG(constants.mode().is_shake());

SHAKE_128_XOF xof;
return FrodoRowGenerator([xof, a = FrodoSeedA(seed_a)](std::span<uint8_t> out, uint16_t i) mutable {
xof.clear();
// TODO: update that once #3707 is merged
// potentially add a new method: std::array<uint8_t, XX> as_le(uintXX_t)
std::array<uint8_t, 2> le;
store_le(i, le.data());
xof.update(le);
xof.update(a);
xof.output(out);
});
}

} // namespace Botan
29 changes: 29 additions & 0 deletions src/lib/pubkey/frodokem/frodokem_shake/frodo_expansion_shake.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* FrodoKEM seed expansion w/ SHAKE
* 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_EXPANSION_SHAKE_H_
#define BOTAN_FRODOKEM_EXPANSION_SHAKE_H_

#include <botan/internal/frodo_constants.h>
#include <botan/internal/frodo_types.h>

#include <tuple>
#include <utility>
#include <vector>

namespace Botan {

FrodoRowGenerator frodo_shake_row_generator(const FrodoKEMConstants& constants, StrongSpan<const FrodoSeedA> seed_a);

} // namespace Botan

#endif
17 changes: 17 additions & 0 deletions src/lib/pubkey/frodokem/frodokem_shake/info.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<defines>
FRODOKEM_SHAKE -> 20231004
</defines>

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

<requires>
shake_xof
sha3
frodokem_common
</requires>

<header:internal>
frodo_expansion_shake.h
</header:internal>
8 changes: 4 additions & 4 deletions src/lib/pubkey/pk_algs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
#include <botan/mceliece.h>
#endif

#if defined(BOTAN_HAS_FRODOKEM)
#if defined(BOTAN_HAS_FRODOKEM_AES) || defined(BOTAN_HAS_FRODOKEM_SHAKE)
#include <botan/frodokem.h>
#endif

Expand Down Expand Up @@ -116,7 +116,7 @@ std::unique_ptr<Public_Key> load_public_key(const AlgorithmIdentifier& alg_id,
}
#endif

#if defined(BOTAN_HAS_FRODOKEM)
#if defined(BOTAN_HAS_FRODOKEM_AES) || defined(BOTAN_HAS_FRODOKEM_SHAKE)
if(alg_name == "FrodoKEM" || alg_name.starts_with("FrodoKEM-") || alg_name.starts_with("eFrodoKEM-")) {
return std::make_unique<FrodoKEM_PublicKey>(alg_id, key_bits);
}
Expand Down Expand Up @@ -251,7 +251,7 @@ std::unique_ptr<Private_Key> load_private_key(const AlgorithmIdentifier& alg_id,
}
#endif

#if defined(BOTAN_HAS_FRODOKEM)
#if defined(BOTAN_HAS_FRODOKEM_AES) || defined(BOTAN_HAS_FRODOKEM_SHAKE)
if(alg_name == "FrodoKEM" || alg_name.starts_with("FrodoKEM-") || alg_name.starts_with("eFrodoKEM-")) {
return std::make_unique<FrodoKEM_PrivateKey>(alg_id, key_bits);
}
Expand Down Expand Up @@ -414,7 +414,7 @@ std::unique_ptr<Private_Key> create_private_key(std::string_view alg_name,
}
#endif

#if defined(BOTAN_HAS_FRODOKEM)
#if defined(BOTAN_HAS_FRODOKEM_AES) || defined(BOTAN_HAS_FRODOKEM_SHAKE)
if(alg_name == "FrodoKEM") {
const auto mode = params.empty() ? FrodoKEMMode::FrodoKEM976_SHAKE : FrodoKEMMode(params);
return std::make_unique<FrodoKEM_PrivateKey>(rng, mode);
Expand Down
Loading

0 comments on commit 0c1a815

Please sign in to comment.