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 @@ -27,8 +27,11 @@
#ifndef CRYPTO3_ALGEBRA_FIELDS_ELEMENT_FP12_2OVER3OVER2_HPP
#define CRYPTO3_ALGEBRA_FIELDS_ELEMENT_FP12_2OVER3OVER2_HPP

#include <cassert>

#include <nil/crypto3/algebra/fields/detail/exponentiation.hpp>
#include <nil/crypto3/algebra/fields/detail/element/operations.hpp>
#include <nil/crypto3/algebra/fields/field_order.hpp>

namespace nil {
namespace crypto3 {
Expand All @@ -53,6 +56,19 @@ namespace nil {

constexpr element_fp12_2over3over2() = default;

constexpr element_fp12_2over3over2(const underlying_type &in_data) :
data({in_data, underlying_type::zero()}) {
}

constexpr element_fp12_2over3over2(const typename underlying_type::underlying_type &in_data) :
element_fp12_2over3over2(underlying_type(in_data)) {
}

constexpr element_fp12_2over3over2(
const typename underlying_type::underlying_type::underlying_type &in_data) :
element_fp12_2over3over2(underlying_type(in_data)) {
}

constexpr element_fp12_2over3over2(const underlying_type &in_data0,
const underlying_type &in_data1) :
data({in_data0, in_data1}) {
Expand Down Expand Up @@ -192,6 +208,79 @@ namespace nil {
return element_fp12_2over3over2(c0, c1);
}

bool is_square() const {
return is_zero() || pow((field_order<field_type>() - 1) >> 1) == one();
}

element_fp12_2over3over2 sqrt_known_square() const {
if (is_zero() || is_one()) {
return *this;
}

using boost::multiprecision::cpp_int;
static const cpp_int order_minus_one = field_order<field_type>() - 1;
static const auto parameters = []() {
cpp_int odd_part = order_minus_one;
std::size_t power_of_two = 0;
while ((odd_part & 1) == 0) {
odd_part >>= 1;
++power_of_two;
}
return std::pair<cpp_int, std::size_t>(odd_part, power_of_two);
}();

const cpp_int &odd_part = parameters.first;
const std::size_t power_of_two = parameters.second;
if (power_of_two == 1) {
return pow((order_minus_one + 2) >> 2);
}

static const element_fp12_2over3over2 non_residue_to_odd_part = []() {
using base_type = typename underlying_type::underlying_type::underlying_type;
for (unsigned candidate = 1; candidate < 256; ++candidate) {
const element_fp12_2over3over2 value(underlying_type::zero(),
underlying_type(base_type(candidate)));
if (value.pow(order_minus_one >> 1) == -one()) {
return value.pow(parameters.first);
}
}
assert(false && "failed to find an Fp12 quadratic non-residue");
return zero();
}();

element_fp12_2over3over2 c = non_residue_to_odd_part;
element_fp12_2over3over2 t = pow(odd_part);
element_fp12_2over3over2 root = pow((odd_part + 1) >> 1);
std::size_t remaining_power = power_of_two;

while (t != one()) {
element_fp12_2over3over2 t_squared = t;
std::size_t i = 0;
for (i = 1; i < remaining_power; ++i) {
t_squared = t_squared.squared();
if (t_squared == one()) {
break;
}
}
assert(i < remaining_power && "Fp12 Tonelli-Shanks step failed");

const element_fp12_2over3over2 b = c.pow(cpp_int(1) << (remaining_power - i - 1));
const element_fp12_2over3over2 b_squared = b.squared();
root *= b;
t *= b_squared;
c = b_squared;
remaining_power = i;
}

assert(root.squared() == *this);
return root;
}

element_fp12_2over3over2 sqrt() const {
assert(is_square() && "sqrt() called on a non-square Fp12 element");
return sqrt_known_square();
}

/** @brief Frobenius map: exponentiation by a degree of field characteristic.
* For \f$a \in F_{p^k}\f$ this returns \f$a^{p^{pwr}}\f$. */
template<typename PowerType>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ namespace nil {
constexpr element_fp2(const data_type &in_data) : data({in_data[0], in_data[1]}) {
}

constexpr element_fp2(const underlying_type &in_data) :
data({in_data, underlying_type::zero()}) {
}

constexpr element_fp2(const underlying_type &in_data0, const underlying_type &in_data1) :
data({in_data0, in_data1}) {
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,14 @@ namespace nil {

constexpr element_fp6_3over2() = default;

constexpr element_fp6_3over2(const underlying_type &in_data) :
data({in_data, underlying_type::zero(), underlying_type::zero()}) {
}

constexpr element_fp6_3over2(const typename underlying_type::underlying_type &in_data) :
element_fp6_3over2(underlying_type(in_data)) {
}

constexpr element_fp6_3over2(const underlying_type &in_data0,
const underlying_type &in_data1,
const underlying_type &in_data2) :
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//---------------------------------------------------------------------------//
// Copyright (c) 2026 Alloc Init Labs Inc.
//
// 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_ALGEBRA_FIELDS_DETAIL_FIELD_ALGORITHMS_HPP
#define CRYPTO3_ALGEBRA_FIELDS_DETAIL_FIELD_ALGORITHMS_HPP

#include <cassert>
#include <cstddef>
#include <stdexcept>

#include <boost/multiprecision/cpp_int.hpp>

#include <nil/crypto3/algebra/type_traits.hpp>

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

// Customization point used by the public free functions in field_algorithms.hpp.
// This primary template provides formulas that work for any FieldValue. A field
// may specialize this class in a separate detail header when its tower structure
// permits a faster implementation. Keeping dispatch here gives callers one stable
// public API while keeping field-specific types and algorithms private.
template<FieldValue Value>
struct field_algorithms {
static Value two_primary_component(const Value &x, const boost::multiprecision::cpp_int &odd_order,
std::size_t) {
return x.pow(odd_order);
}

static Value odd_subgroup_sqrt(const Value &x, const boost::multiprecision::cpp_int &odd_order) {
assert((odd_order & 1) != 0);
const boost::multiprecision::cpp_int exponent = (odd_order + 1) >> 1;
return x.is_zero() || x.is_one() ? x : x.pow(exponent);
}

static Value sqrt_known_square(const Value &x) {
return x.sqrt();
}

static Value primitive_two_power_root_of_unity(std::size_t) {
throw std::invalid_argument("primitive root discovery is not available for this field");
}
};

} // namespace nil::crypto3::algebra::fields::detail

#endif // CRYPTO3_ALGEBRA_FIELDS_DETAIL_FIELD_ALGORITHMS_HPP
Loading
Loading