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);
 
  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()) {
 
  269   return Classic_McEliece_Field_Ordering(std::move(pi), params.
poly_f());
 
 
  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) != 0;
 
 
  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]);
 
  313   return Classic_McEliece_Field_Ordering(std::move(pi), params.
poly_f());
 
 
  321      size_t p_counter = 0;
 
  324         p_counter += mask_is_pivot_set.if_set_return(1);
 
  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 > is_equal(T x, T y)
 
static constexpr Mask< T > expand_bool(bool v)
 
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()
 
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}.
 
Represents an element of the finite field GF(q) for q = 2^m.
 
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()))
 
decltype(auto) begin() noexcept(noexcept(this->get().begin()))
 
decltype(auto) end() noexcept(noexcept(this->get().end()))
 
auto at(size_type i) const
 
BOTAN_FORCE_INLINE constexpr bool is_power_of_2(T arg)
 
Strong< uint16_t, struct CmceGfMod_ > CmceGfMod
Represents a GF(q) modulus.
 
bitvector_base< secure_allocator > secure_bitvector
 
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< secure_bitvector, struct CmceColumnSelection_ > CmceColumnSelection
Represents c of private key.
 
constexpr uint8_t ceil_log2(T x)
 
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