11#include <botan/internal/cmce_field_ordering.h>
13#include <botan/cmce.h>
14#include <botan/mem_ops.h>
15#include <botan/internal/loadstor.h>
27template <std::
unsigned_
integral T1, std::
unsigned_
integral T2>
28 requires(
sizeof(T1) <= 8 &&
sizeof(T2) <= 8)
29void cond_swap_pair(
CT::Mask<uint64_t> cond_mask, std::pair<T1, T2>& a, std::pair<T1, T2>&
b) {
34template <std::
unsigned_
integral T1, std::
unsigned_
integral T2>
35void compare_and_swap_pair(std::span<std::pair<T1, T2>> a,
size_t i,
size_t k,
size_t l) {
36 static_assert(
sizeof(T1) <=
sizeof(uint64_t) &&
sizeof(T2) <=
sizeof(uint64_t),
37 "Types T1 and T2 must be at most 64 bits wide");
40 cond_swap_pair(swap_required_mask, a[i], a[l]);
43 cond_swap_pair(swap_required_mask, a[i], a[l]);
48template <std::
unsigned_
integral T1, std::
unsigned_
integral T2>
49void bitonic_sort_pair(std::span<std::pair<T1, T2>> a) {
50 const size_t n = a.size();
53 for(
size_t k = 2; k <= n; k *= 2) {
54 for(
size_t j = k / 2; j > 0; j /= 2) {
55 for(
size_t i = 0; i < n; ++i) {
56 const size_t l = i ^ j;
58 compare_and_swap_pair(a, i, k, l);
65template <std::
unsigned_
integral T>
66T min(
const T& a,
const T&
b) {
68 return mask.select(a,
b);
76template <std::
unsigned_
integral T1, std::
unsigned_
integral T2>
77std::vector<std::pair<T1, T2>> zip(std::span<const T1> vec_1, std::span<const T2> vec_2) {
78 BOTAN_ARG_CHECK(vec_1.size() == vec_2.size(),
"Vectors' dimensions do not match");
79 std::vector<std::pair<T1, T2>> vec_zipped;
80 vec_zipped.reserve(vec_1.size());
81 for(
size_t i = 0; i < vec_1.size(); ++i) {
82 vec_zipped.push_back(std::make_pair(vec_1[i], vec_2[i]));
87template <std::
unsigned_
integral T1, std::
unsigned_
integral T2>
88std::pair<secure_vector<T1>,
secure_vector<T2>> unzip(
const std::span<std::pair<T1, T2>>& vec_zipped) {
91 res.first.reserve(vec_zipped.size());
92 res.second.reserve(vec_zipped.size());
94 for(
const auto& [elem1, elem2] : vec_zipped) {
95 res.first.push_back(elem1);
96 res.second.push_back(elem2);
102std::vector<std::pair<uint32_t, uint16_t>> enumerate(std::span<const uint32_t> vec) {
105 std::vector<std::pair<uint32_t, uint16_t>> enumerated;
107 std::transform(vec.begin(), vec.end(), std::back_inserter(enumerated), [ctr = uint16_t(0)](uint32_t elem)
mutable {
108 return std::make_pair(elem, ctr++);
122 auto a_pi_zipped = enumerate(a);
123 CMCE_CT::bitonic_sort_pair(std::span(a_pi_zipped));
126 std::tie(a, pi_sorted.get()) = unzip(std::span(a_pi_zipped));
128 return std::make_pair(a, pi_sorted);
137 reversed_bits >>= (
sizeof(uint16_t) * 8 - m);
138 return Classic_McEliece_GF(
CmceGfElem(reversed_bits), modulus);
145 auto pi_c_zipped = zip(pi, c);
146 CMCE_CT::bitonic_sort_pair(std::span(pi_c_zipped));
149 std::transform(pi_c_zipped.begin(), pi_c_zipped.end(), std::back_inserter(c_sorted), [](
const auto& pair) {
158 auto p_new = composeinv(p, q);
159 q = composeinv(q, p);
160 p = std::move(p_new);
169 const auto n = pi.size();
177 for(
size_t x = 0; x < n; ++x) {
178 p.at(x) = pi.at(x ^ 1);
181 for(
size_t x = 0; x < n; ++x) {
182 q.at(x) = pi.at(x) ^ 1;
186 std::iota(range_n.begin(), range_n.end(),
static_cast<uint16_t
>(0));
187 auto piinv = composeinv(range_n, pi);
189 simultaneous_composeinv(p, q);
192 for(uint16_t x = 0;
static_cast<size_t>(x) < n; ++x) {
193 c.at(x) = CMCE_CT::min(x, p.at(x));
196 simultaneous_composeinv(p, q);
198 for(
size_t i = 1; i < m - 1; ++i) {
199 auto cp = composeinv(c, q);
200 simultaneous_composeinv(p, q);
201 for(
size_t x = 0; x < n; ++x) {
202 c.at(x) = CMCE_CT::min(c.at(x), cp.at(x));
207 for(
size_t j = 0; j < n / 2; ++j) {
208 f.at(j) = c.at(2 * j) % 2;
212 for(uint16_t x = 0; size_t(x) < n; ++x) {
213 big_f.at(x) = x ^ f.at(x / 2);
216 auto fpi = composeinv(big_f, piinv);
219 for(
size_t k = 0; k < n / 2; ++k) {
220 l.at(k) = fpi.at(2 * k) % 2;
224 for(uint16_t y = 0; size_t(y) < n; ++y) {
225 big_l.at(y) = y ^ l.at(y / 2);
228 auto big_m = composeinv(fpi, big_l);
232 for(
size_t j = 0; j < n / 2; ++j) {
233 subm0.at(j) = big_m.at(2 * j) / 2;
234 subm1.at(j) = big_m.at(2 * j + 1) / 2;
237 auto subz0 = generate_control_bits_internal(subm0);
238 auto subz1 = generate_control_bits_internal(subm1);
241 for(
size_t j = 0; j < subz0.size(); ++j) {
242 z.at(2 * j) = subz0.at(j);
243 z.at(2 * j + 1) = subz1.at(j);
249CT::Choice ct_has_adjacent_duplicates(std::span<const uint32_t> vec) {
251 for(
size_t i = 0; i < vec.size() - 1; ++i) {
254 return mask.as_choice();
264 auto [sorted_a, pi] = create_pi(std::move(a));
265 if(ct_has_adjacent_duplicates(sorted_a).as_bool()) {
276 std::vector<Classic_McEliece_GF> n_alphas_vec;
278 std::transform(m_pi.begin(), m_pi.begin() + n, std::back_inserter(n_alphas_vec), [
this](uint16_t pi_elem) {
279 return from_pi(CmcePermutationElement(pi_elem), m_poly_f, Classic_McEliece_GF::log_q_from_mod(m_poly_f));
287 const auto control_bits_as_words = generate_control_bits_internal(m_pi.
get());
289 for(
size_t i = 0; i < control_bits.size(); ++i) {
290 control_bits.at(i) = control_bits_as_words.at(i);
301 const uint16_t n = uint16_t(1) << params.
m();
303 std::iota(pi.begin(), pi.end(),
static_cast<uint16_t
>(0));
304 for(
size_t i = 0; i < 2 * params.
m() - 1; ++i) {
305 const size_t gap = size_t(1) << std::min(i, 2 * params.
m() - 2 - i);
306 for(
size_t j = 0; j < size_t(n / 2); ++j) {
307 const size_t pos = (j % gap) + 2 * gap * (j / gap);
309 mask.conditional_swap(pi[pos], pi[pos + gap]);
321 size_t p_counter = 0;
326 (mask_is_pivot_set & mask_is_current_pivot)
327 .conditional_swap(m_pi.
get().at(col_offset + col), m_pi.
get().at(col_offset + p_idx - 1));
#define BOTAN_ASSERT_NOMSG(expr)
#define BOTAN_DEBUG_ASSERT(expr)
#define BOTAN_ARG_CHECK(expr, msg)
void conditional_swap(U &x, U &y) const
static constexpr Mask< T > expand(T v)
static constexpr Mask< T > is_equal(T x, T y)
static constexpr Mask< T > is_gt(T x, T y)
static constexpr Mask< T > is_lt(T x, T y)
static constexpr Mask< T > cleared()
Represents a field ordering for the Classic McEliece cryptosystem.
static std::optional< Classic_McEliece_Field_Ordering > create_field_ordering(const Classic_McEliece_Parameters ¶ms, StrongSpan< const CmceOrderingBits > random_bits)
Creates a field ordering from a random bit sequence. Corresponds to the algorithm described in Classi...
static Classic_McEliece_Field_Ordering create_from_control_bits(const Classic_McEliece_Parameters ¶ms, const secure_bitvector &control_bits)
Create the field ordering from the control bits of a benes network.
secure_bitvector alphas_control_bits() const
Generates the control bits of the benes network corresponding to the field ordering.
void permute_with_pivots(const Classic_McEliece_Parameters ¶ms, const CmceColumnSelection &pivots)
Permute the field ordering with the given pivots.
std::vector< Classic_McEliece_GF > alphas(size_t n) const
Returns the field ordering as a vector of all alphas from alpha_0 to alpha_{n-1}.
size_t m() const
The degree of the Classic McEliece instance's underlying Galois Field, i.e. GF(q) = GF(2^m).
size_t q() const
The field size of the Classic McEliece instance's underlying Galois Field, i.e. GF(q) is the underlyi...
CmceGfMod poly_f() const
The monic irreducible polynomial f(z) of degree m over GF(2). Used for modular reduction in GF(2^m).
static constexpr size_t nu()
Constant nu for semi-systematic matrix creation. (see Classic McEliece ISO 7.2.3)
static constexpr size_t mu()
Constant mu for semi-systematic matrix creation. (see Classic McEliece ISO 7.2.3)
size_t pk_no_rows() const
The number of rows in the public key's matrix.
static constexpr size_t sigma2()
Constant for field-ordering generation. (see Classic McEliece ISO 8.2)
decltype(auto) size() const noexcept(noexcept(this->m_span.size()))
Strong< uint16_t, struct CmceGfMod_ > CmceGfMod
Represents a GF(q) modulus.
bitvector_base< secure_allocator > secure_bitvector
constexpr bool is_power_of_2(T arg)
Strong< uint16_t, struct CmcePermutationElement_ > CmcePermutationElement
Represents an element of a permuation (pi in spec). Used in field ordering creation.
constexpr T ct_reverse_bits(T b)
Strong< uint16_t, struct CmceGfElem_ > CmceGfElem
Represents a GF(q) element.
Strong< secure_vector< uint16_t >, struct CmcePermutation_ > CmcePermutation
Represents a permutation (pi in spec). Used in field ordering creation.
constexpr auto concat(Rs &&... ranges)
constexpr auto load_le(ParamTs &&... params)
std::vector< T, secure_allocator< T > > secure_vector
constexpr uint8_t ceil_log2(T x)