diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/choice_function.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/choice_function.hpp deleted file mode 100644 index 64226bdfc4..0000000000 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/choice_function.hpp +++ /dev/null @@ -1,110 +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 PLONK BBF choice_function component class -//---------------------------------------------------------------------------// - -#ifndef CRYPTO3_BLUEPRINT_PLONK_BBF_CHOICE_FUNCTION_COMPONENT_HPP -#define CRYPTO3_BLUEPRINT_PLONK_BBF_CHOICE_FUNCTION_COMPONENT_HPP - -#include - -#include - -#include -#include -#include -//#include - -#include - -namespace nil { - namespace blueprint { - namespace bbf { - - template - class choice_function : public generic_component { - using typename generic_component::context_type; - using generic_component::allocate; - using generic_component::copy_constrain; - using generic_component::constrain; - - public: - using typename generic_component::TYPE; - - public: - TYPE q, x[num_chunks], y[num_chunks], z[num_chunks]; // interfaces - - choice_function(context_type &context_object, - TYPE input_q, - std::array input_x, - std::array input_y, - bool make_links = true) : - generic_component(context_object) { - - TYPE Q, X[num_chunks], Y[num_chunks], Z[num_chunks]; - - if constexpr (stage == GenerationStage::ASSIGNMENT) { - Q = input_q; - for(std::size_t i = 0; i < num_chunks; i++) { - X[i] = input_x[i]; - Y[i] = input_y[i]; - } - } - - allocate(Q); - for(std::size_t i = 0; i < num_chunks; i++) { - allocate(X[i]); - } - for(std::size_t i = 0; i < num_chunks; i++) { - allocate(Y[i]); - } - - if (make_links) { - copy_constrain(Q,input_q); - for(std::size_t i = 0; i < num_chunks; i++) { - copy_constrain(X[i],input_x[i]); - copy_constrain(Y[i],input_y[i]); - } - } - - constrain(Q*(1-Q)); - for(std::size_t i = 0; i < num_chunks; i++) { - Z[i] = (1-Q)*X[i] + Q*Y[i]; - allocate(Z[i]); - } - - q = Q; - for(std::size_t i = 0; i < num_chunks; i++) { - x[i] = X[i]; - y[i] = Y[i]; - z[i] = Z[i]; - } - }; - }; - - } // namespace bbf - } // namespace blueprint -} // namespace nil - -#endif // CRYPTO3_BLUEPRINT_PLONK_BBF_CHOICE_FUNCTION_COMPONENT_HPP diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/circuit_builder.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/circuit_builder.hpp index f1654237f9..ab7d53df6c 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/circuit_builder.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/circuit_builder.hpp @@ -186,7 +186,7 @@ namespace nil { selector_column.set_row(i); size_t full_selector_id = gates.add_selector(selector_column); - for(const auto& [selector_id, constraints] : gates.constraint_list) { + for(const auto& [selector_id, data] : gates.constraint_list) { /* std::cout << "GATE:\n"; for(const auto& c : constraints) { @@ -194,8 +194,14 @@ namespace nil { } std::cout << "Rows: "; */ + std::vector constraints; + std::vector names; + for(const auto &d : data){ + constraints.push_back(d.first); + names.push_back(d.second); + } bp.add_gate(selector_id, constraints); - + constraint_names.insert({selector_id, names}); //std::cout << "\n"; } @@ -540,6 +546,7 @@ namespace nil { std::cout << "Constraint " << j << " from gate " << i << " on row " << selector_row << " is not satisfied." << std::endl; std::cout << "Constraint result: " << constraint_result << std::endl; + std::cout << "Offending constraint name: " << constraint_names.at(gates[i].selector_index).at(j) << std::endl; std::cout << "Offending contraint: " << gates[i].constraints[j] << std::endl; return false; } @@ -668,6 +675,7 @@ namespace nil { circuit> bp; crypto3::zk::snark::plonk_assignment_table presets; + std::map> constraint_names; }; } // namespace bbf 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 new file mode 100644 index 0000000000..62f60e6f21 --- /dev/null +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_double.hpp @@ -0,0 +1,323 @@ +//---------------------------------------------------------------------------// +// 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 doubling an EC points over a non-native field +//---------------------------------------------------------------------------// + +#ifndef CRYPTO3_BBF_COMPONENTS_EC_DOUBLE_ECDSA_HPP +#define CRYPTO3_BBF_COMPONENTS_EC_DOUBLE_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 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[0], ..., 0[k-1] + // (expects zero vector constant as input) + // Output: xR[0],...,xR[k-1], yR[0],...,yR[k-1] + + template + struct ec_double_raw_input { + using TYPE = typename FieldType::value_type; + std::vector xQ; + std::vector yQ; + std::vector p; + std::vector pp; + std::vector zero; + }; + + template + class ec_double : 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 xR; + std::vector yR; + + static table_params get_minimal_requirements( + std::size_t num_chunks, std::size_t bit_size_chunk) { + std::size_t witness = 4 * 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> + 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); + std::vector input_pp(num_chunks); + std::vector input_zero(num_chunks); + + if constexpr (stage == GenerationStage::ASSIGNMENT) { + for (std::size_t i = 0; i < num_chunks; 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[i] = raw_input.zero[i]; + } + } + for (std::size_t i = 0; i < num_chunks; i++) { + context_object.allocate(input_xQ[i], 0, i, + column_type::public_input); + context_object.allocate(input_yQ[i], 0, i + num_chunks, + column_type::public_input); + context_object.allocate(input_p[i], 0, i + 2 * num_chunks, + column_type::public_input); + context_object.allocate(input_pp[i], 0, i + 3 * num_chunks, + column_type::public_input); + context_object.allocate(input_zero[i], 0, i + 4 * num_chunks, + column_type::public_input); + } + return std::make_tuple(input_xQ, input_yQ, input_p, input_pp, + input_zero); + } + + ec_double(context_type& context_object, std::vector input_xQ, + std::vector input_yQ, std::vector input_p, + std::vector input_pp, std::vector 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 LAMBDA(num_chunks); + std::vector Z(num_chunks); + std::vector XR(num_chunks); + std::vector YR(num_chunks); + + if constexpr (stage == GenerationStage::ASSIGNMENT) { + non_native_integral_type pow = 1; + NON_NATIVE_TYPE xQ = 0, yQ = 0; + + for (std::size_t i = 0; i < num_chunks; ++i) { + 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 = + (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 = [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); + Z = base(z); + XR = base(xR); + YR = base(yR); + } + + for (std::size_t i = 0; i < num_chunks; ++i) { + allocate(LAMBDA[i]); + allocate(Z[i]); + allocate(XR[i]); + allocate(YR[i]); + } + + auto check_chunked = [&context_object, num_chunks, bit_size_chunk, + input_pp, input_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, input_pp, input_zero[0], + 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); + + auto MultModP = [&context_object, input_p, input_pp, input_zero, num_chunks, + bit_size_chunk](std::vector x, + std::vector y) { + Multiplication_Mod_P t = + Multiplication_Mod_P(context_object, x, y, input_p, input_pp, input_zero[0], + num_chunks, bit_size_chunk); + return t.r; + }; + auto AddModP = [&context_object, input_p, input_pp, input_zero, num_chunks, + bit_size_chunk](std::vector x, + std::vector y) { + Addition_Mod_P t = + Addition_Mod_P(context_object, x, y, input_p, input_pp, input_zero, + num_chunks, bit_size_chunk); + return t.r; + }; + auto NegModP = [&context_object, input_p, input_pp, input_zero, num_chunks, + bit_size_chunk](std::vector x) { + Negation_Mod_P t = + Negation_Mod_P(context_object, x, input_p, input_pp, input_zero, num_chunks, + bit_size_chunk); + return t.r; + }; + + auto t1 = MultModP(input_yQ,LAMBDA); // t1 = yQ * lambda + auto t2 = AddModP(t1,t1); // t2 = t1 + t1 = 2yQ * lambda + auto t3 = AddModP(input_xQ,input_xQ); // t3 = xQ + xQ = 2xQ + auto t4 = AddModP(input_xQ,t3); // t4 = xQ + t3 = 3xQ + auto t5 = MultModP(t4,input_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,input_yQ); // t8 = yR + yQ + auto t9 = NegModP(XR); // t9 = -xR + auto t10 = AddModP(input_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 + + for (int i = 0; i < num_chunks; ++i) { + xR.push_back(XR[i]); + yR.push_back(YR[i]); + } + } + }; + + template + class pallas_ec_double + : public ec_double< + FieldType, stage, + crypto3::algebra::curves::pallas::base_field_type> { + using Base = + ec_double; + + public: + using Base::Base; + }; + + template + class vesta_ec_double + : public ec_double { + using Base = + ec_double; + + public: + using Base::Base; + }; + + } // namespace components + } // namespace bbf + } // namespace blueprint +} // namespace nil + +#endif // CRYPTO3_BBF_COMPONENTS_EC_DOUBLE_ECDSA_HPP 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 0000000000..7c6bd649de --- /dev/null +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_full_add.hpp @@ -0,0 +1,438 @@ +//---------------------------------------------------------------------------// +// 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[0], ..., 0[k-1] + // (expects zero vector 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; + std::vector 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 xR; + std::vector 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, std::vector> + 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); + std::vector input_zero(num_chunks); + + 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[i] = raw_input.zero[i]; + } + } + 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[i], 0, i + 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, std::vector 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 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); + + if constexpr (stage == GenerationStage::ASSIGNMENT) { + 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(LAMBDA[i]); + allocate(XR[i]); + allocate(YR[i]); + allocate(ZP[i]); + allocate(ZQ[i]); + allocate(ZPQ[i]); + allocate(WPQ[i]); + } + + auto check_chunked = [&context_object, num_chunks, bit_size_chunk, + input_pp, input_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, input_pp, input_zero[0], + 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); + check_chunked(ZP); + check_chunked(ZQ); + check_chunked(ZPQ); + check_chunked(WPQ); + + auto MultModP = [&context_object, input_p, input_pp, input_zero, + num_chunks, bit_size_chunk]( + std::vector x, std::vector y) { + Multiplication_Mod_P t = Multiplication_Mod_P( + context_object, x, y, input_p, input_pp, input_zero[0], + num_chunks, bit_size_chunk); + return t.r; + }; + auto AddModP = [&context_object, input_p, input_pp, input_zero, + num_chunks, bit_size_chunk](std::vector x, + std::vector y) { + Addition_Mod_P t = + Addition_Mod_P(context_object, x, y, input_p, input_pp, + input_zero, num_chunks, bit_size_chunk); + return t.r; + }; + auto NegModP = [&context_object, input_p, input_pp, input_zero, + num_chunks, bit_size_chunk](std::vector x) { + Negation_Mod_P t = + Negation_Mod_P(context_object, x, input_p, input_pp, + input_zero, num_chunks, bit_size_chunk); + return t.r; + }; + + // part 1 + auto t1 = NegModP(input_xQ); // t1 = -xQ + auto t2 = NegModP(input_yQ); // t2 = -yQ + auto t3 = NegModP(input_xP); // t3 = -xP + auto t4 = NegModP(input_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(input_xP, t1); // t9 = xP - xQ + auto t10 = MultModP(input_yP, ZP); // t10 = yP * zP + auto t11 = MultModP(input_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(input_yP, input_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(input_yP, input_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, input_xP); // t32 = xR - lambda^2 + xP + auto t33 = AddModP(t32, input_xQ); // t33 = xR - lambda^2 + xP + xQ + auto t34 = AddModP(YR, input_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, input_zero); // t37 = 0 + auto t38 = MultModP(t28, t36); // t38 = yP yQ (xP - xQ + (yP + yQ)(1 -ZPQ))(yR + yP + (xR - xP)lambda) + CopyConstrain(t38, input_zero); // 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, input_yQ); // t41 = (xP - xQ) lambda - yP + yQ + auto t42 = MultModP(t9, t41); // t42 = (xP - xQ)((xP - xQ) lambda - yP + yQ) + CopyConstrain(t42, input_zero); // t42 = 0 + auto t43 = MultModP(input_xP, t3); // t43 = -xP^2 + auto t44 = AddModP(t43, t43); // t44 = -2xP^2 + auto t45 = AddModP(t43, t44); // t45 = -3xP^2 + auto t46 = AddModP(input_yP, input_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); // t48 = t49 + + for (int i = 0; i < num_chunks; ++i) { + xR.push_back(XR[i]); + 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 0000000000..658140450f --- /dev/null +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/curves/weierstrass/ec_incomplete_add.hpp @@ -0,0 +1,340 @@ +//---------------------------------------------------------------------------// +// 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[0], ..., 0[k-1] + // (expects zero vector 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; + std::vector 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 xR; + std::vector 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, std::vector> + 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); + std::vector input_zero(num_chunks); + + 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[i] = raw_input.zero[i]; + } + } + 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[i], 0, i + 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, + std::vector 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 LAMBDA(num_chunks); + std::vector XR(num_chunks); + std::vector YR(num_chunks); + + if constexpr (stage == GenerationStage::ASSIGNMENT) { + 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(LAMBDA[i]); + allocate(XR[i]); + allocate(YR[i]); + } + + auto check_chunked = [&context_object, num_chunks, bit_size_chunk, + input_pp, input_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, input_pp, input_zero[0], + 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, input_p, input_pp, input_zero, + num_chunks, bit_size_chunk]( + std::vector x, std::vector y) { + Multiplication_Mod_P t = Multiplication_Mod_P( + context_object, x, y, input_p, input_pp, input_zero[0], + num_chunks, bit_size_chunk); + return t.r; + }; + auto AddModP = [&context_object, input_p, input_pp, input_zero, + num_chunks, bit_size_chunk](std::vector x, + std::vector y) { + Addition_Mod_P t = + Addition_Mod_P(context_object, x, y, input_p, input_pp, + input_zero, num_chunks, bit_size_chunk); + return t.r; + }; + auto NegModP = [&context_object, input_p, input_pp, input_zero, + num_chunks, bit_size_chunk](std::vector x) { + Negation_Mod_P t = + Negation_Mod_P(context_object, x, input_p, input_pp, + input_zero, num_chunks, bit_size_chunk); + return t.r; + }; + + auto t1 = NegModP(input_xP); // t1 = -xP + auto t2 = AddModP(input_xQ, t1); // t2 = xQ + t1 = xQ - xP + auto t3 = MultModP(t2, LAMBDA); // t3 = t2 * lambda = (xQ-xP)lambda + auto t4 = AddModP(t3, input_yP); // t4 = t3 + yP = (xQ-xP)lambda + yP + CopyConstrain(t4, input_yQ); // (xQ - xP)lambda + yP = yQ + auto t5 = AddModP(XR, input_xP); // t5 = xR + xP + auto t6 = AddModP(t5, input_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, input_yP); // t8 = yR + yP + auto t9 = NegModP(XR); // t9 = -xR + auto t10 = AddModP(input_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) + + for (int i = 0; i < num_chunks; ++i) { + xR.push_back(XR[i]); + 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 new file mode 100644 index 0000000000..ada2a200e2 --- /dev/null +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/addition_mod_p.hpp @@ -0,0 +1,264 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2024 Valeh Farzaliyev +// 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 addition function on mod p. +//---------------------------------------------------------------------------// + +#ifndef CRYPTO3_BBF_COMPONENTS_ADDITION_MOD_P_HPP +#define CRYPTO3_BBF_COMPONENTS_ADDITION_MOD_P_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace nil { + namespace blueprint { + namespace bbf { + namespace components { + // Addition mod p + // 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[0], ..., 0[k-1] (expects zero vector constant as input) + // 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 + struct addition_mod_p_raw_input { + using TYPE = typename FieldType::value_type; + std::vector x; + std::vector y; + std::vector p; + std::vector pp; + std::vector zero; + }; + + template + class addition_mod_p : 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 r; + + static table_params get_minimal_requirements( + std::size_t num_chunks, std::size_t bit_size_chunk) { + std::size_t witness = 4 * 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> + 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_x(num_chunks); + std::vector input_y(num_chunks); + std::vector input_p(num_chunks); + std::vector input_pp(num_chunks); + std::vector input_zero(num_chunks); + + if constexpr (stage == GenerationStage::ASSIGNMENT) { + for (std::size_t i = 0; i < num_chunks; i++) { + input_x[i] = raw_input.x[i]; + input_y[i] = raw_input.y[i]; + input_p[i] = raw_input.p[i]; + input_pp[i] = raw_input.pp[i]; + input_zero[i] = raw_input.zero[i]; + } + } + for (std::size_t i = 0; i < num_chunks; i++) { + context_object.allocate(input_x[i], 0, i, + column_type::public_input); + context_object.allocate(input_y[i], 0, i + num_chunks, + column_type::public_input); + context_object.allocate(input_p[i], 0, i + 2 * num_chunks, + column_type::public_input); + context_object.allocate(input_pp[i], 0, i + 3 * num_chunks, + column_type::public_input); + context_object.allocate(input_zero[i], 0, i + 4 * num_chunks, + column_type::public_input); + } + return std::make_tuple(input_x, input_y, input_p, input_pp, + input_zero); + } + + addition_mod_p(context_type &context_object, + std::vector input_x, std::vector input_y, + std::vector input_p, std::vector input_pp, + std::vector 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 extended_integral_type = + nil::crypto3::multiprecision::big_uint< + 2 * NonNativeFieldType::modulus_bits>; + + using Carry_On_Addition = + typename bbf::components::carry_on_addition; + using Choice_Function = + typename bbf::components::choice_function; + using Check_Mod_P = + typename bbf::components::check_mod_p; + using Range_Check = + typename bbf::components::range_check_multi; + + std::vector R(num_chunks); + TYPE Q; + + if constexpr (stage == GenerationStage::ASSIGNMENT) { + Q = 0; + extended_integral_type x = 0, y = 0, r = 0, p = 0, pow = 1; + + // Populate x, y, p + for (std::size_t i = 0; i < num_chunks; ++i) { + x += extended_integral_type( + integral_type(input_x[i].data)) * + pow; + y += extended_integral_type( + integral_type(input_y[i].data)) * + pow; + p += extended_integral_type( + integral_type(input_p[i].data)) * + pow; + pow <<= bit_size_chunk; + } + + r = x + y; // x + y = r + qp + if (r >= p) { + r -= p; + Q = 1; + } + extended_integral_type mask = + (extended_integral_type(1) << bit_size_chunk) - 1; + for (std::size_t i = 0; i < num_chunks; ++i) { + R[i] = TYPE(r & mask); + r >>= bit_size_chunk; + } + } + + for (std::size_t i = 0; i < num_chunks; ++i) { + allocate(R[i]); + } + allocate(Q); + + Carry_On_Addition ca_1 = Carry_On_Addition( + context_object, input_x, input_y, num_chunks, bit_size_chunk); + Range_Check rc_1 = Range_Check(context_object, ca_1.r, num_chunks, + bit_size_chunk); + //(qp = 0 or p) + Choice_Function cf = Choice_Function( + context_object, Q, input_zero, input_p, num_chunks); + + Carry_On_Addition ca_2 = + Carry_On_Addition(context_object, cf.r, R, num_chunks, + bit_size_chunk); // qp + r + + // carry_on_addition results should be equal to each other x + y + // = r + qp + + for (std::size_t i = 0; i < num_chunks; i++) { + copy_constrain(ca_1.r[i], ca_2.r[i]); + } + copy_constrain(ca_1.c, ca_2.c); + + Range_Check rc_2 = Range_Check(context_object, ca_2.r, num_chunks, + bit_size_chunk); + + Range_Check rc_3 = + Range_Check(context_object, R, num_chunks, bit_size_chunk); + + Check_Mod_P cm = + Check_Mod_P(context_object, R, input_pp, input_zero[0], + num_chunks, bit_size_chunk); + + for (int i = 0; i < num_chunks; ++i) { + r.push_back(R[i]); + } + } + }; + + template + class pallas_addition_mod_p + : public addition_mod_p< + FieldType, stage, + crypto3::algebra::curves::pallas::base_field_type> { + using Base = + addition_mod_p; + + public: + using Base::Base; + }; + + template + class vesta_addition_mod_p + : public addition_mod_p< + FieldType, stage, + crypto3::algebra::curves::vesta::base_field_type> { + using Base = + addition_mod_p; + + public: + using Base::Base; + }; + + } // namespace components + } // namespace bbf + } // namespace blueprint +} // namespace nil + +#endif // CRYPTO3_BBF_COMPONENTS_ADDITION_MOD_P_HPP 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 70831e932b..54bc9d2bba 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 @@ -44,7 +44,8 @@ namespace nil { // Parameters: num_chunks = k, bit_size_chunk = b // Checking that x is in the interval [0;p-1] // operates on k-chunked x and p' = 2^(kb) - p - // Input: x[0], ..., x[k-1], pp[0], ..., pp[k-1] + // Input: x[0], ..., x[k-1], pp[0], ..., pp[k-1], 0 + // (expects zero constant as input) // Output: none template @@ -72,13 +73,11 @@ namespace nil { check_mod_p_raw_input, std::tuple<>>::type; public: - std::vector inp_x; - std::vector inp_pp; TYPE output; static table_params get_minimal_requirements(std::size_t num_chunks, std::size_t bit_size_chunk, - bool expect_output) { + bool expect_output = false) { static const std::size_t bit_size_rc = 16; std::size_t num_rc_chunks = (bit_size_chunk / bit_size_rc) + (bit_size_chunk % bit_size_rc > 0); @@ -95,7 +94,7 @@ namespace nil { raw_input_type raw_input, std::size_t num_chunks, std::size_t bit_size_chunk, - bool expect_output) { + bool expect_output = false) { std::vector input_x(num_chunks); std::vector input_pp(num_chunks); TYPE input_zero; @@ -116,7 +115,7 @@ namespace nil { } check_mod_p(context_type &context_object, std::vector input_x, std::vector input_pp, TYPE input_zero, - std::size_t num_chunks, std::size_t bit_size_chunk,bool expect_output, + std::size_t num_chunks, std::size_t bit_size_chunk,bool expect_output = false, bool make_links = true) : generic_component(context_object) { using integral_type = typename FieldType::integral_type; @@ -125,18 +124,13 @@ 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.r,num_chunks,bit_size_chunk); if(expect_output){ - output = ca.res_c; + output = ca.c; } else{ - copy_constrain(ca.res_c,input_zero); - } - - for (std::size_t i = 0; i < num_chunks; i++) { - inp_x.push_back(input_x[i]); - inp_pp.push_back(input_pp[i]); + copy_constrain(ca.c,input_zero); } } 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 7b97d0391c..1690f953f5 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 @@ -23,7 +23,8 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. //---------------------------------------------------------------------------// -// @file Declaration of interfaces for PLONK component wrapping the BBF-component interface +// @file Declaration of interfaces for PLONK component wrapping the BBF-component +// interface //---------------------------------------------------------------------------// #ifndef CRYPTO3_BBF_COMPONENTS_FLEXIBLE_MULTIPLICATION_HPP @@ -34,13 +35,13 @@ #include #include #include -#include #include #include +#include -#include #include -#include +#include +#include namespace nil { namespace blueprint { @@ -50,9 +51,10 @@ namespace nil { // Parameters: num_chunks = k, bit_size_chunk = b, T = k*b // native field module = n, non-native field module = p, pp = 2^T - p ( or -p(mod2^t)) // NB: 2^T * n > p^2 + p - // Input: x[0],..., x[k-1], y[0],..., y[k-1], p[0],..., p[k-1], pp[0],...,p[k-1] + // Input: x[0],..., x[k-1], y[0],..., y[k-1], p[0],..., p[k-1], pp[0],...,p[k-1], 0 + // (expects zero constant as input) // Output: r[0],..., r[k-1] - + template struct flexible_multiplication_raw_input { using TYPE = typename FieldType::value_type; @@ -63,8 +65,10 @@ namespace nil { TYPE zero; }; - template - class flexible_multiplication : public generic_component { + template + class flexible_multiplication + : public generic_component { using generic_component::allocate; using generic_component::copy_constrain; using generic_component::constrain; @@ -75,39 +79,36 @@ namespace nil { 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; - + using raw_input_type = typename std::conditional< + stage == GenerationStage::ASSIGNMENT, + flexible_multiplication_raw_input, std::tuple<>>::type; public: - std::vector inp_x; - std::vector inp_y; - std::vector inp_p; - std::vector inp_pp; - std::vector res; - - 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 - std::size_t witness =3*num_chunks; + std::vector 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 + std::size_t witness = 3 * num_chunks; 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 + // 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,TYPE> form_input(context_type &context_object, - raw_input_type raw_input, - std::size_t num_chunks, - std::size_t bit_size_chunk) { + 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 input_x(num_chunks); std::vector input_y(num_chunks); std::vector input_p(num_chunks); - std::vector input_pp(num_chunks); - TYPE input_zero; - + 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_x[i] = raw_input.x[i]; @@ -117,41 +118,53 @@ namespace nil { } input_zero = raw_input.zero; } - for (std::size_t i = 0; i < num_chunks; i++) - { - context_object.allocate(input_x[i], 0, i, column_type::public_input); - context_object.allocate(input_y[i], 0, i+num_chunks, column_type::public_input); - context_object.allocate(input_p[i], 0, i+2*num_chunks, column_type::public_input); - context_object.allocate(input_pp[i], 0, i+3*num_chunks, column_type::public_input); + for (std::size_t i = 0; i < num_chunks; i++) { + context_object.allocate(input_x[i], 0, i, + column_type::public_input); + context_object.allocate(input_y[i], 0, i + num_chunks, + column_type::public_input); + context_object.allocate(input_p[i], 0, i + 2 * num_chunks, + column_type::public_input); + context_object.allocate(input_pp[i], 0, i + 3 * num_chunks, + column_type::public_input); } - context_object.allocate(input_zero, 0, 4*num_chunks, column_type::public_input); - return std::make_tuple(input_x,input_y,input_p,input_pp,input_zero); + context_object.allocate(input_zero, 0, 4 * num_chunks, + column_type::public_input); + return std::make_tuple(input_x, input_y, input_p, input_pp, + input_zero); } - - flexible_multiplication(context_type &context_object, std::vector input_x, std::vector input_y,std::vector input_p,std::vector input_pp, TYPE input_zero, - std::size_t num_chunks, std::size_t bit_size_chunk, + flexible_multiplication(context_type &context_object, + std::vector input_x, + std::vector input_y, + 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 double_non_native_integral_type = nil::crypto3::multiprecision::big_uint<2* NonNativeFieldType::modulus_bits>; - - using native_integral_type = typename FieldType::integral_type; - - using Check_Mod_P = typename bbf::components::check_mod_p; - using Range_Check = typename bbf::components::range_check_multi; - + using extended_integral_type = + nil::crypto3::multiprecision::big_uint< + 2 * NonNativeFieldType::modulus_bits>; + + using integral_type = typename FieldType::integral_type; + + using Check_Mod_P = + typename bbf::components::check_mod_p; + using Range_Check = + typename bbf::components::range_check_multi; + std::vector X(num_chunks); std::vector Y(num_chunks); std::vector P(num_chunks); std::vector PP(num_chunks); - std::vector Q(num_chunks); - std::vector R(num_chunks); + std::vector Q(num_chunks); + std::vector R(num_chunks); std::vector Z(num_chunks); std::vector A(num_chunks); - std::vector B(2*(num_chunks - 2)); + std::vector B(2 * (num_chunks - 2)); TYPE x_n; TYPE y_n; @@ -166,31 +179,37 @@ namespace nil { P[i] = input_p[i]; PP[i] = input_pp[i]; } - double_non_native_integral_type foreign_p = 0, - foreign_x = 0, - foreign_y = 0, - pow = 1; - + extended_integral_type foreign_p = 0, foreign_x = 0, + foreign_y = 0, pow = 1; + for (std::size_t i = 0; i < num_chunks; ++i) { - foreign_x += double_non_native_integral_type(native_integral_type(X[i].data)) * pow; - foreign_y += double_non_native_integral_type(native_integral_type(Y[i].data)) * pow; - foreign_p += double_non_native_integral_type(native_integral_type(P[i].data)) * pow; + foreign_x += + extended_integral_type(integral_type(X[i].data)) * + pow; + foreign_y += + extended_integral_type(integral_type(Y[i].data)) * + pow; + foreign_p += + extended_integral_type(integral_type(P[i].data)) * + pow; pow <<= bit_size_chunk; } - double_non_native_integral_type foreign_r = (foreign_x * foreign_y) % foreign_p, // r = x*y % p - foreign_q = (foreign_x * foreign_y - foreign_r) / foreign_p; // q = (x*y - r)/p - double_non_native_integral_type mask = (double_non_native_integral_type(1) << bit_size_chunk) - 1; + extended_integral_type foreign_r = (foreign_x * foreign_y) % + foreign_p, // r = x*y % p + foreign_q = (foreign_x * foreign_y - foreign_r) / + foreign_p; // q = (x*y - r)/p + extended_integral_type mask = + (extended_integral_type(1) << bit_size_chunk) - 1; for (std::size_t j = 0; j < num_chunks; ++j) { Q[j] = TYPE(foreign_q & mask); R[j] = TYPE(foreign_r & mask); foreign_q >>= bit_size_chunk; foreign_r >>= bit_size_chunk; } - } - for (std::size_t i = 0; i < num_chunks; ++i){ + for (std::size_t i = 0; i < num_chunks; ++i) { allocate(X[i]); allocate(Y[i]); allocate(PP[i]); @@ -199,7 +218,7 @@ namespace nil { allocate(P[i]); } - native_integral_type pow = 1; + integral_type pow = 1; for (std::size_t j = 0; j < num_chunks; ++j) { x_n += X[j] * pow; y_n += Y[j] * pow; @@ -214,43 +233,50 @@ namespace nil { allocate(q_n); allocate(p_n); allocate(r_n); - //constrain X*Y - Q*P - R = 0 + // constrain X*Y - Q*P - R = 0 constrain(x_n * y_n - q_n * p_n - r_n); // computation mod 2^T - // (mod 2^t)xy + qp' = [x_0, x_1, x_2, x_3] â‹… [y_0, y_1, y_2, y_3] + [q_0, q_1, q_2, q_3] â‹… [pp_0, pp_1, pp_2, pp_3] + // (mod 2^t)xy + qp' = [x_0, x_1, x_2, x_3] â‹… [y_0, y_1, y_2, y_3] + // + [q_0, q_1, q_2, q_3] â‹… [pp_0, pp_1, pp_2, pp_3] // z_0 = x_0 â‹… y_0 + q_0 â‹… pp_0 // z_1 = x_0 â‹… y_1 + x_1 â‹… y_0 + q_0 â‹… pp_1 + q_1 â‹… pp_0 - // z_2 = x_0 â‹… y_2 + x_1 â‹… y_1 + x_2 â‹… y_0 + q_0 â‹… pp_2 + q_1 â‹… pp_1 + q_2 â‹… pp_0 - // z_3 = x_0 â‹… y_3 + x_1 â‹… y_2 + x_2 â‹… y_1 + x_3 â‹… y_0 + q_0 â‹… pp_3 + q_1 â‹… pp_2 + q_2 â‹… pp_1 + q_3 â‹… pp_0 - // Result = z_0 â‹… 2^{0b} + z_1 â‹… 2^{1b} + z_2 â‹… 2^{2b} + z_3 â‹… 2^{3b} + // z_2 = x_0 â‹… y_2 + x_1 â‹… y_1 + x_2 â‹… y_0 + q_0 â‹… pp_2 + q_1 â‹… + // pp_1 + q_2 â‹… pp_0 z_3 = x_0 â‹… y_3 + x_1 â‹… y_2 + x_2 â‹… y_1 + + // x_3 â‹… y_0 + q_0 â‹… pp_3 + q_1 â‹… pp_2 + q_2 â‹… pp_1 + q_3 â‹… + // pp_0 + // Result = z_0 â‹… 2^{0b} + z_1 â‹… 2^{1b} + z_2 â‹… 2^{2b} + z_3 â‹… + // 2^{3b} for (std::size_t i = 0; i < num_chunks; ++i) { Z[i] = TYPE(0); for (std::size_t j = 0; j <= i; ++j) { - Z[i] += X[j] * Y[i-j] + PP[j] * Q[i-j]; + Z[i] += X[j] * Y[i - j] + PP[j] * Q[i - j]; } allocate(Z[i]); } - if constexpr (stage == GenerationStage::ASSIGNMENT) { A[0] = Z[0] - R[0]; - native_integral_type a_integral = native_integral_type(A[0].data) >> bit_size_chunk; + integral_type a_integral = + integral_type(A[0].data) >> bit_size_chunk; A[0] = TYPE(a_integral); for (std::size_t i = 1; i < num_chunks; ++i) { - A[i] = (Z[i] + A[i-1] - R[i]); - a_integral = native_integral_type(A[i].data) >> bit_size_chunk; + A[i] = (Z[i] + A[i - 1] - R[i]); + a_integral = integral_type(A[i].data) >> bit_size_chunk; A[i] = TYPE(a_integral); } for (std::size_t i = 0; i < num_chunks - 2; ++i) { - B[2*i] = TYPE(native_integral_type(A[i].data) & ((native_integral_type(1) << bit_size_chunk) - 1)); - B[2*i + 1] =TYPE(native_integral_type(A[i].data) >> bit_size_chunk); + B[2 * i] = + TYPE(integral_type(A[i].data) & + ((integral_type(1) << bit_size_chunk) - 1)); + B[2 * i + 1] = + TYPE(integral_type(A[i].data) >> bit_size_chunk); } } - native_integral_type b_shift = native_integral_type(1) << bit_size_chunk; + integral_type b_shift = integral_type(1) << bit_size_chunk; allocate(A[0]); - constrain(A[0]*b_shift - Z[0] + R[0]); + constrain(A[0] * b_shift - Z[0] + R[0]); // constrain that the last t bits of z are equal to r: // z_0 - r_0 = a_0 â‹… 2^b // z_1 + a_0 - r_1 = a_1 â‹… 2^b @@ -258,36 +284,42 @@ namespace nil { // z_3 + a_2 - r_3 = a_3 â‹… 2^b for (std::size_t i = 1; i < num_chunks; ++i) { allocate(A[i]); - constrain(A[i]*b_shift - Z[i] - A[i-1]+ R[i]); + constrain(A[i] * b_shift - Z[i] - A[i - 1] + R[i]); } // If there is a fault in the computation: - // a'_0 = a_0 + 2^{3b+1} + // a'_0 = a_0 + 2^{3b+1} // a'_1 = a_1 + 2^{2b+1}, a'_2 = a_2 + 2^{b+1} // - // This results in a faulty `a_2`, which can cause an error in `z_3 - r_3`. - // The same issue applies for `a_1`. However, higher `a_i` values will only - // interfere with other `a_j` values and not with `z_i` or `r_i`. + // This results in a faulty `a_2`, which can cause an error in + // `z_3 - r_3`. The same issue applies for `a_1`. However, higher + // `a_i` values will only interfere with other `a_j` values and + // not with `z_i` or `r_i`. // // a_0 = b_0 + b_1 â‹… 2^b // a_1 = b_2 + b_3 â‹… 2^b for (std::size_t i = 0; i < num_chunks - 2; ++i) { - allocate(B[2*i]); - allocate(B[2*i+1]); - constrain(B[2*i] + B[2*i+1]*b_shift - A[i]); + allocate(B[2 * i]); + allocate(B[2 * i + 1]); + constrain(B[2 * i] + B[2 * i + 1] * b_shift - A[i]); } - Range_Check rc1 = Range_Check(context_object, R,num_chunks,bit_size_chunk); - Range_Check rc2 = Range_Check(context_object, Q,num_chunks,bit_size_chunk); - Range_Check rc3 = Range_Check(context_object, B,num_chunks,bit_size_chunk); - - Check_Mod_P c1 = Check_Mod_P(context_object, R,PP,input_zero,num_chunks,bit_size_chunk,false); - Check_Mod_P c2 = Check_Mod_P(context_object, Q,PP,input_zero,num_chunks,bit_size_chunk,false); - - //Starting b\n - if(num_chunks>2){ - std::vector B_X[2 * (num_chunks > 2)]; + Range_Check rc1 = + Range_Check(context_object, R, num_chunks, bit_size_chunk); + Range_Check rc2 = + Range_Check(context_object, Q, num_chunks, bit_size_chunk); + Range_Check rc3 = + Range_Check(context_object, B, num_chunks, bit_size_chunk); + + Check_Mod_P c1 = Check_Mod_P(context_object, R, PP, input_zero, + num_chunks, bit_size_chunk, false); + Check_Mod_P c2 = Check_Mod_P(context_object, Q, PP, input_zero, + num_chunks, bit_size_chunk, false); + + // Starting b\n + if (num_chunks > 2) { + std::vector B_X[2 * (num_chunks > 2)]; for (int i = 0; i < 2 * (num_chunks > 2); ++i) { B_X[i].resize(num_chunks); @@ -296,14 +328,14 @@ namespace nil { allocate(B_X[i][j]); } - B_X[i].push_back(X[num_chunks - 3]); B_X[i].push_back(X[num_chunks - 3]); - allocate(B_X[i][num_chunks-2]); - allocate(B_X[i][num_chunks-1]); - Range_Check(context_object, B_X[i],num_chunks,bit_size_chunk); - } + B_X[i].push_back(X[num_chunks - 3]); + allocate(B_X[i][num_chunks - 2]); + allocate(B_X[i][num_chunks - 1]); + Range_Check(context_object, B_X[i], num_chunks, + bit_size_chunk); + } } - if (make_links) { for (std::size_t i = 0; i < num_chunks; ++i) { @@ -315,36 +347,37 @@ namespace nil { } for (int i = 0; i < num_chunks; ++i) { - inp_x.push_back(input_x[i]); - inp_y.push_back(input_y[i]); - inp_p.push_back(input_p[i]); - inp_pp.push_back(input_pp[i]); - } - for (int i = 0; i < num_chunks; ++i) { - res.push_back(R[i]); + r.push_back(R[i]); } } - }; template - class pallas_flexible_multiplication : public flexible_multiplication { - - using Base = flexible_multiplication; - public: - using Base::Base; + class pallas_flexible_multiplication + : public flexible_multiplication< + FieldType, stage, + crypto3::algebra::curves::pallas::base_field_type> { + using Base = flexible_multiplication< + FieldType, stage, + crypto3::algebra::curves::pallas::base_field_type>; + + public: + using Base::Base; }; template - class vesta_flexible_multiplication : public flexible_multiplication { - - using Base = flexible_multiplication; - public: - using Base::Base; + class vesta_flexible_multiplication + : public flexible_multiplication< + FieldType, stage, + crypto3::algebra::curves::vesta::base_field_type> { + using Base = flexible_multiplication< + FieldType, stage, + crypto3::algebra::curves::vesta::base_field_type>; + + public: + using Base::Base; }; - + } // namespace components } // namespace bbf } // namespace blueprint 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 new file mode 100644 index 0000000000..f3bf3c21eb --- /dev/null +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/algebra/fields/non_native/negation_mod_p.hpp @@ -0,0 +1,237 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2024 Georgios Fotiadis +// 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 negation function on mod p. +//---------------------------------------------------------------------------// + +#ifndef CRYPTO3_BBF_COMPONENTS_NEGATION_MOD_P_HPP +#define CRYPTO3_BBF_COMPONENTS_NEGATION_MOD_P_HPP + +#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 + // 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[0], ..., 0[k-1] + // (expects zero vector constant as input) + // Output: r[0], ..., r[k-1] + + template + struct negation_mod_p_raw_input { + using TYPE = typename FieldType::value_type; + std::vector x; + std::vector p; + std::vector pp; + std::vector zero; + }; + + template + class negation_mod_p : 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 r; + + static table_params get_minimal_requirements( + std::size_t num_chunks, std::size_t bit_size_chunk) { + std::size_t witness = 3 * 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> + 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_x(num_chunks); + std::vector input_p(num_chunks); + std::vector input_pp(num_chunks); + std::vector input_zero(num_chunks); + + if constexpr (stage == GenerationStage::ASSIGNMENT) { + for (std::size_t i = 0; i < num_chunks; i++) { + input_x[i] = raw_input.x[i]; + input_p[i] = raw_input.p[i]; + input_pp[i] = raw_input.pp[i]; + input_zero[i] = raw_input.zero[i]; + } + } + + for (std::size_t i = 0; i < num_chunks; i++) { + context_object.allocate(input_x[i], 0, i, + column_type::public_input); + context_object.allocate(input_p[i], 0, i + 1 * num_chunks, + column_type::public_input); + context_object.allocate(input_pp[i], 0, i + 2 * num_chunks, + column_type::public_input); + context_object.allocate(input_zero[i], 0, i + 3 * num_chunks, + column_type::public_input); + } + + return std::make_tuple(input_x, input_p, input_pp, input_zero); + } + + negation_mod_p(context_type &context_object, + std::vector input_x, std::vector input_p, + std::vector input_pp, + std::vector 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 extended_integral_type = + nil::crypto3::multiprecision::big_uint< + 2 * NonNativeFieldType::modulus_bits>; + + using Carry_On_Addition = + typename bbf::components::carry_on_addition; + using Choice_Function = + typename bbf::components::choice_function; + using Check_Mod_P = + typename bbf::components::check_mod_p; + using Range_Check = + typename bbf::components::range_check_multi; + + std::vector R(num_chunks); + TYPE Q; + + if constexpr (stage == GenerationStage::ASSIGNMENT) { + extended_integral_type x = 0, r = 0, p = 0, pow = 1; + + // Populate x, p + for (std::size_t i = 0; i < num_chunks; ++i) { + x += extended_integral_type( + integral_type(input_x[i].data)) * + pow; + p += extended_integral_type( + integral_type(input_p[i].data)) * + pow; + pow <<= bit_size_chunk; + } + Q = (x == 0) ? 0 : 1; + r = (x == 0) ? 0 : p - x; // if x = 0, then r = 0 + + extended_integral_type mask = + (extended_integral_type(1) << bit_size_chunk) - 1; + for (std::size_t i = 0; i < num_chunks; ++i) { + R[i] = TYPE(r & mask); + r >>= bit_size_chunk; + } + } + allocate(Q); + for (std::size_t i = 0; i < num_chunks; ++i) { + allocate(R[i]); + } + + Choice_Function cf = Choice_Function( + context_object, Q, input_zero, input_p, num_chunks); + + Carry_On_Addition ca = Carry_On_Addition( + context_object, input_x, R, num_chunks, bit_size_chunk); + + // x + r = 0 or p + for (std::size_t i = 0; i < num_chunks; i++) { + copy_constrain(ca.r[i], cf.r[i]); + } + copy_constrain(ca.c, input_zero[0]); + + Range_Check rc = + Range_Check(context_object, R, num_chunks, bit_size_chunk); + + Check_Mod_P cm = + Check_Mod_P(context_object, R, input_pp, input_zero[0], + num_chunks, bit_size_chunk); + + for (int i = 0; i < num_chunks; ++i) { + r.push_back(R[i]); + } + } + }; + + template + class pallas_negation_mod_p + : public negation_mod_p< + FieldType, stage, + crypto3::algebra::curves::pallas::base_field_type> { + using Base = + negation_mod_p; + + public: + using Base::Base; + }; + + template + class vesta_negation_mod_p + : public negation_mod_p< + FieldType, stage, + crypto3::algebra::curves::vesta::base_field_type> { + using Base = + negation_mod_p; + + public: + using Base::Base; + }; + + } // namespace components + } // namespace bbf + } // namespace blueprint +} // namespace nil + +#endif // CRYPTO3_BBF_COMPONENTS_NEGATION_MOD_P_HPP 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 4b1af55fa4..cc9dc1bde4 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 @@ -22,7 +22,8 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. //---------------------------------------------------------------------------// -// @file Declaration of interfaces for PLONK component wrapping the BBF-component interface +// @file Declaration of interfaces for PLONK component wrapping the BBF-component +// interface //---------------------------------------------------------------------------// #ifndef CRYPTO3_BBF_COMPONENTS_CARRY_ON_ADDITION_HPP @@ -53,7 +54,6 @@ namespace nil { using generic_component::copy_constrain; using generic_component::constrain; using generic_component::lookup; - using component_type = generic_component; public: using typename generic_component::TYPE; @@ -65,23 +65,21 @@ namespace nil { std::tuple<>>::type; public: - std::vector inp_x; - std::vector inp_y; - std::vector res_z; - TYPE res_c; + std::vector r; + TYPE c; - static table_params get_minimal_requirements(std::size_t num_chunks,std::size_t bit_size_chunk) { + static table_params get_minimal_requirements( + std::size_t num_chunks, std::size_t bit_size_chunk) { std::size_t witness = 2; constexpr std::size_t public_inputs = 1; constexpr std::size_t constants = 0; - std::size_t rows = 4*num_chunks; + std::size_t rows = 3 * num_chunks + 1; return {witness, public_inputs, constants, rows}; } - static std::tuple,std::vector> form_input(context_type &context_object, - raw_input_type raw_input, - std::size_t num_chunks, - std::size_t bit_size_chunk) { + static std::tuple, std::vector> 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_x(num_chunks); std::vector input_y(num_chunks); if constexpr (stage == GenerationStage::ASSIGNMENT) { @@ -90,59 +88,57 @@ namespace nil { input_y[i] = raw_input.y[i]; } } - for (std::size_t i = 0; i < num_chunks; ++i) - { - context_object.allocate(input_x[i], 0, i, column_type::public_input); - context_object.allocate(input_y[i], 0, i+num_chunks, column_type::public_input); + for (std::size_t i = 0; i < num_chunks; ++i) { + context_object.allocate(input_x[i], 0, i, + column_type::public_input); + context_object.allocate(input_y[i], 0, i + num_chunks, + column_type::public_input); } - return std::make_tuple(input_x,input_y); + return std::make_tuple(input_x, input_y); } - carry_on_addition(context_type &context_object, std::vector input_x,std::vector input_y, - std::size_t num_chunks, std::size_t bit_size_chunk, - bool make_links = true) + carry_on_addition(context_type &context_object, + std::vector input_x, + std::vector input_y, 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; - TYPE X[num_chunks], Y[num_chunks], C[num_chunks], Z[num_chunks]; + TYPE X[num_chunks], Y[num_chunks], C[num_chunks], R[num_chunks]; integral_type BASE = integral_type(1) << bit_size_chunk; if constexpr (stage == GenerationStage::ASSIGNMENT) { - for(std::size_t i = 0; i < num_chunks; i++) { + for (std::size_t i = 0; i < num_chunks; i++) { X[i] = input_x[i]; Y[i] = input_y[i]; } } - for(std::size_t i = 0; i < num_chunks; i++) { + for (std::size_t i = 0; i < num_chunks; i++) { allocate(X[i]); allocate(Y[i]); - if (make_links){ - copy_constrain(X[i],input_x[i]); - copy_constrain(Y[i],input_y[i]); + if (make_links) { + copy_constrain(X[i], input_x[i]); + copy_constrain(Y[i], input_y[i]); } - Z[i] = X[i] + Y[i]; + R[i] = X[i] + Y[i]; if (i > 0) { - Z[i] += C[i-1]; + R[i] += C[i - 1]; } if constexpr (stage == GenerationStage::ASSIGNMENT) { - C[i] = (Z[i] >= BASE); + C[i] = (R[i] >= BASE); } allocate(C[i]); - constrain(C[i]*(1-C[i])); + constrain(C[i] * (1 - C[i])); - Z[i] -= TYPE(BASE)*C[i]; - allocate(Z[i]); + R[i] -= TYPE(BASE) * C[i]; + allocate(R[i]); } for (int i = 0; i < num_chunks; ++i) { - inp_x.push_back(input_x[i]); - inp_y.push_back(input_y[i]); + r.push_back(R[i]); } - for (int i = 0; i < num_chunks; ++i) { - res_z.push_back(Z[i]); - } - res_c = C[num_chunks-1]; + 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 new file mode 100644 index 0000000000..0fc7465997 --- /dev/null +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/choice_function.hpp @@ -0,0 +1,141 @@ +//---------------------------------------------------------------------------// +// 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 PLONK BBF choice_function component class +//---------------------------------------------------------------------------// + +#ifndef CRYPTO3_BLUEPRINT_PLONK_BBF_CHOICE_FUNCTION_COMPONENT_HPP +#define CRYPTO3_BLUEPRINT_PLONK_BBF_CHOICE_FUNCTION_COMPONENT_HPP + +#include +#include +#include +#include +#include +#include + +namespace nil { + namespace blueprint { + namespace bbf { + namespace components { + + template + struct choice_function_raw_input { + using TYPE = typename FieldType::value_type; + TYPE q; + std::vector x; + std::vector y; + }; + + template + class choice_function : public generic_component { + using generic_component::allocate; + using generic_component::copy_constrain; + using generic_component::constrain; + + 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 r; + + static table_params get_minimal_requirements(std::size_t num_chunks) { + std::size_t witness = num_chunks + 1; + constexpr std::size_t public_inputs = 1; + constexpr std::size_t constants = 0; + std::size_t rows = 3 * num_chunks + 1; + return {witness, public_inputs, constants, rows}; + } + + static std::tuple, std::vector> + form_input(context_type &context_object, raw_input_type raw_input, + std::size_t num_chunks) { + TYPE input_q; + std::vector input_x(num_chunks); + std::vector input_y(num_chunks); + if constexpr (stage == GenerationStage::ASSIGNMENT) { + for (std::size_t i = 0; i < num_chunks; ++i) { + input_q = raw_input.q; + input_x[i] = raw_input.x[i]; + input_y[i] = raw_input.y[i]; + } + } + context_object.allocate(input_q, 0, 0, column_type::public_input); + for (std::size_t i = 0; i < num_chunks; ++i) { + context_object.allocate(input_x[i], 0, i + 1, + column_type::public_input); + context_object.allocate(input_y[i], 0, i + num_chunks + 1, + column_type::public_input); + } + return std::make_tuple(input_q, input_x, input_y); + } + + choice_function(context_type &context_object, TYPE input_q, + std::vector input_x, std::vector input_y, + std::size_t num_chunks, bool make_links = true) + : generic_component(context_object) { + TYPE Q, X[num_chunks], Y[num_chunks], R[num_chunks]; + + if constexpr (stage == GenerationStage::ASSIGNMENT) { + Q = input_q; + for (std::size_t i = 0; i < num_chunks; i++) { + X[i] = input_x[i]; + Y[i] = input_y[i]; + } + } + + allocate(Q); + constrain(Q * (1 - Q)); + for (std::size_t i = 0; i < num_chunks; i++) { + allocate(X[i]); + allocate(Y[i]); + R[i] = (1 - Q) * X[i] + Q * Y[i]; + allocate(R[i]); + } + + if (make_links) { + copy_constrain(Q, input_q); + for (std::size_t i = 0; i < num_chunks; i++) { + copy_constrain(X[i], input_x[i]); + copy_constrain(Y[i], input_y[i]); + } + } + + for (std::size_t i = 0; i < num_chunks; i++) { + r.push_back(R[i]); + } + }; + }; + } // namespace components + } // namespace bbf + } // namespace blueprint +} // namespace nil + +#endif // CRYPTO3_BLUEPRINT_PLONK_BBF_CHOICE_FUNCTION_COMPONENT_HPP diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/range_check_multi.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/range_check_multi.hpp index eb9eb06bf2..2c65bc6e56 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/range_check_multi.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/detail/range_check_multi.hpp @@ -22,7 +22,8 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. //---------------------------------------------------------------------------// -// @file Declaration of interfaces for PLONK component wrapping the BBF-component interface +// @file Declaration of interfaces for PLONK component wrapping the BBF-component +// interface //---------------------------------------------------------------------------// #ifndef CRYPTO3_BBF_COMPONENTS_RANGE_CHECK_MULTI_HPP @@ -39,10 +40,10 @@ namespace nil { namespace blueprint { namespace bbf { namespace components { - // Constraints value to be of a certain bit size at most - // Parameters: num_chunks, bit_size_chunk - // Input: x - // Output: none + // Constraints value to be of a certain bit size at most + // Parameters: num_chunks, bit_size_chunk + // Input: x + // Output: none template struct range_check_multi_raw_input { @@ -69,41 +70,40 @@ namespace nil { static const std::size_t bit_size_rc = 16; public: - std::vector input; - - static table_params get_minimal_requirements(std::size_t num_chunks, - std::size_t bit_size_chunk) { - std::size_t num_rc_chunks = (bit_size_chunk / bit_size_rc) + (bit_size_chunk % bit_size_rc > 0); - std::size_t witness = (num_rc_chunks+1)/2 +1; + static table_params get_minimal_requirements( + std::size_t num_chunks, std::size_t bit_size_chunk) { + std::size_t num_rc_chunks = (bit_size_chunk / bit_size_rc) + + (bit_size_chunk % bit_size_rc > 0); + std::size_t witness = (num_rc_chunks + 1) / 2 + 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 + // 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> form_input(context_type &context_object, - raw_input_type raw_input, - std::size_t num_chunks, - std::size_t bit_size_chunk) { + static std::tuple> form_input( + context_type &context_object, raw_input_type raw_input, + std::size_t num_chunks, std::size_t bit_size_chunk) { std::vector X(num_chunks); for (std::size_t i = 0; i < num_chunks; i++) { if constexpr (stage == GenerationStage::ASSIGNMENT) { X[i] = raw_input.state[i]; } - context_object.allocate(X[i], 0, i, column_type::public_input); + context_object.allocate(X[i], 0, i, + column_type::public_input); } return std::make_tuple(X); } - range_check_multi(context_type &context_object, std::vector input_x, - std::size_t num_chunks, std::size_t bit_size_chunk, - bool make_links = true) + range_check_multi(context_type &context_object, + std::vector input_x, 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; - std::size_t num_rc_chunks = - (bit_size_chunk / bit_size_rc) + (bit_size_chunk % bit_size_rc > 0); + std::size_t num_rc_chunks = (bit_size_chunk / bit_size_rc) + + (bit_size_chunk % bit_size_rc > 0); std::size_t first_chunk_size = bit_size_chunk % bit_size_rc; integral_type mask = (1 << bit_size_rc) - 1; @@ -125,9 +125,9 @@ namespace nil { } } } - + for (std::size_t i = 0; i < num_chunks; ++i) { - integral_type power = 1; + integral_type power = 1; allocate(X[i]); C[i] = X[i]; for (std::size_t j = 0; j < num_rc_chunks; ++j) { @@ -139,14 +139,16 @@ namespace nil { constrain(C[i]); if (first_chunk_size != 0) { - lookup(Y[i][num_rc_chunks - 1] *(integral_type(1) << (bit_size_rc - first_chunk_size)), "chunk_16_bits/full"); + lookup(Y[i][num_rc_chunks - 1] * + (integral_type(1) + << (bit_size_rc - first_chunk_size)), + "chunk_16_bits/full"); } if (make_links) { copy_constrain(X[i], input_x[i]); } - input.push_back(X[i]); - } + } } }; diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/hashes/keccak/keccak_dynamic.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/hashes/keccak/keccak_dynamic.hpp index 56257f3e06..f904ea7ebd 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/hashes/keccak/keccak_dynamic.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/components/hashes/keccak/keccak_dynamic.hpp @@ -729,35 +729,35 @@ namespace nil { // gates: for (std::size_t i = 0; i < 6247 * max_blocks; i++) { - constrain(selector[i] * (1 - selector[i])); + constrain(selector[i] * (1 - selector[i]), "KECCAK_DYNAMIC_SELECTOR"); } for (std::size_t block_counter = 0; block_counter < max_blocks; block_counter++) { // Is_first and is_last definition constrain(m[block_counter].h.is_first * - (m[block_counter].h.is_first - 1)); // HF1 + (m[block_counter].h.is_first - 1), "HF1"); // HF1 constrain(m[block_counter].h.is_last * - (m[block_counter].h.is_last - 1)); // HF2 + (m[block_counter].h.is_last - 1), "HF2"); // HF2 constrain(m[block_counter].h.is_first * - (m[block_counter].h.L - m[block_counter].h.l)); // HF3 + (m[block_counter].h.L - m[block_counter].h.l), "HF3"); // HF3 lookup(m[block_counter].h.is_last * m[block_counter].h.l, // HF4 "keccak_pack_table/range_check_135"); // Hash computation correctness constrain(m[block_counter].h.is_last * (m[block_counter].h.hash_hi - - m[block_counter].h.hash_cur_hi)); // HF5 + m[block_counter].h.hash_cur_hi), "HF5"); // HF5 constrain(m[block_counter].h.is_last * (m[block_counter].h.hash_lo - - m[block_counter].h.hash_cur_lo)); // HF6 + m[block_counter].h.hash_cur_lo), "HF6"); // HF6 // RLC computation correctness constrain(m[block_counter].h.is_first * (m[block_counter].h.rlc_before - - m[block_counter].h.L)); // HF7 + m[block_counter].h.L), "HF7"); // HF7 constrain(m[block_counter].h.is_last * (m[block_counter].h.rlc_after - - m[block_counter].h.RLC)); // HF8 + m[block_counter].h.RLC), "HF8"); // HF8 // copy constraint r with public input if (make_links) { @@ -779,34 +779,34 @@ namespace nil { copy_constrain(m[block_counter].h.RLC, m[block_counter].f.RLC); copy_constrain(m[block_counter].h.r, m[block_counter].f.r); - constrain((1 - m[0].h.is_first)); // BT1 + constrain((1 - m[0].h.is_first), "BT1"); // BT1 lookup(m[block_counter].h.L, "keccak_pack_table/range_check_16bit"); lookup(m[block_counter].h.l, "keccak_pack_table/range_check_16bit"); if (block_counter > 0) { constrain((1 - m[block_counter - 1].f.is_last) * - m[block_counter].h.is_first); // BT2 + m[block_counter].h.is_first, "BT2"); // BT2 // Transition between blocks constrain((1 - m[block_counter].h.is_first) * (m[block_counter].h.L - - m[block_counter - 1].f.L)); // BT4 + m[block_counter - 1].f.L), "BT4"); // BT4 constrain((1 - m[block_counter].h.is_first) * (m[block_counter].h.RLC - - m[block_counter - 1].f.RLC)); // BT5 + m[block_counter - 1].f.RLC), "BT5"); // BT5 constrain((1 - m[block_counter].h.is_first) * (m[block_counter].h.hash_hi - - m[block_counter - 1].f.hash_hi)); // BT6 + m[block_counter - 1].f.hash_hi), "BT6"); // BT6 constrain((1 - m[block_counter].h.is_first) * (m[block_counter].h.hash_lo - - m[block_counter - 1].f.hash_lo)); // BT7 + m[block_counter - 1].f.hash_lo), "BT7"); // BT7 constrain((1 - m[block_counter].h.is_first) * (m[block_counter].h.rlc_before - - m[block_counter - 1].f.rlc_before)); // BT8 + m[block_counter - 1].f.rlc_before), "BT8"); // BT8 constrain((1 - m[block_counter].h.is_first) * (1 - m[block_counter].h.is_last) * (m[block_counter - 1].f.l - m[block_counter].h.l - - 136)); // BT9 + 136), "BT9"); // BT9 } copy_constrain(m[block_counter].s[3].S1, @@ -835,22 +835,22 @@ namespace nil { for (std::size_t i = 0; i < state_rows_amount; i++) { constrain(m[block_counter].s[i].S0 - (1 - m[block_counter].s[i].is_first) * - m[block_counter].s[i].s0); // ST3 + m[block_counter].s[i].s0, "ST3"); // ST3 constrain(m[block_counter].s[i].S1 - (1 - m[block_counter].s[i].is_first) * - m[block_counter].s[i].s1); // ST4 + m[block_counter].s[i].s1, "ST4"); // ST4 constrain(m[block_counter].s[i].S2 - (1 - m[block_counter].s[i].is_first) * - m[block_counter].s[i].s2); // ST5 + m[block_counter].s[i].s2, "ST5"); // ST5 constrain(m[block_counter].s[i].S3 - (1 - m[block_counter].s[i].is_first) * - m[block_counter].s[i].s3); // ST6 + m[block_counter].s[i].s3, "ST6"); // ST6 constrain(m[block_counter].s[i].S4 - (1 - m[block_counter].s[i].is_first) * - m[block_counter].s[i].s4); // ST7 + m[block_counter].s[i].s4, "ST7"); // ST7 if (i > 0) { constrain(m[block_counter].s[i].is_first - - m[block_counter].s[i - 1].is_first); // ST1 + m[block_counter].s[i - 1].is_first, "ST1"); // ST1 constrain(m[block_counter].s[i].out - m[block_counter].s[i - 1].XOR * (integral_type(1) << (48 * 3)) - @@ -858,7 +858,7 @@ namespace nil { (integral_type(1) << (48 * 2)) - m[block_counter].s[i].XOR * (integral_type(1) << (48)) - - m[block_counter].s[i].ch); // ST9 + m[block_counter].s[i].ch, "ST9"); // ST9 } // lookup constraint s.rng at keccak_pack_table/sparse_16bit lookup(m[block_counter].s[i].rng, @@ -868,19 +868,19 @@ namespace nil { constrain((m[block_counter].s[1].rng - sparse_x80 - m[block_counter].s[0].rng) * (m[block_counter].s[0].rng - sparse_x7f + - m[block_counter].s[1].rng)); // XOR1 + m[block_counter].s[1].rng), "XOR1"); // XOR1 constrain((m[block_counter].s[1].rng - sparse_x7f + m[block_counter].s[0].rng) * (m[block_counter].s[0].XOR + sparse_x80 - - m[block_counter].s[1].rng)); // XOR2 + m[block_counter].s[1].rng), "XOR2"); // XOR2 constrain((m[block_counter].s[1].rng - sparse_x80 - m[block_counter].s[0].rng) * (m[block_counter].s[0].XOR - sparse_x80 - - m[block_counter].s[1].rng)); // XOR3 + m[block_counter].s[1].rng), "XOR3"); // XOR3 constrain((m[block_counter].s[1].XOR - m[block_counter].s[0].ch * m[block_counter].s[0].XOR - (1 - m[block_counter].s[0].ch) * - m[block_counter].s[1].rng)); // XOR4 + m[block_counter].s[1].rng), "XOR4"); // XOR4 // Chunk constraints TYPE chunk_factor = TYPE(integral_type(1) << 48); @@ -900,31 +900,31 @@ namespace nil { auto diff = m[block_counter].c[i].l_before - m[block_counter].c[i].l; constrain(diff * (diff - 1) * (diff - 2) * (diff - 3) * - (diff - 4)); // LC4 + (diff - 4), "LC4"); // LC4 constrain(diff * (diff - 1) * (diff - 2) * (diff - 4) * - (m[block_counter].c[i].b3 - 1)); // PC1 + (m[block_counter].c[i].b3 - 1), "PC1"); // PC1 constrain(diff * (diff - 1) * (diff - 3) * (diff - 4) * - (m[block_counter].c[i].b2 - 1)); // PC2 + (m[block_counter].c[i].b2 - 1), "PC2"); // PC2 constrain(diff * (diff - 1) * (diff - 3) * (diff - 4) * - m[block_counter].c[i].b3); // PC3 + m[block_counter].c[i].b3, "PC3"); // PC3 constrain(diff * (diff - 2) * (diff - 3) * (diff - 4) * - (m[block_counter].c[i].b1 - 1)); // PC4 + (m[block_counter].c[i].b1 - 1), "PC4"); // PC4 constrain(diff * (diff - 2) * (diff - 3) * (diff - 4) * - m[block_counter].c[i].b2); // PC5 + m[block_counter].c[i].b2, "PC5"); // PC5 constrain(diff * (diff - 2) * (diff - 3) * (diff - 4) * - m[block_counter].c[i].b3); // PC6 + m[block_counter].c[i].b3, "PC6"); // PC6 constrain(m[block_counter].c[i].first_in_block * (diff - 1) * (diff - 2) * (diff - 3) * (diff - 4) * - (m[block_counter].c[i].b0 - 1)); // PC11 + (m[block_counter].c[i].b0 - 1), "PC11"); // PC11 constrain(m[block_counter].c[i].first_in_block * (diff - 1) * (diff - 2) * (diff - 3) * (diff - 4) * - m[block_counter].c[i].b1); // PC12 + m[block_counter].c[i].b1, "PC12"); // PC12 constrain(m[block_counter].c[i].first_in_block * (diff - 1) * (diff - 2) * (diff - 3) * (diff - 4) * - m[block_counter].c[i].b2); // PC13 + m[block_counter].c[i].b2, "PC13"); // PC13 constrain(m[block_counter].c[i].first_in_block * (diff - 1) * (diff - 2) * (diff - 3) * (diff - 4) * - m[block_counter].c[i].b3); // PC14 + m[block_counter].c[i].b3, "PC14"); // PC14 if (i > 0) { copy_constrain(m[block_counter].c[i].first_in_block, C[0]); // LC1 @@ -935,39 +935,39 @@ namespace nil { m[block_counter].c[i].sp0 * chunk_factor * chunk_factor - m[block_counter].c[i - 1].sp1 * chunk_factor - - m[block_counter].c[i - 1].sp0); // CH7 + m[block_counter].c[i - 1].sp0, "CH7"); // CH7 auto diff_prev = m[block_counter].c[i - 1].l_before - m[block_counter].c[i - 1].l; constrain((1 - m[block_counter].c[i].first_in_block) * (m[block_counter].c[i].l_before - - m[block_counter].c[i - 1].l)); // LC3 + m[block_counter].c[i - 1].l), "LC3"); // LC3 constrain((1 - m[block_counter].c[i].first_in_block) * - diff * (diff_prev - 4)); // LC5 + diff * (diff_prev - 4), "LC5"); // LC5 constrain((1 - m[block_counter].c[i].first_in_block) * (diff_prev - diff) * (diff_prev - diff - 1) * (diff_prev - diff - 2) * (diff_prev - diff - 3) * - (m[block_counter].c[i].b0 - 1)); // PC7 + (m[block_counter].c[i].b0 - 1), "PC7"); // PC7 constrain((1 - m[block_counter].c[i].first_in_block) * (diff_prev - diff) * (diff_prev - diff - 1) * (diff_prev - diff - 2) * (diff_prev - diff - 3) * - m[block_counter].c[i].b1); // PC8 + m[block_counter].c[i].b1, "PC8"); // PC8 constrain((1 - m[block_counter].c[i].first_in_block) * (diff_prev - diff) * (diff_prev - diff - 1) * (diff_prev - diff - 2) * (diff_prev - diff - 3) * - m[block_counter].c[i].b2); // PC9 + m[block_counter].c[i].b2, "PC9"); // PC9 constrain((1 - m[block_counter].c[i].first_in_block) * (diff_prev - diff) * (diff_prev - diff - 1) * (diff_prev - diff - 2) * (diff_prev - diff - 3) * - m[block_counter].c[i].b3); // PC10 + m[block_counter].c[i].b3, "PC10"); // PC10 constrain((1 - m[block_counter].c[i].first_in_block) * (m[block_counter].c[i].rlc_before - - m[block_counter].c[i - 1].rlc)); // RLC6 + m[block_counter].c[i - 1].rlc), "RLC6"); // RLC6 } else { copy_constrain(m[block_counter].c[i].first_in_block, C[1]); // LC1 @@ -992,10 +992,10 @@ namespace nil { constrain(m[block_counter].c[i].r2 - m[block_counter].c[i].r * - m[block_counter].c[i].r); // RLC4 + m[block_counter].c[i].r, "RLC4"); // RLC4 constrain(m[block_counter].c[i].r4 - m[block_counter].c[i].r2 * - m[block_counter].c[i].r2); // RLC5 + m[block_counter].c[i].r2, "RLC5"); // RLC5 constrain( diff * (diff - 1) * (diff - 2) * (diff - 3) * (m[block_counter].c[i].rlc - @@ -1005,7 +1005,7 @@ namespace nil { m[block_counter].c[i].b0 - m[block_counter].c[i].r2 * m[block_counter].c[i].b1 - m[block_counter].c[i].r * m[block_counter].c[i].b2 - - m[block_counter].c[i].b3)); // RLC7 + m[block_counter].c[i].b3), "RLC7"); // RLC7 constrain( diff * (diff - 1) * (diff - 2) * (diff - 4) * @@ -1014,7 +1014,7 @@ namespace nil { m[block_counter].c[i].rlc_before - m[block_counter].c[i].r2 * m[block_counter].c[i].b0 - m[block_counter].c[i].r * m[block_counter].c[i].b1 - - m[block_counter].c[i].b2)); // RLC8 + m[block_counter].c[i].b2), "RLC8"); // RLC8 constrain( diff * (diff - 1) * (diff - 3) * (diff - 4) * @@ -1022,17 +1022,17 @@ namespace nil { m[block_counter].c[i].r2 * m[block_counter].c[i].rlc_before - m[block_counter].c[i].r * m[block_counter].c[i].b0 - - m[block_counter].c[i].b1)); // RLC9 + m[block_counter].c[i].b1), "RLC9"); // RLC9 constrain(diff * (diff - 2) * (diff - 3) * (diff - 4) * (m[block_counter].c[i].rlc - m[block_counter].c[i].r * m[block_counter].c[i].rlc_before - - m[block_counter].c[i].b0)); // RLC10 + m[block_counter].c[i].b0), "RLC10"); // RLC10 constrain((diff - 1) * (diff - 2) * (diff - 3) * (diff - 4) * (m[block_counter].c[i].rlc - - m[block_counter].c[i].rlc_before)); // RLC11 + m[block_counter].c[i].rlc_before), "RLC11"); // RLC11 } // Unparser constraints @@ -1047,7 +1047,7 @@ namespace nil { m[block_counter].u[i].sp0 * (sparsed_factor << 96) - m[block_counter].u[i].sp1 * (sparsed_factor << 48) - m[block_counter].u[i].sp2 * sparsed_factor - - m[block_counter].u[i].sp3); // UN2 + m[block_counter].u[i].sp3, "UN2"); // UN2 if (i > 0) { constrain(m[block_counter].u[i].hash_chunk - m[block_counter].u[i - 1].ch3 * @@ -1062,7 +1062,7 @@ namespace nil { (ufactor << (16 * 2)) - m[block_counter].u[i].ch2 * (ufactor << (16)) - m[block_counter].u[i].ch1 * ufactor - - m[block_counter].u[i].ch0); // UN7 + m[block_counter].u[i].ch0, "UN7"); // UN7 } lookup({m[block_counter].u[i].ch0, m[block_counter].u[i].sp0}, // UN3 diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/exp_wrapper.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/exp_wrapper.hpp index 34ad6519a3..4137f16c6e 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/exp_wrapper.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/exp_wrapper.hpp @@ -209,10 +209,10 @@ namespace nil { ct.optimize_gates(); // compatibility layer: constraint list => gates & selectors - std::unordered_map, std::vector> constraint_list = + std::unordered_map, std::vector>> constraint_list = ct.get_constraints(); - for(const auto& [row_list, constraints] : constraint_list) { + for(const auto& [row_list, data] : constraint_list) { /* std::cout << "GATE:\n"; for(const auto& c : constraints) { @@ -220,6 +220,10 @@ namespace nil { } std::cout << "Rows: "; */ + std::vector constraints; + for(auto const& d : data){ + constraints.push_back(d.first); + } std::size_t selector_index = bp.add_gate(constraints); for(const std::size_t& row_index : row_list) { // std::cout << row_index << " "; diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/gate_optimizer.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/gate_optimizer.hpp index be50419a08..37ecdeeb80 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/gate_optimizer.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/gate_optimizer.hpp @@ -54,7 +54,7 @@ namespace nil { using lookup_constraint_type = std::pair; // Here size_t is the index of the selector from 'selectors_'. - std::unordered_map> constraint_list; + std::unordered_map>> constraint_list; std::vector copy_constraints; std::map, size_t>> dynamic_lookup_tables; @@ -79,7 +79,7 @@ namespace nil { return iter->second; } - void add_constraints(size_t selector_id, const std::vector& constraints) { + void add_constraints(size_t selector_id, const std::vector>& constraints) { auto iter = constraint_list.find(selector_id); if (iter != constraint_list.end()) { iter->second.insert( @@ -115,7 +115,7 @@ namespace nil { os << "Constraints: " << std::endl; if (iter != gates.constraint_list.end()) { for (const auto &constraint : iter->second) { - os << constraint << std::endl; + os << constraint.second << constraint.first << std::endl; } os << "--------------------------------------------------------------" << std::endl; } @@ -155,8 +155,20 @@ namespace nil { : context_(std::make_unique(std::move(c))) { } + std::optional>> shift_constraints( + const std::vector> constraints, int shift) { + std::vector> shifted_constraints; + for (const auto& c: constraints) { + std::optional shifted = c.first.rotate(shift); + if (!shifted) + return std::nullopt; + shifted_constraints.push_back({*shifted, c.second}); + } + return shifted_constraints; + } + std::optional> shift_constraints( - const std::vector& constraints, int shift) { + const std::vector constraints, int shift) { std::vector shifted_constraints; for (const auto& c: constraints) { std::optional shifted = c.rotate(shift); @@ -188,7 +200,7 @@ namespace nil { optimized_gates result; // Take everything out of context, and erase the context to free its memory. - std::unordered_map, std::vector> constraint_list = context_->get_constraints(); + std::unordered_map, std::vector>> constraint_list = context_->get_constraints(); std::map, row_selector<>>> dynamic_lookup_tables = context_->get_dynamic_lookup_tables(); result.copy_constraints = context_->get_copy_constraints(); @@ -526,11 +538,11 @@ namespace nil { // Move all from constraints_list. auto iter = gates.constraint_list.find(id); if (iter != gates.constraint_list.end()) { - std::vector constraints = std::move(iter->second); + std::vector> constraints = std::move(iter->second); gates.constraint_list.erase(id); // We need the minus on the next line, we need to shift the constraints in the // opposite direction of the selector shift. - std::optional> shifted_constraints = + std::optional>> shifted_constraints = shift_constraints(std::move(constraints), -shift); //std::cout << "Shifting " << -shift << " :" << std::endl; @@ -721,8 +733,8 @@ namespace nil { // Check if there is a constraint that can't be shifted. auto iter = gates.constraint_list.find(selector_id); if (iter != gates.constraint_list.end()) { - const std::vector& constraints = iter->second; - std::optional> shifted_constraints = + const std::vector>& constraints = iter->second; + std::optional>> shifted_constraints = shift_constraints(constraints, shift); if (!shifted_constraints) { return false; diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/generic.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/generic.hpp index 2a4c3ec204..eb6b6fc440 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/generic.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/generic.hpp @@ -285,7 +285,7 @@ namespace nil { using var = crypto3::zk::snark::plonk_variable; using constraint_type = crypto3::zk::snark::plonk_constraint; using plonk_copy_constraint = crypto3::zk::snark::plonk_copy_constraint; - using constraints_container_type = std::map>>; + using constraints_container_type = std::map, std::set>>; using copy_constraints_container_type = std::vector; // TODO: maybe it's a set, not a vec? using lookup_input_constraints_type = crypto3::zk::snark::lookup_input_constraints; using lookup_constraints_container_type = std::map, // @@ -405,30 +405,33 @@ namespace nil { } std::size_t row = (min_row + max_row)/2; + + std::optional C_rel = C.rotate(-row); if (!C_rel) { throw std::logic_error("Can't shift the constraint in the given direction."); } - add_constraint(*C_rel, row); + + add_constraint(*C_rel, row, constraint_name); } // accesible only at GenerationStage::CONSTRAINTS ! - void relative_constrain(TYPE C_rel, std::size_t row) { + void relative_constrain(TYPE C_rel, std::size_t row, std::string constraint_name = "") { if (!C_rel.is_relative()) { std::stringstream ss; ss << "Constraint " << C_rel << " has absolute variables, cannot constrain."; throw std::logic_error(ss.str()); } - add_constraint(C_rel, get_row(row)); + add_constraint(C_rel, get_row(row), constraint_name); } - void relative_constrain(TYPE C_rel, std::size_t start_row, std::size_t end_row) { + void relative_constrain(TYPE C_rel, std::size_t start_row, std::size_t end_row, std::string constraint_name = "") { if (!C_rel.is_relative()) { std::stringstream ss; ss << "Constraint " << C_rel << " has absolute variables, cannot constrain."; throw std::logic_error(ss.str()); } - add_constraint(C_rel, get_row(start_row), get_row(end_row)); + add_constraint(C_rel, get_row(start_row), get_row(end_row), constraint_name); } @@ -512,18 +515,24 @@ namespace nil { lookup_tables->insert({name,{cols,rows}}); } - std::unordered_map, std::vector> get_constraints() { + std::unordered_map, std::vector>> get_constraints() { // joins constraints with identic selectors into a single gate // drop the constraint_id from the stored id->(constraint,row_list) map and // join constrains into single element if they have the same row list: - std::unordered_map, std::vector> res; + std::unordered_map, std::vector>> res; for(const auto& [id, data] : *constraints) { - auto it = res.find(data.second); + auto it = res.find(std::get<1>(data)); + std::string name; + bool first = true; + for(auto const &s : std::get<2>(data)){ + if(first) { name = s; first = false;} + else name = name + "," + s; + } if (it == res.end()) { - res[data.second] = {data.first}; + res[std::get<1>(data)] = {{std::get<0>(data), name}}; } else { - it->second.push_back(data.first); + it->second.push_back({std::get<0>(data), name}); } } return res; @@ -600,23 +609,25 @@ namespace nil { } private: - void add_constraint(TYPE &C_rel, std::size_t row) { + void add_constraint(TYPE &C_rel, std::size_t row, std::string name) { std::size_t stored_row = row - (is_fresh ? row_shift : 0); constraint_id_type C_id = constraint_id_type(C_rel); if (constraints->find(C_id) == constraints->end()) { - constraints->insert({C_id, {C_rel, row_selector<>(desc.rows_amount)}}); + constraints->insert({C_id, {C_rel, row_selector<>(desc.rows_amount), {name}}}); } - constraints->at(C_id).second.set_row(stored_row); + std::get<1>(constraints->at(C_id)).set_row(stored_row); + std::get<2>(constraints->at(C_id)).insert(name); } - void add_constraint(TYPE &C_rel, std::size_t start_row, std::size_t end_row) { + void add_constraint(TYPE &C_rel, std::size_t start_row, std::size_t end_row, std::string name) { std::size_t stored_start_row = start_row - (is_fresh ? row_shift : 0); std::size_t stored_end_row = end_row - (is_fresh ? row_shift : 0); constraint_id_type C_id = constraint_id_type(C_rel); if (constraints->find(C_id) == constraints->end()) { - constraints->insert({C_id, {C_rel, row_selector<>(desc.rows_amount)}}); + constraints->insert({C_id, {C_rel, row_selector<>(desc.rows_amount), {name}}}); } - constraints->at(C_id).second.set_interval(stored_start_row, stored_end_row); + std::get<1>(constraints->at(C_id)).set_interval(stored_start_row, stored_end_row); + std::get<2>(constraints->at(C_id)).insert(name); } void add_lookup_constraint( diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/l1_wrapper.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/l1_wrapper.hpp index 703f66ae04..c89aa7c2f9 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/l1_wrapper.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/l1_wrapper.hpp @@ -210,10 +210,10 @@ namespace nil { // ct.optimize_gates(); // compatibility layer: constraint list => gates & selectors - std::unordered_map, std::vector> constraint_list = + std::unordered_map, std::vector>> constraint_list = ct.get_constraints(); - for(const auto& [row_list, constraints] : constraint_list) { + for(const auto& [row_list, data] : constraint_list) { /* std::cout << "GATE:\n"; for(const auto& c : constraints) { @@ -221,6 +221,10 @@ namespace nil { } std::cout << "Rows: "; */ + std::vector constraints; + for(auto const& d : data){ + constraints.push_back(d.first); + } std::size_t selector_index = bp.add_gate(constraints); for(const std::size_t& row_index : row_list) { // std::cout << row_index << " "; diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/opcode_poc.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/opcode_poc.hpp index 083cbd7c2f..3551af0e3b 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/opcode_poc.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/opcode_poc.hpp @@ -106,7 +106,7 @@ namespace nil { std::vector block_list; std::vector> block_selector(max_rows); std::vector> block_row_selector(max_rows); - std::array, std::vector>, 5> block_constraints; + std::array, std::vector>>, 5> block_constraints; if constexpr (stage == GenerationStage::ASSIGNMENT) { std::cout << "Opcode POC assignment" << std::endl; @@ -163,7 +163,7 @@ namespace nil { if( !constr_list.first.is_set(block_row) ) continue; for( auto &constr: constr_list.second ){ //std::cout << pair_selector_relative * constr << std::endl; - context_object.relative_constrain(pair_selector_relative * constr, i); + context_object.relative_constrain(pair_selector_relative * constr.first, i, constr.second); } } } diff --git a/crypto3/libs/blueprint/include/nil/blueprint/bbf/tester.hpp b/crypto3/libs/blueprint/include/nil/blueprint/bbf/tester.hpp index e9a7aa7c7f..55e9117f54 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/bbf/tester.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/bbf/tester.hpp @@ -38,7 +38,7 @@ #include #include -#include +// #include // #include #include @@ -104,7 +104,7 @@ namespace nil { generic_component(context_object) { using Is_Zero = is_zero; - using Choice_Function = choice_function; + // using Choice_Function = choice_function; // using Carry_On_Addition = carry_on_addition; using Useless = useless; @@ -113,9 +113,9 @@ namespace nil { Is_Zero(context_object, X, make_links); // make_links delegated to subcomponent - std::vector ct2_area = {2,3,4,5}; - context_type ct2 = context_object.subcontext(ct2_area,0,4); - auto c2 = Choice_Function(ct2,Q,CX,CY, make_links); // make_links delegated to subcomponent + // std::vector ct2_area = {2,3,4,5}; + // context_type ct2 = context_object.subcontext(ct2_area,0,4); + // auto c2 = Choice_Function(ct2,Q,CX,CY, make_links); // make_links delegated to subcomponent // std::vector ct3_area = {7,8,9,10,11}; // context_type ct3 = context_object.subcontext(ct3_area,0,4); diff --git a/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/zkevm.hpp b/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/zkevm.hpp index 2e83f4801b..dbb434dc9b 100644 --- a/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/zkevm.hpp +++ b/crypto3/libs/blueprint/include/nil/blueprint/zkevm_bbf/zkevm.hpp @@ -443,7 +443,7 @@ namespace nil { auto opcode_constraints = fresh_ct.get_constraints(); for( const auto &constr_list: opcode_constraints){ for( const auto &local_row: constr_list.first){ - for( auto constraint: constr_list.second){ + for( auto [constraint, name]: constr_list.second){ std::size_t real_row = std::ceil(float(current_opcode_bare_rows_amount) / 2) * 2 - local_row - current_opcode_bare_rows_amount % 2; opcode_constraints_aggregator[{current_opcode, real_row}].push_back(constraint); if(opcode_constraints_aggregator[{current_opcode, real_row}].size() > max_opcode_row_constraints){ diff --git a/crypto3/libs/blueprint/test/CMakeLists.txt b/crypto3/libs/blueprint/test/CMakeLists.txt index 38db7a296a..8ef649a413 100644 --- a/crypto3/libs/blueprint/test/CMakeLists.txt +++ b/crypto3/libs/blueprint/test/CMakeLists.txt @@ -101,8 +101,14 @@ set(COMMON_TEST_FILES "bbf/no_assignment_checks" "bbf/detail/range_check_multi" "bbf/detail/carry_on_addition" + "bbf/detail/choice_function" + "bbf/algebra/fields/non_native/addition_mod_p" "bbf/algebra/fields/non_native/check_mod_p" + "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 new file mode 100644 index 0000000000..8e68a36dc1 --- /dev/null +++ b/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_double.cpp @@ -0,0 +1,200 @@ +//---------------------------------------------------------------------------// +// 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_double_test + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +using namespace nil; +using namespace nil::blueprint; + +template +void test_ec_double( + 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 xQ = 0, yQ = 0; + + for (std::size_t i = 0; i < num_chunks; ++i) { + xQ += non_native_integral_type(integral_type(public_input[i].data)) * pow; + yQ += non_native_integral_type(integral_type(public_input[i + num_chunks].data)) * + pow; + pow <<= bit_size_chunk; + } + + NON_NATIVE_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 + expected_xR = lambda * lambda - 2 * xQ, + expected_yR = lambda * (xQ - expected_xR) - yQ; + + auto assign_and_check = [&](auto& B, auto& raw_input) { + raw_input.xQ = + std::vector(public_input.begin(), public_input.begin() + num_chunks); + raw_input.yQ = std::vector(public_input.begin() + num_chunks, + public_input.begin() + 2 * num_chunks); + raw_input.p = std::vector(public_input.begin() + 2 * num_chunks, + public_input.begin() + 3 * num_chunks); + raw_input.pp = std::vector(public_input.begin() + 3 * num_chunks, + public_input.begin() + 4 * num_chunks); + raw_input.zero = std::vector(public_input.begin() + 4 * num_chunks, + public_input.begin() + 5 * 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.xR[i].data)) * pow; + yR += non_native_integral_type(integral_type(A.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_double< + 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_double< + 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_double_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 Q = ec_point_value_type::one(); + Q = Q * d; + + public_input.resize(5 * num_chunks); + 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(xQ & mask); + xQ >>= bit_size_chunk; + + public_input[1 * num_chunks + j] = value_type(yQ & mask); + yQ >>= bit_size_chunk; + + public_input[2 * num_chunks + j] = value_type(p & mask); + p >>= bit_size_chunk; + + public_input[3 * num_chunks + j] = value_type(pp & mask); + pp >>= bit_size_chunk; + + public_input[4 * num_chunks + j] = value_type(0); + } + + test_ec_double(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_double_test) { + // The curve is passed in as an argument to access additionnal properties + using pallas = typename crypto3::algebra::curves::pallas; + using vesta = typename crypto3::algebra::curves::vesta; + + ec_double_tests(); + + ec_double_tests(); + + ec_double_tests(); + + ec_double_tests(); +} + +BOOST_AUTO_TEST_SUITE_END() 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 0000000000..9039294330 --- /dev/null +++ b/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_full_add.cpp @@ -0,0 +1,246 @@ +//---------------------------------------------------------------------------// +// 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 = std::vector(public_input.begin() + 6 * num_chunks, + public_input.begin() + 7 * 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.xR[i].data)) * pow; + yR += non_native_integral_type(integral_type(A.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< + 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(7 * num_chunks); + 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[6 * num_chunks + j] = value_type(0); + } + + 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) { + // The curve is passed in as an argument to access additionnal properties + 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 0000000000..1cbb6f7ed3 --- /dev/null +++ b/crypto3/libs/blueprint/test/bbf/algebra/curves/weierstrass/ec_incomplete_add.cpp @@ -0,0 +1,218 @@ +//---------------------------------------------------------------------------// +// 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 = std::vector(public_input.begin() + 6 * num_chunks, + public_input.begin() + 7 * 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.xR[i].data)) * pow; + yR += non_native_integral_type(integral_type(A.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(7 * num_chunks); + 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[6 * num_chunks + j] = value_type(0); + } + + 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) { + // The curve is passed in as an argument to access additionnal properties + 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 new file mode 100644 index 0000000000..8b8e7d98bb --- /dev/null +++ b/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/addition_mod_p.cpp @@ -0,0 +1,197 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2024 Valeh Farzaliyev +// 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_addition_mod_p_test + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace nil; +using namespace nil::blueprint; + +template +void test_addition_mod_p( + const std::vector &public_input) { + using FieldType = BlueprintFieldType; + using TYPE = typename FieldType::value_type; + using integral_type = typename BlueprintFieldType::integral_type; + typedef nil::crypto3::multiprecision::big_uint<2 * NonNativeFieldType::modulus_bits> + extended_integral_type; + + extended_integral_type x = 0, y = 0, p = 0, pow = 1; + // Populate x, y, p + for (std::size_t i = 0; i < num_chunks; ++i) { + x += extended_integral_type(integral_type(public_input[i].data)) * pow; + y += extended_integral_type(integral_type(public_input[i + num_chunks].data)) * + pow; + p += + extended_integral_type(integral_type(public_input[i + 2 * num_chunks].data)) * + pow; + pow <<= bit_size_chunk; + } + + extended_integral_type r = x + y; + if (r >= p) { + r -= p; + } + + auto assign_and_check = [&](auto &B, auto &raw_input) { + raw_input.x = + std::vector(public_input.begin(), public_input.begin() + num_chunks); + raw_input.y = std::vector(public_input.begin() + num_chunks, + public_input.begin() + 2 * num_chunks); + raw_input.p = std::vector(public_input.begin() + 2 * num_chunks, + public_input.begin() + 3 * num_chunks); + raw_input.pp = std::vector(public_input.begin() + 3 * num_chunks, + public_input.begin() + 4 * num_chunks); + raw_input.zero = std::vector(public_input.begin() + 4 * num_chunks, + public_input.begin() + 5 * 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); + extended_integral_type R = 0; + pow = 1; + for (std::size_t i = 0; i < num_chunks; i++) { + R += extended_integral_type(integral_type(A.r[i].data)) * pow; + pow <<= bit_size_chunk; + } +#ifdef BLUEPRINT_PLONK_PROFILING_ENABLED + std::cout << "addition_mod_p test" << std::endl; + std::cout << "Expected res: " << std::dec << r << std::endl; + std::cout << "Real res: " << std::dec << R << std::endl; +#endif + assert(r == R); + }; + + if constexpr (std::is_same_v) { + typename bbf::components::pallas_addition_mod_p< + 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_addition_mod_p< + 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 addition_mod_p_tests() { + using value_type = typename BlueprintFieldType::value_type; + using integral_type = typename BlueprintFieldType::integral_type; + using foreign_value_type = typename NonNativeFieldType::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; + + foreign_value_type src_x = generate_random(), src_y = generate_random(); + + extended_integral_type x = extended_integral_type(integral_type(src_x.data)), + y = extended_integral_type(integral_type(src_y.data)), + extended_base = 1, + ext_pow = extended_base << (num_chunks * bit_size_chunk), + p = NonNativeFieldType::modulus; + extended_integral_type pp = ext_pow - p; + + public_input.resize(5 * num_chunks); + for (std::size_t j = 0; j < num_chunks; j++) { + public_input[j] = value_type(x & mask); + x >>= bit_size_chunk; + + public_input[num_chunks + j] = value_type(y & mask); + y >>= bit_size_chunk; + + public_input[2 * num_chunks + j] = value_type(p & mask); + p >>= bit_size_chunk; + + public_input[3 * num_chunks + j] = value_type(pp & mask); + pp >>= bit_size_chunk; + + public_input[4 * num_chunks + j] = value_type(0); + } + + test_addition_mod_p(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_addition_mod_p_test) { + using pallas_field_type = typename crypto3::algebra::curves::pallas::base_field_type; + using vesta_field_type = typename crypto3::algebra::curves::vesta::base_field_type; + + addition_mod_p_tests(); + + addition_mod_p_tests(); + + addition_mod_p_tests(); + + addition_mod_p_tests(); + + addition_mod_p_tests(); + + addition_mod_p_tests(); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/check_mod_p.cpp b/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/check_mod_p.cpp index 6824d4b8f2..f4069095de 100644 --- a/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/check_mod_p.cpp +++ b/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/check_mod_p.cpp @@ -26,79 +26,84 @@ #define BOOST_TEST_MODULE bbf_check_mod_p_test #include +#include +#include #include #include -#include - -#include - -#include -#include -#include #include +#include +#include using namespace nil; using namespace nil::blueprint; - -template -void test_mod_p_check(const std::vector &public_input){ - +template +void test_mod_p_check( + const std::vector &public_input) { using FieldType = BlueprintFieldType; using TYPE = typename FieldType::value_type; - typename bbf::components::check_mod_p::raw_input_type raw_input; - raw_input.x = std::vector(public_input.begin(), public_input.begin() + num_chunks); - raw_input.pp = std::vector(public_input.begin() + num_chunks, public_input.begin() + 2 * num_chunks); + typename bbf::components::check_mod_p< + FieldType, bbf::GenerationStage::ASSIGNMENT>::raw_input_type raw_input; + raw_input.x = + std::vector(public_input.begin(), public_input.begin() + num_chunks); + raw_input.pp = std::vector(public_input.begin() + num_chunks, + public_input.begin() + 2 * num_chunks); raw_input.zero = TYPE(0); - auto B = bbf::circuit_builder(num_chunks,bit_size_chunk,expect_output); + auto B = bbf::circuit_builder(num_chunks, bit_size_chunk, + expect_output); auto [at, A, desc] = B.assign(raw_input); bool pass = B.is_satisfied(at); std::cout << "Is_satisfied = " << pass << std::endl; assert(pass == to_pass); - - if (to_pass && expect_output) { - #ifdef BLUEPRINT_PLONK_PROFILING_ENABLED - std::cout << "Expected output: " << std::dec << overflow << std::endl; - std::cout << "Real output: " << std::dec << A.output.data << std::endl; - #endif - assert(overflow == A.output.data); - } + if (to_pass && expect_output) { +#ifdef BLUEPRINT_PLONK_PROFILING_ENABLED + std::cout << "Expected output: " << std::dec << overflow << std::endl; + std::cout << "Real output: " << std::dec << A.output.data << std::endl; +#endif + assert(overflow == A.output.data); + } } - -template +template void mod_p_check_tests() { using integral_type = typename BlueprintFieldType::integral_type; using value_type = typename BlueprintFieldType::value_type; static boost::random::mt19937 seed_seq; - static nil::crypto3::random::algebraic_engine generate_random(seed_seq); + static nil::crypto3::random::algebraic_engine generate_random( + seed_seq); boost::random::uniform_int_distribution<> t_dist(0, 1); const integral_type B = integral_type(1) << bit_size_chunk; for (std::size_t i = 0; i < RandomTestsAmount; i++) { std::vector public_input; integral_type p = integral_type(generate_random().data); - p = (p == 0) ? 1 : p; // avoid p == 0 + p = (p == 0) ? 1 : p; // avoid p == 0 - integral_type x = overflow ? p + 1:(integral_type(generate_random().data) % p); + integral_type x = overflow ? p + 1 : (integral_type(generate_random().data) % p); - for(std::size_t j = 0; j < num_chunks; j++) { // the x's + for (std::size_t j = 0; j < num_chunks; j++) { // the x's public_input.push_back(value_type(x % B)); x /= B; } - for(std::size_t j = 0; j < num_chunks; j++) { // the pp's - public_input.push_back(value_type(B - (j > 0) - (p % B))); // these are B-base digits of (2^{kb} - p) + for (std::size_t j = 0; j < num_chunks; j++) { // the pp's + public_input.push_back(value_type( + B - (j > 0) - (p % B))); // these are B-base digits of (2^{kb} - p) p /= B; } - //Test with output, should always succeed - test_mod_p_check(public_input); + // Test with output, should always succeed + test_mod_p_check(public_input); - //Test without output, should fail when there is an overflow - test_mod_p_check(public_input); + // Test without output, should fail when there is an overflow + test_mod_p_check(public_input); } } @@ -123,13 +128,13 @@ BOOST_AUTO_TEST_CASE(blueprint_plonk_bbf_check_mod_p_test_overflow) { using pallas_field_type = typename crypto3::algebra::curves::pallas::base_field_type; using vesta_field_type = typename crypto3::algebra::curves::vesta::base_field_type; - mod_p_check_tests(); - mod_p_check_tests(); - mod_p_check_tests(); + mod_p_check_tests(); + mod_p_check_tests(); + mod_p_check_tests(); - mod_p_check_tests(); - mod_p_check_tests(); - mod_p_check_tests(); + mod_p_check_tests(); + mod_p_check_tests(); + mod_p_check_tests(); } -BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file +BOOST_AUTO_TEST_SUITE_END() diff --git a/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/flexible_multiplication.cpp b/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/flexible_multiplication.cpp index d1a1f63465..d4a7ee4872 100644 --- a/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/flexible_multiplication.cpp +++ b/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/flexible_multiplication.cpp @@ -26,25 +26,14 @@ #define BOOST_TEST_MODULE bbf_flexible_multiplication_test -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - #include +#include #include #include #include - -#include +#include +#include +#include using namespace nil; using namespace nil::blueprint; @@ -55,24 +44,23 @@ void test_mult(const std::vector &publi using FieldType = BlueprintFieldType; using TYPE = typename FieldType::value_type; using integral_type = typename BlueprintFieldType::integral_type; - using double_non_native_integral_type = + using extended_integral_type = nil::crypto3::multiprecision::big_uint<2 * NonNativeFieldType::modulus_bits>; - double_non_native_integral_type x = 0, y = 0, p = 0, pow = 1; + extended_integral_type x = 0, y = 0, p = 0, pow = 1; // Populate x, y, p for (std::size_t i = 0; i < num_chunks; ++i) { - x += double_non_native_integral_type(integral_type(public_input[i].data)) * pow; - y += double_non_native_integral_type( - integral_type(public_input[i + num_chunks].data)) * - pow; - p += double_non_native_integral_type( - integral_type(public_input[i + 2 * num_chunks].data)) * + x += extended_integral_type(integral_type(public_input[i].data)) * pow; + y += extended_integral_type(integral_type(public_input[i + num_chunks].data)) * pow; + p += + extended_integral_type(integral_type(public_input[i + 2 * num_chunks].data)) * + pow; pow <<= bit_size_chunk; } - double_non_native_integral_type r = x * y % p; + extended_integral_type r = x * y % p; auto assign_and_check = [&](auto &B, auto &raw_input) { raw_input.x = @@ -83,7 +71,7 @@ void test_mult(const std::vector &publi public_input.begin() + 3 * num_chunks); raw_input.pp = std::vector(public_input.begin() + 3 * num_chunks, public_input.begin() + 4 * num_chunks); - raw_input.zero = public_input.back(); + raw_input.zero = public_input[4 * num_chunks]; auto [at, A, desc] = B.assign(raw_input); bool pass = B.is_satisfied(at); @@ -92,10 +80,11 @@ void test_mult(const std::vector &publi assert(pass == to_pass); if (to_pass) { - double_non_native_integral_type R = 0; + assert(pass == true); + extended_integral_type R = 0; pow = 1; for (std::size_t i = 0; i < num_chunks; i++) { - R += double_non_native_integral_type(integral_type(A.res[i].data)) * pow; + R += extended_integral_type(integral_type(A.r[i].data)) * pow; pow <<= bit_size_chunk; } #ifdef BLUEPRINT_PLONK_PROFILING_ENABLED @@ -109,24 +98,24 @@ void test_mult(const std::vector &publi if constexpr (std::is_same_v) { - typename bbf::components::vesta_flexible_multiplication< + typename bbf::components::pallas_flexible_multiplication< 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::pallas_flexible_multiplication< + typename bbf::components::vesta_flexible_multiplication< 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); @@ -139,35 +128,28 @@ void mult_tests() { using value_type = typename BlueprintFieldType::value_type; using integral_type = typename BlueprintFieldType::integral_type; using foreign_value_type = typename NonNativeFieldType::value_type; - using foreign_integral_type = typename NonNativeFieldType::integral_type; typedef nil::crypto3::multiprecision::big_uint<2 * NonNativeFieldType::modulus_bits> - double_non_native_integral_type; + 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); - double_non_native_integral_type mask = - (double_non_native_integral_type(1) << bit_size_chunk) - 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; foreign_value_type src_x = generate_random(), src_y = generate_random(); - double_non_native_integral_type x = double_non_native_integral_type( - foreign_integral_type(src_x.data)), - y = double_non_native_integral_type( - foreign_integral_type(src_y.data)), - extended_base = 1, - ext_pow = extended_base - << (num_chunks * bit_size_chunk), - p = NonNativeFieldType::modulus, pp = ext_pow - p; - - public_input.resize(4 * num_chunks + 1); // public_input should contain x,y,p,pp,zero - // std::cout << "PI x = " << x << std::endl; - // std::cout << "PI y = " << y << std::endl; - // std::cout << "PI p = " << p << std::endl; + extended_integral_type x = extended_integral_type(integral_type(src_x.data)), + y = extended_integral_type(integral_type(src_y.data)), + extended_base = 1, + ext_pow = extended_base << (num_chunks * bit_size_chunk), + p = NonNativeFieldType::modulus, pp = ext_pow - p; + + public_input.resize(5 * num_chunks); + // public_input should contain x,y,p,pp,zero for (std::size_t j = 0; j < num_chunks; j++) { public_input[j] = value_type(x & mask); x >>= bit_size_chunk; @@ -180,8 +162,9 @@ void mult_tests() { public_input[3 * num_chunks + j] = value_type(pp & mask); pp >>= bit_size_chunk; + + public_input[4 * num_chunks + j] = value_type(0); } - public_input[4*num_chunks] = value_type(0); test_mult( public_input); @@ -196,29 +179,28 @@ void mult_tests_to_fail() { using foreign_value_type = typename NonNativeFieldType::value_type; using foreign_integral_type = typename NonNativeFieldType::integral_type; typedef nil::crypto3::multiprecision::big_uint<2 * NonNativeFieldType::modulus_bits> - double_non_native_integral_type; + 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); - double_non_native_integral_type mask = - (double_non_native_integral_type(1) << bit_size_chunk) - 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; foreign_value_type src_x = generate_random(), src_y = generate_random(); - double_non_native_integral_type - x = double_non_native_integral_type(foreign_integral_type(src_x.data)), - y = double_non_native_integral_type(foreign_integral_type(src_y.data)), - extended_base = 1, ext_pow = extended_base << (num_chunks * bit_size_chunk), - p = NonNativeFieldType::modulus, - // Forcing the test to fail by substracting pp by 1 + extended_integral_type x = extended_integral_type(integral_type(src_x.data)), + y = extended_integral_type(integral_type(src_y.data)), + extended_base = 1, + ext_pow = extended_base << (num_chunks * bit_size_chunk), + p = NonNativeFieldType::modulus, + // Forcing the test to fail by substracting pp by 1 pp = ext_pow - p - 1; - public_input.resize(4 * num_chunks); + public_input.resize(4 * num_chunks + 1); for (std::size_t j = 0; j < num_chunks; j++) { public_input[j] = value_type(x & mask); x >>= (bit_size_chunk); @@ -232,6 +214,7 @@ void mult_tests_to_fail() { public_input[3 * num_chunks + j] = value_type(pp & mask); pp >>= bit_size_chunk; } + public_input.push_back(value_type(0)); // the zero test_mult(public_input); 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 new file mode 100644 index 0000000000..93a74031ae --- /dev/null +++ b/crypto3/libs/blueprint/test/bbf/algebra/fields/non_native/negation_mod_p.cpp @@ -0,0 +1,185 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2024 Valeh Farzaliyev +// 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_negation_mod_p_test + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace nil; +using namespace nil::blueprint; + +template +void test_negation_mod_p( + const std::vector &public_input) { + using FieldType = BlueprintFieldType; + using TYPE = typename FieldType::value_type; + using integral_type = typename BlueprintFieldType::integral_type; + typedef nil::crypto3::multiprecision::big_uint<2 * NonNativeFieldType::modulus_bits> + extended_integral_type; + + extended_integral_type x = 0, p = 0, pow = 1; + // Populate x, p + for (std::size_t i = 0; i < num_chunks; ++i) { + x += extended_integral_type(integral_type(public_input[i].data)) * pow; + p += extended_integral_type(integral_type(public_input[i + num_chunks].data)) * + pow; + pow <<= bit_size_chunk; + } + + 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 = + std::vector(public_input.begin(), public_input.begin() + num_chunks); + raw_input.p = std::vector(public_input.begin() + num_chunks, + public_input.begin() + 2 * num_chunks); + raw_input.pp = std::vector(public_input.begin() + 2 * num_chunks, + public_input.begin() + 3 * num_chunks); + raw_input.zero = std::vector(public_input.begin() + 3 * num_chunks, + public_input.begin() + 4 * 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); + extended_integral_type R = 0; + pow = 1; + for (std::size_t i = 0; i < num_chunks; i++) { + R += extended_integral_type(integral_type(A.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 << r << std::endl; + std::cout << "Real res: " << std::dec << R << std::endl; +#endif + assert(r == R); + }; + + if constexpr (std::is_same_v) { + typename bbf::components::pallas_negation_mod_p< + 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_negation_mod_p< + 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 negation_mod_p_tests() { + using value_type = typename BlueprintFieldType::value_type; + using integral_type = typename BlueprintFieldType::integral_type; + using foreign_value_type = typename NonNativeFieldType::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; + + foreign_value_type src_x = generate_random(); + + extended_integral_type x = extended_integral_type(integral_type(src_x.data)), + extended_base = 1, + ext_pow = extended_base << (num_chunks * bit_size_chunk), + p = NonNativeFieldType::modulus; + extended_integral_type pp = ext_pow - p; + + public_input.resize(4 * num_chunks); + for (std::size_t j = 0; j < num_chunks; j++) { + public_input[j] = value_type(x & mask); + x >>= bit_size_chunk; + + public_input[1 * num_chunks + j] = value_type(p & mask); + p >>= bit_size_chunk; + + public_input[2 * num_chunks + j] = value_type(pp & mask); + pp >>= bit_size_chunk; + + public_input[3 * num_chunks + j] = value_type(0); // the zeros + } + + test_negation_mod_p(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_negation_mod_p_test) { + using pallas_field_type = typename crypto3::algebra::curves::pallas::base_field_type; + using vesta_field_type = typename crypto3::algebra::curves::vesta::base_field_type; + + negation_mod_p_tests(); + + negation_mod_p_tests(); + + negation_mod_p_tests(); + + negation_mod_p_tests(); + + negation_mod_p_tests(); + + negation_mod_p_tests(); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/crypto3/libs/blueprint/test/bbf/detail/carry_on_addition.cpp b/crypto3/libs/blueprint/test/bbf/detail/carry_on_addition.cpp index a044bcff53..9ecdb9e4ec 100644 --- a/crypto3/libs/blueprint/test/bbf/detail/carry_on_addition.cpp +++ b/crypto3/libs/blueprint/test/bbf/detail/carry_on_addition.cpp @@ -1,6 +1,6 @@ //---------------------------------------------------------------------------// // Copyright (c) 2024 Georgios Fotiadis -// Copyright (c) 2024 Antoine Cyr +// Copyright (c) 2024 Antoine Cyr // // MIT License // @@ -26,74 +26,79 @@ #define BOOST_TEST_MODULE carry_on_addition_test #include -#include +#include +#include #include #include -#include - -#include - -#include -#include -#include #include +#include +#include using namespace nil; using namespace nil::blueprint; -template -void test_carry_on_addition(const std::vector &public_input){ +template +void test_carry_on_addition( + const std::vector &public_input) { using FieldType = BlueprintFieldType; using integral_type = typename FieldType::integral_type; using TYPE = typename FieldType::value_type; - typename bbf::components::carry_on_addition::raw_input_type raw_input; - raw_input.x = std::vector(public_input.begin(), public_input.begin() + num_chunks); - raw_input.y = std::vector(public_input.begin() + num_chunks, public_input.end()); - auto B = bbf::circuit_builder(num_chunks,bit_size_chunk); + typename bbf::components::carry_on_addition< + FieldType, bbf::GenerationStage::ASSIGNMENT>::raw_input_type raw_input; + raw_input.x = + std::vector(public_input.begin(), public_input.begin() + num_chunks); + raw_input.y = + std::vector(public_input.begin() + num_chunks, public_input.end()); + auto B = bbf::circuit_builder(num_chunks, bit_size_chunk); auto [at, A, desc] = B.assign(raw_input); bool pass = B.is_satisfied(at); std::cout << "Is_satisfied = " << pass << std::endl; assert(pass == true); - integral_type BASE = integral_type(1) << bit_size_chunk; // the representation base + integral_type BASE = integral_type(1) << bit_size_chunk; // the representation base TYPE expected_res[num_chunks], carry[num_chunks]; - for(std::size_t i = 0; i < num_chunks; i++) { + for (std::size_t i = 0; i < num_chunks; i++) { expected_res[i] = public_input[i] + public_input[num_chunks + i]; if (i > 0) { - expected_res[i] += carry[i-1]; + expected_res[i] += carry[i - 1]; } carry[i] = (expected_res[i] >= BASE); - expected_res[i] -= carry[i]*BASE; + expected_res[i] -= carry[i] * BASE; } std::cout << "Carry on addition test" << std::endl; - for(std::size_t i = 0; i < num_chunks; i++) { - #ifdef BLUEPRINT_PLONK_PROFILING_ENABLED + 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[i].data << std::endl; - #endif - assert(A.res_z[i].data == expected_res[i].data); + std::cout << "Real res: " << std::dec << A.r[i].data << std::endl; +#endif + assert(A.r[i].data == expected_res[i].data); } - assert(carry[num_chunks-1] == A.res_c.data); + assert(carry[num_chunks - 1] == A.c.data); } -template +template void carry_on_addition_tests() { using integral_type = typename BlueprintFieldType::integral_type; using value_type = typename BlueprintFieldType::value_type; integral_type chunk_size = (integral_type(1) << bit_size_chunk); static boost::random::mt19937 seed_seq; - static nil::crypto3::random::algebraic_engine generate_random(seed_seq); + static nil::crypto3::random::algebraic_engine generate_random( + seed_seq); for (std::size_t i = 0; i < RandomTestsAmount; i++) { std::vector public_input = {}; - for(std::size_t j = 0; j < 2*num_chunks; j++) { - public_input.push_back(value_type(integral_type(generate_random().data) % chunk_size)); + for (std::size_t j = 0; j < 2 * num_chunks; j++) { + public_input.push_back( + value_type(integral_type(generate_random().data) % chunk_size)); } - test_carry_on_addition(public_input); + test_carry_on_addition( + public_input); } } @@ -145,4 +150,4 @@ BOOST_AUTO_TEST_CASE(blueprint_plonk_bbf_carry_on_addition_pallas_test) { carry_on_addition_tests(); } -BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file +BOOST_AUTO_TEST_SUITE_END() diff --git a/crypto3/libs/blueprint/test/bbf/detail/choice_function.cpp b/crypto3/libs/blueprint/test/bbf/detail/choice_function.cpp new file mode 100644 index 0000000000..d08e6823ae --- /dev/null +++ b/crypto3/libs/blueprint/test/bbf/detail/choice_function.cpp @@ -0,0 +1,134 @@ +//---------------------------------------------------------------------------// +// 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. +//---------------------------------------------------------------------------// + +#define BOOST_TEST_MODULE choice_function_test + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace nil; +using namespace nil::blueprint; + +template +void test_choice_function( + const std::vector &public_input) { + using FieldType = BlueprintFieldType; + using integral_type = typename FieldType::integral_type; + using TYPE = typename FieldType::value_type; + + typename bbf::components::choice_function< + FieldType, bbf::GenerationStage::ASSIGNMENT>::raw_input_type raw_input; + raw_input.q = public_input[0]; + raw_input.x = std::vector(public_input.begin() + 1, + public_input.begin() + num_chunks + 1); + raw_input.y = + std::vector(public_input.begin() + num_chunks + 1, public_input.end()); + auto B = + bbf::circuit_builder( + 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); + + TYPE expected_res[num_chunks]; + for (std::size_t i = 0; i < num_chunks; i++) { + expected_res[i] = + (1 - raw_input.q) * raw_input.x[i] + raw_input.q * raw_input.y[i]; + } + + 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.r[i].data << std::endl; +#endif + assert(A.r[i].data == expected_res[i].data); + } +} + +template +void choice_function_tests() { + 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); + + for (std::size_t i = 0; i < RandomTestsAmount; i++) { + std::vector public_input = { + t_dist(seed_seq)}; // q is the first arg (0 or 1) + for (std::size_t j = 0; j < 2 * num_chunks; j++) { + public_input.push_back(generate_random()); + } + test_choice_function(public_input); + } +} + +constexpr static const std::size_t random_tests_amount = 3; + +BOOST_AUTO_TEST_SUITE(blueprint_plonk_test_suite) + +BOOST_AUTO_TEST_CASE(blueprint_plonk_bbf_choice_function_vesta_test) { + using field_type = typename crypto3::algebra::curves::vesta::base_field_type; + + choice_function_tests(); + + choice_function_tests(); + choice_function_tests(); + choice_function_tests(); + choice_function_tests(); + + choice_function_tests(); + choice_function_tests(); + choice_function_tests(); + choice_function_tests(); +} + +BOOST_AUTO_TEST_CASE(blueprint_plonk_bbf_choice_function_pallas_test) { + using field_type = typename crypto3::algebra::curves::pallas::base_field_type; + + choice_function_tests(); + + choice_function_tests(); + choice_function_tests(); + choice_function_tests(); + choice_function_tests(); + + choice_function_tests(); + choice_function_tests(); + choice_function_tests(); + choice_function_tests(); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/crypto3/libs/blueprint/test/bbf/detail/range_check_multi.cpp b/crypto3/libs/blueprint/test/bbf/detail/range_check_multi.cpp index 86f78b0ae5..695d3421b6 100644 --- a/crypto3/libs/blueprint/test/bbf/detail/range_check_multi.cpp +++ b/crypto3/libs/blueprint/test/bbf/detail/range_check_multi.cpp @@ -26,29 +26,27 @@ #define BOOST_TEST_MODULE bbf_range_check_multi_test #include -#include +#include +#include #include #include -#include - -#include - -#include -#include -#include #include +#include +#include using namespace nil; using namespace nil::blueprint; - -template -void test_range_check(const std::vector &public_input){ - +template +void test_range_check( + const std::vector &public_input) { using FieldType = BlueprintFieldType; - typename bbf::components::range_check_multi::raw_input_type raw_input; + typename bbf::components::range_check_multi< + FieldType, bbf::GenerationStage::ASSIGNMENT>::raw_input_type raw_input; raw_input.state = public_input; - auto B = bbf::circuit_builder(num_chunks,bit_size_chunk); + auto B = bbf::circuit_builder(num_chunks, bit_size_chunk); auto [at, A, desc] = B.assign(raw_input); bool pass = B.is_satisfied(at); std::cout << "Is_satisfied = " << pass << std::endl; @@ -56,45 +54,52 @@ void test_range_check(const std::vector assert(pass == to_pass); } - -template +template void range_check_tests() { using integral_type = typename BlueprintFieldType::integral_type; using value_type = typename BlueprintFieldType::value_type; static boost::random::mt19937 seed_seq; - static nil::crypto3::random::algebraic_engine generate_random(seed_seq); + static nil::crypto3::random::algebraic_engine generate_random( + seed_seq); boost::random::uniform_int_distribution<> t_dist(0, 1); integral_type mask = (integral_type(1) << bit_size_chunk) - 1; for (std::size_t i = 0; i < RandomTestsAmount; i++) { std::vector public_input; for (std::size_t j = 0; j < num_chunks; j++) { - public_input.push_back(value_type(integral_type(generate_random().data) & mask)); + public_input.push_back( + value_type(integral_type(generate_random().data) & mask)); } - test_range_check(public_input); + test_range_check(public_input); } } -template +template void range_check_tests_to_fail() { using integral_type = typename BlueprintFieldType::integral_type; using value_type = typename BlueprintFieldType::value_type; static boost::random::mt19937 seed_seq; - static nil::crypto3::random::algebraic_engine generate_random(seed_seq); + static nil::crypto3::random::algebraic_engine generate_random( + seed_seq); boost::random::uniform_int_distribution<> t_dist(0, 1); integral_type mask = (integral_type(1) << bit_size_chunk) - 1; for (std::size_t i = 0; i < RandomTestsAmount; i++) { integral_type most_significant_bit = integral_type(1) << (bit_size_chunk); std::vector public_input; - //Adding a faulty bits - public_input.push_back(value_type(integral_type(generate_random().data) & mask | most_significant_bit)); + // Adding a faulty bits + public_input.push_back(value_type(integral_type(generate_random().data) & mask | + most_significant_bit)); for (std::size_t j = 1; j < num_chunks; j++) { - public_input.push_back(value_type(integral_type(generate_random().data) & mask)); + public_input.push_back( + value_type(integral_type(generate_random().data) & mask)); } - test_range_check(public_input); + test_range_check( + public_input); } } @@ -106,7 +111,6 @@ BOOST_AUTO_TEST_CASE(blueprint_plonk_bbf_range_check_multi_test) { using pallas_field_type = typename crypto3::algebra::curves::pallas::base_field_type; using vesta_field_type = typename crypto3::algebra::curves::vesta::base_field_type; - range_check_tests(); range_check_tests(); range_check_tests(); @@ -129,4 +133,4 @@ BOOST_AUTO_TEST_CASE(blueprint_plonk_field_operations_test_to_fail) { range_check_tests_to_fail(); } -BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file +BOOST_AUTO_TEST_SUITE_END()