Botan 3.10.0
Crypto and TLS for C&
frodo_matrix.cpp
Go to the documentation of this file.
1/*
2 * FrodoKEM matrix logic
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/internal/frodo_matrix.h>
14
15#include <botan/assert.h>
16#include <botan/xof.h>
17#include <botan/internal/bit_ops.h>
18#include <botan/internal/frodo_constants.h>
19#include <botan/internal/loadstor.h>
20#include <botan/internal/stl_util.h>
21
22#if defined(BOTAN_HAS_FRODOKEM_AES)
23 #include <botan/internal/frodo_aes_generator.h>
24#endif
25
26#if defined(BOTAN_HAS_FRODOKEM_SHAKE)
27 #include <botan/internal/frodo_shake_generator.h>
28#endif
29
30#include <array>
31#include <span>
32#include <utility>
33#include <vector>
34
35namespace Botan {
36
37namespace {
38
39secure_vector<uint16_t> make_elements_vector(const FrodoMatrix::Dimensions& dimensions) {
40 return secure_vector<uint16_t>(static_cast<size_t>(std::get<0>(dimensions)) * std::get<1>(dimensions));
41}
42
43std::function<void(std::span<uint8_t> out, uint16_t i)> make_row_generator(const FrodoKEMConstants& constants,
45#if defined(BOTAN_HAS_FRODOKEM_AES)
46 if(constants.mode().is_aes()) {
47 return create_aes_row_generator(constants, seed_a);
48 }
49#endif
50
51#if defined(BOTAN_HAS_FRODOKEM_SHAKE)
52 if(constants.mode().is_shake()) {
53 return create_shake_row_generator(constants, seed_a);
54 }
55#endif
56
57 // If we don't have AES in this build, the instantiation of the FrodoKEM instance
58 // is blocked upstream already. Hence, assert is save here.
60}
61
62} // namespace
63
67 BOTAN_ASSERT_NOMSG(r.size() % 2 == 0);
68 const auto n = r.size() / 2;
69
70 auto elements = make_elements_vector(dimensions);
71 BOTAN_ASSERT_NOMSG(n == elements.size());
72
73 load_le<uint16_t>(elements.data(), r.data(), n);
74
75 for(auto& elem : elements) {
76 const auto prnd = CT::value_barrier(static_cast<uint16_t>(elem >> 1)); // Drop the least significant bit
77 const auto sign = CT::Mask<uint16_t>::expand_bit(elem, 0); // Pick the least significant bit
78
79 uint32_t sample = 0; // Avoid integral promotion
80
81 // No need to compare with the last value.
82 for(size_t j = 0; j < constants.cdf_table_len() - 1; ++j) {
83 // Constant time comparison: 1 if CDF_TABLE[j] < s, 0 otherwise.
84 sample += CT::Mask<uint16_t>::is_lt(constants.cdf_table_at(j), prnd).if_set_return(1);
85 }
86 // Assuming that sign is either 0 or 1, flips sample iff sign = 1
87 const uint16_t sample_u16 = static_cast<uint16_t>(sample);
88
89 elem = sign.select(~sample_u16 + 1, sample_u16);
90 }
91
92 return FrodoMatrix(dimensions, std::move(elements));
93}
94
96 const FrodoKEMConstants& constants, Botan::XOF& shake) {
97 return [&constants, &shake](const FrodoMatrix::Dimensions& dimensions) mutable {
98 return sample(constants,
100 shake.output<FrodoSampleR>(sizeof(uint16_t) * std::get<0>(dimensions) * std::get<1>(dimensions)));
101 };
102}
103
105 m_dim1(std::get<0>(dims)), m_dim2(std::get<1>(dims)), m_elements(make_elements_vector(dims)) {}
106
108 const FrodoMatrix& s,
109 const FrodoMatrix& e,
111 BOTAN_ASSERT(std::get<0>(e.dimensions()) == std::get<1>(s.dimensions()) &&
112 std::get<1>(e.dimensions()) == std::get<0>(s.dimensions()),
113 "FrodoMatrix dimension mismatch of E and S");
114 BOTAN_ASSERT(std::get<0>(e.dimensions()) == constants.n() && std::get<1>(e.dimensions()) == constants.n_bar(),
115 "FrodoMatrix dimension mismatch of new matrix dimensions and E");
116
117 auto elements = make_elements_vector(e.dimensions());
118 auto row_generator = make_row_generator(constants, seed_a);
119
120 /*
121 We perform 4 invocations of SHAKE128 per iteration to obtain n 16-bit values per invocation.
122 a_row_data contains the 16-bit values of the current 4 rows. a_row_data_bytes represents the corresponding bytes.
123 */
124 std::vector<uint16_t> a_row_data(4 * constants.n(), 0);
125 // TODO: maybe use std::as_bytes() instead
126 // (take extra care, as it produces a std::span<std::byte>)
127 std::span<uint8_t> a_row_data_bytes(reinterpret_cast<uint8_t*>(a_row_data.data()),
128 sizeof(uint16_t) * a_row_data.size());
129
130 for(size_t i = 0; i < constants.n(); i += 4) {
131 auto a_row = BufferStuffer(a_row_data_bytes);
132
133 // Do 4 invocations to fill 4 rows
134 row_generator(a_row.next(constants.n() * sizeof(uint16_t)), static_cast<uint16_t>(i + 0));
135 row_generator(a_row.next(constants.n() * sizeof(uint16_t)), static_cast<uint16_t>(i + 1));
136 row_generator(a_row.next(constants.n() * sizeof(uint16_t)), static_cast<uint16_t>(i + 2));
137 row_generator(a_row.next(constants.n() * sizeof(uint16_t)), static_cast<uint16_t>(i + 3));
138
139 // Use generated bytes to fill 16-bit data
140 load_le<uint16_t>(a_row_data.data(), a_row_data_bytes.data(), 4 * constants.n());
141
142 for(size_t k = 0; k < constants.n_bar(); ++k) {
143 std::array<uint16_t, 4> sum = {0};
144 for(size_t j = 0; j < constants.n(); ++j) { // Matrix-vector multiplication
145 // Note: we use uint32_t for `sp` to avoid an integral promotion to `int`
146 // when multiplying `sp` with other row values. Otherwise we might
147 // suffer from undefined behaviour due to a signed integer overflow.
148 // See: https://learn.microsoft.com/en-us/cpp/cpp/standard-conversions#integral-promotions
149 const uint32_t sp = s.elements_at(k * constants.n() + j);
150
151 // Go through four lines with same sp
152 sum.at(0) += static_cast<uint16_t>(a_row_data.at(0 * constants.n() + j) * sp);
153 sum.at(1) += static_cast<uint16_t>(a_row_data.at(1 * constants.n() + j) * sp);
154 sum.at(2) += static_cast<uint16_t>(a_row_data.at(2 * constants.n() + j) * sp);
155 sum.at(3) += static_cast<uint16_t>(a_row_data.at(3 * constants.n() + j) * sp);
156 }
157 elements.at((i + 0) * constants.n_bar() + k) = e.elements_at((i + 0) * constants.n_bar() + k) + sum.at(0);
158 elements.at((i + 3) * constants.n_bar() + k) = e.elements_at((i + 3) * constants.n_bar() + k) + sum.at(3);
159 elements.at((i + 2) * constants.n_bar() + k) = e.elements_at((i + 2) * constants.n_bar() + k) + sum.at(2);
160 elements.at((i + 1) * constants.n_bar() + k) = e.elements_at((i + 1) * constants.n_bar() + k) + sum.at(1);
161 }
162 }
163
164 return FrodoMatrix(e.dimensions(), std::move(elements));
165}
166
168 const FrodoMatrix& s,
169 const FrodoMatrix& e,
171 BOTAN_ASSERT(std::get<0>(e.dimensions()) == std::get<0>(s.dimensions()) &&
172 std::get<1>(e.dimensions()) == std::get<1>(s.dimensions()),
173 "FrodoMatrix dimension mismatch of E and S");
174 BOTAN_ASSERT(std::get<0>(e.dimensions()) == constants.n_bar() && std::get<1>(e.dimensions()) == constants.n(),
175 "FrodoMatrix dimension mismatch of new matrix dimensions and E");
176
177 auto elements = e.m_elements;
178 auto row_generator = make_row_generator(constants, seed_a);
179
180 /*
181 We perform 8 invocations of SHAKE128 per iteration to obtain n 16-bit values per invocation.
182 a_row_data contains the 16-bit values of the current 8 rows. a_row_data_bytes represents the corresponding bytes.
183 */
184 std::vector<uint16_t> a_row_data(8 * constants.n(), 0);
185 // TODO: maybe use std::as_bytes()
186 std::span<uint8_t> a_row_data_bytes(reinterpret_cast<uint8_t*>(a_row_data.data()),
187 sizeof(uint16_t) * a_row_data.size());
188
189 // Start matrix multiplication
190 for(size_t i = 0; i < constants.n(); i += 8) {
191 auto a_row = BufferStuffer(a_row_data_bytes);
192
193 // Do 8 invocations to fill 8 rows
194 row_generator(a_row.next(sizeof(uint16_t) * constants.n()), static_cast<uint16_t>(i + 0));
195 row_generator(a_row.next(sizeof(uint16_t) * constants.n()), static_cast<uint16_t>(i + 1));
196 row_generator(a_row.next(sizeof(uint16_t) * constants.n()), static_cast<uint16_t>(i + 2));
197 row_generator(a_row.next(sizeof(uint16_t) * constants.n()), static_cast<uint16_t>(i + 3));
198 row_generator(a_row.next(sizeof(uint16_t) * constants.n()), static_cast<uint16_t>(i + 4));
199 row_generator(a_row.next(sizeof(uint16_t) * constants.n()), static_cast<uint16_t>(i + 5));
200 row_generator(a_row.next(sizeof(uint16_t) * constants.n()), static_cast<uint16_t>(i + 6));
201 row_generator(a_row.next(sizeof(uint16_t) * constants.n()), static_cast<uint16_t>(i + 7));
202
203 // Use generated bytes to fill 16-bit data
204 load_le<uint16_t>(a_row_data.data(), a_row_data_bytes.data(), 8 * constants.n());
205
206 for(size_t j = 0; j < constants.n_bar(); ++j) {
207 uint16_t sum = 0;
208 std::array<uint32_t /* to avoid integral promotion */, 8> sp{};
209 for(size_t p = 0; p < 8; ++p) {
210 sp[p] = s.elements_at(j * constants.n() + i + p);
211 }
212 for(size_t q = 0; q < constants.n(); ++q) {
213 sum = elements.at(j * constants.n() + q);
214 for(size_t p = 0; p < 8; ++p) {
215 sum += static_cast<uint16_t>(sp[p] * a_row_data.at(p * constants.n() + q));
216 }
217 elements.at(j * constants.n() + q) = sum;
218 }
219 }
220 }
221
222 return FrodoMatrix(e.dimensions(), std::move(elements));
223}
224
226 const FrodoMatrix& b,
227 const FrodoMatrix& s,
228 const FrodoMatrix& e) {
229 BOTAN_ASSERT(std::get<0>(b.dimensions()) == std::get<1>(s.dimensions()) &&
230 std::get<1>(b.dimensions()) == std::get<0>(s.dimensions()),
231 "FrodoMatrix dimension mismatch of B and S");
232 BOTAN_ASSERT(std::get<0>(b.dimensions()) == constants.n() && std::get<1>(b.dimensions()) == constants.n_bar(),
233 "FrodoMatrix dimension mismatch of B");
234 BOTAN_ASSERT(std::get<0>(e.dimensions()) == constants.n_bar() && std::get<1>(e.dimensions()) == constants.n_bar(),
235 "FrodoMatrix dimension mismatch of E");
236
237 auto elements = make_elements_vector(e.dimensions());
238
239 for(size_t k = 0; k < constants.n_bar(); ++k) {
240 for(size_t i = 0; i < constants.n_bar(); ++i) {
241 elements.at(k * constants.n_bar() + i) = e.elements_at(k * constants.n_bar() + i);
242 for(size_t j = 0; j < constants.n(); ++j) {
243 elements.at(k * constants.n_bar() + i) += static_cast<uint16_t>(
244 static_cast<uint32_t /* to avoid integral promotion */>(s.elements_at(k * constants.n() + j)) *
245 b.elements_at(j * constants.n_bar() + i));
246 }
247 }
248 }
249
250 return FrodoMatrix(e.dimensions(), std::move(elements));
251}
252
254 const uint64_t mask = (uint64_t(1) << constants.b()) - 1;
255
256 const auto dimensions = std::make_tuple<size_t, size_t>(constants.n_bar(), constants.n_bar());
257 auto elements = make_elements_vector(dimensions);
258
259 BOTAN_ASSERT_NOMSG(in.size() * 8 == constants.n_bar() * constants.n_bar() * constants.b());
260
261 size_t pos = 0;
262 for(size_t i = 0; i < (constants.n_bar() * constants.n_bar()) / 8; ++i) {
263 uint64_t temp = 0;
264 for(size_t j = 0; j < constants.b(); ++j) {
265 temp |= static_cast<uint64_t /* avoiding integral promotion */>(in[i * constants.b() + j]) << (8 * j);
266 }
267 for(size_t j = 0; j < 8; ++j) {
268 elements.at(pos++) = static_cast<uint16_t>((temp & mask) << (constants.d() - constants.b())); // k*2^(D-B)
269 temp >>= constants.b();
270 }
271 }
272
273 return FrodoMatrix(dimensions, std::move(elements));
274}
275
277 // Addition is defined for n_bar x n_bar matrices only
279 BOTAN_ASSERT_NOMSG(std::get<0>(a.dimensions()) == constants.n_bar() &&
280 std::get<1>(a.dimensions()) == constants.n_bar());
281
282 auto elements = make_elements_vector(a.dimensions());
283
284 for(size_t i = 0; i < constants.n_bar() * constants.n_bar(); ++i) {
285 elements.at(i) = a.elements_at(i) + b.elements_at(i);
286 }
287
288 return FrodoMatrix(a.dimensions(), std::move(elements));
289}
290
292 // Subtraction is defined for n_bar x n_bar matrices only
294 BOTAN_ASSERT_NOMSG(std::get<0>(a.dimensions()) == constants.n_bar() &&
295 std::get<1>(a.dimensions()) == constants.n_bar());
296
297 auto elements = make_elements_vector(a.dimensions());
298
299 for(size_t i = 0; i < constants.n_bar() * constants.n_bar(); ++i) {
300 elements.at(i) = a.elements_at(i) - b.elements_at(i);
301 }
302
303 return FrodoMatrix(a.dimensions(), std::move(elements));
304}
305
308 // TODO: Possibly use range-based comparison after #3715 is merged
309 return CT::is_equal(reinterpret_cast<const uint8_t*>(m_elements.data()),
310 reinterpret_cast<const uint8_t*>(other.m_elements.data()),
311 sizeof(decltype(m_elements)::value_type) * m_elements.size());
312}
313
315 Dimensions dimensions = {constants.n_bar(), constants.n_bar()};
316 auto elements = make_elements_vector(dimensions);
317
318 for(size_t i = 0; i < constants.n_bar(); ++i) {
319 for(size_t j = 0; j < constants.n_bar(); ++j) {
320 auto& current = elements.at(i * constants.n_bar() + j);
321 current = 0;
322 for(size_t k = 0; k < constants.n(); ++k) {
323 // Explicitly store the values in 32-bit variables to avoid integral promotion
324 const uint32_t b_ink = b.elements_at(i * constants.n() + k);
325
326 // Since the input is s^T, we multiply the i-th row of b with the j-th row of s^t
327 const uint32_t s_ink = s.elements_at(j * constants.n() + k);
328
329 current += static_cast<uint16_t>(b_ink * s_ink);
330 }
331 }
332 }
333
334 return FrodoMatrix(dimensions, std::move(elements));
335}
336
338 const size_t outlen = packed_size(constants);
339 BOTAN_ASSERT_NOMSG(out.size() == outlen);
340
341 size_t i = 0; // whole bytes already filled in
342 size_t j = 0; // whole uint16_t already copied
343 uint16_t w = 0; // the leftover, not yet copied
344 uint8_t bits = 0; // the number of lsb in w
345
346 while(i < outlen && (j < element_count() || ((j == element_count()) && (bits > 0)))) {
347 /*
348 in: | | |********|********|
349 ^
350 j
351 w : | ****|
352 ^
353 bits
354 out:|**|**|**|**|**|**|**|**|* |
355 ^^
356 ib
357 */
358 uint8_t b = 0; // bits in out[i] already filled in
359 while(b < 8) {
360 const uint8_t nbits = std::min(static_cast<uint8_t>(8 - b), bits);
361 const uint16_t mask = static_cast<uint16_t>(1 << nbits) - 1;
362 const auto t = static_cast<uint8_t>((w >> (bits - nbits)) & mask); // the bits to copy from w to out
363 out[i] = out[i] + static_cast<uint8_t>(t << (8 - b - nbits));
364 b += nbits;
365 bits -= nbits;
366
367 if(bits == 0) {
368 if(j < element_count()) {
369 w = m_elements.at(j);
370 bits = static_cast<uint8_t>(constants.d());
371 j++;
372 } else {
373 break; // the input vector is exhausted
374 }
375 }
376 }
377 if(b == 8) { // out[i] is filled in
378 i++;
379 }
380 }
381}
382
384 FrodoSerializedMatrix out(2 * m_elements.size());
385
386 for(unsigned int i = 0; i < m_elements.size(); ++i) {
387 store_le(m_elements.at(i), out.data() + 2 * i);
388 }
389
390 return out;
391}
392
394 const size_t nwords = (constants.n_bar() * constants.n_bar()) / 8;
395 const uint16_t maskex = static_cast<uint16_t>(1 << constants.b()) - 1;
396 const uint16_t maskq = static_cast<uint16_t>(1 << constants.d()) - 1;
397
398 FrodoPlaintext out(nwords * constants.b());
399
400 size_t index = 0;
401 for(size_t i = 0; i < nwords; i++) {
402 uint64_t templong = 0;
403 for(size_t j = 0; j < 8; j++) {
404 const auto temp =
405 static_cast<uint16_t>(((m_elements.at(index) & maskq) + (1 << (constants.d() - constants.b() - 1))) >>
406 (constants.d() - constants.b()));
407 templong |= static_cast<uint64_t>(temp & maskex) << (constants.b() * j);
408 index++;
409 }
410 for(size_t j = 0; j < constants.b(); j++) {
411 out[i * constants.b() + j] = (templong >> (8 * j)) & 0xFF;
412 }
413 }
414
415 return out;
416}
417
419 const Dimensions& dimensions,
421 const uint8_t lsb = static_cast<uint8_t>(constants.d());
422 const size_t inlen = packed_bytes.size();
423 const size_t outlen = static_cast<size_t>(std::get<0>(dimensions)) * std::get<1>(dimensions);
424
425 BOTAN_ASSERT_NOMSG(inlen == ceil_tobytes(outlen * lsb));
426
427 auto elements = make_elements_vector(dimensions);
428
429 size_t i = 0; // whole uint16_t already filled in
430 size_t j = 0; // whole bytes already copied
431 uint8_t w = 0; // the leftover, not yet copied
432 uint8_t bits = 0; // the number of lsb bits of w
433
434 while(i < outlen && (j < inlen || ((j == inlen) && (bits > 0)))) {
435 /*
436 in: | | | | | | |**|**|...
437 ^
438 j
439 w : | *|
440 ^
441 bits
442 out:| *****| *****| *** | |...
443 ^ ^
444 i b
445 */
446 uint8_t b = 0; // bits in out[i] already filled in
447 while(b < lsb) {
448 const uint8_t nbits = std::min(static_cast<uint8_t>(lsb - b), bits);
449 const uint16_t mask = static_cast<uint16_t>(1 << nbits) - 1;
450 uint8_t t = (w >> (bits - nbits)) & mask; // the bits to copy from w to out
451
452 elements.at(i) = elements.at(i) + static_cast<uint16_t>(t << (lsb - b - nbits));
453 b += nbits;
454 bits -= nbits;
455 w &= static_cast<uint8_t>(~(mask << bits)); // not strictly necessary; mostly for debugging
456
457 if(bits == 0) {
458 if(j < inlen) {
459 w = packed_bytes[j];
460 bits = 8;
461 j++;
462 } else {
463 break; // the input vector is exhausted
464 }
465 }
466 }
467 if(b == lsb) { // out[i] is filled in
468 i++;
469 }
470 }
471
472 return FrodoMatrix(dimensions, std::move(elements));
473}
474
476 auto elements = make_elements_vector(dimensions);
477 BOTAN_ASSERT_NOMSG(elements.size() * 2 == bytes.size());
478 load_le<uint16_t>(elements.data(), bytes.data(), elements.size());
479 return FrodoMatrix(dimensions, std::move(elements));
480}
481
483 // Reduction is inherent if D is 16, because we use uint16_t in m_elements
484 if(constants.d() < sizeof(decltype(m_elements)::value_type) * 8) {
485 const uint16_t mask = static_cast<uint16_t>(1 << constants.d()) - 1;
486 for(auto& elem : m_elements) {
487 elem = elem & mask; // mod q
488 }
489 }
490}
491
492} // namespace Botan
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75
#define BOTAN_ASSERT(expr, assertion_made)
Definition assert.h:62
#define BOTAN_ASSERT_UNREACHABLE()
Definition assert.h:163
Helper class to ease in-place marshalling of concatenated fixed-length values.
Definition stl_util.h:133
static constexpr Mask< T > expand_bit(T v, size_t bit)
Definition ct_utils.h:449
static constexpr Mask< T > is_lt(T x, T y)
Definition ct_utils.h:478
uint16_t cdf_table_at(size_t i) const
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)
void reduce(const FrodoKEMConstants &constants)
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)
FrodoPlaintext decode(const FrodoKEMConstants &constants) const
static FrodoMatrix add(const FrodoKEMConstants &constants, const FrodoMatrix &a, const FrodoMatrix &b)
std::tuple< size_t, size_t > Dimensions
static FrodoMatrix sample(const FrodoKEMConstants &constants, const Dimensions &dimensions, StrongSpan< const FrodoSampleR > r)
CT::Mask< uint8_t > constant_time_compare(const FrodoMatrix &other) const
FrodoPackedMatrix pack(const FrodoKEMConstants &constants) const
static FrodoMatrix encode(const FrodoKEMConstants &constants, StrongSpan< const FrodoPlaintext > in)
Dimensions dimensions() const
FrodoMatrix(Dimensions dims)
static FrodoMatrix unpack(const FrodoKEMConstants &constants, const Dimensions &dimensions, StrongSpan< const FrodoPackedMatrix > packed_bytes)
uint16_t elements_at(size_t i) const
size_t element_count() const
static FrodoMatrix mul_bs(const FrodoKEMConstants &constants, const FrodoMatrix &b_p, const FrodoMatrix &s)
static FrodoMatrix deserialize(const Dimensions &dimensions, StrongSpan< const FrodoSerializedMatrix > bytes)
size_t packed_size(const FrodoKEMConstants &constants) const
FrodoSerializedMatrix serialize() const
decltype(auto) data() noexcept(noexcept(this->m_span.data()))
decltype(auto) size() const noexcept(noexcept(this->m_span.size()))
T output(size_t bytes)
Definition xof.h:153
decltype(auto) data() noexcept(noexcept(this->get().data()))
constexpr T value_barrier(T x)
Definition ct_utils.h:277
constexpr CT::Mask< T > is_equal(const T x[], const T y[], size_t len)
Definition ct_utils.h:826
Strong< secure_vector< uint8_t >, struct FrodoSerializedMatrix_ > FrodoSerializedMatrix
Definition frodo_types.h:44
auto create_shake_row_generator(const FrodoKEMConstants &constants, StrongSpan< const FrodoSeedA > seed_a)
constexpr auto store_le(ParamTs &&... params)
Definition loadstor.h:736
auto create_aes_row_generator(const FrodoKEMConstants &constants, StrongSpan< const FrodoSeedA > seed_a)
BOTAN_FORCE_INLINE constexpr T ceil_tobytes(T bits)
Definition bit_ops.h:168
constexpr auto load_le(ParamTs &&... params)
Definition loadstor.h:495
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:69
Strong< secure_vector< uint8_t >, struct FrodoPlaintext_ > FrodoPlaintext
Definition frodo_types.h:50
Strong< secure_vector< uint8_t >, struct FrodoSampleR_ > FrodoSampleR
Definition frodo_types.h:35