13#include <botan/frodokem.h>
15#include <botan/assert.h>
18#include <botan/internal/buffer_slicer.h>
19#include <botan/internal/buffer_stuffer.h>
20#include <botan/internal/concat_util.h>
21#include <botan/internal/ct_utils.h>
22#include <botan/internal/frodo_constants.h>
23#include <botan/internal/frodo_matrix.h>
24#include <botan/internal/frodo_types.h>
25#include <botan/internal/pk_ops_impl.h>
33class FrodoKEM_PublicKeyInternal {
35 FrodoKEM_PublicKeyInternal(FrodoKEMConstants constants,
FrodoSeedA seed_a, FrodoMatrix b) :
36 m_constants(std::move(constants)), m_seed_a(std::move(seed_a)), m_b(std::move(b)) {
37 auto shake = m_constants.create_xof();
38 shake->update(serialize());
42 const FrodoKEMConstants& constants()
const {
return m_constants; }
44 const FrodoSeedA& seed_a()
const {
return m_seed_a; }
46 const FrodoMatrix& b()
const {
return m_b; }
53 FrodoKEMConstants m_constants;
59class FrodoKEM_PrivateKeyInternal {
61 FrodoKEM_PrivateKeyInternal(
FrodoSeedS s, FrodoMatrix s_trans) :
62 m_s(std::move(s)), m_s_trans(std::move(s_trans)) {}
66 const FrodoMatrix& s_trans()
const {
return m_s_trans; }
68 constexpr void _const_time_poison()
const {
CT::poison_all(m_s, m_s_trans); }
70 constexpr void _const_time_unpoison()
const {
CT::unpoison_all(m_s, m_s_trans); }
74 FrodoMatrix m_s_trans;
85 Frodo_KEM_Encryptor(std::shared_ptr<FrodoKEM_PublicKeyInternal> key, std::string_view kdf) :
86 KEM_Encryption_with_KDF(kdf), m_public_key(std::move(key)) {}
88 size_t raw_kem_shared_key_length()
const override {
return m_public_key->constants().len_sec_bytes(); }
90 size_t encapsulated_key_length()
const override {
return m_public_key->constants().len_ct_bytes(); }
92 void raw_kem_encrypt(std::span<uint8_t> out_encapsulated_key,
93 std::span<uint8_t> out_shared_key,
94 RandomNumberGenerator& rng)
override {
95 const auto& constants = m_public_key->constants();
96 auto shake = constants.create_xof();
99 BufferStuffer out_ct_bs(out_encapsulated_key);
103 auto salt = out_ct_bs.next<
FrodoSalt>(constants.len_salt_bytes());
107 const auto u = rng.random_vec<
FrodoPlaintext>(constants.len_sec_bytes());
112 shake->update(m_public_key->hash());
115 const auto seed_se = shake->output<
FrodoSeedSE>(constants.len_se_bytes());
119 shake->update(constants.encapsulation_domain_separator());
120 shake->update(seed_se);
122 const auto s_p = sample_generator(std::tuple(constants.n_bar(), constants.n()));
124 const auto e_p = sample_generator(std::tuple(constants.n_bar(), constants.n()));
128 b_p.pack(constants, c_1);
130 const auto e_pp = sample_generator(std::tuple(constants.n_bar(), constants.n_bar()));
139 c.pack(constants, c_2);
141 shake->update(out_encapsulated_key);
143 shake->output(out_shared_key);
149 std::shared_ptr<FrodoKEM_PublicKeyInternal> m_public_key;
154 Frodo_KEM_Decryptor(std::shared_ptr<FrodoKEM_PublicKeyInternal> public_key,
155 std::shared_ptr<FrodoKEM_PrivateKeyInternal> private_key,
156 std::string_view kdf) :
157 KEM_Decryption_with_KDF(kdf), m_public_key(std::move(public_key)), m_private_key(std::move(private_key)) {}
159 size_t raw_kem_shared_key_length()
const override {
return m_public_key->constants().len_sec_bytes(); }
161 size_t encapsulated_key_length()
const override {
return m_public_key->constants().len_ct_bytes(); }
163 void raw_kem_decrypt(std::span<uint8_t> out_shared_key, std::span<const uint8_t> encapsulated_key)
override {
166 const auto& constants = m_public_key->constants();
167 auto shake = constants.create_xof();
170 if(encapsulated_key.size() != constants.len_ct_bytes()) {
171 throw Invalid_Argument(
"FrodoKEM ciphertext does not have the correct byte count");
174 BufferSlicer ct_bs(encapsulated_key);
177 auto salt = ct_bs.take<
FrodoSalt>(constants.len_salt_bytes());
181 const auto c =
FrodoMatrix::unpack(constants, {constants.n_bar(), constants.n_bar()}, c_2);
186 const auto seed_u_p = m.decode(constants);
188 shake->update(m_public_key->hash());
189 shake->update(seed_u_p);
192 const auto seed_se_p = shake->output<
FrodoSeedSE>(constants.len_se_bytes());
196 shake->update(constants.encapsulation_domain_separator());
197 shake->update(seed_se_p);
198 const auto s_p = sample_generator(std::tuple(constants.n_bar(), constants.n()));
200 const auto e_p = sample_generator(std::tuple(constants.n_bar(), constants.n()));
204 const auto e_pp = sample_generator(std::tuple(constants.n_bar(), constants.n_bar()));
215 b_pp.reduce(constants);
216 c_p.reduce(constants);
221 const auto cmp = b_p.constant_time_compare(b_pp) & c.constant_time_compare(c_p);
223 std::vector<uint8_t> k_bar(constants.len_sec_bytes(), 0);
226 shake->update(encapsulated_key);
227 shake->update(k_bar);
228 shake->output(out_shared_key);
234 std::shared_ptr<FrodoKEM_PublicKeyInternal> m_public_key;
235 std::shared_ptr<FrodoKEM_PrivateKeyInternal> m_private_key;
247 throw Invalid_Argument(
"FrodoKEM public key does not have the correct byte count");
257 m_public = std::make_shared<FrodoKEM_PublicKeyInternal>(std::move(constants), std::move(seed_a), std::move(b));
264 m_public = std::make_shared<FrodoKEM_PublicKeyInternal>(
270 m_public = std::make_shared<FrodoKEM_PublicKeyInternal>(
281 return m_public->constants().mode().object_identifier();
289 return m_public->constants().estimated_strength();
307 return std::make_unique<FrodoKEM_PrivateKey>(rng,
m_public->constants().mode());
311 std::string_view provider)
const {
312 if(provider.empty() || provider ==
"base") {
313 return std::make_unique<Frodo_KEM_Encryptor>(
m_public, params);
337 shake->update(seed_se);
340 auto s_trans = sample_generator(std::tuple(constants.
n_bar(), constants.
n()));
341 auto e = sample_generator(std::tuple(constants.
n(), constants.
n_bar()));
348 m_public = std::make_shared<FrodoKEM_PublicKeyInternal>(std::move(constants), std::move(seed_a), std::move(b));
349 m_private = std::make_shared<FrodoKEM_PrivateKeyInternal>(std::move(s), std::move(s_trans));
356 throw Invalid_Argument(
"FrodoKEM private key does not have the correct byte count");
370 m_public = std::make_shared<FrodoKEM_PublicKeyInternal>(std::move(constants), std::move(seed_a), std::move(b));
371 m_private = std::make_shared<FrodoKEM_PrivateKeyInternal>(std::move(s), std::move(s_trans));
380 return std::make_unique<FrodoKEM_PublicKey>(*
this);
391 m_private->s_trans().serialize(),
396 std::string_view params,
397 std::string_view provider)
const {
399 if(provider.empty() || provider ==
"base") {
400 return std::make_unique<Frodo_KEM_Decryptor>(
m_public, m_private, params);
#define BOTAN_ASSERT_NOMSG(expr)
#define BOTAN_STATE_CHECK(expr)
auto copy(const size_t count)
std::span< const uint8_t > take(const size_t count)
FrodoDomainSeparator keygen_domain_separator() const
size_t len_private_key_bytes() const
size_t len_public_key_bytes() const
std::unique_ptr< XOF > create_xof() const
size_t len_sec_bytes() const
size_t len_se_bytes() const
size_t len_a_bytes() const
FrodoKEM_PrivateKey(RandomNumberGenerator &rng, FrodoKEMMode mode)
std::unique_ptr< PK_Ops::KEM_Decryption > create_kem_decryption_op(RandomNumberGenerator &rng, std::string_view params, std::string_view provider) const override
secure_vector< uint8_t > raw_private_key_bits() const override
secure_vector< uint8_t > private_key_bits() const override
std::unique_ptr< Public_Key > public_key() const override
size_t estimated_strength() const override
AlgorithmIdentifier algorithm_identifier() const override
std::unique_ptr< PK_Ops::KEM_Encryption > create_kem_encryption_op(std::string_view params, std::string_view provider) const override
size_t key_length() const override
std::shared_ptr< FrodoKEM_PublicKeyInternal > m_public
FrodoKEM_PublicKey(std::span< const uint8_t > pub_key, FrodoKEMMode mode)
std::unique_ptr< Private_Key > generate_another(RandomNumberGenerator &rng) const final
std::vector< uint8_t > public_key_bits() const override
FrodoKEM_PublicKey & operator=(const FrodoKEM_PublicKey &other)
std::string algo_name() const override
bool check_key(RandomNumberGenerator &rng, bool strong) const override
std::vector< uint8_t > raw_public_key_bits() const override
FrodoKEM_PublicKey()=default
OID object_identifier() const override
static FrodoMatrix mul_add_sa_plus_e(const FrodoKEMConstants &constants, const FrodoMatrix &s, const FrodoMatrix &e, StrongSpan< const FrodoSeedA > seed_a)
static std::function< FrodoMatrix(const Dimensions &dimensions)> make_sample_generator(const FrodoKEMConstants &constants, Botan::XOF &shake)
static FrodoMatrix mul_add_sb_plus_e(const FrodoKEMConstants &constants, const FrodoMatrix &b, const FrodoMatrix &s, const FrodoMatrix &e)
static FrodoMatrix mul_add_as_plus_e(const FrodoKEMConstants &constants, const FrodoMatrix &s, const FrodoMatrix &e, StrongSpan< const FrodoSeedA > seed_a)
static FrodoMatrix sub(const FrodoKEMConstants &constants, const FrodoMatrix &a, const FrodoMatrix &b)
static FrodoMatrix add(const FrodoKEMConstants &constants, const FrodoMatrix &a, const FrodoMatrix &b)
static FrodoMatrix encode(const FrodoKEMConstants &constants, StrongSpan< const FrodoPlaintext > in)
static FrodoMatrix unpack(const FrodoKEMConstants &constants, const Dimensions &dimensions, StrongSpan< const FrodoPackedMatrix > packed_bytes)
static FrodoMatrix mul_bs(const FrodoKEMConstants &constants, const FrodoMatrix &b_p, const FrodoMatrix &s)
static FrodoMatrix deserialize(const Dimensions &dimensions, StrongSpan< const FrodoSerializedMatrix > bytes)
void random_vec(std::span< uint8_t > v)
constexpr void poison_all(const Ts &... ts)
constexpr Mask< T > conditional_copy_mem(Mask< T > mask, T *dest, const T *if_set, const T *if_unset, size_t elems)
constexpr auto scoped_poison(const Ts &... xs)
constexpr void unpoison_all(const Ts &... ts)
constexpr void unpoison(const T *p, size_t n)
constexpr void poison(const T *p, size_t n)
Strong< secure_vector< uint8_t >, struct FrodoSeedSE_ > FrodoSeedSE
Strong< secure_vector< uint8_t >, struct FrodoSerializedMatrix_ > FrodoSerializedMatrix
Strong< std::vector< uint8_t >, struct FrodoSeedZ_ > FrodoSeedZ
Strong< secure_vector< uint8_t >, struct FrodoIntermediateSharedSecret_ > FrodoIntermediateSharedSecret
Strong< std::vector< uint8_t >, struct FrodoPublicKeyHash_ > FrodoPublicKeyHash
constexpr auto concat(Rs &&... ranges)
std::vector< T, secure_allocator< T > > secure_vector
Strong< std::vector< uint8_t >, struct FrodoSeedA_ > FrodoSeedA
Strong< secure_vector< uint8_t >, struct FrodoPlaintext_ > FrodoPlaintext
Strong< std::vector< uint8_t >, struct FrodoSalt_ > FrodoSalt
Strong< std::vector< uint8_t >, struct FrodoPackedMatrix_ > FrodoPackedMatrix
Strong< secure_vector< uint8_t >, struct FrodoSeedS_ > FrodoSeedS