12#include <botan/internal/cmce_field_ordering.h>
14#include <botan/internal/loadstor.h>
25template <std::
unsigned_
integral T1, std::
unsigned_
integral T2>
26 requires(
sizeof(T1) <= 8 &&
sizeof(T2) <= 8)
27void cond_swap_pair(
CT::Mask<uint64_t> cond_mask, std::pair<T1, T2>& a, std::pair<T1, T2>& b) {
32template <std::
unsigned_
integral T1, std::
unsigned_
integral T2>
33void compare_and_swap_pair(std::span<std::pair<T1, T2>> a,
size_t i,
size_t k,
size_t l) {
34 static_assert(
sizeof(T1) <=
sizeof(uint64_t) &&
sizeof(T2) <=
sizeof(uint64_t),
35 "Types T1 and T2 must be at most 64 bits wide");
38 cond_swap_pair(swap_required_mask, a[i], a[l]);
41 cond_swap_pair(swap_required_mask, a[i], a[l]);
46template <std::
unsigned_
integral T1, std::
unsigned_
integral T2>
47void bitonic_sort_pair(std::span<std::pair<T1, T2>> a) {
48 const size_t n = a.size();
51 for(
size_t k = 2; k <= n; k *= 2) {
52 for(
size_t j = k / 2; j > 0; j /= 2) {
53 for(
size_t i = 0; i < n; ++i) {
54 const size_t l = i ^ j;
56 compare_and_swap_pair(a, i, k, l);
63template <std::
unsigned_
integral T>
64T min(
const T& a,
const T& b) {
66 return mask.select(a, b);
74template <std::
unsigned_
integral T1, std::
unsigned_
integral T2>
75std::vector<std::pair<T1, T2>> zip(std::span<const T1> vec_1, std::span<const T2> vec_2) {
76 BOTAN_ARG_CHECK(vec_1.size() == vec_2.size(),
"Vectors' dimensions do not match");
77 std::vector<std::pair<T1, T2>> vec_zipped;
78 vec_zipped.reserve(vec_1.size());
79 for(
size_t i = 0; i < vec_1.size(); ++i) {
80 vec_zipped.push_back(std::make_pair(vec_1[i], vec_2[i]));
85template <std::
unsigned_
integral T1, std::
unsigned_
integral T2>
86std::pair<secure_vector<T1>,
secure_vector<T2>> unzip(
const std::span<std::pair<T1, T2>>& vec_zipped) {
89 res.first.reserve(vec_zipped.size());
90 res.second.reserve(vec_zipped.size());
92 for(
const auto& [elem1, elem2] : vec_zipped) {
93 res.first.push_back(elem1);
94 res.second.push_back(elem2);
100std::vector<std::pair<uint32_t, uint16_t>> enumerate(std::span<const uint32_t> vec) {
103 std::vector<std::pair<uint32_t, uint16_t>> enumerated;
105 std::transform(vec.begin(), vec.end(), std::back_inserter(enumerated), [ctr = uint16_t(0)](uint32_t elem)
mutable {
106 return std::make_pair(elem, ctr++);
120 auto a_pi_zipped = enumerate(a);
121 CMCE_CT::bitonic_sort_pair(std::span(a_pi_zipped));
124 std::tie(a, pi_sorted.get()) = unzip(std::span(a_pi_zipped));
126 return std::make_pair(a, pi_sorted);
135 reversed_bits >>= (
sizeof(uint16_t) * 8 - m);
143 auto pi_c_zipped = zip(pi, c);
144 CMCE_CT::bitonic_sort_pair(std::span(pi_c_zipped));
147 std::transform(pi_c_zipped.begin(), pi_c_zipped.end(), std::back_inserter(c_sorted), [](
const auto& pair) {
156 auto p_new = composeinv(p, q);
157 q = composeinv(q, p);
158 p = std::move(p_new);
167 const auto n = pi.size();
175 for(
size_t x = 0; x < n; ++x) {
176 p.at(x) = pi.at(x ^ 1);
179 for(
size_t x = 0; x < n; ++x) {
180 q.at(x) = pi.at(x) ^ 1;
184 std::iota(range_n.begin(), range_n.end(),
static_cast<uint16_t
>(0));
185 auto piinv = composeinv(range_n, pi);
187 simultaneous_composeinv(p, q);
190 for(uint16_t x = 0;
static_cast<size_t>(x) < n; ++x) {
191 c.at(x) = CMCE_CT::min(x, p.at(x));
194 simultaneous_composeinv(p, q);
196 for(
size_t i = 1; i < m - 1; ++i) {
197 auto cp = composeinv(c, q);
198 simultaneous_composeinv(p, q);
199 for(
size_t x = 0; x < n; ++x) {
200 c.at(x) = CMCE_CT::min(c.at(x), cp.at(x));
205 for(
size_t j = 0; j < n / 2; ++j) {
206 f.at(j) = c.at(2 * j) % 2;
210 for(uint16_t x = 0; size_t(x) < n; ++x) {
211 big_f.at(x) = x ^ f.at(x / 2);
214 auto fpi = composeinv(big_f, piinv);
217 for(
size_t k = 0; k < n / 2; ++k) {
218 l.at(k) = fpi.at(2 * k) % 2;
222 for(uint16_t y = 0; size_t(y) < n; ++y) {
223 big_l.at(y) = y ^ l.at(y / 2);
226 auto big_m = composeinv(fpi, big_l);
230 for(
size_t j = 0; j < n / 2; ++j) {
231 subm0.at(j) = big_m.at(2 * j) / 2;
232 subm1.at(j) = big_m.at(2 * j + 1) / 2;
235 auto subz0 = generate_control_bits_internal(subm0);
236 auto subz1 = generate_control_bits_internal(subm1);
239 for(
size_t j = 0; j < subz0.size(); ++j) {
240 z.at(2 * j) = subz0.at(j);
241 z.at(2 * j + 1) = subz1.at(j);
247CT::Choice ct_has_adjacent_duplicates(std::span<const uint32_t> vec) {
249 for(
size_t i = 0; i < vec.size() - 1; ++i) {
252 return mask.as_choice();
262 auto [sorted_a, pi] = create_pi(std::move(a));
263 if(ct_has_adjacent_duplicates(sorted_a).as_bool()) {
267 return Classic_McEliece_Field_Ordering(std::move(pi), params.
poly_f());
274 std::vector<Classic_McEliece_GF> n_alphas_vec;
276 std::transform(m_pi.begin(), m_pi.begin() + n, std::back_inserter(n_alphas_vec), [
this](uint16_t pi_elem) {
277 return from_pi(CmcePermutationElement(pi_elem), m_poly_f, Classic_McEliece_GF::log_q_from_mod(m_poly_f));
285 const auto control_bits_as_words = generate_control_bits_internal(m_pi.get());
287 for(
size_t i = 0; i < control_bits.size(); ++i) {
288 control_bits.at(i) = control_bits_as_words.at(i) != 0;
299 const uint16_t n = uint16_t(1) << params.
m();
301 std::iota(pi.
begin(), pi.
end(),
static_cast<uint16_t
>(0));
302 for(
size_t i = 0; i < 2 * params.
m() - 1; ++i) {
303 const size_t gap = size_t(1) << std::min(i, 2 * params.
m() - 2 - i);
304 for(
size_t j = 0; j < size_t(n) / 2; ++j) {
305 const size_t pos = (j % gap) + 2 * gap * (j / gap);
307 mask.conditional_swap(pi[pos], pi[pos + gap]);
311 return Classic_McEliece_Field_Ordering(std::move(pi), params.
poly_f());
319 size_t p_counter = 0;
322 p_counter += mask_is_pivot_set.if_set_return(1);
324 (mask_is_pivot_set & mask_is_current_pivot)
325 .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 permutation (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