Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,19 @@

namespace nil::crypto3::algebra::fields {

/** Return the characteristic of FieldType. Extension fields have the same characteristic as their prime field. */
template<typename FieldType>
boost::multiprecision::cpp_int field_characteristic() {
return boost::multiprecision::cpp_int(FieldType::modulus.backend().to_cpp_int());
}

/**
* Return the number of elements in FieldType. Crypto3 field types describe extensions with an arity equal to their
* degree over the prime field, so a field of characteristic p and arity d has p^d elements.
*/
template<typename FieldType>
boost::multiprecision::cpp_int field_order() {
const boost::multiprecision::cpp_int characteristic(FieldType::modulus.backend().to_cpp_int());
const boost::multiprecision::cpp_int characteristic = field_characteristic<FieldType>();
boost::multiprecision::cpp_int order = 1;
for (std::size_t i = 0; i < FieldType::arity; ++i) {
order *= characteristic;
Expand Down
2 changes: 2 additions & 0 deletions libs/algebra/test/field_order.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ BOOST_AUTO_TEST_CASE(prime_field_order_equals_its_characteristic) {
const boost::multiprecision::cpp_int expected(
"21888242871839275222246405745257275088696311157297823662689037894645226208583");

BOOST_CHECK(fields::field_characteristic<fq_field_type>() == expected);
BOOST_CHECK(fields::field_characteristic<fq12_field_type>() == expected);
BOOST_CHECK(fields::field_order<fq_field_type>() == expected);
}

Expand Down
30 changes: 13 additions & 17 deletions libs/mac/include/nil/crypto3/mac/poly1305.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,8 @@ namespace nil {
std::copy(key.begin() + r_bytes.size(), key.end(), s_bytes.begin());

clamp_poly1305_r(r_bytes);
return {
load_little_endian_integer(r_bytes.cbegin(), r_bytes.size()),
load_little_endian_integer(s_bytes.cbegin(), s_bytes.size())
};
return {load_little_endian_integer(r_bytes.cbegin(), r_bytes.size()),
load_little_endian_integer(s_bytes.cbegin(), s_bytes.size())};
}

template<typename InputIterator>
Expand Down Expand Up @@ -338,15 +336,13 @@ namespace nil {
const std::uint64_t t0 = load_little_endian_64(key.data());
const std::uint64_t t1 = load_little_endian_64(key.data() + 8);

key_schedule_type schedule = {
t0 & 0xffc0fffffff,
((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff,
(t1 >> 24) & 0x00ffffffc0f,
0,
0,
load_little_endian_64(key.data() + 16),
load_little_endian_64(key.data() + 24)
};
key_schedule_type schedule = {t0 & 0xffc0fffffff,
((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff,
(t1 >> 24) & 0x00ffffffc0f,
0,
0,
load_little_endian_64(key.data() + 16),
load_little_endian_64(key.data() + 24)};

schedule.s1 = schedule.r1 * (5 << 2);
schedule.s2 = schedule.r2 * (5 << 2);
Expand All @@ -371,7 +367,7 @@ namespace nil {
#else
typedef poly1305_reference_backend poly1305_default_backend;
#endif
} // namespace detail
} // namespace detail

template<typename Backend = detail::poly1305_default_backend>
struct basic_poly1305 {
Expand Down Expand Up @@ -447,8 +443,8 @@ namespace nil {

key_schedule_type schedule;
};
} // namespace mac
} // namespace crypto3
} // namespace nil
} // namespace mac
} // namespace crypto3
} // namespace nil

#endif // CRYPTO3_MAC_POLY1305_HPP
6 changes: 3 additions & 3 deletions libs/math/include/nil/crypto3/math/matrix/compressed.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ namespace nil::crypto3::math {
source.find_element(row, column);
destination(row, column) = *source.find_element(row, column);
}
void assign_if_stored(const matrix<SourceBackend> &source, std::size_t source_row,
std::size_t source_column, matrix<DestinationBackend> &destination,
std::size_t destination_row, std::size_t destination_column) {
void assign_if_stored(const matrix<SourceBackend> &source, std::size_t source_row, std::size_t source_column,
matrix<DestinationBackend> &destination, std::size_t destination_row,
std::size_t destination_column) {
if (auto element = source.backend().find_element(source_row, source_column)) {
destination(destination_row, destination_column) = *element;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
//---------------------------------------------------------------------------//
// Copyright (c) 2026
//
// MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//---------------------------------------------------------------------------//

#ifndef CRYPTO3_MATH_DISTINCT_DEGREE_FACTORIZATION_HPP
#define CRYPTO3_MATH_DISTINCT_DEGREE_FACTORIZATION_HPP

#include <concepts>
#include <cstddef>
#include <stdexcept>
#include <utility>

#include <nil/crypto3/math/polynomial/gcd.hpp>
#include <nil/crypto3/math/polynomial/polynomial_factorization.hpp>
#include <nil/crypto3/math/polynomial/polynomial_frobenius.hpp>

namespace nil::crypto3::math {

/**
* Split a square-free polynomial into products of irreducible factors of equal degree using the classical
* distinct-degree algorithm. This implementation is intended as a correctness reference for faster blocked
* algorithms.
*
* Over a finite field with Q elements, X^(Q^d) - X is the product of all monic irreducible polynomials whose
* degrees divide d. The algorithm visits d = 1, 2, ... and removes the factors found at earlier degrees. Therefore
*
* gcd(remaining, X^(Q^d) - X)
*
* contains exactly the remaining irreducible factors of degree d. Frobenius powers are computed modulo the
* original monic input. This is also valid modulo every factor subsequently removed from that input and avoids
* rebuilding the Frobenius precomputation after each split.
*
* For example, let F = L1 * L2 * Q1 * Q2 * C, where L1 and L2 are irreducible linears, Q1 and Q2 are
* irreducible quadratics, and C is an irreducible cubic. At d = 1, the GCD extracts L1 * L2. At d = 2,
* X^(Q^2) - X contains factors of degrees one and two, but the linears have already been removed, so the GCD
* extracts Q1 * Q2. The remaining C is then reported with degree three. The algorithm therefore returns three
* groups: (L1 * L2, 1), (Q1 * Q2, 2), and (C, 3).
*
* The input is normalized to monic form and its original leading coefficient is preserved in the result. Zero
* and constant inputs return that coefficient and no factors. Nonconstant input must be square-free; this is
* checked before the decomposition begins.
*
* Factors are emitted in increasing irreducible-factor degree. After each factor is appended to the result,
* factor_callback may request an early stop. A stopped result includes that factor and has complete set to false.
*
* @throws std::invalid_argument if a nonconstant input is not square-free.
* @pre input is a nonempty coefficient polynomial.
*/
template<detail::SupportsDivrem Backend, typename FactorCallback>
requires requires(FactorCallback &callback,
const distinct_degree_factor<typename Backend::polynomial_type> &factor) {
{ callback(factor) } -> std::same_as<factorization_control>;
}
distinct_degree_factorization_result<typename Backend::polynomial_type>
distinct_degree_factorization_reference(const typename Backend::polynomial_type &input,
polynomial_arithmetic::polynomial_context<Backend> &arithmetic_context,
FactorCallback &&factor_callback) {
using polynomial_type = typename Backend::polynomial_type;
using value_type = typename polynomial_type::value_type;
using result_type = distinct_degree_factorization_result<polynomial_type>;

result_type result;
polynomial_type monic_input(input);
condense(monic_input);
result.leading_coefficient = monic_input.back();
if (monic_input.size() == 1) {
return result;
}
make_monic(monic_input, monic_input);

polynomial_type input_derivative;
derivative(input_derivative, monic_input);
polynomial_type repeated_factor;
gcd(repeated_factor, monic_input, input_derivative, arithmetic_context);
if (repeated_factor.size() > 1) {
throw std::invalid_argument("distinct-degree factorization requires a square-free polynomial");
}

const polynomial_type x = {value_type {}, value_type::one()};
polynomial_type frobenius_power(x);
polynomial_frobenius_context<Backend> frobenius_context(monic_input, arithmetic_context);
polynomial_type remaining(std::move(monic_input));

std::size_t irreducible_factor_degree = 1;
// Every factor of degree below the current degree has already been removed. If remaining has degree less
// than twice the current degree, it can contain at most one irreducible factor and is emitted after the loop.
while (irreducible_factor_degree <= (remaining.size() - 1) / 2) {
frobenius_map(frobenius_power, frobenius_power, frobenius_context, arithmetic_context);

polynomial_type frobenius_difference;
subtraction(frobenius_difference, frobenius_power, x);
polynomial_type factor;
gcd(factor, remaining, frobenius_difference, arithmetic_context);
if (factor.size() > 1) {
result.factors.push_back({std::move(factor), irreducible_factor_degree});
if (factor_callback(result.factors.back()) == factorization_control::stop_factorization) {
result.complete = false;
return result;
}

polynomial_type quotient;
detail::factorization_exact_quotient(quotient, remaining, result.factors.back().polynomial,
arithmetic_context);
remaining = std::move(quotient);
}
++irreducible_factor_degree;
}

if (remaining.size() > 1) {
const std::size_t remaining_degree = remaining.size() - 1;
result.factors.push_back({std::move(remaining), remaining_degree});
if (factor_callback(result.factors.back()) == factorization_control::stop_factorization) {
result.complete = false;
}
}

return result;
}

/** Compute the complete reference distinct-degree factorization without a staged callback. */
template<detail::SupportsDivrem Backend>
distinct_degree_factorization_result<typename Backend::polynomial_type> distinct_degree_factorization_reference(
const typename Backend::polynomial_type &input,
polynomial_arithmetic::polynomial_context<Backend> &arithmetic_context) {
using factor_type = distinct_degree_factor<typename Backend::polynomial_type>;
return distinct_degree_factorization_reference<Backend>(input, arithmetic_context, [](const factor_type &) {
return factorization_control::continue_factorization;
});
}

} // namespace nil::crypto3::math

#endif // CRYPTO3_MATH_DISTINCT_DEGREE_FACTORIZATION_HPP
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
//---------------------------------------------------------------------------//
// Copyright (c) 2026
//
// MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//---------------------------------------------------------------------------//

#ifndef CRYPTO3_MATH_POLYNOMIAL_FACTORIZATION_HPP
#define CRYPTO3_MATH_POLYNOMIAL_FACTORIZATION_HPP

#include <cstddef>
#include <vector>

#include <nil/crypto3/math/polynomial/concepts.hpp>
#include <nil/crypto3/math/polynomial/polynomial_division.hpp>

namespace nil::crypto3::math {

/** The action requested by a callback after a factorization stage produces a factor. */
enum class factorization_control { continue_factorization, stop_factorization };

/** A polynomial factor together with its positive multiplicity in the input polynomial. */
template<CoefficientPolynomial Polynomial>
struct polynomial_factor {
Polynomial polynomial;
std::size_t multiplicity = 1;

bool operator==(const polynomial_factor &) const = default;
};

/**
* A collected polynomial factorization. A complete result satisfies
*
* input = leading_coefficient * product(factor.polynomial ^ factor.multiplicity).
*
* Nonconstant factors are stored in monic canonical form. When a staged callback requests an early stop, factors
* contains the produced prefix, including the factor that caused the stop, and complete is false.
*/
template<CoefficientPolynomial Polynomial>
struct polynomial_factorization_result {
using polynomial_type = Polynomial;
using value_type = typename polynomial_type::value_type;
using factor_type = polynomial_factor<polynomial_type>;

value_type leading_coefficient {};
std::vector<factor_type> factors;
bool complete = true;

bool operator==(const polynomial_factorization_result &) const = default;
};

/**
* One group produced by distinct-degree factorization. polynomial is the product of all irreducible input factors
* whose degree equals irreducible_factor_degree; it need not itself be irreducible.
*/
template<CoefficientPolynomial Polynomial>
struct distinct_degree_factor {
Polynomial polynomial;
std::size_t irreducible_factor_degree = 1;

bool operator==(const distinct_degree_factor &) const = default;
};

/**
* A collected distinct-degree factorization. A complete result satisfies
*
* input = leading_coefficient * product(factor.polynomial).
*
* Each stored polynomial is monic and square-free, and contains all input factors having the associated
* irreducible_factor_degree. A stopped result contains the produced prefix, including the factor that caused the
* stop, and has complete set to false.
*/
template<CoefficientPolynomial Polynomial>
struct distinct_degree_factorization_result {
using polynomial_type = Polynomial;
using value_type = typename polynomial_type::value_type;
using factor_type = distinct_degree_factor<polynomial_type>;

value_type leading_coefficient {};
std::vector<factor_type> factors;
bool complete = true;

bool operator==(const distinct_degree_factorization_result &) const = default;
};

namespace detail {

template<SupportsDivrem Backend>
void factorization_exact_quotient(typename Backend::polynomial_type &output,
const typename Backend::polynomial_type &dividend,
const typename Backend::polynomial_type &divisor,
polynomial_arithmetic::polynomial_context<Backend> &arithmetic_context) {
const std::size_t quotient_coefficient_count =
dividend.size() >= divisor.size() ? dividend.size() - divisor.size() + 1 : 1;
polynomial_divisor_context<Backend> divisor_context(divisor, quotient_coefficient_count,
arithmetic_context);
exact_division(output, dividend, divisor_context, arithmetic_context);
}

} // namespace detail

} // namespace nil::crypto3::math

#endif // CRYPTO3_MATH_POLYNOMIAL_FACTORIZATION_HPP
Loading
Loading