Botan 3.11.0
Crypto and TLS for C&
cmce_encaps.cpp
Go to the documentation of this file.
1/*
2 * Classic McEliece Encapsulation
3 * Based on the public domain reference implementation by the designers
4 * (https://classic.mceliece.org/impl.html - released in Oct 2022 for NISTPQC-R4)
5 *
6 * (C) 2023 Jack Lloyd
7 * 2023,2024 Fabian Albert, Amos Treiber - Rohde & Schwarz Cybersecurity
8 *
9 * Botan is released under the Simplified BSD License (see license.txt)
10 **/
11
12#include <botan/internal/cmce_encaps.h>
13
14#include <botan/rng.h>
15#include <botan/internal/buffer_slicer.h>
16#include <botan/internal/buffer_stuffer.h>
17
18namespace Botan {
19
20CmceCodeWord Classic_McEliece_Encryptor::encode(const Classic_McEliece_Parameters& params,
21 const CmceErrorVector& e,
22 const Classic_McEliece_Matrix& mat) const {
23 return mat.mul(params, e);
24}
25
26std::optional<CmceErrorVector> Classic_McEliece_Encryptor::fixed_weight_vector_gen(
27 const Classic_McEliece_Parameters& params, RandomNumberGenerator& rng) const {
28 const auto rand = rng.random_vec((params.sigma1() / 8) * params.tau());
29 CT::poison(rand);
30 const uint16_t mask_m = (uint32_t(1) << params.m()) - 1; // Only take m least significant bits
32 a_values.reserve(params.tau());
33 BufferSlicer rand_slicer(rand);
34
35 // Steps 2 & 3: Create d_j from uniform random bits. The first t d_j entries
36 // in range {0,...,n-1} are defined as a_0,...,a_(t-1). ...
37 for(size_t j = 0; j < params.tau(); ++j) {
38 auto d = load_le<uint16_t>(rand_slicer.take(params.sigma1() / 8).data(), 0);
39 // This is not CT, but neither is the reference implementation here.
40 // This side channel only leaks which random elements are selected and which are dropped,
41 // but no information about their content is leaked.
42 d &= mask_m;
43 const bool d_in_range = d < params.n();
44 CT::unpoison(d_in_range);
45 if(d_in_range && a_values.size() < params.t()) {
46 a_values.push_back(d);
47 }
48 }
49 if(a_values.size() < params.t()) {
50 // Step 3: ... If fewer than t of such elements exist restart
51 return std::nullopt;
52 }
53
54 // Step 4: Restart if not all a_i are distinct
55 for(size_t i = 1; i < params.t(); ++i) {
56 for(size_t j = 0; j < i; ++j) {
57 const bool a_i_j_equal = a_values.at(i) == a_values.at(j);
58 CT::unpoison(a_i_j_equal);
59 if(a_i_j_equal) {
60 return std::nullopt;
61 }
62 }
63 }
64
65 secure_vector<uint8_t> a_value_byte(params.t());
66 secure_vector<uint8_t> e_bytes(ceil_tobytes(params.n()));
67
68 // Step 5: Set all bits of e at the positions of a_values
69 // Prepare the associated byte in e_bytes that is represented by each bit index in a_values
70 // if we e is represented as a byte vector
71 for(size_t j = 0; j < a_values.size(); ++j) {
72 a_value_byte[j] = 1 << (a_values[j] % 8);
73 }
74
75 for(size_t i = 0; i < params.n() / 8; ++i) {
76 for(size_t j = 0; j < a_values.size(); ++j) {
77 // If the current byte is the one that is represented by the current bit index in a_values
78 // then set the bit in e_bytes (in-byte position prepared above)
79 auto mask = CT::Mask<uint16_t>::is_equal(static_cast<uint16_t>(i), static_cast<uint16_t>(a_values[j] >> 3));
80 e_bytes[i] |= mask.if_set_return(a_value_byte[j]);
81 }
82 }
83
84 return CmceErrorVector(secure_bitvector(e_bytes, params.n()));
85}
86
87void Classic_McEliece_Encryptor::raw_kem_encrypt(std::span<uint8_t> out_encapsulated_key,
88 std::span<uint8_t> out_shared_key,
90 BOTAN_ARG_CHECK(out_encapsulated_key.size() == m_key->params().ciphertext_size(),
91 "Incorrect encapsulated key output length");
92 BOTAN_ARG_CHECK(out_shared_key.size() == m_key->params().hash_out_bytes(), "Incorrect shared key output length");
93
94 const auto& params = m_key->params();
95
96 // Call fixed_weight until it is successful to
97 // create a random error vector e of weight tau
98 const CmceErrorVector e = [&] {
99 // Emergency abort in case unexpected logical error to prevent endless loops
100 // Success probability: >24% per attempt (25% that elements are distinct * 96% enough elements are in range)
101 // => 647 attempts for 2^(-256) fail probability
102 constexpr size_t MAX_ATTEMPTS = 647;
103 for(size_t attempt = 0; attempt < MAX_ATTEMPTS; ++attempt) {
104 if(auto maybe_e = fixed_weight_vector_gen(params, rng)) {
105 return maybe_e.value();
106 }
107 }
108 throw Internal_Error("Cannot created fixed weight vector. Is your RNG broken?");
109 }();
110
111 auto hash_func = params.hash_func();
112
113 BufferStuffer big_c_stuf(out_encapsulated_key);
114 const auto e_bytes = e.get().to_bytes();
115 // Compute and store ciphertext C/C_0 from spec
116 const auto big_c_0 = encode(params, e, m_key->matrix());
117 big_c_0.to_bytes(big_c_stuf.next(ceil_tobytes(big_c_0.size())));
118 if(params.is_pc()) {
119 // Compute and store ciphertext C_1 from spec
120 hash_func->update(0x02);
121 hash_func->update(e_bytes);
122 hash_func->final(big_c_stuf.next(hash_func->output_length()));
123 }
124 BOTAN_ASSERT_NOMSG(big_c_stuf.full());
125
126 // Compute K = Hash(1,e,C) from spec
127 hash_func->update(0x01);
128 hash_func->update(e_bytes);
129 hash_func->update(out_encapsulated_key);
130 hash_func->final(out_shared_key);
131 CT::unpoison_all(out_encapsulated_key, out_shared_key);
132}
133
134} // namespace Botan
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:33
Helper class to ease in-place marshalling of concatenated fixed-length values.
constexpr std::span< uint8_t > next(size_t bytes)
constexpr bool full() const
static constexpr Mask< T > is_equal(T x, T y)
Definition ct_utils.h:442
void raw_kem_encrypt(std::span< uint8_t > out_encapsulated_key, std::span< uint8_t > out_shared_key, RandomNumberGenerator &rng) override
Representation of the binary Classic McEliece matrix H, with H = (I_mt | T).
Definition cmce_matrix.h:26
OutT to_bytes() const
Definition bitvector.h:493
constexpr T & get() &
Definition strong_type.h:85
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_bitvector, struct CmceCodeWord_ > CmceCodeWord
Represents C of decapsulation.
Definition cmce_types.h:52
bitvector_base< secure_allocator > secure_bitvector
Definition bitvector.h:1304
Strong< secure_bitvector, struct CmceErrorVector_ > CmceErrorVector
Represents e of encapsulation.
Definition cmce_types.h:49
BOTAN_FORCE_INLINE constexpr T ceil_tobytes(T bits)
Definition bit_ops.h:175
constexpr auto load_le(ParamTs &&... params)
Definition loadstor.h:495
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:68