From 56221dbe880a8ca3dad55e367b360a069c785009 Mon Sep 17 00:00:00 2001 From: Vasiliy Olekhov Date: Fri, 26 Apr 2024 13:57:36 +0300 Subject: [PATCH] Refactored MNT4 code and added MNT6 exponentiation #355 --- .../plonk/non_native/detail/abstract_fp6.hpp | 98 ++++ .../plonk/non_native/mnt4_fp4_fixed_power.hpp | 53 +- .../plonk/non_native/mnt6_fp6_fixed_power.hpp | 72 +-- .../weierstrass/plonk/mnt4_exponentiation.hpp | 9 +- .../weierstrass/plonk/mnt6_exponentiation.hpp | 492 ++++++++++++++++++ test/CMakeLists.txt | 2 + .../plonk/non_native/mnt4_fp4_fixed_power.cpp | 6 +- .../plonk/non_native/mnt6_fp6_fixed_power.cpp | 174 +++++++ .../weierstrass/plonk/mnt6_exponentiation.cpp | 152 ++++++ test/test_plonk_component.hpp | 8 +- 10 files changed, 992 insertions(+), 74 deletions(-) create mode 100644 include/nil/blueprint/components/algebra/fields/plonk/non_native/detail/abstract_fp6.hpp create mode 100644 include/nil/blueprint/components/algebra/pairing/weierstrass/plonk/mnt6_exponentiation.hpp create mode 100644 test/algebra/fields/plonk/non_native/mnt6_fp6_fixed_power.cpp create mode 100644 test/algebra/pairing/weierstrass/plonk/mnt6_exponentiation.cpp diff --git a/include/nil/blueprint/components/algebra/fields/plonk/non_native/detail/abstract_fp6.hpp b/include/nil/blueprint/components/algebra/fields/plonk/non_native/detail/abstract_fp6.hpp new file mode 100644 index 000000000..950e70aa5 --- /dev/null +++ b/include/nil/blueprint/components/algebra/fields/plonk/non_native/detail/abstract_fp6.hpp @@ -0,0 +1,98 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2024 Vasiliy Olekhov +// +// 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. +//---------------------------------------------------------------------------// +// @file Declaration of F_p^6 elements over an abstract entity (to be used with constraints) +// with F_p^6 = Fp^2 over Fp^3: +// Fp^6 = Fp^2[x]/(x^2 - u), u = (0,1,0) +// Fp^3 = Fp[y]/(y^3 - v), for MNT6: v = 5 +//---------------------------------------------------------------------------// + +#ifndef CRYPTO3_BLUEPRINT_COMPONENTS_PLONK_ABSTRACT_FP4_HPP +#define CRYPTO3_BLUEPRINT_COMPONENTS_PLONK_ABSTRACT_FP4_HPP + +#include +#include + +#include + +namespace nil { + namespace blueprint { + namespace components { + namespace detail { + + template + class abstract_fp6_element{ + public: + using policy_type_fp6 = crypto3::algebra::fields::fp6_2over3; + std::array x; + + T& operator[](std::size_t idx) { + return x[idx]; + } + const T& operator[](std::size_t idx) const { + return x[idx]; + } + + constexpr abstract_fp6_element operator*(abstract_fp6_element const& y) { + // Devegili et al - Multiplication and squaring in pairing-friendly fields + // https://eprint.iacr.org/2006/471.pdf, page 15, direct sextic + // Take note on isomorphism between a (Fp 2 over 3) and c (direct sextic) + // Indices map is on page 17 + constexpr std::size_t + _0 = 0, _1 = 3, _2 = 1, + _3 = 4, _4 = 2, _5 = 5; + + constexpr auto s = policy_type_fp6::extension_policy::non_residue; + + T c[6] = { + x[_0]*y[_0] + s*(x[_1]*y[_5] + x[_2]*y[_4] + x[_3]*y[_3] + x[_4]*y[_2] + x[_5]*y[_1]), + x[_0]*y[_1] + x[_1]*y[_0] + s*(x[_2]*y[_5] + x[_3]*y[_4] + x[_4]*y[_3] + x[_5]*y[_2]), + x[_0]*y[_2] + x[_1]*y[_1] + x[_2]*y[_0] + s*(x[_3]*y[_5] + x[_4]*y[_4] + x[_5]*y[_3]), + x[_0]*y[_3] + x[_1]*y[_2] + x[_2]*y[_1] + x[_3]*y[_0] + s*(x[_4]*y[_5] + x[_5]*y[_4]), + x[_0]*y[_4] + x[_1]*y[_3] + x[_2]*y[_2] + x[_3]*y[_1] + x[_4]*y[_0] + s* x[_5]*y[_5], + x[_0]*y[_5] + x[_1]*y[_4] + x[_2]*y[_3] + x[_3]*y[_2] + x[_4]*y[_1] + x[_5]*y[_0] + }; + + return { c[0], c[2], c[4], c[1], c[3], c[5]}; + } + + constexpr abstract_fp6_element operator*(const int a) { + return { x[0]*a, x[1]*a, x[2]*a, x[3]*a, x[4]*a, x[5]*a }; + } + friend abstract_fp6_element operator*(const int a, abstract_fp6_element const& x) { + return { x[0]*a, x[1]*a, x[2]*a, x[3]*a, x[4]*a, x[5]*a }; + } + constexpr abstract_fp6_element operator+(abstract_fp6_element const& y) { + return { x[0] + y[0], x[1] + y[1], x[2] + y[2], x[3] + y[3], x[4] + y[4], x[5] + y[5]}; + } + constexpr abstract_fp6_element operator-(abstract_fp6_element const& y) { + return { x[0] - y[0], x[1] - y[1], x[2] - y[2], x[3] - y[3], x[4] - y[4], x[5] - y[5]}; + } + }; + + } // namespace detail + } // namespace components + } // namespace blueprint +} // namespace nil + +#endif // CRYPTO3_BLUEPRINT_COMPONENTS_PLONK_abstract_FP4_HPP diff --git a/include/nil/blueprint/components/algebra/fields/plonk/non_native/mnt4_fp4_fixed_power.hpp b/include/nil/blueprint/components/algebra/fields/plonk/non_native/mnt4_fp4_fixed_power.hpp index 7d2eb26d8..78e715171 100644 --- a/include/nil/blueprint/components/algebra/fields/plonk/non_native/mnt4_fp4_fixed_power.hpp +++ b/include/nil/blueprint/components/algebra/fields/plonk/non_native/mnt4_fp4_fixed_power.hpp @@ -66,12 +66,11 @@ namespace nil { using constraint_type = crypto3::zk::snark::plonk_constraint; using policy_type = crypto3::algebra::fields::fp4; using integral_type = typename BlueprintFieldType::integral_type; - using extended_integral_type = typename BlueprintFieldType::extended_integral_type; using fp4_element = typename policy_type::value_type; using fp4_constraint = detail::abstract_fp4_element; private: - static std::vector base4(extended_integral_type x) { + static std::vector base4(integral_type x) { if (x > 0) { std::vector res = {std::uint8_t(x % 4)}; x /= 4; @@ -85,7 +84,7 @@ namespace nil { } } - static std::size_t gates_amount_internal(extended_integral_type power) { + static std::size_t gates_amount_internal(integral_type power) { std::size_t gates = 1; // at least one for power-4 operations std::vector exp_plan = base4(power); if (exp_plan.size() - std::count(exp_plan.begin(),exp_plan.end(),0) > 1) { @@ -100,28 +99,28 @@ namespace nil { public: using manifest_type = plonk_component_manifest; - const extended_integral_type power/* = pairing::detail::pairing_params::final_exponent_last_chunk_abs_of_w0*/; + const integral_type power/* = pairing::detail::pairing_params::final_exponent_last_chunk_abs_of_w0*/; const std::vector exp_plan, exp_precompute; const std::size_t rows_amount; class gate_manifest_type : public component_gate_manifest { - const extended_integral_type power; - std::array gates_footprint(extended_integral_type power) const { + const integral_type power; + std::array gates_footprint(integral_type power) const { std::vector exp_plan = base4(power); return { (exp_plan.size() - std::count(exp_plan.begin(),exp_plan.end(),0) > 1), (std::count(exp_plan.begin(),exp_plan.end(),3) > 0), (std::count(exp_plan.begin(),exp_plan.end(),2) > 0) }; } public: - gate_manifest_type(extended_integral_type power) : power(power) {} + gate_manifest_type(integral_type power) : power(power) {} std::uint32_t gates_amount() const override { return mnt4_fp4_fixed_power::gates_amount_internal(power); } bool operator<(const component_gate_manifest *other) const override { - extended_integral_type o_power = dynamic_cast(other)->power; + integral_type o_power = dynamic_cast(other)->power; std::array gates = gates_footprint(power), @@ -132,8 +131,7 @@ namespace nil { static gate_manifest get_gate_manifest( std::size_t witness_amount, - std::size_t lookup_column_amount, - extended_integral_type power) + integral_type power) { static gate_manifest manifest = gate_manifest(gate_manifest_type(power)); return manifest; @@ -141,7 +139,7 @@ namespace nil { static manifest_type get_manifest() { static manifest_type manifest = manifest_type( - std::shared_ptr(new manifest_range_param(4, 300, 1)), + std::shared_ptr(new manifest_single_value_param(policy_type::arity)), false ); return manifest; @@ -159,7 +157,9 @@ namespace nil { return precompute; } - static std::size_t get_rows_amount(extended_integral_type power) + static std::size_t get_rows_amount( + std::size_t witness_amount, + integral_type power) { std::vector exp_plan = base4(power), @@ -208,12 +208,12 @@ namespace nil { template explicit mnt4_fp4_fixed_power( ContainerType witness, - extended_integral_type power) : + integral_type power) : component_type(witness, {}, {}, get_manifest()), power(power), exp_plan(base4(power)), exp_precompute(get_precomputed_exps(exp_plan)), - rows_amount(get_rows_amount(power)) + rows_amount(get_rows_amount(this->witness_amount(), power)) { }; template @@ -221,31 +221,33 @@ namespace nil { WitnessContainerType witness, ConstantContainerType constant, PublicInputContainerType public_input, - extended_integral_type power) : + integral_type power) : component_type(witness, constant, public_input, get_manifest()), power(power), exp_plan(base4(power)), exp_precompute(get_precomputed_exps(exp_plan)), - rows_amount(get_rows_amount(power)) + rows_amount(get_rows_amount(this->witness_amount(), power)) { }; mnt4_fp4_fixed_power( std::initializer_list witnesses, std::initializer_list constants, std::initializer_list public_inputs, - extended_integral_type power) : + integral_type power) : component_type(witnesses, constants, public_inputs, get_manifest()), power(power), exp_plan(base4(power)), exp_precompute(get_precomputed_exps(exp_plan)), - rows_amount(get_rows_amount(power)) + rows_amount(get_rows_amount(this->witness_amount(), power)) { }; }; /* */ template - using component_type = mnt4_fp4_fixed_power, BlueprintFieldType>; + using component_type = mnt4_fp4_fixed_power< + crypto3::zk::snark::plonk_constraint_system, + BlueprintFieldType>; template typename component_type::result_type @@ -275,20 +277,9 @@ namespace nil { std::size_t row = 0; auto fill_row = [&component, &assignment, &start_row_index, &row](fp4_element const& V) { - value_type d00 = V.data[0].data[0]; - value_type d01 = V.data[0].data[1]; - value_type d10 = V.data[1].data[0]; - value_type d11 = V.data[1].data[1]; - assignment.witness(component.W(0),start_row_index + row) = d00; - assignment.witness(component.W(1),start_row_index + row) = d01; - assignment.witness(component.W(2),start_row_index + row) = d10; - assignment.witness(component.W(3),start_row_index + row) = d11; - - /* - for(std::size_t i = 0; i < policy_type::arity; i++) { + for(std::size_t i = 0; i < 4; i++) { assignment.witness(component.W(i),start_row_index + row) = V.data[i/2].data[i % 2]; } - */ row++; }; diff --git a/include/nil/blueprint/components/algebra/fields/plonk/non_native/mnt6_fp6_fixed_power.hpp b/include/nil/blueprint/components/algebra/fields/plonk/non_native/mnt6_fp6_fixed_power.hpp index 1ede12082..755449b06 100644 --- a/include/nil/blueprint/components/algebra/fields/plonk/non_native/mnt6_fp6_fixed_power.hpp +++ b/include/nil/blueprint/components/algebra/fields/plonk/non_native/mnt6_fp6_fixed_power.hpp @@ -40,7 +40,7 @@ #include #include -#include +#include namespace nil { namespace blueprint { @@ -52,11 +52,11 @@ namespace nil { // Output: y[6]: y = x^t as elements of F_p^6 // - template + template class mnt6_fp6_fixed_power; template - class mnt6_fp6_fixed_power> + class mnt6_fp6_fixed_power, BlueprintFieldType> : public plonk_component { public: @@ -67,7 +67,7 @@ namespace nil { using policy_type = crypto3::algebra::fields::fp6_2over3; using integral_type = typename policy_type::extension_policy::integral_type; using fp6_element = typename policy_type::value_type; - using fp6_constraint = detail::mnt6_fp6_element; + using fp6_constraint = detail::abstract_fp6_element; private: static std::vector base4(integral_type x) { @@ -105,6 +105,7 @@ namespace nil { const std::size_t rows_amount; class gate_manifest_type : public component_gate_manifest { + const integral_type power; std::array gates_footprint(integral_type power) const { std::vector exp_plan = base4(power); return { (exp_plan.size() - std::count(exp_plan.begin(),exp_plan.end(),0) > 1), @@ -112,7 +113,6 @@ namespace nil { (std::count(exp_plan.begin(),exp_plan.end(),2) > 0) }; } public: - const integral_type power; gate_manifest_type(integral_type power) : power(power) {} std::uint32_t gates_amount() const override { @@ -131,7 +131,6 @@ namespace nil { static gate_manifest get_gate_manifest( std::size_t witness_amount, - std::size_t lookup_column_amount, integral_type power) { static gate_manifest manifest = gate_manifest(gate_manifest_type(power)); @@ -140,7 +139,7 @@ namespace nil { static manifest_type get_manifest() { static manifest_type manifest = manifest_type( - std::shared_ptr(new manifest_single_value_param(policy_type::arity)), // ?? + std::shared_ptr(new manifest_single_value_param(policy_type::arity)), false ); return manifest; @@ -160,7 +159,6 @@ namespace nil { static std::size_t get_rows_amount( std::size_t witness_amount, - std::size_t lookup_column_amount, integral_type power) { std::vector @@ -215,7 +213,7 @@ namespace nil { power(power), exp_plan(base4(power)), exp_precompute(get_precomputed_exps(exp_plan)), - rows_amount(get_rows_amount(this->witness_amount(), 0, power)) + rows_amount(get_rows_amount(this->witness_amount(), power)) { }; template @@ -228,7 +226,7 @@ namespace nil { power(power), exp_plan(base4(power)), exp_precompute(get_precomputed_exps(exp_plan)), - rows_amount(get_rows_amount(this->witness_amount(), 0, power)) + rows_amount(get_rows_amount(this->witness_amount(), power)) { }; mnt6_fp6_fixed_power( @@ -240,40 +238,46 @@ namespace nil { power(power), exp_plan(base4(power)), exp_precompute(get_precomputed_exps(exp_plan)), - rows_amount(get_rows_amount(this->witness_amount(), 0, power)) + rows_amount(get_rows_amount(this->witness_amount(), power)) { }; }; /* */ template - typename mnt6_fp6_fixed_power::result_type + using component_type = mnt6_fp6_fixed_power< + crypto3::zk::snark::plonk_constraint_system, + BlueprintFieldType>; + + template + typename component_type::result_type generate_assignments( - mnt6_fp6_fixed_power const& component, - assignment> const& assignment, - typename mnt6_fp6_fixed_power::input_type const& instance_input, + component_type const& component, + assignment> & assignment, + typename component_type::input_type const& instance_input, const std::uint32_t start_row_index) { using value_type = typename BlueprintFieldType::value_type; + using policy_type = typename component_type::policy_type; const std::vector exp_plan = component.exp_plan, exp_precompute = component.exp_precompute; - std::array::policy_type::arity> x; + std::array::policy_type::arity> x; for(std::size_t i = 0; i < x.size(); i++) { x[i] = var_value(assignment, instance_input.x[i]); } - using fp6_element = typename mnt6_fp6_fixed_power::fp6_element; - fp6_element X = fp6_element({ {x[0],x[1], x[2]}, {x[3],x[4]},x[5]}), Y = X; + using fp6_element = typename component_type::fp6_element; + fp6_element X = fp6_element({ {x[0],x[1],x[2]}, {x[3],x[4],x[5]} }), Y = X; std::size_t row = 0; auto fill_row = [&component, &assignment, &start_row_index, &row](fp6_element V) { - for(std::size_t i = 0; i < V.arity; i++) { + for(std::size_t i = 0; i < 6; i++) { assignment.witness(component.W(i),start_row_index + row) = V.data[i/3].data[i % 3]; } row++; @@ -295,17 +299,18 @@ namespace nil { } } - return typename mnt6_fp6_fixed_power::result_type( + return typename component_type::result_type( component, start_row_index); } template std::vector generate_gates( - mnt6_fp6_fixed_power const& component, + component_type const& component, circuit> & bp, assignment> const& assignment, - typename mnt6_fp6_fixed_power::input_type const& instance_input) + typename component_type::input_type const& instance_input) { + using var = typename component_type::var; const std::vector exp_plan = component.exp_plan, @@ -314,8 +319,8 @@ namespace nil { std::vector gate_list = {}; // at most 4 gate ids - using policy_type = typename mnt6_fp6_fixed_power::policy_type; - typename mnt6_fp6_fixed_power::fp4_constraint X, Y, Z, C; + using policy_type = typename component_type::policy_type; + typename component_type::fp6_constraint X, Y, Z, C; // power-4 gate for(std::size_t i = 0; i < policy_type::arity; i++) { @@ -324,7 +329,7 @@ namespace nil { } C = (X * X) * (X * X); - using constraint_type = typename mnt6_fp6_fixed_power::constraint_type; + using constraint_type = typename component_type::constraint_type; std::vector pow4_constrs = {}; for(std::size_t i = 0; i < policy_type::arity; i++) { @@ -378,19 +383,20 @@ namespace nil { } gate_list.push_back(bp.add_gate(square_constrs)); } + return gate_list; } template void generate_copy_constraints( - mnt6_fp6_fixed_power const& component, + component_type const& component, circuit> &bp, assignment> &assignment, - const typename mnt6_fp6_fixed_power::input_type &instance_input, + const typename component_type::input_type &instance_input, const std::size_t start_row_index) { - using var = typename mnt6_fp6_fixed_power::var; - using policy_type = typename mnt6_fp6_fixed_power::policy_type; + using var = typename component_type::var; + using policy_type = typename component_type::policy_type; const std::vector exp_plan = component.exp_plan, @@ -439,12 +445,12 @@ namespace nil { } template - typename mnt6_fp6_fixed_power::result_type + typename component_type::result_type generate_circuit( - mnt6_fp6_fixed_power const& component, + component_type const& component, circuit>& bp, assignment>& assignment, - typename mnt6_fp6_fixed_power::input_type const& instance_input, + typename component_type::input_type const& instance_input, const std::size_t start_row_index) { @@ -485,7 +491,7 @@ namespace nil { generate_copy_constraints(component, bp, assignment, instance_input, start_row_index); - return typename mnt6_fp6_fixed_power::result_type( + return typename component_type::result_type( component, start_row_index); } } // namespace components diff --git a/include/nil/blueprint/components/algebra/pairing/weierstrass/plonk/mnt4_exponentiation.hpp b/include/nil/blueprint/components/algebra/pairing/weierstrass/plonk/mnt4_exponentiation.hpp index 12336f795..76ed0c60f 100644 --- a/include/nil/blueprint/components/algebra/pairing/weierstrass/plonk/mnt4_exponentiation.hpp +++ b/include/nil/blueprint/components/algebra/pairing/weierstrass/plonk/mnt4_exponentiation.hpp @@ -27,7 +27,6 @@ #ifndef CRYPTO3_BLUEPRINT_COMPONENTS_PLONK_MNT4_EXPONENTIATION_HPP #define CRYPTO3_BLUEPRINT_COMPONENTS_PLONK_MNT4_EXPONENTIATION_HPP -#include "nil/blueprint/components/algebra/fields/plonk/non_native/mnt4_fp4_fixed_power.hpp" #include #include #include @@ -41,6 +40,7 @@ #include #include +#include namespace nil { namespace blueprint { @@ -87,7 +87,8 @@ namespace nil { using manifest_type = plonk_component_manifest; using curve_type = nil::crypto3::algebra::curves::mnt4<298>; - using fixed_power_type = mnt4_fp4_fixed_power, BlueprintFieldType>; + using fixed_power_type = mnt4_fp4_fixed_power< + crypto3::zk::snark::plonk_constraint_system, BlueprintFieldType>; class gate_manifest_type : public component_gate_manifest { public: @@ -117,7 +118,9 @@ namespace nil { constexpr static std::size_t get_rows_amount( std::size_t witness_amount) { - return fixed_power_type::get_rows_amount(crypto3::algebra::pairing::detail::pairing_params::final_exponent_last_chunk_abs_of_w0) + 9 - 1; + return fixed_power_type::get_rows_amount(witness_amount, + crypto3::algebra::pairing::detail::pairing_params::final_exponent_last_chunk_abs_of_w0) + + 9 - 1; } constexpr static const std::size_t gates_amount = 7; diff --git a/include/nil/blueprint/components/algebra/pairing/weierstrass/plonk/mnt6_exponentiation.hpp b/include/nil/blueprint/components/algebra/pairing/weierstrass/plonk/mnt6_exponentiation.hpp new file mode 100644 index 000000000..90772c319 --- /dev/null +++ b/include/nil/blueprint/components/algebra/pairing/weierstrass/plonk/mnt6_exponentiation.hpp @@ -0,0 +1,492 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2024 Vasiliy Olekhov +// +// 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. +//---------------------------------------------------------------------------// +// @file Circuit for final exponentiation for MNT6 elliptic curve pairings +//---------------------------------------------------------------------------// + +#ifndef CRYPTO3_BLUEPRINT_COMPONENTS_PLONK_MNT6_EXPONENTIATION_HPP +#define CRYPTO3_BLUEPRINT_COMPONENTS_PLONK_MNT6_EXPONENTIATION_HPP + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include + +namespace nil { + namespace blueprint { + namespace components { + // + // Curve E over prime field (F_p) as q points + // + // Pairing is possible due to q | p^k-1 + // + // This component raises element in F_{p^k} to power F = (p^k-1)/q + // + // For MNT6 curve k = 6 and F = (p^3 - 1)*(p + 1)*(p - w_0) + // + // The process of raising x to power F takes 6 stages: + // 1. Raise x to power p, x <- x^p (Frobenius map) + // 2. Repeat: x <- x^p, now x holds x^(p^2) + // 3. Repeat: x <- x^p, now x holds x^(p^3) + // 4. Divide by initial value x, now x holds x^(p^3-1), save to x' + // 5. Raise x' to power p: x1 <- x'^p = x^((p^3-1)*p) + // 6. Multiply x1 by x', now x1 holds x^((p^3-1)*(p+1)), save to x'' + // 7. Raise x'' to power p: x2 <- x''^p, x2 = x^((p^3-1)*(p+1)*p) + // 8. Raise x'' to power w_0: x3 <- x''^w_0, x3 = x^((p^3-1)*(p+1)*w_0), done with sub-circuit + // 9. Final result: inverse division x2 * x3^-1 + // + // Circuit requires 6 witnesses, 6 inputs and 6 outputs + // 6 gates are used: + // Gate 0: Raising to power p, "Frobenius map" + // Gate 1: "Division in Fp6" : x_next = x_prev / x + // Gate 2: "Inverse Division in Fp6": x_next = x / x_prev + // Gate 3: "Multiplication" + // Gate 4: "Squaring" + // Gate 5: "Cubing" + // Gate 6: "Fourth power" + // Gates 3-5 are used for powering to w_0 + using namespace detail; + + template + class mnt6_exponentiation; + + template + class mnt6_exponentiation> + : public plonk_component { + + public: + using component_type = plonk_component; + + using var = typename component_type::var; + using manifest_type = plonk_component_manifest; + using curve_type = nil::crypto3::algebra::curves::mnt6<298>; + + using fixed_power_type = mnt6_fp6_fixed_power< + crypto3::zk::snark::plonk_constraint_system, BlueprintFieldType>; + + class gate_manifest_type : public component_gate_manifest { + public: + gate_manifest_type() {} + + std::uint32_t gates_amount() const override { + return mnt6_exponentiation::gates_amount; + } + }; + + static gate_manifest get_gate_manifest( + std::size_t witness_amount) + { + static gate_manifest manifest = gate_manifest(gate_manifest_type()) + .merge_with(fixed_power_type::get_gate_manifest(witness_amount, crypto3::algebra::pairing::detail::pairing_params::final_exponent_last_chunk_abs_of_w0)); + return manifest; + } + + static manifest_type get_manifest() { + static manifest_type manifest = manifest_type( + std::shared_ptr(new manifest_single_value_param(4)), + false + ); + + return manifest; + } + + constexpr static std::size_t get_rows_amount( + std::size_t witness_amount) + { + auto x = fixed_power_type::get_rows_amount( + witness_amount, + crypto3::algebra::pairing::detail::pairing_params::final_exponent_last_chunk_abs_of_w0) + + 12; + std::cout << "Get rows: " << x << std::endl; + return x; + } + + constexpr static const std::size_t gates_amount = 3; + const std::size_t rows_amount = get_rows_amount(0); + + struct input_type { + std::array x; + + std::vector> all_vars() { + return {x[0], x[1], x[2], x[3], x[4], x[5]}; + } + }; + + struct result_type { + std::array output; + + result_type(const mnt6_exponentiation &component, std::uint32_t start_row_index) { + std::size_t last_row = start_row_index + component.rows_amount - 1; + for(std::size_t i = 0; i < 6; i++) { + output[i] = var(component.W(i), last_row, false, var::column_type::witness); + } + } + + std::vector> all_vars() { + std::vector> res = {}; + + for(auto & e : output) { res.push_back(e); } + return res; + } + }; + + template + explicit mnt6_exponentiation(ContainerType witness) : + component_type(witness, {}, {}, get_manifest()) {}; + + template + mnt6_exponentiation( + WitnessContainerType witness, + ConstantContainerType constant, + PublicInputContainerType public_input) : + component_type(witness, constant, public_input, get_manifest()) {}; + + mnt6_exponentiation( + std::initializer_list + witnesses, + std::initializer_list + constants, + std::initializer_list + public_inputs, unsigned long long T_) : + component_type(witnesses, constants, public_inputs, get_manifest()) {}; + }; + + template + using plonk_mnt6_exponentiation = + mnt6_exponentiation>; + + template + typename plonk_mnt6_exponentiation::result_type + generate_assignments( + plonk_mnt6_exponentiation const& component, + assignment> &assignment, + typename plonk_mnt6_exponentiation::input_type const& instance_input, + const std::uint32_t start_row_index) + { + using component_type = plonk_mnt6_exponentiation; + using var = typename component_type::var; + using value_type = typename BlueprintFieldType::value_type; + using curve_type = nil::crypto3::algebra::curves::mnt6<298>; + + using fixed_power_type = mnt6_fp6_fixed_power< + crypto3::zk::snark::plonk_constraint_system, BlueprintFieldType>; + + fixed_power_type fixed_power_instance( + component._W, component._C, component._PI, + crypto3::algebra::pairing::detail::pairing_params::final_exponent_last_chunk_abs_of_w0); + + std::array x; + + for(std::size_t i = 0; i < x.size(); i++) { + x[i] = var_value(assignment, instance_input.x[i]); + } + + using policy_type_fp6 = crypto3::algebra::fields::fp6_2over3; + using fp6_element = typename policy_type_fp6::value_type; + + fp6_element + input = fp6_element({ {x[0], x[1], x[2]}, {x[3], x[4], x[5]} }), + elt = input; + + std::size_t row = start_row_index; + + auto fill_row = [&assignment, &component, &row](fp6_element const& V) + { + for(std::size_t i = 0; i < 6; ++i) { + assignment.witness(component.W(i),row) = V.data[i/3].data[i%3]; + } + ++row; + }; + + // 0: Initial value + fill_row(elt); + + // 1: elt <- elt^p + elt = elt.Frobenius_map(1); + fill_row(elt); + + // 2: elt <- (elt^p), now elt holds= x^(p^2) + elt = elt.Frobenius_map(1); + fill_row(elt); + + // 3: elt <- (elt^p), now elt holds= x^(p^3) + elt = elt.Frobenius_map(1); + fill_row(elt); + + // 4: elt <- elt/x, elt now holds x^(p^3-1) + fill_row(input); + elt = elt*input.inversed(); + // 5: + fill_row(elt); + + // 6: elt2 <- (elt^p), now elt2 holds x^((p^3-1)*p) + fp6_element elt2 = elt.Frobenius_map(1); + fill_row(elt2); + + // 7: elt2 <- elt2*elt, now elt2 holds x^((p^3-1)*(p+1)) + elt2 = elt2*elt; + fill_row(elt2); + + // 8: elt <- (elt2^p), now elt holds x^((p^3-1)*(p+1)*p) + elt = elt2.Frobenius_map(1); + fill_row(elt); + + /* Fill rows for raising elt2 = x^((p^3-1)*(p+1)) to power w0 */ + + // The input is from 7th row + std::array transfer_vars = { + var(component.W(0), start_row_index + 7, false), + var(component.W(1), start_row_index + 7, false), + var(component.W(2), start_row_index + 7, false), + var(component.W(3), start_row_index + 7, false), + var(component.W(4), start_row_index + 7, false), + var(component.W(5), start_row_index + 7, false), + }; + + typename fixed_power_type::input_type pow_input = { transfer_vars }; + typename fixed_power_type::result_type pow_output = + generate_assignments(fixed_power_instance, assignment, pow_input, row); + row += fixed_power_instance.rows_amount; + + fp6_element elt3({ + { + var_value(assignment, pow_output.output[0]), + var_value(assignment, pow_output.output[1]), + var_value(assignment, pow_output.output[2]), + } , { + var_value(assignment, pow_output.output[3]), + var_value(assignment, pow_output.output[4]), + var_value(assignment, pow_output.output[5]) + } + }); + // Now elt3 holds x^((p^3-1)*(p+1)*w0) + // Do not fill as sub-circuit output results are on the last row + // fill_row(elt3); + + // 8+R-1: Final result is elt/elt3 = x^((p^3-1)*(p+1)*p) * x^(-(p^3-1)(p+1)*w0) = x^((p^3-1)*(p+1)*(p-w0)) + fill_row(elt); + fill_row(elt3); + elt = elt*elt3.inversed(); + // 10+R-1 + fill_row(elt); + + return typename plonk_mnt6_exponentiation::result_type( + component, start_row_index); + } + + template + std::vector + generate_gates( + plonk_mnt6_exponentiation const& component, + circuit> &bp, + assignment> &assignment, + typename plonk_mnt6_exponentiation::input_type const& instance_input) + { + using var = typename plonk_mnt6_exponentiation::var; + using constraint_type = crypto3::zk::snark::plonk_constraint; + using fp6_constraint = detail::abstract_fp6_element; + + std::vector gate_list = {}; + + std::vector constrs = {}; + + fp6_constraint X, Xn, Xp, R; + + for(std::size_t i = 0; i < 6; ++i) { + X[i] = var(component.W(i), 0, true); + Xn[i] = var(component.W(i), 1, true); + Xp[i] = var(component.W(i), -1, true); + } + + /* Frobenius gate - 0 + * Ensures x_next = x^p = x.frobenius_map(1) + */ + { + using fp6_ep = typename crypto3::algebra::fields::fp6_2over3::extension_policy; + using fp3_ep = typename crypto3::algebra::fields::fp3::extension_policy; + + typename BlueprintFieldType::value_type fc3[] = { + 1, + fp3_ep::Frobenius_coeffs_c1[1], + fp3_ep::Frobenius_coeffs_c2[1] + }; + + typename BlueprintFieldType::value_type fc6[] = { + 1, + fp6_ep::Frobenius_coeffs_c1[1], + }; + + constrs.clear(); + for(std::size_t i = 0; i < 6; ++i) { + constraint_type coeff = constraint_type() + fc6[i/3]*fc3[i%3]; + constrs.push_back(Xn[i] - coeff*X[i]); + } + + gate_list.push_back(bp.add_gate(constrs)); + } + + /* Division gate - 1 + * Ensures x_next = x_prev/x : x_next * x - x_prev = 0 + */ + { + R = Xn*X - Xp; + + constrs.clear(); + for(std::size_t i = 0; i < 6; ++i) { + constrs.push_back(R[i]); + } + + gate_list.push_back(bp.add_gate(constrs)); + } + + /* Multiplication gate - 2 + * Ensures x_next = x*x_prev: x_next - x*x_prev = 0 + */ + { + R = Xn - X*Xp; + + constrs.clear(); + for(std::size_t i = 0; i < 6; ++i) { + constrs.push_back(R[i]); + } + + gate_list.push_back(bp.add_gate(constrs)); + } + + return gate_list; + } + + template + void generate_copy_constraints( + plonk_mnt6_exponentiation const& component, + circuit> &bp, + assignment> &assignment, + const typename plonk_mnt6_exponentiation::input_type &instance_input, + const std::size_t start_row_index) + { + using component_type = plonk_mnt6_exponentiation; + using var = typename plonk_mnt6_exponentiation::var; + + using fixed_power_type = typename component_type::fixed_power_type; + using curve_type = nil::crypto3::algebra::curves::mnt6<298>; + fixed_power_type power_instance( component._W, component._C, component._PI, + crypto3::algebra::pairing::detail::pairing_params::final_exponent_last_chunk_abs_of_w0); + std::size_t R = power_instance.rows_amount; + + // initial data in row 0 + for(std::size_t i = 0; i < 6; ++i) { + bp.add_copy_constraint({var(component.W(i), start_row_index, false), instance_input.x[i]}); + } + + // initial data in row 4 + for(std::size_t i = 0; i < 6; ++i) { + bp.add_copy_constraint({var(component.W(i), start_row_index + 4, false), instance_input.x[i]}); + } + + // Copy from 8 row to R+9 row + for(std::size_t i = 0; i < 6; ++i) { + bp.add_copy_constraint({ + var(component.W(i), start_row_index + R + 9, false), + var(component.W(i), start_row_index + 8, false), + }); + } + + // Copy from R+8 row to R+10 row + for(std::size_t i = 0; i < 6; ++i) { + bp.add_copy_constraint({ + var(component.W(i), start_row_index + R + 10, false), + var(component.W(i), start_row_index + R + 8, false), + }); + } + } + + template + typename plonk_mnt6_exponentiation::result_type + generate_circuit( + plonk_mnt6_exponentiation const& component, + circuit> &bp, + assignment> &assignment, + const typename plonk_mnt6_exponentiation::input_type &instance_input, + const std::size_t start_row_index) + { + using component_type = plonk_mnt6_exponentiation; + using var = typename component_type::var; + using fixed_power_type = typename component_type::fixed_power_type; + using curve_type = nil::crypto3::algebra::curves::mnt6<298>; + + fixed_power_type power_instance( component._W, component._C, component._PI, + crypto3::algebra::pairing::detail::pairing_params::final_exponent_last_chunk_abs_of_w0); + + std::vector selector_index = generate_gates(component, bp, assignment, instance_input); + + // Frobenius gates + assignment.enable_selector(selector_index[0], start_row_index + 0); + assignment.enable_selector(selector_index[0], start_row_index + 1); + assignment.enable_selector(selector_index[0], start_row_index + 2); + // Copy at 3 + // Division gate at 4 + assignment.enable_selector(selector_index[1], start_row_index + 4); + // Frobenius at 5 + assignment.enable_selector(selector_index[0], start_row_index + 5); + // Multiplication at 6 + assignment.enable_selector(selector_index[2], start_row_index + 6); + // Frobenius at 7 + assignment.enable_selector(selector_index[0], start_row_index + 7); + + // Power to w0 sub-circuit takes input from 7-th rouw + std::array power_input_vars; + for(std::size_t i = 0 ; i < 6; ++i ) { + power_input_vars[i] = var(component.W(i), start_row_index + 7, false); + } + + typename fixed_power_type::input_type power_input = { power_input_vars }; + typename fixed_power_type::result_type power_output = + generate_circuit(power_instance, bp, assignment, power_input, start_row_index + 9); + std::size_t R = power_instance.rows_amount; + + // expect result at start_rows_index + R + 9 + + // Inverse division gate + assignment.enable_selector(selector_index[1], start_row_index + R + 10); + + generate_copy_constraints(component, bp, assignment, instance_input, start_row_index); + + return typename plonk_mnt6_exponentiation::result_type( + component, start_row_index); + } + } // namespace components + } // namespace blueprint +} // namespace nil + +#endif // CRYPTO3_BLUEPRINT_COMPONENTS_PLONK_mnt6_exponentiation_HPP diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index bab8a9b70..6129519ef 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -81,6 +81,7 @@ set(NON_NATIVE_TESTS_FILES "algebra/fields/plonk/non_native/equality_flag" "algebra/fields/plonk/non_native/division_remainder" "algebra/fields/plonk/non_native/mnt4_fp4_fixed_power" + "algebra/fields/plonk/non_native/mnt6_fp6_fixed_power" "non_native/plonk/bool_scalar_multiplication" "non_native/plonk/add_mul_zkllvm_compatible" "non_native/plonk/scalar_non_native_range" @@ -191,6 +192,7 @@ set(HASHES_TESTS_FILES set(PAIRING_TESTS_FILES "algebra/pairing/weierstrass/plonk/mnt4_pairing" "algebra/pairing/weierstrass/plonk/mnt4_exponentiation" + "algebra/pairing/weierstrass/plonk/mnt6_exponentiation" "algebra/pairing/weierstrass/r1cs/miller_loop" "algebra/pairing/weierstrass/r1cs/precomputation") diff --git a/test/algebra/fields/plonk/non_native/mnt4_fp4_fixed_power.cpp b/test/algebra/fields/plonk/non_native/mnt4_fp4_fixed_power.cpp index 536620f2b..4275238cb 100644 --- a/test/algebra/fields/plonk/non_native/mnt4_fp4_fixed_power.cpp +++ b/test/algebra/fields/plonk/non_native/mnt4_fp4_fixed_power.cpp @@ -49,7 +49,7 @@ using namespace nil; template void test_mnt4_fp4_fixed_power( std::vector public_input, - typename CurveType::base_field_type::extended_integral_type power, + typename CurveType::base_field_type::integral_type power, typename CurveType::gt_type::value_type expected_res) { using curve_type = CurveType; @@ -141,8 +141,8 @@ BOOST_AUTO_TEST_CASE(blueprint_plonk_mnt4_fp4_fixed_power_test) { ), }; - //auto fixed_power = pairing::detail::pairing_params::final_exponent_last_chunk_abs_of_w0; - auto fixed_power = pairing::detail::pairing_params::final_exponent; + auto fixed_power = pairing::detail::pairing_params::final_exponent_last_chunk_abs_of_w0; +// auto fixed_power = pairing::detail::pairing_params::final_exponent; // auto fixed_power = integral_type("100"); for(std::size_t i = 0; i < test_gt_elems.size(); i++) { diff --git a/test/algebra/fields/plonk/non_native/mnt6_fp6_fixed_power.cpp b/test/algebra/fields/plonk/non_native/mnt6_fp6_fixed_power.cpp new file mode 100644 index 000000000..bd2a6e726 --- /dev/null +++ b/test/algebra/fields/plonk/non_native/mnt6_fp6_fixed_power.cpp @@ -0,0 +1,174 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2024 Vasiliy Olekhov +// +// 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. +//---------------------------------------------------------------------------// +// +// exponentiation to a fixed power in Fp4 for mnt6 GT +// +#define BOOST_TEST_MODULE blueprint_plonk_mnt6_fp4_fixed_power_test + +#include + +#include +#include +#include +#include + +#include + +#include + +#include +#include + +#include + +#include "../../../../test_plonk_component.hpp" + +using namespace nil; + +template +void test_mnt6_fp6_fixed_power( + std::vector public_input, + typename CurveType::base_field_type::integral_type power, + typename CurveType::gt_type::value_type expected_res) +{ + using curve_type = CurveType; + using BlueprintFieldType = typename curve_type::base_field_type; + + constexpr std::size_t WitnessColumns = WitnessAmount; + constexpr std::size_t PublicInputColumns = 1; + constexpr std::size_t ConstantColumns = 0; + constexpr std::size_t SelectorColumns = 5; + zk::snark::plonk_table_description desc( + WitnessColumns, PublicInputColumns, ConstantColumns, SelectorColumns); + + using ArithmetizationType = crypto3::zk::snark::plonk_constraint_system; + using AssignmentType = blueprint::assignment; + using hash_type = crypto3::hashes::keccak_1600<256>; + constexpr std::size_t Lambda = 40; + + using var = crypto3::zk::snark::plonk_variable; + + using component_type = blueprint::components::mnt6_fp6_fixed_power; + + typename component_type::input_type instance_input = { + var(0, 0, false, var::column_type::public_input), + var(0, 1, false, var::column_type::public_input), + var(0, 2, false, var::column_type::public_input), + var(0, 3, false, var::column_type::public_input), + var(0, 4, false, var::column_type::public_input), + var(0, 5, false, var::column_type::public_input) + }; + + auto result_check = [&expected_res, public_input](AssignmentType &assignment, + typename component_type::result_type &real_res) { + #ifdef BLUEPRINT_PLONK_PROFILING_ENABLED + std::cout << "GT (mnt6_FP6) fixed power test: " << "\n"; + std::cout << "input : " << public_input[0].data << "," << public_input[1].data << "\n"; + std::cout << "input : " << public_input[2].data << "," << public_input[3].data << "\n"; + std::cout << "input : " << public_input[4].data << "," << public_input[5].data << "\n"; + std::cout << "expected: " << expected_res.data[0].data[0] << "," << expected_res.data[0].data[1] << ",\n"; + std::cout << " : " << expected_res.data[0].data[2] << "," << expected_res.data[1].data[0] << ",\n"; + std::cout << " : " << expected_res.data[1].data[1] << "," << expected_res.data[1].data[2] << ",\n"; + std::cout << "real : " << var_value(assignment, real_res.output[0]).data << "," << var_value(assignment, real_res.output[1]).data << ",\n"; + std::cout << " " << var_value(assignment, real_res.output[2]).data << "," << var_value(assignment, real_res.output[3]).data << "\n\n"; + std::cout << " " << var_value(assignment, real_res.output[4]).data << "," << var_value(assignment, real_res.output[5]).data << "\n\n"; + #endif + assert(expected_res.data[0].data[0] == var_value(assignment, real_res.output[0])); + assert(expected_res.data[0].data[1] == var_value(assignment, real_res.output[1])); + assert(expected_res.data[0].data[2] == var_value(assignment, real_res.output[2])); + assert(expected_res.data[1].data[0] == var_value(assignment, real_res.output[3])); + assert(expected_res.data[1].data[1] == var_value(assignment, real_res.output[4])); + assert(expected_res.data[1].data[2] == var_value(assignment, real_res.output[5])); + return true; + }; + + std::array witnesses; + for (std::uint32_t i = 0; i < WitnessColumns; i++) { + witnesses[i] = i; + } + + component_type component_instance(witnesses, + std::array{}, + std::array{}, + power); + + crypto3::test_component( + component_instance, desc, public_input, result_check, instance_input, + nil::blueprint::connectedness_check_type::type::STRONG, + power); +} + +constexpr static const std::size_t random_tests_amount = 10; + +BOOST_AUTO_TEST_SUITE(blueprint_plonk_test_suite) + +BOOST_AUTO_TEST_CASE(blueprint_plonk_mnt6_fp4_fixed_power_test) { + using curve_type = crypto3::algebra::curves::mnt6_298; + using group_type = typename curve_type::gt_type; + using base_field_value = curve_type::base_field_type::value_type; + + typedef typename group_type::value_type group_value_type; + typedef typename group_type::underlying_field_type::value_type underlying_field_type; + typedef typename group_type::base_field_type::value_type field_value_type; + typedef typename group_type::base_field_type::integral_type integral_type; + + std::vector test_gt_elems = { + group_value_type( + underlying_field_type( + 3,2,1 +// 0x22c26a3c19d56fc8790485554be5dc4351961a5162c3634965dc8ae56701157e_cppui254, +// 0x1e3305b98bf381650491b7b63559d20d662b70f1616e680a19170715b59a3426_cppui254 + ), + underlying_field_type( + 4,5,6 +// 0x148a1f438a4cd0d807549cb7f9ec9f41dba3d8b14a6b0f2489d9b9f626d6fd31_cppui254, +// 0x3cc907ef65b0eff91d027e4771e9116a0b125325627b6bdf55037702220b1b2_cppui254 + ) + ), + }; + + auto fixed_power = pairing::detail::pairing_params::final_exponent_last_chunk_abs_of_w0; +// auto fixed_power = pairing::detail::pairing_params::final_exponent; +// auto fixed_power = integral_type("100"); + + for(std::size_t i = 0; i < test_gt_elems.size(); i++) { + std::cout << "Test instance # " << (i+1) << "\n"; + group_value_type P = test_gt_elems[i]; + group_value_type R = P.pow(fixed_power); + + test_mnt6_fp6_fixed_power( + std::vector{ + P.data[0].data[0], + P.data[0].data[1], + P.data[0].data[2], + P.data[1].data[0], + P.data[1].data[1], + P.data[1].data[2], + }, + fixed_power, + R); + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/algebra/pairing/weierstrass/plonk/mnt6_exponentiation.cpp b/test/algebra/pairing/weierstrass/plonk/mnt6_exponentiation.cpp new file mode 100644 index 000000000..5abeeb2f6 --- /dev/null +++ b/test/algebra/pairing/weierstrass/plonk/mnt6_exponentiation.cpp @@ -0,0 +1,152 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2024 Vasiliy Olekhov +// +// 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. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE blueprint_plonk_pairing_mnt6_298 + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#include + +#include "../../../../test_plonk_component.hpp" + +using namespace nil; +using namespace blueprint::components::detail; + +template +void test_mnt6_298_exponentiation(std::vector public_input, + std::vector expected_res) { + constexpr std::size_t PublicInputColumns = 1; + constexpr std::size_t ConstantColumns = 1; + constexpr std::size_t SelectorColumns = 8; + + zk::snark::plonk_table_description desc( + WitnessColumns, PublicInputColumns, ConstantColumns, SelectorColumns); + using ArithmetizationType = crypto3::zk::snark::plonk_constraint_system; + using hash_type = nil::crypto3::hashes::keccak_1600<256>; + constexpr std::size_t Lambda = 40; + using AssignmentType = nil::blueprint::assignment; + + using value_type = typename FieldType::value_type; + using var = crypto3::zk::snark::plonk_variable; + + using component_type = blueprint::components::mnt6_exponentiation; + + typename component_type::input_type instance_input = { + var(0,0, false, var::column_type::public_input), // f[0] + var(0,1, false, var::column_type::public_input), // f[1] + var(0,2, false, var::column_type::public_input), // f[2] + var(0,3, false, var::column_type::public_input), // f[3] + var(0,4, false, var::column_type::public_input), // f[3] + var(0,5, false, var::column_type::public_input), // f[3] + }; + + auto result_check = [&expected_res](AssignmentType const& assignment, + typename component_type::result_type const& real_res) { + #ifdef BLUEPRINT_PLONK_PROFILING_ENABLED + std::cout << "mnt6-298 Final exponentiation: expected res VS output\n"; + for(std::size_t i = 0; i < 6; i++) { + std::cout << std::dec << expected_res[i].data << " =? " << var_value(assignment, real_res.output[i]).data << "\n"; + } + #endif + for(std::size_t i = 0; i < 6; i++) { + assert(expected_res[i] == var_value(assignment, real_res.output[i])); + } + }; + + std::array witnesses; + for (std::uint32_t i = 0; i < WitnessColumns; i++) { + witnesses[i] = i; + } + + component_type component_instance(witnesses, // witnesses + std::array{}, // constants + std::array{} // public inputs + ); + + nil::crypto3::test_component ( + component_instance, desc, public_input, result_check, instance_input); +} + +static const std::size_t random_tests_amount = 5; + +BOOST_AUTO_TEST_SUITE(blueprint_plonk_test_suite) + +BOOST_AUTO_TEST_CASE(blueprint_plonk_mnt6_pairing_test) { + using curve_type = crypto3::algebra::curves::mnt6_298; + using gt_group_type = typename curve_type::gt_type; + using base_field_value = curve_type::base_field_type::value_type; + using field_type = typename curve_type::gt_type::base_field_type; + + nil::crypto3::random::algebraic_engine generate_random; + boost::random::mt19937 seed_seq; + generate_random.seed(seed_seq); + + std::vector + AB_ML = { + 0x02f487892d5db56458de095daa86a1ebb90a07517cccad41a46b48438ca24173be6f3a32c6cb_cppui298, + 0x01217e7c9d35c9c75d1fbcb5d46e482d053c9da4ab9f3c37b741900af9ca42ff9b50001aec5f_cppui298, + 0x01f0324b79887ef191ff8d0c9152cfed7445abb63faa598eaa51ddfea0af7a642f7cf6ba70fe_cppui298, + 0x033f650fdb078d7fb4a8153c8c621d84dd01460a4173bd01371d360e71c6cb46392dd0e00f1f_cppui298, + 0x0023d3795211bb71c579250426dc77d6c7a32a24136b0f02780be3b2f4c674b54a6a5989f9f4_cppui298, + 0x01b5c328e47a03bddb00f0992ddbd9945af3e0f4bb8244d29b9b24ca2390e92ecc5666a76191_cppui298 + }, + AB_FE = { + /* + 0x15dec519566f20aa6a3bd4ddb0cee93f9ea157499f20273124883934daeea1867ea53ac4b9b_cppui298, + 0x3b5fc396c41a54c7c661b3d34ead6f284a50886534f036c004eb31d8d7cb061d3419f6a9d58_cppui298, + 0x1b79ac259f41bfdc8aa623c65075d0a0fb1823467b174c4ac82cada904d96f3640fd491baf7_cppui298, + 0x667fef1c7f96557416d9728951128edb921b4ecad5592fd898db5867bf40dfa20de956a717_cppui298, + 0x39143f4b1cee4646b2a1a77d27fc21aead95a0922a4a5f9facb82d88120b01737fafb1f1d8d_cppui298, + 0x2f84e7545b29729839b5871c25a131756558cd8bba38d2ef7439f20b5cb54be2a271a3c1bba_cppui298, + */ + 0x025aba200efbefa81017a858457abfc1e83ce8f7e92788e414fe90bacd465395dec8463bf09a_cppui298, + 0x002ca86c9adeb0cfd62db143cc3fc5b6adb9fd09419a43b6c5b841f129a0ef71fa3881a4b743_cppui298, + 0x00e7bc013d484cc770ddcaa994422f153265c143a64549b916f6893c2e2ab5458e7c3ea5f3d7_cppui298, + 0x01b26a752dd48454cc5361994c65bbea4f5315383c0051be7285afebd49608614a17945879ff_cppui298, + 0x0378d4dd54964822cabd59be83661224fb84a4820c190c62d3a701e2eaf60ac8dc13e0db1c99_cppui298, + 0x037f4a31f3bc24e9876d57a5b224d8f6475d36407e092bc03144d1bf042a0aee471639db2439_cppui298 + }; + + std::cout << "mnt6-298 Final exponentiation test\n"; + test_mnt6_298_exponentiation(AB_ML, AB_FE); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/test_plonk_component.hpp b/test/test_plonk_component.hpp index d7d7de74e..73498e9fc 100644 --- a/test/test_plonk_component.hpp +++ b/test/test_plonk_component.hpp @@ -252,7 +252,7 @@ namespace nil { variable.get() = assignment.get_batch_variable_map().at(variable); } } -/* +#if 0 std::ofstream fass("circuit.tbl"); assignment.export_table(fass); fass.close(); @@ -260,7 +260,7 @@ namespace nil { std::ofstream fcirc("circuit.crt"); bp.export_circuit(fcirc); fcirc.close(); -*/ +#endif result_check(assignment, component_result); if constexpr (!PrivateInput) { @@ -317,12 +317,12 @@ namespace nil { } desc.rows_amount = zk::snark::basic_padding(assignment); -//#ifdef BLUEPRINT_PLONK_PROFILING_ENABLED +#ifdef BLUEPRINT_PLONK_PROFILING_ENABLED std::cout << "Usable rows: " << desc.usable_rows_amount << std::endl; std::cout << "Padded rows: " << desc.rows_amount << std::endl; // profiling(assignment); -//#endif +#endif //assignment.export_table(std::cout); //bp.export_circuit(std::cout);