diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_double.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_double.hpp index 7518c6203..e70280e68 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_double.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_double.hpp @@ -1,6 +1,6 @@ //---------------------------------------------------------------------------// // Copyright (c) 2024 Alexey Yashunsky -// Copyright (c) 2024 Antoine Cyr +// Copyright (c) 2024 Antoine Cyr // // MIT License // @@ -22,7 +22,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. //---------------------------------------------------------------------------// -// @file Declaration of interfaces for FRI verification array swapping component. +// @file Declaration of interfaces for doubling an EC points over a non-native field //---------------------------------------------------------------------------// #ifndef CRYPTO3_BBF_COMPONENTS_EC_DOUBLE_ECDSA_HPP @@ -56,8 +56,9 @@ namespace nil { // Expects input as k-chunked values with b bits per chunk // p' = 2^(kb) - p // Input: xQ[0],...,xQ[k-1], yQ[0],...,yQ[k-1], p[0],...,p[k-1], - // pp[0],...,pp[k-1], 0 (expects zero constant as input) Output: - // xR[0],...,xR[k-1], yR[0],...,yR[k-1] + // pp[0],...,pp[k-1], 0 + // (expects zero constant as input) + // Output: xR[0],...,xR[k-1], yR[0],...,yR[k-1] template struct ec_double_raw_input { @@ -70,7 +71,7 @@ namespace nil { }; template + typename NonNativeFieldType> class ec_double : public generic_component { using generic_component::allocate; using generic_component::copy_constrain; @@ -78,16 +79,16 @@ namespace nil { using generic_component::lookup; using component_type = generic_component; - public: + public: using typename generic_component::TYPE; using typename generic_component::context_type; using typename generic_component::table_params; using raw_input_type = typename std::conditional, - std::tuple<>>::type; + ec_double_raw_input, + std::tuple<>>::type; - public: + public: std::vector inp_xQ; std::vector inp_yQ; std::vector inp_p; @@ -103,13 +104,13 @@ namespace nil { // rows = 4096-1 so that lookup table is not too hard to fit and // padding doesn't inflate the table constexpr std::size_t rows = 4095; - return { witness, public_inputs, constants, rows }; + return {witness, public_inputs, constants, rows}; } static std::tuple, std::vector, - std::vector, std::vector, TYPE> - form_input(context_type& context_object, raw_input_type raw_input, - std::size_t num_chunks, std::size_t bit_size_chunk) { + std::vector, std::vector, TYPE> + form_input(context_type& context_object, raw_input_type raw_input, + std::size_t num_chunks, std::size_t bit_size_chunk) { std::vector input_xQ(num_chunks); std::vector input_yQ(num_chunks); std::vector input_p(num_chunks); @@ -127,29 +128,30 @@ namespace nil { } for (std::size_t i = 0; i < num_chunks; i++) { context_object.allocate(input_xQ[i], 0, i, - column_type::public_input); + column_type::public_input); context_object.allocate(input_yQ[i], 0, i + num_chunks, - column_type::public_input); + column_type::public_input); context_object.allocate(input_p[i], 0, i + 2 * num_chunks, - column_type::public_input); + column_type::public_input); context_object.allocate(input_pp[i], 0, i + 3 * num_chunks, - column_type::public_input); + column_type::public_input); } context_object.allocate(input_zero, 0, 4 * num_chunks, - column_type::public_input); + column_type::public_input); return std::make_tuple(input_xQ, input_yQ, input_p, input_pp, - input_zero); + input_zero); } ec_double(context_type& context_object, std::vector input_xQ, - std::vector input_yQ, std::vector input_p, - std::vector input_pp, TYPE input_zero, - std::size_t num_chunks, std::size_t bit_size_chunk, - bool make_links = true) + std::vector input_yQ, std::vector input_p, + std::vector input_pp, TYPE input_zero, + std::size_t num_chunks, std::size_t bit_size_chunk, + bool make_links = true) : generic_component(context_object) { using integral_type = typename FieldType::integral_type; using NON_NATIVE_TYPE = typename NonNativeFieldType::value_type; - using non_native_integral_type = typename NonNativeFieldType::integral_type; + using non_native_integral_type = + typename NonNativeFieldType::integral_type; using Choice_Function = typename bbf::components::choice_function; @@ -158,12 +160,14 @@ namespace nil { using Check_Mod_P = typename bbf::components::check_mod_p; using Addition_Mod_P = - typename bbf::components::addition_mod_p; + typename bbf::components::addition_mod_p; using Negation_Mod_P = - typename bbf::components::negation_mod_p; + typename bbf::components::negation_mod_p; using Multiplication_Mod_P = - typename bbf::components::flexible_multiplication; + typename bbf::components::flexible_multiplication< + FieldType, stage, NonNativeFieldType>; std::vector XQ(num_chunks); std::vector YQ(num_chunks); @@ -190,34 +194,36 @@ namespace nil { for (std::size_t i = 0; i < num_chunks; ++i) { xQ += non_native_integral_type( - integral_type(input_xQ[i].data)) * - pow; + integral_type(input_xQ[i].data)) * + pow; yQ += non_native_integral_type( - integral_type(input_yQ[i].data)) * - pow; + integral_type(input_yQ[i].data)) * + pow; pow <<= bit_size_chunk; } NON_NATIVE_TYPE - lambda = + lambda = (yQ == 0) - ? 0 - : 3 * xQ * xQ * - ((2 * yQ).inversed()), // if yQ = 0, lambda = 0 + ? 0 + : 3 * xQ * xQ * + ((2 * yQ).inversed()), // if yQ = 0, lambda = 0 z = (yQ == 0) ? 0 : yQ.inversed(), // if yQ = 0, z = 0 xR = lambda * lambda - 2 * xQ, - yR = lambda * (xQ - xR) - yQ; + yR = lambda * (xQ - xR) - yQ; auto base = [num_chunks, bit_size_chunk](NON_NATIVE_TYPE x) { std::vector res(num_chunks); - non_native_integral_type mask = (non_native_integral_type(1) << bit_size_chunk) - 1; - non_native_integral_type x_value = non_native_integral_type(x.data); + non_native_integral_type mask = + (non_native_integral_type(1) << bit_size_chunk) - 1; + non_native_integral_type x_value = + non_native_integral_type(x.data); for (std::size_t i = 0; i < num_chunks; i++) { res[i] = TYPE(x_value & mask); x_value >>= bit_size_chunk; } return res; - }; + }; LAMBDA = base(lambda); Z = base(z); @@ -238,21 +244,21 @@ namespace nil { } allocate(ZERO); - auto check_chunked = - [&context_object, num_chunks, bit_size_chunk, PP, ZERO](std::vector x) { - Range_Check rc = Range_Check(context_object, x, - num_chunks, bit_size_chunk); + auto check_chunked = [&context_object, num_chunks, bit_size_chunk, + PP, ZERO](std::vector x) { + Range_Check rc = Range_Check(context_object, x, num_chunks, + bit_size_chunk); Check_Mod_P cm = Check_Mod_P(context_object, x, PP, ZERO, - num_chunks, bit_size_chunk); - }; + num_chunks, bit_size_chunk); + }; // Copy constraint generation lambda expression - auto CopyConstrain = [this, num_chunks](std::vector x, std::vector y) { + auto CopyConstrain = [this, num_chunks](std::vector x, + std::vector y) { for (std::size_t i = 0; i < num_chunks; i++) { copy_constrain(x[i], y[i]); } - }; - + }; // perform range checks and mod p checks on all stored variables check_chunked(LAMBDA); @@ -260,67 +266,46 @@ namespace nil { check_chunked(XR); check_chunked(YR); - Multiplication_Mod_P t1 = Multiplication_Mod_P( - context_object, YQ, LAMBDA, P, PP, ZERO, num_chunks, bit_size_chunk); // t1 = yQ * lambda - - - Addition_Mod_P t2 = - Addition_Mod_P(context_object, t1.res_z, t1.res_z, P, - PP, ZERO, num_chunks, bit_size_chunk); // t2 = t1 + t1 = 2yQ * lambda - Addition_Mod_P t3 = Addition_Mod_P(context_object, XQ, XQ, P, PP, - ZERO, num_chunks, bit_size_chunk); // t3 = xQ + xQ = 2xQ - if constexpr (stage == GenerationStage::ASSIGNMENT) { - non_native_integral_type a = 0, b = 0, pow = 1; - for (std::size_t i = 0; i < num_chunks; ++i) { - a += non_native_integral_type(integral_type( - t1.res_z[i].data)) * - pow; - b += non_native_integral_type(integral_type( - t3.res_z[i].data)) * - pow; - pow <<= bit_size_chunk; - } - } - Addition_Mod_P t4 = - Addition_Mod_P(context_object, XQ, t3.res_z, P, PP, - ZERO, num_chunks, bit_size_chunk); // t4 = xQ + t3 = 3xQ - Multiplication_Mod_P t5 = Multiplication_Mod_P( - context_object, t4.res_z, XQ, P, PP, ZERO, num_chunks, bit_size_chunk); // t5 = t4 * xQ = 3xQ^2 - if constexpr (stage == GenerationStage::ASSIGNMENT) { - non_native_integral_type a = 0, b = 0, pow = 1; - for (std::size_t i = 0; i < num_chunks; ++i) { - a += non_native_integral_type( - integral_type(t2.res_z[i].data)) * - pow; - b += non_native_integral_type( - integral_type(t5.res_z[i].data)) * - pow; - pow <<= bit_size_chunk; - } - } - CopyConstrain(t2.res_z, t5.res_z); // 2yQ * lambda = 3xQ^2 - Addition_Mod_P t6 = - Addition_Mod_P(context_object, XR, t3.res_z, P, PP, - ZERO, num_chunks, bit_size_chunk); // t6 = xR + t3 = xR + 2xQ - Multiplication_Mod_P t7 = - Multiplication_Mod_P(context_object, LAMBDA, LAMBDA, P, - PP, ZERO, num_chunks, bit_size_chunk); // t7 = lambda * lambda - CopyConstrain(t6.res_z, t7.res_z); // xR + 2xQ = lambda^2 - Addition_Mod_P t8 = Addition_Mod_P(context_object, YR, YQ, P, PP, - ZERO, num_chunks, bit_size_chunk); // t8 = yR + yQ - Negation_Mod_P t9 = - Negation_Mod_P(context_object, XR, P, PP, ZERO, num_chunks, bit_size_chunk); // t9 = -xR - Addition_Mod_P t10 = - Addition_Mod_P(context_object, XQ, t9.res_z, P, PP, - ZERO, num_chunks, bit_size_chunk); // t10 = xQ + t9 = xQ - xR - Multiplication_Mod_P t11 = Multiplication_Mod_P( - context_object, LAMBDA, t10.res_z, P, - PP, ZERO, num_chunks, bit_size_chunk); // t11 = lambda * t10 =lambda(xQ-xR) - CopyConstrain(t8.res_z, t11.res_z); // yR + yQ = lambda(xQ - xR) - Multiplication_Mod_P t12 = - Multiplication_Mod_P(context_object, Z, t1.res_z, P, PP, ZERO, - num_chunks, bit_size_chunk); // t12 = z * t1 = z * yQ * lambda - CopyConstrain(LAMBDA, t12.res_z); // lambda = z yQ lambda + auto MultModP = [&context_object, P, PP, ZERO, num_chunks, + bit_size_chunk](std::vector x, + std::vector y) { + Multiplication_Mod_P t = + Multiplication_Mod_P(context_object, x, y, P, PP, ZERO, + num_chunks, bit_size_chunk); + return t.res_r; + }; + auto AddModP = [&context_object, P, PP, ZERO, num_chunks, + bit_size_chunk](std::vector x, + std::vector y) { + Addition_Mod_P t = + Addition_Mod_P(context_object, x, y, P, PP, ZERO, + num_chunks, bit_size_chunk); + return t.res_r; + }; + auto NegModP = [&context_object, P, PP, ZERO, num_chunks, + bit_size_chunk](std::vector x) { + Negation_Mod_P t = + Negation_Mod_P(context_object, x, P, PP, ZERO, num_chunks, + bit_size_chunk); + return t.res_r; + }; + + auto t1 = MultModP(YQ,LAMBDA); // t1 = yQ * lambda + auto t2 = AddModP(t1,t1); // t2 = t1 + t1 = 2yQ * lambda + auto t3 = AddModP(XQ,XQ); // t3 = xQ + xQ = 2xQ + auto t4 = AddModP(XQ,t3); // t4 = xQ + t3 = 3xQ + auto t5 = MultModP(t4,XQ); // t5 = t4 * xQ = 3xQ^2 + CopyConstrain(t2, t5); // 2yQ lambda = 3xQ^2 + auto t6 = AddModP(XR,t3); // t6 = xR + t3 = xR + 2xQ + auto t7 = MultModP(LAMBDA,LAMBDA); // t7 = lambda * lambda + CopyConstrain(t6, t7); // xR + 2xQ = lambda^2 + auto t8 = AddModP(YR,YQ); // t8 = yR + yQ + auto t9 = NegModP(XR); // t9 = -xR + auto t10 = AddModP(XQ,t9); // t10 = xQ + t9 = xQ - xR + auto t11 = MultModP(LAMBDA,t10); // t11 = lambda * t10 =lambda(xQ-xR) + CopyConstrain(t8, t11); // yR + yQ = lambda(xQ - xR) + auto t12 = MultModP(Z,t1); // t12 = z * t1 = z * yQ * lambda + CopyConstrain(LAMBDA, t12); // lambda = z yQ lambda if (make_links) { for (std::size_t i = 0; i < num_chunks; ++i) { @@ -348,25 +333,25 @@ namespace nil { template class pallas_ec_double : public ec_double< - FieldType, stage, - crypto3::algebra::curves::pallas::base_field_type> { + FieldType, stage, + crypto3::algebra::curves::pallas::base_field_type> { using Base = ec_double; + crypto3::algebra::curves::pallas::base_field_type>; - public: + public: using Base::Base; }; template class vesta_ec_double : public ec_double { + crypto3::algebra::curves::vesta::base_field_type> { using Base = ec_double; + crypto3::algebra::curves::vesta::base_field_type>; - public: + public: using Base::Base; }; diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_double_old.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_double_old.hpp deleted file mode 100644 index 596de4945..000000000 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_double_old.hpp +++ /dev/null @@ -1,561 +0,0 @@ -//---------------------------------------------------------------------------// -// Copyright (c) 2024 Alexey Yashunsky -// -// 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 interfaces for doubling an EC point over a non-native field -//---------------------------------------------------------------------------// - -#ifndef CRYPTO3_BLUEPRINT_COMPONENTS_PLONK_EC_DOUBLE_ECDSA_HPP -#define CRYPTO3_BLUEPRINT_COMPONENTS_PLONK_EC_DOUBLE_ECDSA_HPP - -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -namespace nil { - namespace blueprint { - namespace components { - // Parameters: num_chunks = k, bit_size_chunk = b - // For a point Q = (x_Q,y_Q) from an elliptic curve over F[p] - // computes R = (x_R, y_R) = 2Q (EC doubling) - // Expects input as k-chunked values with b bits per chunk - // p' = 2^(kb) - p - // Input: xQ[0],...,xQ[k-1], yQ[0],...,yQ[k-1], p[0],...,p[k-1], pp[0],...,pp[k-1], 0 - // (expects zero constant as input) - // Output: xR[0],...,xR[k-1], yR[0],...,yR[k-1] - // - template - class ec_double; - - template - class ec_double, - BlueprintFieldType, - NonNativeFieldType, - num_chunks, - bit_size_chunk> - : public plonk_component { - - public: - using component_type = plonk_component; - - using var = typename component_type::var; - using manifest_type = plonk_component_manifest; - using range_check_component = range_check_multi, - BlueprintFieldType, num_chunks, bit_size_chunk>; - using check_mod_p_component = check_mod_p, - BlueprintFieldType, num_chunks, bit_size_chunk>; - using mult_mod_p_component = flexible_mult, - BlueprintFieldType, NonNativeFieldType, num_chunks, bit_size_chunk>; - using neg_mod_p_component = negation_mod_p, - BlueprintFieldType, NonNativeFieldType, num_chunks, bit_size_chunk>; - using add_mod_p_component = addition_mod_p, - BlueprintFieldType, NonNativeFieldType, num_chunks, bit_size_chunk>; - - // needed only for gate_manifest: - using choice_function_component = - choice_function, BlueprintFieldType, num_chunks>; - - class gate_manifest_type : public component_gate_manifest { - public: - std::uint32_t gates_amount() const override { - return ec_double::gates_amount; - } - }; - - static gate_manifest get_gate_manifest(std::size_t witness_amount) { - // NB: this uses a workaround, as manifest cannot process intersecting sets of gates. - // We merge only non-intersecting sets of gates which cover all gates in the circuit. - gate_manifest manifest = - gate_manifest(gate_manifest_type()) - // .merge_with(range_check_component::get_gate_manifest(witness_amount)) - // .merge_with(check_mod_p_component::get_gate_manifest(witness_amount)) - .merge_with(mult_mod_p_component::get_gate_manifest(witness_amount)) // constains everything except choice_function - .merge_with(choice_function_component::get_gate_manifest(witness_amount)) - // .merge_with(add_mod_p_component::get_gate_manifest(witness_amount)) - // .merge_with(neg_mod_p_component::get_gate_manifest(witness_amount)) - ; - return manifest; - } - - static manifest_type get_manifest() { - manifest_type manifest = manifest_type( - // all requirements come from sub-components, the component itself has no personal requirements - std::shared_ptr(new manifest_range_param(1,4*num_chunks,1)), // we need place for 4k variables - false // constant column not needed - ).merge_with(range_check_component::get_manifest()) - .merge_with(check_mod_p_component::get_manifest()) - .merge_with(mult_mod_p_component::get_manifest()) - .merge_with(add_mod_p_component::get_manifest()) - .merge_with(neg_mod_p_component::get_manifest()); - return manifest; - } - - constexpr static std::size_t get_rows_amount(std::size_t witness_amount) { - return (4*num_chunks)/witness_amount + ((4*num_chunks) % witness_amount > 0) // to store 4k variables - + 4*range_check_component::get_rows_amount(witness_amount) - + 4*check_mod_p_component::get_rows_amount(witness_amount) - + 5*mult_mod_p_component::get_rows_amount(witness_amount) - + 6*add_mod_p_component::get_rows_amount(witness_amount) - + 1*neg_mod_p_component::get_rows_amount(witness_amount) - ; - } - - constexpr static const std::size_t gates_amount = 0; - const std::size_t rows_amount = get_rows_amount(this->witness_amount()); - const std::string component_name = "non-native field EC point doubling function"; - - struct input_type { - var xQ[num_chunks], yQ[num_chunks], p[num_chunks], pp[num_chunks], zero; - - std::vector> all_vars() { - std::vector> res = {zero}; - for(std::size_t i = 0; i < num_chunks; i++) { - res.push_back(xQ[i]); - res.push_back(yQ[i]); - res.push_back(p[i]); - res.push_back(pp[i]); - } - return res; - } - }; - - struct result_type { - var xR[num_chunks], yR[num_chunks]; - - result_type(const ec_double &component, std::uint32_t start_row_index) { - const std::size_t WA = component.witness_amount(); - for(std::size_t i = 0; i < num_chunks; i++) { - xR[i] = var(component.W((2*num_chunks + i) % WA), - start_row_index + (2*num_chunks + i)/WA, false, var::column_type::witness); - yR[i] = var(component.W((3*num_chunks + i) % WA), - start_row_index + (3*num_chunks + i)/WA, false, var::column_type::witness); - } - } - - std::vector> all_vars() { - std::vector> res = {}; - for(std::size_t i = 0; i < num_chunks; i++) { - res.push_back(xR[i]); - res.push_back(yR[i]); - } - return res; - } - }; - - template - explicit ec_double(ContainerType witness) : component_type(witness, {}, {}, get_manifest()) {}; - - template - ec_double(WitnessContainerType witness, ConstantContainerType constant, - PublicInputContainerType public_input) : - component_type(witness, constant, public_input, get_manifest()) {}; - - ec_double( - std::initializer_list - witnesses, - std::initializer_list - constants, - std::initializer_list - public_inputs) : - component_type(witnesses, constants, public_inputs, get_manifest()) {}; - - std::map component_lookup_tables(){ - std::map lookup_tables; - lookup_tables["range_16bit/full"] = 0; - - return lookup_tables; - } - }; - - template - using plonk_ec_double = - ec_double< - crypto3::zk::snark::plonk_constraint_system, - BlueprintFieldType, - NonNativeFieldType, - num_chunks, - bit_size_chunk>; - - template - typename plonk_ec_double::result_type generate_assignments( - const plonk_ec_double &component, - assignment> - &assignment, - const typename plonk_ec_double::input_type - &instance_input, - const std::uint32_t start_row_index) { - - using component_type = plonk_ec_double; - using var = typename component_type::var; - - using range_check_type = typename component_type::range_check_component; - using check_mod_p_type = typename component_type::check_mod_p_component; - using mult_mod_p_type = typename component_type::mult_mod_p_component; - using add_mod_p_type = typename component_type::add_mod_p_component; - using neg_mod_p_type = typename component_type::neg_mod_p_component; - - using value_type = typename BlueprintFieldType::value_type; - using integral_type = typename BlueprintFieldType::integral_type; - using non_native_value_type = typename NonNativeFieldType::value_type; - using non_native_integral_type = typename NonNativeFieldType::integral_type; - - const std::size_t WA = component.witness_amount(); - - // instances of used subcomponents - range_check_type range_check_instance( component._W, component._C, component._PI); - check_mod_p_type check_mod_p_instance( component._W, component._C, component._PI); - mult_mod_p_type mult_mod_p_instance( component._W, component._C, component._PI); - add_mod_p_type add_mod_p_instance( component._W, component._C, component._PI); - neg_mod_p_type neg_mod_p_instance( component._W, component._C, component._PI); - - non_native_integral_type B = non_native_integral_type(1) << bit_size_chunk; - non_native_value_type xQ = 0, - yQ = 0; - - for(std::size_t i = num_chunks; i > 0; i--) { - xQ *= B; - xQ += non_native_integral_type(integral_type(var_value(assignment, instance_input.xQ[i-1]).data)); - yQ *= B; - yQ += non_native_integral_type(integral_type(var_value(assignment, instance_input.yQ[i-1]).data)); - } - - non_native_value_type lambda = (yQ == 0) ? 0 : 3*xQ*xQ*((2*yQ).inversed()), // if yQ = 0, lambda = 0 - z = (yQ == 0) ? 0 : yQ.inversed(), // if yQ = 0, z = 0 - xR = lambda*lambda - 2*xQ, - yR = lambda*(xQ - xR) - yQ; - - auto base_B = [&B](non_native_value_type x) { - std::array res; - non_native_integral_type t = non_native_integral_type(x.data); - for(std::size_t i = 0; i < num_chunks; i++) { - res[i] = t % B; - t /= B; - } - return res; - }; - - std::array lambda_B = base_B(lambda), - z_B = base_B(z), - xR_B = base_B(xR), - yR_B = base_B(yR); - // place to store locations for further reference - var xQ_var[num_chunks], yQ_var[num_chunks], - lambda_var[num_chunks], z_var[num_chunks], xR_var[num_chunks], yR_var[num_chunks]; - - // Store vars for future reference; fill cells with chunks of lambda, z, xR, yR consecutively - for(std::size_t i = 0; i < num_chunks; i++) { - xQ_var[i] = instance_input.xQ[i]; - yQ_var[i] = instance_input.yQ[i]; - - assignment.witness(component.W(i % WA), start_row_index + i/WA) = lambda_B[i]; - lambda_var[i] = var(component.W(i % WA), start_row_index + i/WA, false); - - assignment.witness(component.W((num_chunks + i) % WA), start_row_index + (num_chunks + i)/WA) = z_B[i]; - z_var[i] = var(component.W((num_chunks + i) % WA), start_row_index + (num_chunks + i)/WA,false); - - assignment.witness(component.W((2*num_chunks + i) % WA), start_row_index + (2*num_chunks + i)/WA) = xR_B[i]; - xR_var[i] = var(component.W((2*num_chunks + i) % WA), start_row_index + (2*num_chunks + i)/WA,false); - - assignment.witness(component.W((3*num_chunks + i) % WA), start_row_index + (3*num_chunks + i)/WA) = yR_B[i]; - yR_var[i] = var(component.W((3*num_chunks + i) % WA), start_row_index + (3*num_chunks + i)/WA,false); - } - - // the number of rows used up to now - std::size_t current_row_shift = (4*num_chunks)/WA + ((4*num_chunks) % WA > 0); - - auto check_chunked_var = [&assignment, &instance_input, &range_check_instance, &check_mod_p_instance, - &start_row_index, ¤t_row_shift ] (var x[num_chunks]) { - typename range_check_type::input_type range_check_input; - for(std::size_t i = 0; i < num_chunks; i++) { - range_check_input.x[i] = x[i]; - } - generate_assignments(range_check_instance, assignment, range_check_input, start_row_index + current_row_shift); - current_row_shift += range_check_instance.rows_amount; - - typename check_mod_p_type::input_type mod_p_check_input; - for(std::size_t i = 0; i < num_chunks; i++) { - mod_p_check_input.x[i] = x[i]; - mod_p_check_input.pp[i] = instance_input.pp[i]; - } - mod_p_check_input.zero = instance_input.zero; - generate_assignments(check_mod_p_instance, assignment, mod_p_check_input, - start_row_index + current_row_shift); // check_mod_p - current_row_shift += check_mod_p_instance.rows_amount; - }; - // perform range checks and mod p checks on all stored variables - check_chunked_var(lambda_var); - check_chunked_var(z_var); - check_chunked_var(xR_var); - check_chunked_var(yR_var); - - // assignment generation lambda expressions for mod p arithemetic - auto MultModP = [&instance_input, &mult_mod_p_instance, &assignment, &start_row_index, ¤t_row_shift] - (var x[num_chunks], var y[num_chunks]) { - typename mult_mod_p_type::input_type mult_input; - for(std::size_t i = 0; i < num_chunks; i++) { - mult_input.x[i] = x[i]; - mult_input.y[i] = y[i]; - mult_input.p[i] = instance_input.p[i]; - mult_input.pp[i] = instance_input.pp[i]; - } - mult_input.zero = instance_input.zero; - typename mult_mod_p_type::result_type res = generate_assignments(mult_mod_p_instance, assignment, mult_input, - start_row_index + current_row_shift); - current_row_shift += mult_mod_p_instance.rows_amount; - return res; - }; - auto AddModP = [&instance_input, &add_mod_p_instance, &assignment, &start_row_index, ¤t_row_shift] - (var x[num_chunks], var y[num_chunks]) { - typename add_mod_p_type::input_type add_input; - for(std::size_t i = 0; i < num_chunks; i++) { - add_input.x[i] = x[i]; - add_input.y[i] = y[i]; - add_input.p[i] = instance_input.p[i]; - add_input.pp[i] = instance_input.pp[i]; - } - add_input.zero = instance_input.zero; - typename add_mod_p_type::result_type res = generate_assignments(add_mod_p_instance, assignment, add_input, - start_row_index + current_row_shift); - current_row_shift += add_mod_p_instance.rows_amount; - return res; - }; - auto NegModP = [&instance_input, &neg_mod_p_instance, &assignment, &start_row_index, ¤t_row_shift] - (var x[num_chunks]) { - typename neg_mod_p_type::input_type neg_input; - for(std::size_t i = 0; i < num_chunks; i++) { - neg_input.x[i] = x[i]; - neg_input.p[i] = instance_input.p[i]; - neg_input.pp[i] = instance_input.pp[i]; - } - neg_input.zero = instance_input.zero; - typename neg_mod_p_type::result_type res = generate_assignments(neg_mod_p_instance, assignment, neg_input, - start_row_index + current_row_shift); - current_row_shift += neg_mod_p_instance.rows_amount; - return res; - }; - - typename mult_mod_p_type::result_type t1 = MultModP(yQ_var,lambda_var); // t1 = yQ * lambda - typename add_mod_p_type::result_type t2 = AddModP(t1.r,t1.r); // t2 = t1 + t1 = 2yQ * lambda - typename add_mod_p_type::result_type t3 = AddModP(xQ_var,xQ_var); // t3 = xQ + xQ = 2xQ - typename add_mod_p_type::result_type t4 = AddModP(xQ_var,t3.z); // t4 = xQ + t3 = 3xQ - typename mult_mod_p_type::result_type t5 = MultModP(t4.z,xQ_var); // t5 = t4 * xQ = 3xQ^2 - typename add_mod_p_type::result_type t6 = AddModP(xR_var,t3.z); // t6 = xR + t3 = xR + 2xQ - typename mult_mod_p_type::result_type t7 = MultModP(lambda_var,lambda_var); // t7 = lambda * lambda - typename add_mod_p_type::result_type t8 = AddModP(yR_var,yQ_var); // t8 = yR + yQ - typename neg_mod_p_type::result_type t9 = NegModP(xR_var); // t9 = -xR - typename add_mod_p_type::result_type t10= AddModP(xQ_var,t9.y); // t10 = xQ + t9 = xQ - xR - typename mult_mod_p_type::result_type t11= MultModP(lambda_var,t10.z); // t11 = lambda * t10 =lambda(xQ-xR) - typename mult_mod_p_type::result_type t12= MultModP(z_var,t1.r); // t12 = z * t1 = z * yQ * lambda - - return typename component_type::result_type(component, start_row_index); - } - - template - std::vector generate_gates( - const plonk_ec_double &component, - circuit> &bp, - assignment> - &assignment, - const typename plonk_ec_double::input_type - &instance_input) { - - // never actually called - return {}; - } - - template - void generate_copy_constraints( - const plonk_ec_double &component, - circuit> &bp, - assignment> - &assignment, - const typename plonk_ec_double::input_type &instance_input, - const std::size_t start_row_index) { - - // all copy constraints are moved to generate_circuit - } - - template - typename plonk_ec_double::result_type generate_circuit( - const plonk_ec_double &component, - circuit> &bp, - assignment> - &assignment, - const typename plonk_ec_double::input_type &instance_input, - const std::size_t start_row_index) { - using component_type = plonk_ec_double; - using var = typename component_type::var; - - using range_check_type = typename component_type::range_check_component; - using check_mod_p_type = typename component_type::check_mod_p_component; - using mult_mod_p_type = typename component_type::mult_mod_p_component; - using add_mod_p_type = typename component_type::add_mod_p_component; - using neg_mod_p_type = typename component_type::neg_mod_p_component; - - using value_type = typename BlueprintFieldType::value_type; - using integral_type = typename BlueprintFieldType::integral_type; - using non_native_value_type = typename NonNativeFieldType::value_type; - using non_native_integral_type = typename NonNativeFieldType::integral_type; - - const std::size_t WA = component.witness_amount(); - - // instances of used subcomponents - range_check_type range_check_instance( component._W, component._C, component._PI); - check_mod_p_type check_mod_p_instance( component._W, component._C, component._PI); - mult_mod_p_type mult_mod_p_instance( component._W, component._C, component._PI); - add_mod_p_type add_mod_p_instance( component._W, component._C, component._PI); - neg_mod_p_type neg_mod_p_instance( component._W, component._C, component._PI); - - var xQ_var[num_chunks], yQ_var[num_chunks], - lambda_var[num_chunks], z_var[num_chunks], xR_var[num_chunks], yR_var[num_chunks]; - - for(std::size_t i = 0; i < num_chunks; i++) { - xQ_var[i] = instance_input.xQ[i]; - yQ_var[i] = instance_input.yQ[i]; - lambda_var[i] = var(component.W(i % WA), start_row_index + i/WA, false); - z_var[i] = var(component.W((num_chunks + i) % WA), start_row_index + (num_chunks + i)/WA,false); - xR_var[i] = var(component.W((2*num_chunks + i) % WA), start_row_index + (2*num_chunks + i)/WA,false); - yR_var[i] = var(component.W((3*num_chunks + i) % WA), start_row_index + (3*num_chunks + i)/WA,false); - } - - // the number of rows used by data storage - std::size_t current_row_shift = (4*num_chunks)/WA + ((4*num_chunks) % WA > 0); - - auto check_chunked_var = [&bp, &assignment, &instance_input, &range_check_instance, &check_mod_p_instance, - &start_row_index, ¤t_row_shift ] (var x[num_chunks]) { - typename range_check_type::input_type range_check_input; - for(std::size_t i = 0; i < num_chunks; i++) { - range_check_input.x[i] = x[i]; - } - generate_circuit(range_check_instance, bp, assignment, range_check_input, start_row_index + current_row_shift); - current_row_shift += range_check_instance.rows_amount; - - typename check_mod_p_type::input_type mod_p_check_input; - for(std::size_t i = 0; i < num_chunks; i++) { - mod_p_check_input.x[i] = x[i]; - mod_p_check_input.pp[i] = instance_input.pp[i]; - } - mod_p_check_input.zero = instance_input.zero; - generate_circuit(check_mod_p_instance, bp, assignment, mod_p_check_input, - start_row_index + current_row_shift); // check_mod_p - current_row_shift += check_mod_p_instance.rows_amount; - }; - // perform range checks and mod p checks on all stored variables - check_chunked_var(lambda_var); - check_chunked_var(z_var); - check_chunked_var(xR_var); - check_chunked_var(yR_var); - - // circuit generation lambda expressions for mod p arithemetic - auto MultModP = [&instance_input, &mult_mod_p_instance, &bp, &assignment, &start_row_index, ¤t_row_shift] - (var x[num_chunks], var y[num_chunks]) { - typename mult_mod_p_type::input_type mult_input; - for(std::size_t i = 0; i < num_chunks; i++) { - mult_input.x[i] = x[i]; - mult_input.y[i] = y[i]; - mult_input.p[i] = instance_input.p[i]; - mult_input.pp[i] = instance_input.pp[i]; - } - mult_input.zero = instance_input.zero; - typename mult_mod_p_type::result_type res = generate_circuit(mult_mod_p_instance, bp, assignment, mult_input, - start_row_index + current_row_shift); - current_row_shift += mult_mod_p_instance.rows_amount; - return res; - }; - auto AddModP = [&instance_input, &add_mod_p_instance, &bp, &assignment, &start_row_index, ¤t_row_shift] - (var x[num_chunks], var y[num_chunks]) { -//std::cout << "Add starting at row " << (start_row_index + current_row_shift) << "\n"; - typename add_mod_p_type::input_type add_input; - for(std::size_t i = 0; i < num_chunks; i++) { - add_input.x[i] = x[i]; - add_input.y[i] = y[i]; - add_input.p[i] = instance_input.p[i]; - add_input.pp[i] = instance_input.pp[i]; - } - add_input.zero = instance_input.zero; - typename add_mod_p_type::result_type res = generate_circuit(add_mod_p_instance, bp, assignment, add_input, - start_row_index + current_row_shift); - current_row_shift += add_mod_p_instance.rows_amount; -//std::cout << "Add ending at row " << (start_row_index + current_row_shift) << "\n"; - return res; - }; - auto NegModP = [&instance_input, &neg_mod_p_instance, &bp, &assignment, &start_row_index, ¤t_row_shift] - (var x[num_chunks]) { - typename neg_mod_p_type::input_type neg_input; - for(std::size_t i = 0; i < num_chunks; i++) { - neg_input.x[i] = x[i]; - neg_input.p[i] = instance_input.p[i]; - neg_input.pp[i] = instance_input.pp[i]; - } - neg_input.zero = instance_input.zero; - typename neg_mod_p_type::result_type res = generate_circuit(neg_mod_p_instance, bp, assignment, neg_input, - start_row_index + current_row_shift); - current_row_shift += neg_mod_p_instance.rows_amount; - return res; - }; - - // Copy constraint generation lambda expression - auto CopyConstrain = [&bp](var x[num_chunks], var y[num_chunks]) { - for(std::size_t i = 0; i < num_chunks; i++) { - bp.add_copy_constraint({x[i], y[i]}); - } - }; - - typename mult_mod_p_type::result_type t1 = MultModP(yQ_var,lambda_var); // t1 = yQ * lambda - typename add_mod_p_type::result_type t2 = AddModP(t1.r,t1.r); // t2 = t1 + t1 = 2yQ * lambda - typename add_mod_p_type::result_type t3 = AddModP(xQ_var,xQ_var); // t3 = xQ + xQ = 2xQ - typename add_mod_p_type::result_type t4 = AddModP(xQ_var,t3.z); // t4 = xQ + t3 = 3xQ - typename mult_mod_p_type::result_type t5 = MultModP(t4.z,xQ_var); // t5 = t4 * xQ = 3xQ^2 - CopyConstrain(t2.z, t5.r); // 2yQ lambda = 3xQ^2 - typename add_mod_p_type::result_type t6 = AddModP(xR_var,t3.z); // t6 = xR + t3 = xR + 2xQ - typename mult_mod_p_type::result_type t7 = MultModP(lambda_var,lambda_var); // t7 = lambda * lambda - CopyConstrain(t6.z, t7.r); // xR + 2xQ = lambda^2 - typename add_mod_p_type::result_type t8 = AddModP(yR_var,yQ_var); // t8 = yR + yQ - typename neg_mod_p_type::result_type t9 = NegModP(xR_var); // t9 = -xR - typename add_mod_p_type::result_type t10= AddModP(xQ_var,t9.y); // t10 = xQ + t9 = xQ - xR - typename mult_mod_p_type::result_type t11= MultModP(lambda_var,t10.z); // t11 = lambda * t10 =lambda(xQ-xR) - CopyConstrain(t8.z, t11.r); // yR + yQ = lambda(xQ - xR) - typename mult_mod_p_type::result_type t12= MultModP(z_var,t1.r); // t12 = z * t1 = z * yQ * lambda - CopyConstrain(lambda_var, t12.r); // lambda = z yQ lambda - - generate_copy_constraints(component, bp, assignment, instance_input, start_row_index); // does nothing, may be skipped? - - return typename component_type::result_type(component, start_row_index); - } - - } // namespace components - } // namespace blueprint -} // namespace nil - -#endif // CRYPTO3_BLUEPRINT_COMPONENTS_PLONK_EC_DOUBLE_ECDSA_HPP \ No newline at end of file diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_full_add.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_full_add.hpp new file mode 100644 index 000000000..170907547 --- /dev/null +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_full_add.hpp @@ -0,0 +1,493 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2024 Alexey Yashunsky +// Copyright (c) 2024 Antoine Cyr +// +// 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 interfaces for full addition of EC points over a non-native field +//---------------------------------------------------------------------------// + +#ifndef CRYPTO3_BBF_COMPONENTS_EC_FULL_ADD_ECDSA_HPP +#define CRYPTO3_BBF_COMPONENTS_EC_FULL_ADD_ECDSA_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace nil { + namespace blueprint { + namespace bbf { + namespace components { + // Parameters: num_chunks = k, bit_size_chunk = b + // For points P = (x_P,y_P), Q = (x_Q,y_Q), x_P != x_Q, P,Q != O + // from an elliptic curve over F[p] + // computes R = (x_R, y_R) = P + Q + // Expects input as k-chunked values with b bits per chunk + // p' = 2^(kb) - p + // Input: xP[0],...,xP[k-1],yP[0],...,yP[k-1],xQ[0],...,xQ[k-1], + // yQ[0],...,yQ[k-1], p[0], ..., p[k-1], pp[0], ..., pp[k-1], 0 + // (expects zero constant as input) + // Output: xR[0],...,xR[k-1], + // yR[0],...,yR[k-1] + // + template + struct ec_full_add_raw_input { + using TYPE = typename FieldType::value_type; + std::vector xQ; + std::vector yQ; + std::vector xP; + std::vector yP; + std::vector p; + std::vector pp; + TYPE zero; + }; + + template + class ec_full_add : public generic_component { + using generic_component::allocate; + using generic_component::copy_constrain; + using generic_component::constrain; + using generic_component::lookup; + using component_type = generic_component; + + public: + using typename generic_component::TYPE; + using typename generic_component::context_type; + using typename generic_component::table_params; + using raw_input_type = + typename std::conditional, + std::tuple<>>::type; + + public: + std::vector inp_xP; + std::vector inp_yP; + std::vector inp_xQ; + std::vector inp_yQ; + std::vector inp_p; + std::vector inp_pp; + std::vector res_xR; + std::vector res_yR; + + static table_params get_minimal_requirements( + std::size_t num_chunks, std::size_t bit_size_chunk) { + std::size_t witness = 6 * num_chunks + 1; + constexpr std::size_t public_inputs = 1; + constexpr std::size_t constants = 0; + // rows = 4096-1 so that lookup table is not too hard to fit and + // padding doesn't inflate the table + constexpr std::size_t rows = 4095; + return {witness, public_inputs, constants, rows}; + } + + static std::tuple, std::vector, + std::vector, std::vector, + std::vector, std::vector, TYPE> + form_input(context_type& context_object, raw_input_type raw_input, + std::size_t num_chunks, std::size_t bit_size_chunk) { + std::vector input_xP(num_chunks); + std::vector input_yP(num_chunks); + std::vector input_xQ(num_chunks); + std::vector input_yQ(num_chunks); + std::vector input_p(num_chunks); + std::vector input_pp(num_chunks); + TYPE input_zero; + + if constexpr (stage == GenerationStage::ASSIGNMENT) { + for (std::size_t i = 0; i < num_chunks; i++) { + input_xP[i] = raw_input.xP[i]; + input_yP[i] = raw_input.yP[i]; + input_xQ[i] = raw_input.xQ[i]; + input_yQ[i] = raw_input.yQ[i]; + input_p[i] = raw_input.p[i]; + input_pp[i] = raw_input.pp[i]; + } + input_zero = raw_input.zero; + } + for (std::size_t i = 0; i < num_chunks; i++) { + context_object.allocate(input_xP[i], 0, i, + column_type::public_input); + context_object.allocate(input_yP[i], 0, i + num_chunks, + column_type::public_input); + context_object.allocate(input_xQ[i], 0, i + 2 * num_chunks, + column_type::public_input); + context_object.allocate(input_yQ[i], 0, i + 3 * num_chunks, + column_type::public_input); + context_object.allocate(input_p[i], 0, i + 4 * num_chunks, + column_type::public_input); + context_object.allocate(input_pp[i], 0, i + 5 * num_chunks, + column_type::public_input); + } + context_object.allocate(input_zero, 0, 6 * num_chunks, + column_type::public_input); + return std::make_tuple(input_xP, input_yP, input_xQ, input_yQ, + input_p, input_pp, input_zero); + } + + ec_full_add(context_type& context_object, std::vector input_xP, + std::vector input_yP, std::vector input_xQ, + std::vector input_yQ, std::vector input_p, + std::vector input_pp, TYPE input_zero, + std::size_t num_chunks, std::size_t bit_size_chunk, + bool make_links = true) + : generic_component(context_object) { + using integral_type = typename FieldType::integral_type; + using NON_NATIVE_TYPE = typename NonNativeFieldType::value_type; + using non_native_integral_type = + typename NonNativeFieldType::integral_type; + + using Choice_Function = + typename bbf::components::choice_function; + using Range_Check = + typename bbf::components::range_check_multi; + using Check_Mod_P = + typename bbf::components::check_mod_p; + using Addition_Mod_P = + typename bbf::components::addition_mod_p; + using Negation_Mod_P = + typename bbf::components::negation_mod_p; + using Multiplication_Mod_P = + typename bbf::components::flexible_multiplication< + FieldType, stage, NonNativeFieldType>; + + std::vector XP(num_chunks); + std::vector YP(num_chunks); + std::vector XQ(num_chunks); + std::vector YQ(num_chunks); + std::vector P(num_chunks); + std::vector PP(num_chunks); + TYPE ZERO; + + std::vector LAMBDA(num_chunks); + std::vector XR(num_chunks); + std::vector YR(num_chunks); + std::vector ZP(num_chunks); + std::vector ZQ(num_chunks); + std::vector ZPQ(num_chunks); + std::vector WPQ(num_chunks); + std::vector ZEROv(num_chunks); + + if constexpr (stage == GenerationStage::ASSIGNMENT) { + for (std::size_t i = 0; i < num_chunks; ++i) { + XP[i] = input_xP[i]; + YP[i] = input_yP[i]; + XQ[i] = input_xQ[i]; + YQ[i] = input_yQ[i]; + P[i] = input_p[i]; + PP[i] = input_pp[i]; + } + ZERO = input_zero; + + non_native_integral_type pow = 1; + NON_NATIVE_TYPE xP = 0, yP = 0, xQ = 0, yQ = 0; + + for (std::size_t i = 0; i < num_chunks; ++i) { + xP += non_native_integral_type( + integral_type(input_xP[i].data)) * + pow; + yP += non_native_integral_type( + integral_type(input_yP[i].data)) * + pow; + xQ += non_native_integral_type( + integral_type(input_xQ[i].data)) * + pow; + yQ += non_native_integral_type( + integral_type(input_yQ[i].data)) * + pow; + pow <<= bit_size_chunk; + } + + NON_NATIVE_TYPE + lambda, xR, yR, + // indicator variables + zP = (yP == 0) ? 0 : yP.inversed(), + zQ = (yQ == 0) ? 0 : yQ.inversed(), + zPQ = (xP == xQ) ? 0 : (xP - xQ).inversed(), + wPQ = ((xP == xQ) && (yP + yQ != 0)) + ? (yP + yQ).inversed() + : 0; + + if (yP == 0) { + xR = xQ; + yR = yQ; + // lambda doesn't matter for (xR,yR), but needs to satisfy + // the constraints + lambda = + (xP == xQ) ? 0 : (yQ - yP) * ((xQ - xP).inversed()); + } else if (yQ == 0) { + xR = xP; + yR = yP; + // lambda doesn't matter for (xR,yR), but needs to satisfy + // the constraints + lambda = + (xP == xQ) ? 0 : (yQ - yP) * ((xQ - xP).inversed()); + } else if ((xP == xQ) && (yP + yQ == 0)) { + xR = 0; + yR = 0; + // lambda doesn't matter for (xR,yR), but needs to satisfy + // the constraints + lambda = 3 * xP * xP * ((2 * yP).inversed()); + } else { + if (xP == xQ) { // point doubling + lambda = 3 * xP * xP * ((2 * yP).inversed()); + } else { // regular addition + NON_NATIVE_TYPE diff = xQ - xP; + lambda = (yQ - yP) * (diff.inversed()); + } + xR = lambda * lambda - xP - xQ, + yR = lambda * (xP - xR) - yP; + } + + auto base = [num_chunks, bit_size_chunk](NON_NATIVE_TYPE x) { + std::vector res(num_chunks); + non_native_integral_type mask = + (non_native_integral_type(1) << bit_size_chunk) - 1; + non_native_integral_type x_value = + non_native_integral_type(x.data); + for (std::size_t i = 0; i < num_chunks; i++) { + res[i] = TYPE(x_value & mask); + x_value >>= bit_size_chunk; + } + return res; + }; + + LAMBDA = base(lambda); + XR = base(xR); + YR = base(yR); + ZP = base(zP), ZQ = base(zQ), ZPQ = base(zPQ), + WPQ = base(wPQ); + } + + for (std::size_t i = 0; i < num_chunks; ++i) { + allocate(XP[i]); + allocate(YP[i]); + allocate(XQ[i]); + allocate(YQ[i]); + allocate(P[i]); + allocate(PP[i]); + + allocate(LAMBDA[i]); + allocate(XR[i]); + allocate(YR[i]); + allocate(ZP[i]); + allocate(ZQ[i]); + allocate(ZPQ[i]); + allocate(WPQ[i]); + + ZEROv[i] = ZERO; + allocate(ZEROv[i]); + } + allocate(ZERO); + + auto check_chunked = [&context_object, num_chunks, bit_size_chunk, + PP, ZERO](std::vector x) { + Range_Check rc = Range_Check(context_object, x, num_chunks, + bit_size_chunk); + Check_Mod_P cm = Check_Mod_P(context_object, x, PP, ZERO, + num_chunks, bit_size_chunk); + }; + + // Copy constraint generation lambda expression + auto CopyConstrain = [this, num_chunks](std::vector x, + std::vector y) { + for (std::size_t i = 0; i < num_chunks; i++) { + copy_constrain(x[i], y[i]); + } + }; + + // perform range checks and mod p checks on all stored variables + check_chunked(LAMBDA); + check_chunked(Z); + check_chunked(XR); + check_chunked(YR); + check_chunked(ZP); + check_chunked(ZQ); + check_chunked(ZPQ); + check_chunked(WPQ); + + auto MultModP = [&context_object, P, PP, ZERO, num_chunks, + bit_size_chunk](std::vector x, + std::vector y) { + Multiplication_Mod_P t = + Multiplication_Mod_P(context_object, x, y, P, PP, ZERO, + num_chunks, bit_size_chunk); + return t.res_r; + }; + auto AddModP = [&context_object, P, PP, ZERO, num_chunks, + bit_size_chunk](std::vector x, + std::vector y) { + Addition_Mod_P t = + Addition_Mod_P(context_object, x, y, P, PP, ZERO, + num_chunks, bit_size_chunk); + return t.res_r; + }; + auto NegModP = [&context_object, P, PP, ZERO, num_chunks, + bit_size_chunk](std::vector x) { + Negation_Mod_P t = + Negation_Mod_P(context_object, x, P, PP, ZERO, num_chunks, + bit_size_chunk); + return t.res_r; + }; + + // part 1 + auto t1 = NegModP(XQ); // t1 = -xQ + auto t2 = NegModP(YQ); // t2 = -yQ + auto t3 = NegModP(XP); // t3 = -xP + auto t4 = NegModP(YP); // t4 = -yP + auto t5 = AddModP(XR, t1); // t5 = xR - xQ + auto t6 = AddModP(YR, t2); // t6 = yR - yQ + auto t7 = AddModP(XR, t3); // t5 = xR - xP + auto t8 = AddModP(YR, t4); // t6 = yR - yP + auto t9 = AddModP(XP, t1); // t9 = xP - xQ + auto t10 = MultModP(YP, ZP); // t10 = yP * zP + auto t11 = MultModP(YQ, ZQ); // t11 = yQ * zQ + auto t12 = MultModP(t9, ZPQ); // t12 = (xP - xQ) zPQ = ZPQ + auto t13 = MultModP(t5, t10); // t13 = (xR - xQ) yP zP + CopyConstrain(t5, t13); // t5 = t13 + auto t14 = MultModP(t6, t10); // t14 = (yR - yQ) yP zP + CopyConstrain(t6, t14); // t6 = t14 + auto t15 = MultModP(t7, t11); // t15 = (xR - xP) yQ zQ + CopyConstrain(t7, t15); // t7 = t15 + auto t16 = MultModP(t8, t11); // t16 = (yR - yP) yQ zQ + CopyConstrain(t8, t16); // t8 = t16 + auto t17 = MultModP(t9, t12); // t17 = (xP - xQ) ZPQ + CopyConstrain(t9, t17); // t9 = t17 + + // part 2 + auto t18 = AddModP(YP, YQ); // t18 = yP + yQ + auto t19 = MultModP(t18, WPQ); // t19 = (yP + yQ) wPQ = WPQ + auto t20 = AddModP(t12, t19); // t20 = ZPQ + WPQ + auto t21 = MultModP(XR, t20); // t21 = xR(ZPQ + WPQ) + CopyConstrain(XR, t21); // xR = t21 + auto t22 = MultModP(YR, t20); // t22 = yR(ZPQ + WPQ) + CopyConstrain(YR, t22); // yR = t22 + + // part 3 + auto t23 = NegModP(t12); // t23 = -ZPQ + auto t24 = MultModP(t18, t23); // t24 = -(yP + yQ) ZPQ + auto t25 = AddModP(t18, t24); // t25 = (yP + yQ)(1 - ZPQ) + auto t26 = AddModP(t9, t25); // t26 = (xP - xQ) + (yP + yQ)(1 - ZPQ) + auto t27 = MultModP(YP, YQ); // t27 = yP * yQ + auto t28 = MultModP(t26, t27); // t28 = yP yQ (xP - xQ + (yP + yQ)(1 - ZPQ)) + auto t29 = MultModP(LAMBDA, LAMBDA); // t29 = lambda * lambda + auto t30 = NegModP(t29); // t30 = -lambda^2 + auto t31 = AddModP(XR, t30); // t31 = xR - lambda^2 + auto t32 = AddModP(t31, XP); // t32 = xR - lambda^2 + xP + auto t33 = AddModP(t32, XQ); // t33 = xR - lambda^2 + xP + xQ + auto t34 = AddModP(YR, YP); // t34 = yR + yP + auto t35 = MultModP(t7, LAMBDA); // t35 = (xR - xP) lambda + auto t36 = AddModP(t34, t35); // t36 = yR + yP + (xR - xP)lambda + auto t37 = MultModP(t28, t33); // t37 = yP yQ (xP - xQ + (yP + yQ)(1 - ZPQ))(xR - lambda^2 + xP + xQ) + CopyConstrain(t37, ZEROv); // t37 = 0 + auto t38 = MultModP(t28, t36); // t38 = yP yQ (xP - xQ + (yP + yQ)(1 -ZPQ))(yR + yP + (xR - xP)lambda) + CopyConstrain(t38, ZEROv); // t38 = 0 + + // part 4 + auto t39 = MultModP(t9, LAMBDA); // t39 = (xP - xQ) lambda + auto t40 = AddModP(t39, t4); // t40 = (xP - xQ) lambda - yP + auto t41 = AddModP(t40, YQ); // t41 = (xP - xQ) lambda - yP + yQ + auto t42 = MultModP(t9, t41); // t42 = (xP - xQ)((xP - xQ) lambda - yP + yQ) + CopyConstrain(t42, ZEROv); // t42 = 0 + auto t43 = MultModP(XP, t3); // t43 = -xP^2 + auto t44 = AddModP(t43, t43); // t44 = -2xP^2 + auto t45 = AddModP(t43, t44); // t45 = -3xP^2 + auto t46 = AddModP(YP, YP); // t46 = 2yP + auto t47 = MultModP(t46, LAMBDA); // t47 = 2yP lambda + auto t48 = AddModP(t47, t45); // t48 = 2yP lambda - 3xP^2 + auto t49 = MultModP(t48, t12); // t49 = (2yP lambda - 3xP^2) ZPQ + CopyConstrain(t48, t49); // t38 = 0t48 = t49 + + if (make_links) { + for (std::size_t i = 0; i < num_chunks; ++i) { + copy_constrain(XP[i], input_xP[i]); + copy_constrain(YP[i], input_yP[i]); + copy_constrain(XQ[i], input_xQ[i]); + copy_constrain(YQ[i], input_yQ[i]); + copy_constrain(P[i], input_p[i]); + copy_constrain(PP[i], input_pp[i]); + } + copy_constrain(ZERO, input_zero); + } + + for (int i = 0; i < num_chunks; ++i) { + inp_xP.push_back(input_xP[i]); + inp_yP.push_back(input_yP[i]); + inp_xQ.push_back(input_xQ[i]); + inp_yQ.push_back(input_yQ[i]); + inp_pp.push_back(input_p[i]); + inp_pp.push_back(input_pp[i]); + } + for (int i = 0; i < num_chunks; ++i) { + res_xR.push_back(XR[i]); + res_yR.push_back(YR[i]); + } + } + }; + + template + class pallas_ec_full_add + : public ec_full_add< + FieldType, stage, + crypto3::algebra::curves::pallas::base_field_type> { + using Base = + ec_full_add; + + public: + using Base::Base; + }; + + template + class vesta_ec_full_add + : public ec_full_add< + FieldType, stage, + crypto3::algebra::curves::vesta::base_field_type> { + using Base = + ec_full_add; + + public: + using Base::Base; + }; + + } // namespace components + } // namespace bbf + } // namespace blueprint +} // namespace nil + +#endif // CRYPTO3_BBF_COMPONENTS_EC_FULL_ADD_ECDSA_HPP diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_incomplete_add.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_incomplete_add.hpp new file mode 100644 index 000000000..a01b01b06 --- /dev/null +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_incomplete_add.hpp @@ -0,0 +1,389 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2024 Alexey Yashunsky +// Copyright (c) 2024 Antoine Cyr +// +// 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 interfaces for full addition of EC points over a non-native field +//---------------------------------------------------------------------------// + +#ifndef CRYPTO3_BBF_COMPONENTS_EC_INCOMPLETE_ADD_ECDSA_HPP +#define CRYPTO3_BBF_COMPONENTS_EC_INCOMPLETE_ADD_ECDSA_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace nil { + namespace blueprint { + namespace bbf { + namespace components { + // Parameters: num_chunks = k, bit_size_chunk = b + // For points P = (x_P,y_P), Q = (x_Q,y_Q), x_P != x_Q, P,Q != O + // from an elliptic curve over F[p] + // computes R = (x_R, y_R) = P + Q + // Expects input as k-chunked values with b bits per chunk + // p' = 2^(kb) - p + // Input: xP[0],...,xP[k-1],yP[0],...,yP[k-1],xQ[0],...,xQ[k-1], + // yQ[0],...,yQ[k-1], p[0], ..., p[k-1], pp[0], ..., pp[k-1], 0 + // (expects zero constant as input) + // Output: xR[0],...,xR[k-1], yR[0],...,yR[k-1] + // + template + struct ec_incomplete_add_raw_input { + using TYPE = typename FieldType::value_type; + std::vector xQ; + std::vector yQ; + std::vector xP; + std::vector yP; + std::vector p; + std::vector pp; + TYPE zero; + }; + + template + class ec_incomplete_add : public generic_component { + using generic_component::allocate; + using generic_component::copy_constrain; + using generic_component::constrain; + using generic_component::lookup; + using component_type = generic_component; + + public: + using typename generic_component::TYPE; + using typename generic_component::context_type; + using typename generic_component::table_params; + using raw_input_type = + typename std::conditional, + std::tuple<>>::type; + + public: + std::vector inp_xP; + std::vector inp_yP; + std::vector inp_xQ; + std::vector inp_yQ; + std::vector inp_p; + std::vector inp_pp; + std::vector res_xR; + std::vector res_yR; + + static table_params get_minimal_requirements( + std::size_t num_chunks, std::size_t bit_size_chunk) { + std::size_t witness = 6 * num_chunks + 1; + constexpr std::size_t public_inputs = 1; + constexpr std::size_t constants = 0; + // rows = 4096-1 so that lookup table is not too hard to fit and + // padding doesn't inflate the table + constexpr std::size_t rows = 4095; + return {witness, public_inputs, constants, rows}; + } + + static std::tuple, std::vector, + std::vector, std::vector, + std::vector, std::vector, TYPE> + form_input(context_type& context_object, raw_input_type raw_input, + std::size_t num_chunks, std::size_t bit_size_chunk) { + std::vector input_xP(num_chunks); + std::vector input_yP(num_chunks); + std::vector input_xQ(num_chunks); + std::vector input_yQ(num_chunks); + std::vector input_p(num_chunks); + std::vector input_pp(num_chunks); + TYPE input_zero; + + if constexpr (stage == GenerationStage::ASSIGNMENT) { + for (std::size_t i = 0; i < num_chunks; i++) { + input_xP[i] = raw_input.xP[i]; + input_yP[i] = raw_input.yP[i]; + input_xQ[i] = raw_input.xQ[i]; + input_yQ[i] = raw_input.yQ[i]; + input_p[i] = raw_input.p[i]; + input_pp[i] = raw_input.pp[i]; + } + input_zero = raw_input.zero; + } + for (std::size_t i = 0; i < num_chunks; i++) { + context_object.allocate(input_xP[i], 0, i, + column_type::public_input); + context_object.allocate(input_yP[i], 0, i + num_chunks, + column_type::public_input); + context_object.allocate(input_xQ[i], 0, i + 2 * num_chunks, + column_type::public_input); + context_object.allocate(input_yQ[i], 0, i + 3 * num_chunks, + column_type::public_input); + context_object.allocate(input_p[i], 0, i + 4 * num_chunks, + column_type::public_input); + context_object.allocate(input_pp[i], 0, i + 5 * num_chunks, + column_type::public_input); + } + context_object.allocate(input_zero, 0, 6 * num_chunks, + column_type::public_input); + return std::make_tuple(input_xP, input_yP, input_xQ, input_yQ, + input_p, input_pp, input_zero); + } + + ec_incomplete_add(context_type& context_object, + std::vector input_xP, + std::vector input_yP, + std::vector input_xQ, + std::vector input_yQ, + std::vector input_p, + std::vector input_pp, TYPE input_zero, + std::size_t num_chunks, std::size_t bit_size_chunk, + bool make_links = true) + : generic_component(context_object) { + using integral_type = typename FieldType::integral_type; + using NON_NATIVE_TYPE = typename NonNativeFieldType::value_type; + using non_native_integral_type = + typename NonNativeFieldType::integral_type; + + using Choice_Function = + typename bbf::components::choice_function; + using Range_Check = + typename bbf::components::range_check_multi; + using Check_Mod_P = + typename bbf::components::check_mod_p; + using Addition_Mod_P = + typename bbf::components::addition_mod_p; + using Negation_Mod_P = + typename bbf::components::negation_mod_p; + using Multiplication_Mod_P = + typename bbf::components::flexible_multiplication< + FieldType, stage, NonNativeFieldType>; + + std::vector XP(num_chunks); + std::vector YP(num_chunks); + std::vector XQ(num_chunks); + std::vector YQ(num_chunks); + std::vector P(num_chunks); + std::vector PP(num_chunks); + TYPE ZERO; + + std::vector LAMBDA(num_chunks); + std::vector XR(num_chunks); + std::vector YR(num_chunks); + + if constexpr (stage == GenerationStage::ASSIGNMENT) { + for (std::size_t i = 0; i < num_chunks; ++i) { + XP[i] = input_xP[i]; + YP[i] = input_yP[i]; + XQ[i] = input_xQ[i]; + YQ[i] = input_yQ[i]; + P[i] = input_p[i]; + PP[i] = input_pp[i]; + } + ZERO = input_zero; + + non_native_integral_type pow = 1; + NON_NATIVE_TYPE xP = 0, yP = 0, xQ = 0, yQ = 0; + + for (std::size_t i = 0; i < num_chunks; ++i) { + xP += non_native_integral_type( + integral_type(input_xP[i].data)) * + pow; + yP += non_native_integral_type( + integral_type(input_yP[i].data)) * + pow; + xQ += non_native_integral_type( + integral_type(input_xQ[i].data)) * + pow; + yQ += non_native_integral_type( + integral_type(input_yQ[i].data)) * + pow; + pow <<= bit_size_chunk; + } + + NON_NATIVE_TYPE lambda = + (xQ == xP) + ? 0 + : (yQ - yP) * ((xQ - xP).inversed()), + xR = lambda * lambda - xP - xQ, + yR = lambda * (xP - xR) - yP; + + auto base = [num_chunks, bit_size_chunk](NON_NATIVE_TYPE x) { + std::vector res(num_chunks); + non_native_integral_type mask = + (non_native_integral_type(1) << bit_size_chunk) - 1; + non_native_integral_type x_value = + non_native_integral_type(x.data); + for (std::size_t i = 0; i < num_chunks; i++) { + res[i] = TYPE(x_value & mask); + x_value >>= bit_size_chunk; + } + return res; + }; + + LAMBDA = base(lambda); + XR = base(xR); + YR = base(yR); + } + + for (std::size_t i = 0; i < num_chunks; ++i) { + allocate(XP[i]); + allocate(YP[i]); + allocate(XQ[i]); + allocate(YQ[i]); + allocate(P[i]); + allocate(PP[i]); + + allocate(LAMBDA[i]); + allocate(XR[i]); + allocate(YR[i]); + } + allocate(ZERO); + + auto check_chunked = [&context_object, num_chunks, bit_size_chunk, + PP, ZERO](std::vector x) { + Range_Check rc = Range_Check(context_object, x, num_chunks, + bit_size_chunk); + Check_Mod_P cm = Check_Mod_P(context_object, x, PP, ZERO, + num_chunks, bit_size_chunk); + }; + + // Copy constraint generation lambda expression + auto CopyConstrain = [this, num_chunks](std::vector x, + std::vector y) { + for (std::size_t i = 0; i < num_chunks; i++) { + copy_constrain(x[i], y[i]); + } + }; + + // perform range checks and mod p checks on all stored variables + check_chunked(LAMBDA); + check_chunked(XR); + check_chunked(YR); + + auto MultModP = [&context_object, P, PP, ZERO, num_chunks, + bit_size_chunk](std::vector x, + std::vector y) { + Multiplication_Mod_P t = + Multiplication_Mod_P(context_object, x, y, P, PP, ZERO, + num_chunks, bit_size_chunk); + return t.res_r; + }; + auto AddModP = [&context_object, P, PP, ZERO, num_chunks, + bit_size_chunk](std::vector x, + std::vector y) { + Addition_Mod_P t = + Addition_Mod_P(context_object, x, y, P, PP, ZERO, + num_chunks, bit_size_chunk); + return t.res_r; + }; + auto NegModP = [&context_object, P, PP, ZERO, num_chunks, + bit_size_chunk](std::vector x) { + Negation_Mod_P t = + Negation_Mod_P(context_object, x, P, PP, ZERO, num_chunks, + bit_size_chunk); + return t.res_r; + }; + + auto t1 = NegModP(XP); // t1 = -xP + auto t2 = AddModP(XQ, t1); // t2 = xQ + t1 = xQ - xP + auto t3 = MultModP(t2, LAMBDA); // t3 = t2 * lambda = (xQ-xP)lambda + auto t4 = AddModP(t3, YP); // t4 = t3 + yP = (xQ-xP)lambda + yP + CopyConstrain(t4, YQ); // (xQ - xP)lambda + yP = yQ + auto t5 = AddModP(XR, XP); // t5 = xR + xP + auto t6 = AddModP(t5, XQ); // t6 = t5 + xQ = xR + xP + xQ + auto t7 = MultModP(LAMBDA, LAMBDA); // t7 = lambda * lambda + CopyConstrain(t6, t7); // xR + xP + xQ = lambda^2 + auto t8 = AddModP(YR, YP); // t8 = yR + yP + auto t9 = NegModP(XR); // t9 = -xR + auto t10 = AddModP(XP, t9); // t10 = xP + t9 = xP - xR + auto t11 = MultModP(LAMBDA,t10); // t11 = lambda * t10 =lambda(xP-xR) + CopyConstrain(t8, t11); // yR + yP = lambda(xP - xR) + + if (make_links) { + for (std::size_t i = 0; i < num_chunks; ++i) { + copy_constrain(XP[i], input_xP[i]); + copy_constrain(YP[i], input_yP[i]); + copy_constrain(XQ[i], input_xQ[i]); + copy_constrain(YQ[i], input_yQ[i]); + copy_constrain(P[i], input_p[i]); + copy_constrain(PP[i], input_pp[i]); + } + copy_constrain(ZERO, input_zero); + } + + for (int i = 0; i < num_chunks; ++i) { + inp_xP.push_back(input_xP[i]); + inp_yP.push_back(input_yP[i]); + inp_xQ.push_back(input_xQ[i]); + inp_yQ.push_back(input_yQ[i]); + inp_pp.push_back(input_p[i]); + inp_pp.push_back(input_pp[i]); + } + for (int i = 0; i < num_chunks; ++i) { + res_xR.push_back(XR[i]); + res_yR.push_back(YR[i]); + } + } + }; + + template + class pallas_ec_incomplete_add + : public ec_incomplete_add< + FieldType, stage, + crypto3::algebra::curves::pallas::base_field_type> { + using Base = ec_incomplete_add< + FieldType, stage, + crypto3::algebra::curves::pallas::base_field_type>; + + public: + using Base::Base; + }; + + template + class vesta_ec_incomplete_add + : public ec_incomplete_add< + FieldType, stage, + crypto3::algebra::curves::vesta::base_field_type> { + using Base = ec_incomplete_add< + FieldType, stage, + crypto3::algebra::curves::vesta::base_field_type>; + + public: + using Base::Base; + }; + + } // namespace components + } // namespace bbf + } // namespace blueprint +} // namespace nil + +#endif // CRYPTO3_BBF_COMPONENTS_EC_INCOMPLETE_ADD_ECDSA_HPP diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/addition_mod_p.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/addition_mod_p.hpp index 5624e025b..8fea6ac38 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/addition_mod_p.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/addition_mod_p.hpp @@ -1,6 +1,6 @@ //---------------------------------------------------------------------------// // Copyright (c) 2024 Valeh Farzaliyev -// Copyright (c) 2024 Antoine Cyr +// Copyright (c) 2024 Antoine Cyr // // MIT License // @@ -22,7 +22,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. //---------------------------------------------------------------------------// -// @file Declaration of interfaces for FRI verification array swapping component. +// @file Declaration of interfaces for addition function on mod p. //---------------------------------------------------------------------------// #ifndef CRYPTO3_BBF_COMPONENTS_ADDITION_MOD_P_HPP @@ -52,8 +52,8 @@ namespace nil { // operates on k-chunked x,y, p, p' // Parameters: num_chunks = k, bit_size_chunk = b // Input: x[0], ..., x[k-1], y[0], ..., y[k-1], p[0], ..., p[k-1], p'[0], ..., p'[k-1], 0 - // Intemmediate values: q, t[0], ..., t[k-1], carry[k-1], t'[0], ..., t'[k-1], t"[0], ..., t"[k-1], carry"[k-1] - // Output: z[0] = x[0] + y[0] - qp[0], ..., z[k-1] = x[k-1] + y[k-1] -qp[k-1] + // Intermediate values: q, t[0], ..., t[k-1], carry[k-1], t'[0], ..., t'[k-1], t"[0], ..., t"[k-1], carry"[k-1] + // Output: r[0] = x[0] + y[0] - qp[0], ..., r[k-1] = x[k-1] + y[k-1] -qp[k-1] // template @@ -111,7 +111,7 @@ namespace nil { std::vector inp_y; std::vector inp_p; std::vector inp_pp; - std::vector res_z; + std::vector res_r; static table_params get_minimal_requirements( std::size_t num_chunks, std::size_t bit_size_chunk) { @@ -234,24 +234,24 @@ namespace nil { Carry_On_Addition ca_1 = Carry_On_Addition( context_object, X, Y, num_chunks, bit_size_chunk); - Range_Check rc_1 = Range_Check(context_object, ca_1.res_z, + Range_Check rc_1 = Range_Check(context_object, ca_1.res_r, num_chunks, bit_size_chunk); //(qp = 0 or p) Choice_Function cf = Choice_Function(context_object, Q, ZERO, P, num_chunks); Carry_On_Addition ca_2 = - Carry_On_Addition(context_object, cf.res_z, Z, num_chunks, + Carry_On_Addition(context_object, cf.res_r, Z, num_chunks, bit_size_chunk); // qp + z // carry_on_addition results should be equal to each other x + y = z + qp for (std::size_t i = 0; i < num_chunks; i++) { - copy_constrain(ca_1.res_z[i], ca_2.res_z[i]); + copy_constrain(ca_1.res_r[i], ca_2.res_r[i]); } copy_constrain(ca_1.res_c, ca_2.res_c); - Range_Check rc_2 = Range_Check(context_object, ca_2.res_z, + Range_Check rc_2 = Range_Check(context_object, ca_2.res_r, num_chunks, bit_size_chunk); Range_Check rc_3 = @@ -277,7 +277,7 @@ namespace nil { inp_pp.push_back(input_pp[i]); } for (int i = 0; i < num_chunks; ++i) { - res_z.push_back(Z[i]); + res_r.push_back(Z[i]); } } }; diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/check_mod_p.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/check_mod_p.hpp index ff0ca66a7..bb2e916f5 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/check_mod_p.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/check_mod_p.hpp @@ -125,7 +125,7 @@ namespace nil { using Range_Check = typename bbf::components::range_check_multi; Carry_On_Addition ca = Carry_On_Addition(context_object,input_x,input_pp,num_chunks,bit_size_chunk); - Range_Check rc = Range_Check(context_object, ca.res_z,num_chunks,bit_size_chunk); + Range_Check rc = Range_Check(context_object, ca.res_r,num_chunks,bit_size_chunk); if(expect_output){ output = ca.res_c; diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/flexible_multiplication.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/flexible_multiplication.hpp index e65666ccb..458344a76 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/flexible_multiplication.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/flexible_multiplication.hpp @@ -86,7 +86,7 @@ namespace nil { std::vector inp_y; std::vector inp_p; std::vector inp_pp; - std::vector res_z; + std::vector res_r; static table_params get_minimal_requirements(std::size_t num_chunks,std::size_t bit_size_chunk) { //The 6 variables chunks fit in 2 rows, and there is a 3rd additionnal row available for the constraint values @@ -321,7 +321,7 @@ namespace nil { inp_pp.push_back(input_pp[i]); } for (int i = 0; i < num_chunks; ++i) { - res_z.push_back(R[i]); + res_r.push_back(R[i]); } } diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/negation_mod_p.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/negation_mod_p.hpp index dafb76010..da476ba85 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/negation_mod_p.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/negation_mod_p.hpp @@ -1,7 +1,7 @@ //---------------------------------------------------------------------------// // Copyright (c) 2024 Georgios Fotiadis // Copyright (c) 2024 Alexey Yashunsky -// Copyright (c) 2024 Antoine Cyr +// Copyright (c) 2024 Antoine Cyr // // MIT License // @@ -23,7 +23,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. //---------------------------------------------------------------------------// -// @file Declaration of interfaces for FRI verification array swapping component. +// @file Declaration of interfaces for negation function on mod p. //---------------------------------------------------------------------------// #ifndef CRYPTO3_BBF_COMPONENTS_NEGATION_MOD_P_HPP @@ -50,9 +50,9 @@ namespace nil { namespace bbf { namespace components { // Parameters: num_chunks = k, bit_size_chunk = b - // Finding the negative y of integer x, modulo p and checking that x + y = 0 mod p + // Finding the negative r of integer x, modulo p and checking that x + r = 0 mod p // Input: x[0], ..., x[k-1], p[0], ..., p[k-1], pp[0], ..., pp[k-1], 0 (expects zero constant as input) - // Output: y[0], ..., y[k-1] + // Output: r[0], ..., r[k-1] template struct negation_mod_p_raw_input { @@ -107,7 +107,7 @@ namespace nil { std::vector inp_x; std::vector inp_p; std::vector inp_pp; - std::vector res_z; + std::vector res_r; static table_params get_minimal_requirements( std::size_t num_chunks, std::size_t bit_size_chunk) { @@ -224,7 +224,7 @@ namespace nil { // x + y = 0 or p for (std::size_t i = 0; i < num_chunks; i++) { - copy_constrain(ca.res_z[i], cf.res_z[i]); + copy_constrain(ca.res_r[i], cf.res_r[i]); } copy_constrain(ca.res_c, ZERO[0]); @@ -249,7 +249,7 @@ namespace nil { inp_pp.push_back(input_pp[i]); } for (int i = 0; i < num_chunks; ++i) { - res_z.push_back(Y[i]); + res_r.push_back(Y[i]); } } }; diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/carry_on_addition.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/carry_on_addition.hpp index 59c6d9c45..de5d51dac 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/carry_on_addition.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/carry_on_addition.hpp @@ -66,7 +66,7 @@ namespace nil { public: std::vector inp_x; std::vector inp_y; - std::vector res_z; + std::vector res_r; TYPE res_c; static table_params get_minimal_requirements(std::size_t num_chunks,std::size_t bit_size_chunk) { @@ -137,7 +137,7 @@ namespace nil { for (int i = 0; i < num_chunks; ++i) { inp_x.push_back(input_x[i]); inp_y.push_back(input_y[i]); - res_z.push_back(Z[i]); + res_r.push_back(Z[i]); } res_c = C[num_chunks-1]; } diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/choice_function.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/choice_function.hpp index 6b3e02396..319a86447 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/choice_function.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/choice_function.hpp @@ -1,6 +1,6 @@ //---------------------------------------------------------------------------// // Copyright (c) 2024 Alexey Yashunsky -// Copyright (c) 2024 Antoine Cyr +// Copyright (c) 2024 Antoine Cyr // // MIT License // @@ -65,7 +65,7 @@ namespace nil { public: TYPE inp_q; - std::vector inp_x, inp_y, res_z; + std::vector inp_x, inp_y, res_r; static table_params get_minimal_requirements(std::size_t num_chunks) { std::size_t witness = num_chunks + 1; @@ -133,7 +133,7 @@ namespace nil { for (std::size_t i = 0; i < num_chunks; i++) { inp_x.push_back(X[i]); inp_y.push_back(Y[i]); - res_z.push_back(Z[i]); + res_r.push_back(Z[i]); } }; }; diff --git a/crypto3/libs/blueprint/test/CMakeLists.txt b/crypto3/libs/blueprint/test/CMakeLists.txt index afa4cd20d..8ef649a41 100644 --- a/crypto3/libs/blueprint/test/CMakeLists.txt +++ b/crypto3/libs/blueprint/test/CMakeLists.txt @@ -107,6 +107,8 @@ set(COMMON_TEST_FILES "bbf/algebra/fields/non_native/negation_mod_p" "bbf/algebra/fields/non_native/flexible_multiplication" "bbf/algebra/curves/weierstrass/ec_double" + "bbf/algebra/curves/weierstrass/ec_full_add" + "bbf/algebra/curves/weierstrass/ec_incomplete_add" ) set(NON_NATIVE_TESTS_FILES diff --git a/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_double.cpp b/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_double.cpp index b0335aa7a..55b093ccd 100644 --- a/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_double.cpp +++ b/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_double.cpp @@ -1,5 +1,5 @@ //---------------------------------------------------------------------------// -// Copyright (c) 2024 Antoine Cyr +// Copyright (c) 2024 Antoine Cyr // // MIT License // @@ -22,7 +22,7 @@ // SOFTWARE. //---------------------------------------------------------------------------// -#define BOOST_TEST_MODULE bbf_check_mod_p_test +#define BOOST_TEST_MODULE bbf_ec_double_test #include #include diff --git a/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_full_add.cpp b/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_full_add.cpp new file mode 100644 index 000000000..7b727ab1a --- /dev/null +++ b/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_full_add.cpp @@ -0,0 +1,253 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2024 Antoine Cyr +// +// 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 bbf_ec_full_add_test + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +using namespace nil; +using namespace nil::blueprint; + +template +void test_ec_full_add( + const std::vector& public_input) { + using FieldType = BlueprintFieldType; + using TYPE = typename FieldType::value_type; + using NON_NATIVE_TYPE = typename NonNativeFieldType::value_type; + using integral_type = typename BlueprintFieldType::integral_type; + using non_native_integral_type = typename BlueprintFieldType::integral_type; + + + non_native_integral_type pow = 1; + + NON_NATIVE_TYPE xP = 0, yP = 0, xQ = 0, yQ = 0; + + for (std::size_t i = 0; i < num_chunks; ++i) { + xP += non_native_integral_type( + integral_type(public_input[i].data)) * + pow; + yP += non_native_integral_type( + integral_type(public_input[i + num_chunks].data)) * + pow; + xQ += non_native_integral_type( + integral_type(public_input[i + 2* num_chunks].data)) * + pow; + yQ += non_native_integral_type( + integral_type(public_input[i + 3*num_chunks].data)) * + pow; + pow <<= bit_size_chunk; + } + + NON_NATIVE_TYPE + lambda, expected_xR, expected_yR, + // indicator variables + zP = (yP == 0)? 0 : yP.inversed(), + zQ = (yQ == 0)? 0 : yQ.inversed(), + zPQ= (xP == xQ)? 0 : (xP - xQ).inversed(), + wPQ= ((xP == xQ) && (yP + yQ != 0))? (yP + yQ).inversed() : 0; + + if (yP == 0) { + expected_xR = xQ; + expected_yR = yQ; + // lambda doesn't matter for (xR,yR), but needs to satisfy the constraints + lambda = (xP == xQ)? 0 : (yQ - yP)*((xQ - xP).inversed()); + } else if (yQ == 0) { + expected_xR = xP; + expected_yR = yP; + // lambda doesn't matter for (xR,yR), but needs to satisfy the constraints + lambda = (xP == xQ)? 0 : (yQ - yP)*((xQ - xP).inversed()); + } else if ((xP == xQ) && (yP + yQ == 0)) { + expected_xR = 0; + expected_yR = 0; + // lambda doesn't matter for (xR,yR), but needs to satisfy the constraints + lambda = 3*xP*xP*((2*yP).inversed()); + } else { + if (xP == xQ) { // point doubling + lambda = 3*xP*xP*((2*yP).inversed()); + } else { // regular addition + NON_NATIVE_TYPE diff = xQ - xP; + lambda = (yQ - yP)*(diff.inversed()); + } + expected_xR = lambda*lambda - xP - xQ, + expected_yR = lambda*(xP - expected_xR) - yP; + } + + + auto assign_and_check = [&](auto& B, auto& raw_input) { + raw_input.xP = + std::vector(public_input.begin(), public_input.begin() + num_chunks); + raw_input.yP = + std::vector(public_input.begin() + num_chunks, public_input.begin() + 2 * num_chunks); + raw_input.xQ = + std::vector(public_input.begin() + 2*num_chunks, public_input.begin() + 3 * num_chunks); + raw_input.yQ = + std::vector(public_input.begin() + 3*num_chunks, public_input.begin() + 4 * num_chunks); + raw_input.p = std::vector(public_input.begin() + 4 * num_chunks, + public_input.begin() + 5 * num_chunks); + raw_input.pp = std::vector(public_input.begin() + 5 * num_chunks, + public_input.begin() + 6 * num_chunks); + raw_input.zero = public_input[6 * num_chunks]; + + auto [at, A, desc] = B.assign(raw_input); + bool pass = B.is_satisfied(at); + std::cout << "Is_satisfied = " << pass << std::endl; + + assert(pass == true); + non_native_integral_type xR = 0; + non_native_integral_type yR = 0; + pow = 1; + for (std::size_t i = 0; i < num_chunks; i++) { + xR += non_native_integral_type(integral_type(A.res_xR[i].data)) * pow; + yR += non_native_integral_type(integral_type(A.res_yR[i].data)) * pow; + pow <<= bit_size_chunk; + } + //#ifdef BLUEPRINT_PLONK_PROFILING_ENABLED + std::cout << "Expected xR - yR: " << std::dec << expected_xR.data << " - " << expected_yR.data << std::endl; + std::cout << "Real res xR - yR: " << std::dec << xR << " - " << yR << std::endl; + //#endif + assert(xR == expected_xR.data); + assert(yR == expected_yR.data); + }; + + if constexpr (std::is_same_v) { + typename bbf::components::pallas_ec_full_add< + FieldType, bbf::GenerationStage::ASSIGNMENT>::raw_input_type raw_input; + + auto B = + bbf::circuit_builder(num_chunks, bit_size_chunk); + + assign_and_check(B, raw_input); + } + else if constexpr (std::is_same_v< + NonNativeFieldType, + crypto3::algebra::curves::vesta::base_field_type>) { + typename bbf::components::vesta_ec_full_add< + FieldType, bbf::GenerationStage::ASSIGNMENT>::raw_input_type raw_input; + auto B = + bbf::circuit_builder(num_chunks, bit_size_chunk); + + assign_and_check(B, raw_input); + } +} + +template +void ec_full_add_tests() { + using NonNativeFieldType = typename Curve::base_field_type; + using value_type = typename BlueprintFieldType::value_type; + using integral_type = typename BlueprintFieldType::integral_type; + using foreign_value_type = typename NonNativeFieldType::value_type; + using ec_point_value_type = typename Curve::template g1_type::value_type; + + typedef nil::crypto3::multiprecision::big_uint<2 * NonNativeFieldType::modulus_bits> + extended_integral_type; + + static boost::random::mt19937 seed_seq; + static nil::crypto3::random::algebraic_engine generate_random( + seed_seq); + boost::random::uniform_int_distribution<> t_dist(0, 1); + + + extended_integral_type mask = (extended_integral_type(1) << bit_size_chunk) - 1; + + for (std::size_t i = 0; i < RandomTestsAmount; i++) { + std::vector public_input; + + extended_integral_type extended_base = 1, + ext_pow = extended_base << (num_chunks * bit_size_chunk), + p = NonNativeFieldType::modulus, + pp = ext_pow - p; + + value_type d = generate_random(); + ec_point_value_type P = ec_point_value_type::one(), Q = ec_point_value_type::one(); + P = P * d; + Q = Q * d; + + public_input.resize(6 * num_chunks + 1); + integral_type xP = integral_type(P.X.data); + integral_type yP = integral_type(P.Y.data); + integral_type xQ = integral_type(Q.X.data); + integral_type yQ = integral_type(Q.Y.data); + for (std::size_t j = 0; j < num_chunks; j++) { + public_input[j] = value_type(xP & mask); + xP >>= bit_size_chunk; + + public_input[1 * num_chunks + j] = value_type(yP & mask); + yP >>= bit_size_chunk; + + public_input[2 * num_chunks + j] = value_type(xQ & mask); + xQ >>= bit_size_chunk; + + public_input[3 * num_chunks + j] = value_type(yQ & mask); + yQ >>= bit_size_chunk; + + public_input[4 * num_chunks + j] = value_type(p & mask); + p >>= bit_size_chunk; + + public_input[5 * num_chunks + j] = value_type(pp & mask); + pp >>= bit_size_chunk; + } + public_input.push_back(value_type(0)); // the zero + + test_ec_full_add(public_input); + } +} + +constexpr static const std::size_t random_tests_amount = 10; + +BOOST_AUTO_TEST_SUITE(blueprint_plonk_test_suite) + +BOOST_AUTO_TEST_CASE(blueprint_plonk_bbf_ec_full_add_test) { + using pallas = typename crypto3::algebra::curves::pallas; + using vesta = typename crypto3::algebra::curves::vesta; + + ec_full_add_tests(); + + ec_full_add_tests(); + + ec_full_add_tests(); + + ec_full_add_tests(); + +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_incomplete_add.cpp b/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_incomplete_add.cpp new file mode 100644 index 000000000..11e3742e1 --- /dev/null +++ b/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_incomplete_add.cpp @@ -0,0 +1,215 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2024 Antoine Cyr +// +// 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 bbf_ec_incomplete_add_test + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +using namespace nil; +using namespace nil::blueprint; + +template +void test_ec_incomplete_add( + const std::vector& public_input) { + using FieldType = BlueprintFieldType; + using TYPE = typename FieldType::value_type; + using NON_NATIVE_TYPE = typename NonNativeFieldType::value_type; + using integral_type = typename BlueprintFieldType::integral_type; + using non_native_integral_type = typename BlueprintFieldType::integral_type; + + non_native_integral_type pow = 1; + + NON_NATIVE_TYPE xP = 0, yP = 0, xQ = 0, yQ = 0; + + for (std::size_t i = 0; i < num_chunks; ++i) { + xP += non_native_integral_type(integral_type(public_input[i].data)) * pow; + yP += non_native_integral_type(integral_type(public_input[i + num_chunks].data)) * + pow; + xQ += non_native_integral_type( + integral_type(public_input[i + 2 * num_chunks].data)) * + pow; + yQ += non_native_integral_type( + integral_type(public_input[i + 3 * num_chunks].data)) * + pow; + pow <<= bit_size_chunk; + } + + NON_NATIVE_TYPE lambda = (xQ == xP) ? 0 : (yQ - yP) * ((xQ - xP).inversed()), + expected_xR = lambda * lambda - xP - xQ, + expected_yR = lambda * (xP - expected_xR) - yP; + + auto assign_and_check = [&](auto& B, auto& raw_input) { + raw_input.xP = + std::vector(public_input.begin(), public_input.begin() + num_chunks); + raw_input.yP = std::vector(public_input.begin() + num_chunks, + public_input.begin() + 2 * num_chunks); + raw_input.xQ = std::vector(public_input.begin() + 2 * num_chunks, + public_input.begin() + 3 * num_chunks); + raw_input.yQ = std::vector(public_input.begin() + 3 * num_chunks, + public_input.begin() + 4 * num_chunks); + raw_input.p = std::vector(public_input.begin() + 4 * num_chunks, + public_input.begin() + 5 * num_chunks); + raw_input.pp = std::vector(public_input.begin() + 5 * num_chunks, + public_input.begin() + 6 * num_chunks); + raw_input.zero = public_input[6 * num_chunks]; + + auto [at, A, desc] = B.assign(raw_input); + bool pass = B.is_satisfied(at); + std::cout << "Is_satisfied = " << pass << std::endl; + + assert(pass == true); + non_native_integral_type xR = 0; + non_native_integral_type yR = 0; + pow = 1; + for (std::size_t i = 0; i < num_chunks; i++) { + xR += non_native_integral_type(integral_type(A.res_xR[i].data)) * pow; + yR += non_native_integral_type(integral_type(A.res_yR[i].data)) * pow; + pow <<= bit_size_chunk; + } + // #ifdef BLUEPRINT_PLONK_PROFILING_ENABLED + std::cout << "Expected xR - yR: " << std::dec << expected_xR.data << " - " + << expected_yR.data << std::endl; + std::cout << "Real res xR - yR: " << std::dec << xR << " - " << yR << std::endl; + // #endif + assert(xR == expected_xR.data); + assert(yR == expected_yR.data); + }; + + if constexpr (std::is_same_v) { + typename bbf::components::pallas_ec_incomplete_add< + FieldType, bbf::GenerationStage::ASSIGNMENT>::raw_input_type raw_input; + + auto B = + bbf::circuit_builder(num_chunks, bit_size_chunk); + + assign_and_check(B, raw_input); + } else if constexpr (std::is_same_v< + NonNativeFieldType, + crypto3::algebra::curves::vesta::base_field_type>) { + typename bbf::components::vesta_ec_incomplete_add< + FieldType, bbf::GenerationStage::ASSIGNMENT>::raw_input_type raw_input; + auto B = + bbf::circuit_builder(num_chunks, bit_size_chunk); + + assign_and_check(B, raw_input); + } +} + +template +void ec_incomplete_add_tests() { + using NonNativeFieldType = typename Curve::base_field_type; + using value_type = typename BlueprintFieldType::value_type; + using integral_type = typename BlueprintFieldType::integral_type; + using foreign_value_type = typename NonNativeFieldType::value_type; + using ec_point_value_type = typename Curve::template g1_type< + nil::crypto3::algebra::curves::coordinates::affine>::value_type; + + typedef nil::crypto3::multiprecision::big_uint<2 * NonNativeFieldType::modulus_bits> + extended_integral_type; + + static boost::random::mt19937 seed_seq; + static nil::crypto3::random::algebraic_engine generate_random( + seed_seq); + boost::random::uniform_int_distribution<> t_dist(0, 1); + + extended_integral_type mask = (extended_integral_type(1) << bit_size_chunk) - 1; + + for (std::size_t i = 0; i < RandomTestsAmount; i++) { + std::vector public_input; + + extended_integral_type extended_base = 1, + ext_pow = extended_base << (num_chunks * bit_size_chunk), + p = NonNativeFieldType::modulus, pp = ext_pow - p; + + value_type d = generate_random(); + ec_point_value_type P = ec_point_value_type::one(), + Q = ec_point_value_type::one(); + P = P * d; + Q = Q * d; + + public_input.resize(6 * num_chunks + 1); + integral_type xP = integral_type(P.X.data); + integral_type yP = integral_type(P.Y.data); + integral_type xQ = integral_type(Q.X.data); + integral_type yQ = integral_type(Q.Y.data); + for (std::size_t j = 0; j < num_chunks; j++) { + public_input[j] = value_type(xP & mask); + xP >>= bit_size_chunk; + + public_input[1 * num_chunks + j] = value_type(yP & mask); + yP >>= bit_size_chunk; + + public_input[2 * num_chunks + j] = value_type(xQ & mask); + xQ >>= bit_size_chunk; + + public_input[3 * num_chunks + j] = value_type(yQ & mask); + yQ >>= bit_size_chunk; + + public_input[4 * num_chunks + j] = value_type(p & mask); + p >>= bit_size_chunk; + + public_input[5 * num_chunks + j] = value_type(pp & mask); + pp >>= bit_size_chunk; + } + public_input.push_back(value_type(0)); // the zero + + test_ec_incomplete_add(public_input); + } +} + +constexpr static const std::size_t random_tests_amount = 10; + +BOOST_AUTO_TEST_SUITE(blueprint_plonk_test_suite) + +BOOST_AUTO_TEST_CASE(blueprint_plonk_bbf_ec_incomplete_add_test) { + using pallas = typename crypto3::algebra::curves::pallas; + using vesta = typename crypto3::algebra::curves::vesta; + + ec_incomplete_add_tests(); + + ec_incomplete_add_tests(); + + ec_incomplete_add_tests(); + + ec_incomplete_add_tests(); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/addition_mod_p.cpp b/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/addition_mod_p.cpp index 4343786c2..2963351b5 100644 --- a/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/addition_mod_p.cpp +++ b/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/addition_mod_p.cpp @@ -1,6 +1,6 @@ //---------------------------------------------------------------------------// // Copyright (c) 2024 Valeh Farzaliyev -// Copyright (c) 2024 Antoine Cyr +// Copyright (c) 2024 Antoine Cyr // // MIT License // @@ -23,7 +23,7 @@ // SOFTWARE. //---------------------------------------------------------------------------// -#define BOOST_TEST_MODULE bbf_check_mod_p_test +#define BOOST_TEST_MODULE bbf_addition_mod_p_test #include #include @@ -63,9 +63,9 @@ void test_addition_mod_p(const std::vector= p) { - z -= p; + extended_integral_type r = x + y; + if (r >= p) { + r -= p; } auto assign_and_check = [&](auto &B, auto &raw_input) { @@ -84,18 +84,18 @@ void test_addition_mod_p(const std::vector &publi extended_integral_type R = 0; pow = 1; for (std::size_t i = 0; i < num_chunks; i++) { - R += extended_integral_type(integral_type(A.res_z[i].data)) * pow; + R += extended_integral_type(integral_type(A.res_r[i].data)) * pow; pow <<= bit_size_chunk; } #ifdef BLUEPRINT_PLONK_PROFILING_ENABLED diff --git a/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/negation_mod_p.cpp b/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/negation_mod_p.cpp index 8a114cfac..8d367c582 100644 --- a/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/negation_mod_p.cpp +++ b/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/negation_mod_p.cpp @@ -1,6 +1,6 @@ //---------------------------------------------------------------------------// // Copyright (c) 2024 Valeh Farzaliyev -// Copyright (c) 2024 Antoine Cyr +// Copyright (c) 2024 Antoine Cyr // // MIT License // @@ -23,7 +23,7 @@ // SOFTWARE. //---------------------------------------------------------------------------// -#define BOOST_TEST_MODULE bbf_check_mod_p_test +#define BOOST_TEST_MODULE bbf_negation_mod_p_test #include #include @@ -59,7 +59,7 @@ void test_negation_mod_p( pow <<= bit_size_chunk; } - extended_integral_type y = (x == 0) ? 0 : p - x; // if x = 0, then y = 0 + extended_integral_type r = (x == 0) ? 0 : p - x; // if x = 0, then r = 0 auto assign_and_check = [&](auto &B, auto &raw_input) { raw_input.x = @@ -75,18 +75,18 @@ void test_negation_mod_p( std::cout << "Is_satisfied = " << pass << std::endl; assert(pass == true); - extended_integral_type Y = 0; + extended_integral_type R = 0; pow = 1; for (std::size_t i = 0; i < num_chunks; i++) { - Y += extended_integral_type(integral_type(A.res_z[i].data)) * pow; + R += extended_integral_type(integral_type(A.res_r[i].data)) * pow; pow <<= bit_size_chunk; } #ifdef BLUEPRINT_PLONK_PROFILING_ENABLED std::cout << "negation_mod_p test" << std::endl; - std::cout << "Expected res: " << std::dec << z << std::endl; - std::cout << "Real res: " << std::dec << Z << std::endl; + std::cout << "Expected res: " << std::dec << r << std::endl; + std::cout << "Real res: " << std::dec << R << std::endl; #endif - assert(y == Y); + assert(r == R); }; if constexpr (std::is_same_v -// Copyright (c) 2024 Antoine Cyr +// Copyright (c) 2024 Antoine Cyr // // MIT License // @@ -72,9 +72,9 @@ void test_carry_on_addition(const std::vector -// Copyright (c) 2024 Antoine Cyr +// Copyright (c) 2024 Antoine Cyr // // MIT License // @@ -74,9 +74,9 @@ void test_choice_function( for (std::size_t i = 0; i < num_chunks; i++) { #ifdef BLUEPRINT_PLONK_PROFILING_ENABLED std::cout << "Expected res: " << std::dec << expected_res[i] << std::endl; - std::cout << "Real res: " << std::dec << A.res_z[i].data << std::endl; + std::cout << "Real res: " << std::dec << A.res_r[i].data << std::endl; #endif - assert(A.res_z[i].data == expected_res[i].data); + assert(A.res_r[i].data == expected_res[i].data); } }