Botan 3.12.0
Crypto and TLS for C&
frodokem.cpp
Go to the documentation of this file.
1/*
2 * FrodoKEM implementation
3 * Based on the MIT licensed reference implementation by the designers
4 * (https://github.com/microsoft/PQCrypto-LWEKE/tree/master)
5 *
6 * The Fellowship of the FrodoKEM:
7 * (C) 2023 Jack Lloyd
8 * 2023 René Meusel, Amos Treiber - Rohde & Schwarz Cybersecurity
9 *
10 * Botan is released under the Simplified BSD License (see license.txt)
11 */
12
13#include <botan/frodokem.h>
14
15#include <botan/assert.h>
16#include <botan/pubkey.h>
17#include <botan/rng.h>
18#include <botan/xof.h>
19#include <botan/internal/buffer_slicer.h>
20#include <botan/internal/buffer_stuffer.h>
21#include <botan/internal/concat_util.h>
22#include <botan/internal/ct_utils.h>
23#include <botan/internal/frodo_constants.h>
24#include <botan/internal/frodo_matrix.h>
25#include <botan/internal/frodo_types.h>
26#include <botan/internal/pk_ops_impl.h>
27
28#include <memory>
29#include <tuple>
30#include <vector>
31
32namespace Botan {
33
34class FrodoKEM_PublicKeyInternal final {
35 public:
36 FrodoKEM_PublicKeyInternal(FrodoKEMConstants constants, FrodoSeedA seed_a, FrodoMatrix b) :
37 m_constants(std::move(constants)), m_seed_a(std::move(seed_a)), m_b(std::move(b)) {
38 auto shake = m_constants.create_xof();
39 shake->update(serialize());
40 m_hash = shake->output<FrodoPublicKeyHash>(m_constants.len_sec_bytes());
41 }
42
43 const FrodoKEMConstants& constants() const { return m_constants; }
44
45 const FrodoSeedA& seed_a() const { return m_seed_a; }
46
47 const FrodoMatrix& b() const { return m_b; }
48
49 const FrodoPublicKeyHash& hash() const { return m_hash; }
50
51 std::vector<uint8_t> serialize() const { return concat<std::vector<uint8_t>>(seed_a(), b().pack(m_constants)); }
52
53 private:
54 FrodoKEMConstants m_constants;
55 FrodoSeedA m_seed_a;
56 FrodoMatrix m_b;
57 FrodoPublicKeyHash m_hash;
58};
59
60class FrodoKEM_PrivateKeyInternal final {
61 public:
62 FrodoKEM_PrivateKeyInternal(FrodoSeedS s, FrodoMatrix s_trans) :
63 m_s(std::move(s)), m_s_trans(std::move(s_trans)) {}
64
65 const FrodoSeedS& s() const { return m_s; }
66
67 const FrodoMatrix& s_trans() const { return m_s_trans; }
68
69 constexpr void _const_time_poison() const { CT::poison_all(m_s, m_s_trans); }
70
71 constexpr void _const_time_unpoison() const { CT::unpoison_all(m_s, m_s_trans); }
72
73 private:
74 FrodoSeedS m_s;
75 FrodoMatrix m_s_trans;
76};
77
78//
79// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
80//
81
82namespace {
83
84class Frodo_KEM_Encryptor final : public PK_Ops::KEM_Encryption_with_KDF {
85 public:
86 Frodo_KEM_Encryptor(std::shared_ptr<FrodoKEM_PublicKeyInternal> key, std::string_view kdf) :
87 KEM_Encryption_with_KDF(kdf), m_public_key(std::move(key)) {}
88
89 size_t raw_kem_shared_key_length() const override { return m_public_key->constants().len_sec_bytes(); }
90
91 size_t encapsulated_key_length() const override { return m_public_key->constants().len_ct_bytes(); }
92
93 void raw_kem_encrypt(std::span<uint8_t> out_encapsulated_key,
94 std::span<uint8_t> out_shared_key,
95 RandomNumberGenerator& rng) override {
96 const auto& constants = m_public_key->constants();
97 auto shake = constants.create_xof();
98 auto sample_generator = FrodoMatrix::make_sample_generator(constants, *shake);
99
100 BufferStuffer out_ct_bs(out_encapsulated_key);
101
102 auto c_1 = out_ct_bs.next<FrodoPackedMatrix>(constants.len_packed_b_bytes());
103 auto c_2 = out_ct_bs.next<FrodoPackedMatrix>(constants.len_packed_c_bytes());
104 auto salt = out_ct_bs.next<FrodoSalt>(constants.len_salt_bytes());
105
106 BOTAN_ASSERT_NOMSG(out_ct_bs.full());
107
108 const auto u = rng.random_vec<FrodoPlaintext>(constants.len_sec_bytes());
109 rng.randomize(salt);
110
111 CT::poison(u);
112
113 shake->update(m_public_key->hash());
114 shake->update(u);
115 shake->update(salt);
116 const auto seed_se = shake->output<FrodoSeedSE>(constants.len_se_bytes());
117 const auto k = shake->output<FrodoIntermediateSharedSecret>(constants.len_sec_bytes());
118 shake->clear();
119
120 shake->update(constants.encapsulation_domain_separator());
121 shake->update(seed_se);
122
123 const auto s_p = sample_generator(std::tuple(constants.n_bar(), constants.n()));
124
125 const auto e_p = sample_generator(std::tuple(constants.n_bar(), constants.n()));
126
127 const auto b_p = FrodoMatrix::mul_add_sa_plus_e(constants, s_p, e_p, m_public_key->seed_a());
128
129 b_p.pack(constants, c_1);
130
131 const auto e_pp = sample_generator(std::tuple(constants.n_bar(), constants.n_bar()));
132 shake->clear();
133
134 const auto v = FrodoMatrix::mul_add_sb_plus_e(constants, m_public_key->b(), s_p, e_pp);
135
136 const auto encoded = FrodoMatrix::encode(constants, u);
137
138 const auto c = FrodoMatrix::add(constants, v, encoded);
139
140 c.pack(constants, c_2);
141
142 shake->update(out_encapsulated_key);
143 shake->update(k);
144 shake->output(out_shared_key);
145
146 CT::unpoison_all(out_shared_key, out_encapsulated_key);
147 }
148
149 private:
150 std::shared_ptr<FrodoKEM_PublicKeyInternal> m_public_key;
151};
152
153class Frodo_KEM_Decryptor final : public PK_Ops::KEM_Decryption_with_KDF {
154 public:
155 Frodo_KEM_Decryptor(std::shared_ptr<FrodoKEM_PublicKeyInternal> public_key,
156 std::shared_ptr<FrodoKEM_PrivateKeyInternal> private_key,
157 std::string_view kdf) :
158 KEM_Decryption_with_KDF(kdf), m_public_key(std::move(public_key)), m_private_key(std::move(private_key)) {}
159
160 size_t raw_kem_shared_key_length() const override { return m_public_key->constants().len_sec_bytes(); }
161
162 size_t encapsulated_key_length() const override { return m_public_key->constants().len_ct_bytes(); }
163
164 void raw_kem_decrypt(std::span<uint8_t> out_shared_key, std::span<const uint8_t> encapsulated_key) override {
165 auto scope = CT::scoped_poison(*m_private_key);
166
167 const auto& constants = m_public_key->constants();
168 auto shake = constants.create_xof();
169 auto sample_generator = FrodoMatrix::make_sample_generator(constants, *shake);
170
171 if(encapsulated_key.size() != constants.len_ct_bytes()) {
172 throw Invalid_Argument("FrodoKEM ciphertext does not have the correct byte count");
173 }
174
175 BufferSlicer ct_bs(encapsulated_key);
176 auto c_1 = ct_bs.take<FrodoPackedMatrix>(constants.len_packed_b_bytes());
177 auto c_2 = ct_bs.take<FrodoPackedMatrix>(constants.len_packed_c_bytes());
178 auto salt = ct_bs.take<FrodoSalt>(constants.len_salt_bytes());
179 BOTAN_ASSERT_NOMSG(ct_bs.empty());
180
181 const auto b_p = FrodoMatrix::unpack(constants, {constants.n_bar(), constants.n()}, c_1);
182 const auto c = FrodoMatrix::unpack(constants, {constants.n_bar(), constants.n_bar()}, c_2);
183
184 const auto w = FrodoMatrix::mul_bs(constants, b_p, m_private_key->s_trans());
185 const auto m = FrodoMatrix::sub(constants, c, w);
186
187 const auto seed_u_p = m.decode(constants);
188
189 shake->update(m_public_key->hash());
190 shake->update(seed_u_p);
191 shake->update(salt);
192
193 const auto seed_se_p = shake->output<FrodoSeedSE>(constants.len_se_bytes());
194 const auto k_p = shake->output<FrodoIntermediateSharedSecret>(constants.len_sec_bytes());
195 shake->clear();
196
197 shake->update(constants.encapsulation_domain_separator());
198 shake->update(seed_se_p);
199 const auto s_p = sample_generator(std::tuple(constants.n_bar(), constants.n()));
200
201 const auto e_p = sample_generator(std::tuple(constants.n_bar(), constants.n()));
202
203 auto b_pp = FrodoMatrix::mul_add_sa_plus_e(constants, s_p, e_p, m_public_key->seed_a());
204
205 const auto e_pp = sample_generator(std::tuple(constants.n_bar(), constants.n_bar()));
206 shake->clear();
207
208 const auto v = FrodoMatrix::mul_add_sb_plus_e(constants, m_public_key->b(), s_p, e_pp);
209
210 const auto encoded = FrodoMatrix::encode(constants, seed_u_p);
211 auto c_p = FrodoMatrix::add(constants, v, encoded);
212
213 // b_p and c are unpacked values that are reduced by definition.
214 // b_pp and c_p are calculated values that need the reduction for
215 // an unambiguous comparison that is required next.
216 b_pp.reduce(constants);
217 c_p.reduce(constants);
218
219 // The spec concats the matrices b_p and c (b_pp and c_p respectively)
220 // and performs a single CT comparison. For convenience we compare the
221 // matrices individually in CT and CT-&& the resulting masks.
222 const auto cmp = b_p.constant_time_compare(b_pp) & c.constant_time_compare(c_p);
223
224 secure_vector<uint8_t> k_bar(constants.len_sec_bytes(), 0);
225 CT::conditional_copy_mem(cmp, k_bar.data(), k_p.data(), m_private_key->s().data(), constants.len_sec_bytes());
226
227 shake->update(encapsulated_key);
228 shake->update(k_bar);
229 shake->output(out_shared_key);
230
231 CT::unpoison(out_shared_key);
232 }
233
234 private:
235 std::shared_ptr<FrodoKEM_PublicKeyInternal> m_public_key;
236 std::shared_ptr<FrodoKEM_PrivateKeyInternal> m_private_key;
237};
238
239} // namespace
240
241//
242// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
243//
244
245FrodoKEM_PublicKey::FrodoKEM_PublicKey(std::span<const uint8_t> pub_key, FrodoKEMMode mode) {
246 FrodoKEMConstants constants(mode);
247 if(pub_key.size() != constants.len_public_key_bytes()) {
248 throw Invalid_Argument("FrodoKEM public key does not have the correct byte count");
249 }
250
251 BufferSlicer pk_bs(pub_key);
252 auto seed_a = pk_bs.copy<FrodoSeedA>(constants.len_a_bytes());
253 const auto packed_b = pk_bs.take<FrodoPackedMatrix>(constants.d() * constants.n() * constants.n_bar() / 8);
254 BOTAN_ASSERT_NOMSG(pk_bs.empty());
255
256 auto b = FrodoMatrix::unpack(constants, std::tuple(constants.n(), constants.n_bar()), packed_b);
257
258 m_public = std::make_shared<FrodoKEM_PublicKeyInternal>(std::move(constants), std::move(seed_a), std::move(b));
259}
260
261FrodoKEM_PublicKey::FrodoKEM_PublicKey(const AlgorithmIdentifier& alg_id, std::span<const uint8_t> key_bits) :
262 FrodoKEM_PublicKey(key_bits, FrodoKEMMode(alg_id.oid())) {}
263
265 m_public = std::make_shared<FrodoKEM_PublicKeyInternal>(
266 other.m_public->constants(), other.m_public->seed_a(), other.m_public->b());
267}
268
270 if(this != &other) {
271 m_public = std::make_shared<FrodoKEM_PublicKeyInternal>(
272 other.m_public->constants(), other.m_public->seed_a(), other.m_public->b());
273 }
274 return *this;
275}
276
280
282 return m_public->constants().mode().object_identifier();
283}
284
286 return m_public->constants().n();
287}
288
290 return m_public->constants().estimated_strength();
291}
292
293std::vector<uint8_t> FrodoKEM_PublicKey::raw_public_key_bits() const {
294 return concat<std::vector<uint8_t>>(m_public->seed_a(), m_public->b().pack(m_public->constants()));
295}
296
297std::vector<uint8_t> FrodoKEM_PublicKey::public_key_bits() const {
298 // Currently, there isn't a finalized definition of an ASN.1 structure for
299 // FrodoKEM public keys. Therefore, we return the raw public key bits.
300 return raw_public_key_bits();
301}
302
303bool FrodoKEM_PublicKey::check_key(RandomNumberGenerator& /*rng*/, bool /*strong*/) const {
304 // The public key consists of (seed_a, b) where b is a matrix of elements
305 // mod q = 2^d. Length validation is performed in the constructor, and bit
306 // unpacking naturally constrains all matrix elements to [0, 2^d - 1] which
307 // is the full valid range, leaving no further structural checks to perform.
308 return true;
309}
310
311std::unique_ptr<Private_Key> FrodoKEM_PublicKey::generate_another(RandomNumberGenerator& rng) const {
312 return std::make_unique<FrodoKEM_PrivateKey>(rng, m_public->constants().mode());
313}
314
315std::unique_ptr<PK_Ops::KEM_Encryption> FrodoKEM_PublicKey::create_kem_encryption_op(std::string_view params,
316 std::string_view provider) const {
317 if(provider.empty() || provider == "base") {
318 return std::make_unique<Frodo_KEM_Encryptor>(m_public, params);
319 }
320 throw Provider_Not_Found(algo_name(), provider);
321}
322
323//
324// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
325//
326
328 FrodoKEMConstants constants(mode);
329 auto shake = constants.create_xof();
330
331 auto s = rng.random_vec<FrodoSeedS>(constants.len_sec_bytes());
332 const auto seed_se = rng.random_vec<FrodoSeedSE>(constants.len_se_bytes());
333 const auto z = rng.random_vec<FrodoSeedZ>(constants.len_a_bytes());
334
335 CT::poison_all(s, seed_se);
336
337 shake->update(z);
338 auto seed_a = shake->output<FrodoSeedA>(constants.len_a_bytes());
339 shake->clear();
340
341 shake->update(constants.keygen_domain_separator());
342 shake->update(seed_se);
343
344 auto sample_generator = FrodoMatrix::make_sample_generator(constants, *shake);
345 auto s_trans = sample_generator(std::tuple(constants.n_bar(), constants.n()));
346 auto e = sample_generator(std::tuple(constants.n(), constants.n_bar()));
347 shake->clear();
348
349 auto b = FrodoMatrix::mul_add_as_plus_e(constants, s_trans, e, seed_a);
350
351 CT::unpoison_all(s, s_trans, b);
352
353 m_public = std::make_shared<FrodoKEM_PublicKeyInternal>(std::move(constants), std::move(seed_a), std::move(b));
354 m_private = std::make_shared<FrodoKEM_PrivateKeyInternal>(std::move(s), std::move(s_trans));
355}
356
357FrodoKEM_PrivateKey::FrodoKEM_PrivateKey(std::span<const uint8_t> sk, FrodoKEMMode mode) {
358 FrodoKEMConstants constants(mode);
359
360 if(sk.size() != constants.len_private_key_bytes()) {
361 throw Invalid_Argument("FrodoKEM private key does not have the correct byte count");
362 }
363
364 BufferSlicer sk_bs(sk);
365 auto s = sk_bs.copy<FrodoSeedS>(constants.len_sec_bytes());
366 auto seed_a = sk_bs.copy<FrodoSeedA>(constants.len_a_bytes());
367 const auto packed_b = sk_bs.take<FrodoPackedMatrix>(constants.d() * constants.n() * constants.n_bar() / 8);
368 const auto s_trans_bytes = sk_bs.take<FrodoSerializedMatrix>(constants.n_bar() * constants.n() * 2);
369 const auto pkh = sk_bs.copy<FrodoPublicKeyHash>(constants.len_sec_bytes());
370 BOTAN_ASSERT_NOMSG(sk_bs.empty());
371
372 auto b = FrodoMatrix::unpack(constants, std::tuple(constants.n(), constants.n_bar()), packed_b);
373 auto s_trans = FrodoMatrix::deserialize({constants.n_bar(), constants.n()}, s_trans_bytes);
374
375 m_public = std::make_shared<FrodoKEM_PublicKeyInternal>(std::move(constants), std::move(seed_a), std::move(b));
376 m_private = std::make_shared<FrodoKEM_PrivateKeyInternal>(std::move(s), std::move(s_trans));
377
378 BOTAN_STATE_CHECK(pkh == m_public->hash());
379}
380
381FrodoKEM_PrivateKey::FrodoKEM_PrivateKey(const AlgorithmIdentifier& alg_id, std::span<const uint8_t> key_bits) :
382 FrodoKEM_PrivateKey(key_bits, FrodoKEMMode(alg_id.oid())) {}
383
384std::unique_ptr<Public_Key> FrodoKEM_PrivateKey::public_key() const {
385 return std::make_unique<FrodoKEM_PublicKey>(*this);
386}
387
389 if(!FrodoKEM_PublicKey::check_key(rng, strong)) {
390 return false;
391 }
392
393 if(strong) {
394 PK_KEM_Encryptor enc(*this, "Raw");
395 PK_KEM_Decryptor dec(*this, rng, "Raw");
396 const auto [c, K] = KEM_Encapsulation::destructure(enc.encrypt(rng));
397 const auto K_prime = dec.decrypt(c);
398 return K == K_prime;
399 }
400
401 return true;
402}
403
405 return raw_private_key_bits(); // TODO: check if we need to do something else here
406}
407
409 return concat<secure_vector<uint8_t>>(m_private->s(),
410 m_public->seed_a(),
411 m_public->b().pack(m_public->constants()),
412 m_private->s_trans().serialize(),
413 m_public->hash());
414}
415
416std::unique_ptr<PK_Ops::KEM_Decryption> FrodoKEM_PrivateKey::create_kem_decryption_op(RandomNumberGenerator& rng,
417 std::string_view params,
418 std::string_view provider) const {
419 BOTAN_UNUSED(rng);
420 if(provider.empty() || provider == "base") {
421 return std::make_unique<Frodo_KEM_Decryptor>(m_public, m_private, params);
422 }
423 throw Provider_Not_Found(algo_name(), provider);
424}
425
426} // namespace Botan
#define BOTAN_UNUSED
Definition assert.h:144
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75
#define BOTAN_STATE_CHECK(expr)
Definition assert.h:49
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
FrodoKEM_PrivateKey(RandomNumberGenerator &rng, FrodoKEMMode mode)
Definition frodokem.cpp:327
std::unique_ptr< PK_Ops::KEM_Decryption > create_kem_decryption_op(RandomNumberGenerator &rng, std::string_view params, std::string_view provider) const override
Definition frodokem.cpp:416
secure_vector< uint8_t > raw_private_key_bits() const override
Definition frodokem.cpp:408
bool check_key(RandomNumberGenerator &rng, bool strong) const override
Definition frodokem.cpp:388
secure_vector< uint8_t > private_key_bits() const override
Definition frodokem.cpp:404
std::unique_ptr< Public_Key > public_key() const override
Definition frodokem.cpp:384
size_t estimated_strength() const override
Definition frodokem.cpp:289
AlgorithmIdentifier algorithm_identifier() const override
Definition frodokem.cpp:277
std::unique_ptr< PK_Ops::KEM_Encryption > create_kem_encryption_op(std::string_view params, std::string_view provider) const override
Definition frodokem.cpp:315
size_t key_length() const override
Definition frodokem.cpp:285
std::shared_ptr< FrodoKEM_PublicKeyInternal > m_public
Definition frodokem.h:75
FrodoKEM_PublicKey(std::span< const uint8_t > pub_key, FrodoKEMMode mode)
Definition frodokem.cpp:245
std::unique_ptr< Private_Key > generate_another(RandomNumberGenerator &rng) const final
Definition frodokem.cpp:311
std::vector< uint8_t > public_key_bits() const override
Definition frodokem.cpp:297
FrodoKEM_PublicKey & operator=(const FrodoKEM_PublicKey &other)
Definition frodokem.cpp:269
std::string algo_name() const override
Definition frodokem.h:46
bool check_key(RandomNumberGenerator &rng, bool strong) const override
Definition frodokem.cpp:303
std::vector< uint8_t > raw_public_key_bits() const override
Definition frodokem.cpp:293
OID object_identifier() const override
Definition frodokem.cpp:281
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)
static std::pair< std::vector< uint8_t >, secure_vector< uint8_t > > destructure(KEM_Encapsulation &&kem)
Definition pubkey.h:580
void decrypt(std::span< uint8_t > out_shared_key, std::span< const uint8_t > encap_key, size_t desired_shared_key_len=32, std::span< const uint8_t > salt={})
Definition pubkey.cpp:204
KEM_Encapsulation encrypt(RandomNumberGenerator &rng, size_t desired_shared_key_len=32, std::span< const uint8_t > salt={})
Definition pubkey.h:664
void random_vec(std::span< uint8_t > v)
Definition rng.h:204
constexpr Mask< T > conditional_copy_mem(Mask< T > mask, T *dest, const T *if_set, const T *if_unset, size_t elems)
Definition ct_utils.h:732
constexpr void poison_all(const Ts &... ts)
Definition ct_utils.h:201
constexpr auto scoped_poison(const Ts &... xs)
Definition ct_utils.h:222
constexpr void unpoison_all(const Ts &... ts)
Definition ct_utils.h:207
constexpr void unpoison(const T *p, size_t n)
Definition ct_utils.h:67
constexpr void poison(const T *p, size_t n)
Definition ct_utils.h:56
Strong< secure_vector< uint8_t >, struct FrodoSeedSE_ > FrodoSeedSE
Definition frodo_types.h:29
Strong< secure_vector< uint8_t >, struct FrodoSerializedMatrix_ > FrodoSerializedMatrix
Definition frodo_types.h:44
Strong< std::vector< uint8_t >, struct FrodoSeedZ_ > FrodoSeedZ
Definition frodo_types.h:32
Strong< secure_vector< uint8_t >, struct FrodoIntermediateSharedSecret_ > FrodoIntermediateSharedSecret
Definition frodo_types.h:56
Strong< std::vector< uint8_t >, struct FrodoPublicKeyHash_ > FrodoPublicKeyHash
Definition frodo_types.h:38
constexpr auto concat(Rs &&... ranges)
Definition concat_util.h:90
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:68
Strong< std::vector< uint8_t >, struct FrodoSeedA_ > FrodoSeedA
Definition frodo_types.h:23
Strong< secure_vector< uint8_t >, struct FrodoPlaintext_ > FrodoPlaintext
Definition frodo_types.h:50
Strong< std::vector< uint8_t >, struct FrodoSalt_ > FrodoSalt
Definition frodo_types.h:53
Strong< std::vector< uint8_t >, struct FrodoPackedMatrix_ > FrodoPackedMatrix
Definition frodo_types.h:41
Strong< secure_vector< uint8_t >, struct FrodoSeedS_ > FrodoSeedS
Definition frodo_types.h:26