diff --git a/libs/transpiler/CMakeLists.txt b/libs/transpiler/CMakeLists.txt new file mode 100644 index 000000000..556f00202 --- /dev/null +++ b/libs/transpiler/CMakeLists.txt @@ -0,0 +1,28 @@ +include(CMConfig) +include(CMSetupVersion) + +cm_project(transpiler WORKSPACE_NAME ${CMAKE_WORKSPACE_NAME} LANGUAGES ASM C CXX) + +include(CMDeploy) + +cm_setup_version(VERSION 0.1.0 PREFIX ${CMAKE_WORKSPACE_NAME}_${CURRENT_PROJECT_NAME}) + +add_library(${CMAKE_WORKSPACE_NAME}_${CURRENT_PROJECT_NAME} INTERFACE) + +set_target_properties(${CMAKE_WORKSPACE_NAME}_${CURRENT_PROJECT_NAME} PROPERTIES + EXPORT_NAME ${CURRENT_PROJECT_NAME}) + +target_include_directories(${CMAKE_WORKSPACE_NAME}_${CURRENT_PROJECT_NAME} INTERFACE + $ + $) + +target_link_libraries(${CMAKE_WORKSPACE_NAME}_${CURRENT_PROJECT_NAME} INTERFACE + ${Boost_LIBRARIES} +) + +cm_deploy(TARGETS ${CMAKE_WORKSPACE_NAME}_${CURRENT_PROJECT_NAME} + INCLUDE include + NAMESPACE ${CMAKE_WORKSPACE_NAME}::) + +include(CMTest) +cm_add_test_subdirectory(test) diff --git a/libs/transpiler/README.md b/libs/transpiler/README.md new file mode 100644 index 000000000..58b4fc2f6 --- /dev/null +++ b/libs/transpiler/README.md @@ -0,0 +1,56 @@ +# Circuits Traspiler Library for =nil; Foundation's zkLLVM circuit compiler + +[![Run tests](https://github.com/NilFoundation/zkllvm-transpiler/actions/workflows/run_tests.yml/badge.svg)](https://github.com/NilFoundation/zkllvm-transpiler/actions/workflows/run_tests.yml) + +## Building + +This library uses Boost CMake build modules (https://github.com/BoostCMake/cmake_modules.git). +To actually include this library in a project it is required to: + +1. Add [CMake Modules](https://github.com/BoostCMake/cmake_modules.git) as submodule to target project repository. +2. Add all the internal dependencies using [CMake Modules](https://github.com/BoostCMake/cmake_modules.git) as submodules to target project repository. +3. Initialize parent project with [CMake Modules](https://github.com/BoostCMake/cmake_modules.git) (Look at [crypto3](https://github.com/nilfoundation/crypto3.git) for the example) + +## Run examples +This library is used in the [zkLLVM](https://github.com/NilFoundation/zkllvm) transpiler binary. +It produces gate argument for EVM from zkllvm-assigner which consists of `circuit.crct` and `assignment.tbl` file. +It can also create test proof to check gate argument by [evm-placeholder-verification](https://github.com/NilFoundation/zkllvm) +To build transpiler app follow zkLLVM instructions to prepare evironment and input data. Use this branch [zkLLVM](https://github.com/NilFoundation/zkllvm/tree/64-add-optimize-option-to-transpiler-app). + +1. Build transpiler binary file +```bash +make -C ${ZKLLVM_BUILD:-build} transpiler -j$(nproc) +``` +2. Let `input_folder` is a folder contains transpiler input (`circuit.crct` and `assignment.tbl` file). Let `output_folder` is a folder for transpiler output. Run to generate gate argument files: +```bash +${ZKLLVM_BUILD:-build}/bin/transpiler/transpiler -m gen-gate-argument -i input_folder -o output_folder +``` +Use `--optimize-gates` option to place small sequental gates to one `.sol` file +Let `public_input_file` is a file with public input. Run to generate test proof: +```bash +${ZKLLVM_BUILD:-build}/bin/transpiler/transpiler -m gen-test-proof -i input_folder -o output_folder -p public_input_file +``` +3. Copy `output_folder` to `evm-placeholder-verification/contracts/zkllvm`. + +4. Run hardhat to verify proof: +```bash +npx hardhat deploy +npx hardhat verify-circuit-proof --test output_folder +``` +## Dependencies + +### Internal + +Crypto3 suite: + +* [Crypto3.Algebra](https://github.com/nilfoundation/crypto3-algebra.git). +* [Crypto3.Math](https://github.com/nilfoundation/crypto3-math.git). +* [Crypto3.Multiprecision](https://github.com/nilfoundation/crypto3-multiprecision.git). +* [Crypto3.ZK](https://github.com/nilfoundation/crypto3-zk.git). + +zkLLVM compiler ecosystem: + +* [zkLLVM Blueprint](https://github.com/NilFoundation/zkllvm-blueprint.git). + +### External +* [Boost](https://boost.org) (>= 1.76) diff --git a/libs/transpiler/include/nil/blueprint/transpiler/evm_verifier_gen.hpp b/libs/transpiler/include/nil/blueprint/transpiler/evm_verifier_gen.hpp new file mode 100644 index 000000000..a6f79d94a --- /dev/null +++ b/libs/transpiler/include/nil/blueprint/transpiler/evm_verifier_gen.hpp @@ -0,0 +1,952 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2023 Elena Tatuzova +// +// 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 unified addition component. +//---------------------------------------------------------------------------// +#ifndef __EVM_VERIFIER_GEN_HPP__ +#define __EVM_VERIFIER_GEN_HPP__ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +namespace nil { + namespace blueprint { + template + class evm_verifier_printer{ + using common_data_type = typename nil::crypto3::zk::snark::placeholder_public_preprocessor< + typename PlaceholderParams::field_type, + PlaceholderParams + >::preprocessed_data_type::common_data_type; + + using variable_type = nil::crypto3::zk::snark::plonk_variable; + using constraint_type = nil::crypto3::zk::snark::plonk_constraint; + using lookup_constraint_type = nil::crypto3::zk::snark::plonk_lookup_constraint; + using gate_type = nil::crypto3::zk::snark::plonk_gate; + using lookup_gate_type = nil::crypto3::zk::snark::plonk_lookup_gate; + using variable_indices_type = std::map, std::size_t>; + using columns_rotations_type = std::vector>; + + // Detect whether combination is a polynomial over one variable + bool detect_polynomial(crypto3::math::non_linear_combination const& comb) { + std::unordered_set comb_vars; + + for (auto it = std::begin(comb); it != std::cend(comb); ++it ) { + const auto &vars = it->get_vars(); + for (auto v = std::cbegin(vars); v != std::cend(vars); ++v) { + comb_vars.insert(*v); + } + } + + return comb_vars.size() == 1; + } + + // Detect whether term is a power of one variable. If such, return this power + std::size_t term_is_power(crypto3::math::term const& term) { + const auto &vars = term.get_vars(); + auto var = std::cbegin(vars); + + if (var == std::cend(vars)) + return 0; + + variable_type prev_var = *var; + ++var; + + std::size_t power = 1; + + while (var != std::cend(vars)) { + if (*var != prev_var) { + return 0; + } + ++power; + prev_var = *var; + ++var; + } + + return power; + } + + std::string constraint_computation_code_optimized( + variable_indices_type &_var_indices, + const constraint_type &constraint + ){ + std::stringstream result; + + crypto3::math::expression_to_non_linear_combination_visitor visitor; + auto comb = visitor.convert(constraint); + + if (_deduce_horner && detect_polynomial(comb)) { + comb.sort_terms_by_degree(); + /* First term always exists, as polynomial contains at least one term */ + std::size_t degree = comb.terms[0].get_vars().size(); + result << "\t\t/* Constraint is a polynomial over one variable. Using Horner's formula */" << std::endl; + auto it = std::cbegin(comb); + /* Load temporary variable */ + result << "\t\tx = basic_marshalling.get_uint256_be(blob, " << _var_indices.at(comb.terms[0].get_vars()[0]) * 0x20 << ");" << std::endl; + if (it->get_coeff() == PlaceholderParams::field_type::value_type::one()) { + result << "\t\tsum = x;" << std::endl; + } else { + result << "\t\tsum = " << it->get_coeff() <<";" << std::endl; + result << "\t\tsum = mulmod(sum, x, modulus);" << std::endl; + } + ++it; + --degree; + while (degree != 0) { + if ((degree == it->get_vars().size()) && (it->get_coeff() != 0) ) { + result << "\t\tsum = addmod(sum, " << it->get_coeff() << ", modulus);" << std::endl; + ++it; + } else { + result << "\t\t/* term with zero coeficient is skipped */" << std::endl; + } + result << "\t\tsum = mulmod(sum, x, modulus);" << std::endl; + --degree; + } + if (it != std::cend(comb) && (it->get_coeff() != 0) ) { + result << "/* last term */" << std::endl; + result << "\t\tsum = addmod(sum, " << it->get_coeff() << ", modulus);" << std::endl; + } + result << "\t\t/* End using Horner's formula */" << std::endl; + } else { + result << "\t\tsum = 0;" << std::endl; + for (auto term = std::cbegin(comb); term != std::cend(comb); ++term) { + if ( term->get_coeff() == 0) { + continue; + } + const auto &vars = term->get_vars(); + std::size_t power; + + /* Using special powX function is only feasible for powers >= 4 */ + if ( _optimize_powers && ((power = term_is_power(*term)) >= 4) ) { + _term_powers.insert(power); + result << "\t\tprod = modular_utils_" << _test_name << ".pow" << power << "(basic_marshalling.get_uint256_be(blob, " << _var_indices.at(vars[0]) * 0x20 << "));" << std::endl; + } else { + for (auto var = std::cbegin(vars); var != std::cend(vars); ++var) { + if (var == std::cbegin(vars)) { + result << "\t\tprod = basic_marshalling.get_uint256_be(blob, " << _var_indices.at(*var) * 0x20 << ");" << std::endl; + } else { + result << "\t\tprod = mulmod(prod, basic_marshalling.get_uint256_be(blob, " << _var_indices.at(*var) * 0x20 << "), modulus);" << std::endl; + } + } + } + if (vars.size() == 0) { + result << "\t\tsum = addmod(sum, " << term->get_coeff() << ", modulus);" << std::endl; + } else { + if (term->get_coeff() != PlaceholderParams::field_type::value_type::one()) { + result << "\t\tprod = mulmod(prod, " << term->get_coeff() << ", modulus);" << std::endl; + } + result << "\t\tsum = addmod(sum, prod, modulus);" << std::endl; + } + } + } + return result.str(); + } + + std::string constraint_computation_code( + variable_indices_type &_var_indices, + const constraint_type &constraint + ){ + using variable_type = nil::crypto3::zk::snark::plonk_variable; + std::stringstream result; + + crypto3::math::expression_to_non_linear_combination_visitor visitor; + auto comb = visitor.convert(constraint); + result << "\t\tsum = 0;" << std::endl; + for( auto it = std::cbegin(comb); it != std::cend(comb); ++it ){ + bool coeff_one = (it->get_coeff() == PlaceholderParams::field_type::value_type::one()); + if(!coeff_one) result << "\t\tprod = " << it->get_coeff() << ";" << std::endl; + const auto &vars = it->get_vars(); + for( auto it2 = std::cbegin(vars); it2 != std::cend(vars); it2++ ){ + const variable_type &v = *it2; + if(coeff_one){ + coeff_one = false; + result << "\t\tprod = basic_marshalling.get_uint256_be(blob, " << _var_indices.at(v) * 0x20 << ");" << std::endl; + } else{ + result << "\t\tprod = mulmod(prod, basic_marshalling.get_uint256_be(blob, " << _var_indices.at(v) * 0x20 << "), modulus);" << std::endl; + } + } + result << "\t\tsum = addmod(sum, prod, modulus);" << std::endl; + } + return result.str(); + } + public: + evm_verifier_printer( + const typename PlaceholderParams::constraint_system_type &constraint_system, + const common_data_type &common_data, + std::string folder_name, + std::size_t gates_contract_size_threshold = 800, + std::size_t lookups_library_size_threshold = 1000, + std::size_t lookups_contract_size_threshold = 1000, + bool deduce_horner = true, + bool optimize_powers = true + ) : + _constraint_system(constraint_system), + _common_data(common_data), + _folder_name(folder_name), + _lookups_library_size_threshold(lookups_library_size_threshold), + _gates_contract_size_threshold(gates_contract_size_threshold), + _lookups_contract_size_threshold(lookups_contract_size_threshold), + _deduce_horner(deduce_horner), + _optimize_powers(optimize_powers), + _desc(common_data.desc), + _permutation_size(common_data.permuted_columns.size()), + _fri_params(common_data.commitment_params) + { + _placeholder_info = nil::crypto3::zk::snark::prepare_placeholder_info( + constraint_system, + common_data + ); + std::size_t found = folder_name.rfind("/"); + if( found == std::string::npos ){ + _test_name = folder_name; + } else{ + _test_name = folder_name.substr(found + 1); + } + _use_lookups = _constraint_system.lookup_gates().size() > 0; + _use_permutations = common_data.permuted_columns.size() > 0; + + _z_offset = (_placeholder_info.batches_num - 1) * 0x28 + 0x29; + _special_selectors_offset = _z_offset + _permutation_size * 0x40; + _table_offset = _special_selectors_offset + 0x80; + + _variable_values_offset = 0; + for( std::size_t i = 0; i < _desc.constant_columns + _desc.selector_columns; i++){ + _variable_values_offset += 0x20 * (_common_data.columns_rotations[i + _desc.witness_columns + _desc.public_input_columns].size()); + } + + _permutation_offset = _variable_values_offset; + _public_input_offset = _variable_values_offset; + for( std::size_t i = 0; i < _desc.witness_columns + _desc.public_input_columns; i++){ + if(i == _desc.witness_columns){ + _public_input_offset = _permutation_offset; + } + _permutation_offset += 0x20 * (_common_data.columns_rotations[i].size()); + } + + _table_end_offset = _permutation_offset + _table_offset; + _quotient_offset = _permutation_offset; + + if(_use_permutations) _quotient_offset += (_placeholder_info.permutation_poly_amount + 1) * 0x20; + _v_l_offset = _quotient_offset; + if(_use_lookups) _quotient_offset += (_placeholder_info.lookup_poly_amount + 1) * 0x20; + + _lookup_offset = _table_offset + _quotient_offset + 0x20 * (_placeholder_info.quotient_size); + + _var_indices = _placeholder_info.var_indices; + } + + void print_gates_library_file(std::size_t library_id, + std::vector const& gates_list, + std::unordered_map const& gate_codes) { + + std::string library_gates; + + for (auto i: gates_list) { + std::string gate_evaluation = gate_evaluation_template; + boost::replace_all(gate_evaluation, "$GATE_ID$" , to_string(i) ); + boost::replace_all(gate_evaluation, "$GATE_ASSEMBLY_CODE$", gate_codes.at(i)); + library_gates += gate_evaluation; + } + + std::string result = modular_external_gate_library_template; + boost::replace_all(result, "$TEST_NAME$", _test_name); + boost::replace_all(result, "$GATE_LIB_ID$", to_string(library_id)); + boost::replace_all(result, "$GATES_COMPUTATION_CODE$", library_gates); + boost::replace_all(result, "$MODULUS$", to_string(PlaceholderParams::field_type::modulus)); + + std::ofstream out; + out.open(_folder_name + "/gate_" + to_string(library_id) + ".sol"); + out << result; + out.close(); + } + + void print_lookups_library_file(std::size_t library_id, + std::vector const& lookups_list, + std::unordered_map const& lookup_codes) { + + std::string library_lookups; + + for(auto const& i: lookups_list) { + std::string lookup_evaluation = lookup_evaluation_template; + boost::replace_all(lookup_evaluation, "$LOOKUP_ID$" , to_string(i) ); + boost::replace_all(lookup_evaluation, "$LOOKUP_ASSEMBLY_CODE$", lookup_codes.at(i)); + library_lookups += lookup_evaluation; + } + + std::string result = modular_external_lookup_library_template; + boost::replace_all(result, "$TEST_NAME$", _test_name); + boost::replace_all(result, "$LOOKUP_LIB_ID$", to_string(library_id)); + boost::replace_all(result, "$LOOKUP_COMPUTATION_CODE$", library_lookups); + boost::replace_all(result, "$MODULUS$", to_string(PlaceholderParams::field_type::modulus)); + boost::replace_all(result, "$STATE$", ""); + + std::ofstream out; + out.open(_folder_name + "/lookup_" + to_string(library_id) + ".sol"); + out << result; + out.close(); + } + + std::string gate_computation_code(const gate_type& gate) { + std::stringstream out; + + out << "\t\tgate = 0;" << std::endl; + int c = 0; + for(const auto &constraint: gate.constraints){ + out << constraint_computation_code_optimized(_var_indices, constraint); + out << "\t\tgate = addmod(gate, mulmod(theta_acc, sum, modulus), modulus);" << std::endl; + out << "\t\ttheta_acc = mulmod(theta_acc, theta, modulus);" << std::endl; + c++; + } + variable_type sel_var(gate.selector_index, 0, true, variable_type::column_type::selector); + out << "\t\tgate = mulmod(gate, basic_marshalling.get_uint256_be(blob, " << _var_indices.at(sel_var) * 0x20 << "), modulus);" << std::endl; + out << "\t\tF = addmod(F, gate, modulus);" < [item_id]) + * */ + std::unordered_map> split_items_into_buckets( + std::vector> &items, + std::size_t max_bucket_size) { + + std::unordered_map> buckets; + std::vector bucket_sizes; + + for (auto const& item : items) { + bool bucket_found = false; + for (std::size_t i = 0; i < bucket_sizes.size(); ++i) { + if (bucket_sizes[i]+item.second <= max_bucket_size) { + buckets[i].push_back(item.first); + bucket_sizes[i] += item.second; + bucket_found = true; + break; + } + } + + if (!bucket_found) { + bucket_sizes.push_back(item.second); + buckets[bucket_sizes.size()-1].push_back(item.first); + } + } + return buckets; + } + + std::string generate_power_function(std::size_t power) { + std::stringstream result; + std::vector ops; + + result << "\tfunction pow" << power << "(uint256 base) internal pure returns (uint256 result) {" << std::endl; + result << "\t\tresult = base;" << std::endl; + + while (power > 1) { + if (power & 1) { + ops.push_back("\t\tresult = mulmod(result, base, modulus);"); + } + ops.push_back("\t\tresult = mulmod(result, result, modulus);"); + power >>= 1; + } + + for(auto op = ops.rbegin(); op != ops.rend(); ++op) { + result << *op << std::endl; + } + + result << "\t}" << std::endl; + return result.str(); + } + + struct constraint_info { + std::string code; + std::size_t cost; + std::size_t gate_index; + std::size_t constraint_index; + std::size_t selector_index; + }; + + std::string print_constraint_series(typename std::vector::iterator &it, + typename std::vector::iterator const& last) { + std::stringstream result; + std::size_t printed_cost = 0; + std::size_t prev_sel = 0; + + bool first_constraint = true; + + while ((printed_cost <= _gates_contract_size_threshold) && (it != last) ) { + + if (first_constraint) { + result << "// gate === " << it->gate_index << " ===" << std::endl; + result << "\t\tgate = 0;" << std::endl; + first_constraint = false; + prev_sel = it->selector_index; + } else if (prev_sel != it->selector_index) { + result << "\t\tgate = mulmod(gate, basic_marshalling.get_uint256_be(blob, "<gate_index << " ===" << std::endl; + result << "\t\tgate = 0;" << std::endl; + prev_sel = it->selector_index; + } + result << "// constraint " << it->constraint_index << std::endl; + result << it->code; + result << "\t\tsum = mulmod(sum, theta_acc, modulus);" << std::endl; + result << "\t\ttheta_acc = mulmod(theta, theta_acc, modulus);" << std::endl; + result << "\t\tgate = addmod(gate, sum, modulus);" << std::endl; + + printed_cost += it->cost; + ++it; + } + + if (it != last) { + result << "// gate computation code ended prematurely. continue in next library" << std::endl; + } + result << "\t\tgate = mulmod(gate, basic_marshalling.get_uint256_be(blob, "< gate_codes; + std::vector> gate_costs(gates_count); + std::vector gate_ids(gates_count); + + std::vector constraints; + std::size_t total_cost = 0; + + i = 0; + for (const auto& gate: _constraint_system.gates()) { + variable_type sel_var(gate.selector_index, 0, true, variable_type::column_type::selector); + std::size_t j = 0; + for (const auto& constraint: gate.constraints) { + std::string code = constraint_computation_code_optimized(_var_indices, constraint); + std::size_t cost = estimate_constraint_cost(code); + std::size_t selector_index = _var_indices.at(sel_var)*0x20; + + constraints.push_back( {code, cost, i, j, selector_index} ); + + total_cost += cost; + ++j; + } + ++i; + } + + + std::size_t gate_modules_count = 0; + std::size_t current_selector = 0; + if (total_cost <= _gates_contract_size_threshold) { + auto it = constraints.begin(); + gate_argument_str << "\t\tuint256 prod;" << std::endl; + gate_argument_str << "\t\tuint256 sum;" << std::endl; + gate_argument_str << "\t\tuint256 gate;" << std::endl; + gate_argument_str << print_constraint_series(it, constraints.end()); + } else { + auto it = constraints.begin(); + while (it != constraints.end()) { + std::string code = print_constraint_series(it, constraints.end()); + + std::string result = modular_external_gate_library_template; + boost::replace_all(result, "$TEST_NAME$", _test_name); + boost::replace_all(result, "$GATE_LIB_ID$", to_string(gate_modules_count)); + boost::replace_all(result, "$CONSTRAINT_SERIES_CODE$", code); + boost::replace_all(result, "$MODULUS$", to_string(PlaceholderParams::field_type::modulus)); + boost::replace_all(result, "$UTILS_LIBRARY_IMPORT$", _term_powers.size() >0? "import \"./utils.sol\";" : ""); + + + std::ofstream out; + out.open(_folder_name + "/gate_" + to_string(gate_modules_count) + ".sol"); + out << result; + out.close(); + _gate_includes += "import \"./gate_" + to_string(gate_modules_count) + ".sol\";\n"; + + ++gate_modules_count; + } + } + + if (_term_powers.size() > 0) { + std::stringstream power_functions; + for(std::size_t power: _term_powers) { + power_functions << generate_power_function(power); + } + + std::string utils_library(utils_library_template); + boost::replace_all(utils_library, "$MODULUS$", to_string(PlaceholderParams::field_type::modulus)); + boost::replace_all(utils_library, "$POWER_FUNCTIONS$", power_functions.str()); + boost::replace_all(utils_library, "$TEST_NAME$", _test_name); + std::ofstream utils; + utils.open(_folder_name + "/utils.sol"); + utils << utils_library; + utils.close(); + } + + for ( i = 0; i < gate_modules_count; ++i ) { + std::string gate_eval_string = gate_call_template; + boost::replace_all(gate_eval_string, "$TEST_NAME$", _test_name); + boost::replace_all(gate_eval_string, "$GATE_LIB_ID$", to_string(i)); + gate_argument_str << gate_eval_string << std::endl; + } + i = 0; + + if ( gate_modules_count > 0) { + std::ofstream out; + out.open(_folder_name + "/gate_libs_list.json"); + out << "[" << std::endl; + for(i = 0; i < gate_modules_count-1; ++i ) { + out << "\"" << "gate_" << _test_name << "_" << i << "\"," << std::endl; + } + out << "\"" << "gate_" << _test_name << "_" << gate_modules_count-1 << "\"" << std::endl; + out << "]" << std::endl; + out.close(); + } + + return gate_argument_str.str(); + } + + std::string print_lookup_argument(){ + std::size_t lookup_count = _constraint_system.lookup_gates().size(); + if (lookup_count == 0) + return ""; + + std::stringstream lookup_str; + std::size_t j = 0; + std::size_t i = 0; + std::size_t cur = 0; + std::unordered_map lookup_codes; + std::vector lookup_ids(lookup_count); + std::vector> lookup_costs(lookup_count); + std::vector lookup_lib(lookup_count); + + i = 0; + for(const auto &lookup: _constraint_system.lookup_gates()) { + std::string code = lookup_computation_code(lookup); + lookup_costs[i] = std::make_pair(i, estimate_lookup_cost(code)); + lookup_codes[i] = code; + ++i; + } + + std::sort(lookup_costs.begin(), lookup_costs.end(), + [](const std::pair &a, + const std::pair &b) { + return a.second > b.second; + }); + + // Fill contract inline lookup computation, inline small first + std::unordered_set inlined_lookup_codes; + std::size_t inlined_lookup_codes_size = 0; + for (auto lookup = lookup_costs.rbegin(); lookup != lookup_costs.rend(); ++lookup) { + if (lookup->second + inlined_lookup_codes_size < _lookups_contract_size_threshold) { + inlined_lookup_codes.insert(lookup->first); + inlined_lookup_codes_size += lookup->second; + } + } + + auto inlined_lookups_end = std::remove_if(lookup_costs.begin(), lookup_costs.end(), + [&inlined_lookup_codes](const std::pair& cost) { + return inlined_lookup_codes.count(cost.first) == 1 ; + }); + lookup_costs.erase(inlined_lookups_end, lookup_costs.end()); + + auto library_lookup_buckets = split_items_into_buckets(lookup_costs, _lookups_library_size_threshold); + + _lookup_includes = ""; + for(auto const& lib: library_lookup_buckets) { + _lookup_includes += "import \"./lookup_" + to_string(lib.first) + ".sol\";\n"; + for(auto l: lib.second) { + lookup_lib[l] = lib.first; + } + print_lookups_library_file(lib.first, lib.second, lookup_codes); + } + + if (inlined_lookup_codes.size() > 0) { + lookup_str << "\t\t\tuint256 sum;" << std::endl; + lookup_str << "\t\t\tuint256 prod;" << std::endl; + } + + for (i = 0; i < _constraint_system.lookup_gates().size(); ++i) { + if (inlined_lookup_codes.count(i) == 1) { + boost::replace_all(lookup_codes[i], "$STATE$", "state."); + lookup_str << "// -- lookup " << i << " is inlined -- " << std::endl; + lookup_str << lookup_codes[i] << std::endl; + lookup_str << "// -- /lookup " << i << " is inlined -- " << std::endl; + } else { + std::string lookup_eval_string = lookup_call_template; + boost::replace_all(lookup_eval_string, "$TEST_NAME$", _test_name); + boost::replace_all(lookup_eval_string, "$LOOKUP_LIB_ID$", to_string(lookup_lib[i])); + boost::replace_all(lookup_eval_string, "$LOOKUP_ID$", to_string(i)); + boost::replace_all(lookup_eval_string, "$MODULUS$", to_string(PlaceholderParams::field_type::modulus)); + lookup_str << lookup_eval_string; + } + } + + if (library_lookup_buckets.size() > 0) { + std::ofstream out; + out.open(_folder_name + "/lookup_libs_list.json"); + out << "[" << std::endl; + for(i = 0; i < library_lookup_buckets.size()-1; ++i ) { + out << "\"" << "lookup_" << _test_name << "_" << i << "\"," << std::endl; + } + out << "\"" << "lookup_" << _test_name << "_" << library_lookup_buckets.size()-1 << "\"" << std::endl; + out << "]" << std::endl; + out.close(); + } + + j = 0; + std::size_t table_index = 1; + for(const auto &table: _constraint_system.lookup_tables()){ + variable_type sel_var(table.tag_index, 0, true, variable_type::column_type::selector); + variable_type shifted_sel_var(table.tag_index, 1, true, variable_type::column_type::selector); + lookup_str << "\t\t\tstate.selector_value = basic_marshalling.get_uint256_be(blob, " << _var_indices.at(sel_var) * 0x20 << ");" << std::endl; + lookup_str << "\t\t\tstate.shifted_selector_value = basic_marshalling.get_uint256_be(blob, " << _var_indices.at(shifted_sel_var) * 0x20 << ");" << std::endl; + + for( const auto &option: table.lookup_options ){ + lookup_str << + "\t\t\tl = mulmod( " << table_index << ", state.selector_value, modulus);" << std::endl; + lookup_str << + "\t\t\tstate.l_shifted = mulmod( " << table_index << ", state.shifted_selector_value, modulus);" << std::endl; + lookup_str << "\t\t\tstate.theta_acc=state.theta;" << std::endl; + for( const auto &var: option ){ + lookup_str << + "\t\t\tl = addmod( l, mulmod(state.selector_value, mulmod( state.theta_acc, basic_marshalling.get_uint256_be(blob, " << _var_indices.at(var) * 0x20 << "), modulus), modulus), modulus);" << std::endl; + variable_type shifted_var = var; + shifted_var.rotation = 1; + lookup_str << + "\t\t\tstate.l_shifted = addmod( state.l_shifted, mulmod(state.shifted_selector_value, mulmod( state.theta_acc, basic_marshalling.get_uint256_be(blob, " << _var_indices.at(shifted_var) * 0x20 << "), modulus), modulus), modulus);" << std::endl; + lookup_str << "\t\t\tstate.theta_acc = mulmod(state.theta_acc, state.theta, modulus);" << std::endl; + } + lookup_str << + "\t\t\tl = mulmod( l, state.mask, modulus);" << std::endl; + lookup_str << + "\t\t\tstate.l_shifted = mulmod( state.l_shifted, state.shifted_mask, modulus);" << std::endl; + lookup_str << "\t\t\tstate.g = mulmod(state.g, addmod( state.factor, addmod(l, mulmod(state.beta, state.l_shifted, modulus), modulus), modulus), modulus);" << std::endl; + j++; + } + table_index++; + } + lookup_str << std::endl; + + return lookup_str.str(); + } + + std::string eta_point_verification_code() { + std::stringstream result; + auto fixed_poly_values = _common_data.commitment_scheme_data; + using eta_hash = crypto3::hashes::keccak_1600<256>; + using field_element_type = nil::crypto3::marshalling::types::field_element< + nil::marshalling::field_type, + typename PlaceholderParams::field_type::value_type>; + + if (fixed_poly_values.size() == 0) + return ""; + + result << "\t\t\t// 1 - 2*permutation_size " << std::endl; + std::vector eta_buf; + + std::size_t poly_points = 2*_permutation_size; + /* special_selectors */ + poly_points += 2; + poly_points += _desc.constant_columns; + poly_points += _desc.selector_columns; + eta_buf.resize( 32*poly_points ); + + std::array empty; + auto writer = eta_buf.begin(); + + result << "\t\t///* eta points check */" << std::endl; + result << "\t\t{" << std::endl; + result << "\t\t\tuint256[" << poly_points << "] memory points;" << std::endl; + + std::size_t i = 0, j = 0; + std::size_t point_offset = 8; + + + result << std::showbase << std::hex; + + poly_points = 2; + while (j < 2*_permutation_size) { + result << "\t\t\tpoints[" << i << "] = basic_marshalling.get_uint256_be(blob,"; + result << point_offset + (poly_points-1)*32 << ");" << std::endl; + field_element_type value(fixed_poly_values[0][i]); + value.write(writer, 32); + point_offset += 32*poly_points; + ++i; + ++j; + } + + poly_points = 3; + + j = 0; + while (j < 2) { + result << "\t\t\tpoints[" << i << "] = basic_marshalling.get_uint256_be(blob,"; + result << point_offset + (poly_points-1)*32 << ");" << std::endl; + field_element_type value(fixed_poly_values[0][i]); + value.write(writer, 32); + point_offset += 32*poly_points; + ++i; + ++j; + } + + std::size_t column_rotation_offset = _desc.witness_columns + _desc.public_input_columns; + j = 0; + while (j < _desc.constant_columns) { + poly_points = _common_data.columns_rotations[column_rotation_offset + j].size()+1; + result << "\t\t\tpoints[" << i << "] = basic_marshalling.get_uint256_be(blob,"; + result << point_offset + (poly_points-1)*32 << ");" << std::endl; + field_element_type value(fixed_poly_values[0][i]); + value.write(writer, 32); + point_offset += 32*poly_points; + ++i; + ++j; + } + + column_rotation_offset += _desc.constant_columns; + j = 0; + while (j < _desc.selector_columns) { + poly_points = _common_data.columns_rotations[column_rotation_offset + j].size()+1; + result << "\t\t\tpoints[" << i << "] = basic_marshalling.get_uint256_be(blob,"; + result << point_offset + (poly_points-1)*32 << ");" << std::endl; + field_element_type value(fixed_poly_values[0][i]); + value.write(writer, 32); + point_offset += 32*(poly_points); + ++i; + ++j; + } + + eta_hash::digest_type hash_result = crypto3::hash(eta_buf); + result << "\t\t\t// Check keccak(points) " << std::endl; + result << "\t\t\tif ( bytes32(0x" << std::to_string(hash_result).data() << ") != keccak256(abi.encode(points))) {" << std::endl; + result << "\t\t\t\treturn false;" << std::endl; + result << "\t\t\t}" << std::endl; + result << "\t\t}" << std::endl; + + return result.str(); + } + + std::string permuted_indices_to_hex_str(std::vector indices){ + std::stringstream result; + for(std::size_t i = 0; i < indices.size(); i++){ + result << std::hex << std::setfill('0') << std::setw(4) << indices[i] * 0x20; + } + return result.str(); + } + + std::string lookup_parts_hex_string(const std::vector &lookup_parts){ + std::stringstream result; + for(std::size_t i = 0; i < lookup_parts.size(); i++){ + result << std::hex << std::setw(2) << std::setfill('0') << lookup_parts[i]; + } + return result.str(); + } + + void print(){ + if(_use_lookups && _placeholder_info.lookup_poly_amount > 1){ + std::cout << "Lookup argument chunking not supported" << std::endl; + exit(1); + } + std::filesystem::create_directory(_folder_name); + std::string gate_argument = print_gate_argument(); + std::string lookup_argument = print_lookup_argument(); + + std::string commitment_code = generate_commitment_scheme_code(_common_data, _fri_params); + + // Prepare all necessary replacements + transpiler_replacements reps; + reps["$LOOKUP_LIBRARY_CALL$"] = _use_lookups ? lookup_library_call :"//No lookups"; + reps["$PERMUTATION_ARGUMENT_CALL$"] = _common_data.permuted_columns.size() == 0 ? "//No permutations" : permutation_call; + reps["$PERMUTATION_BATCH_TRANSCRIPT_PUSH$"] = _use_lookups || _use_permutations ? "transcript.update_transcript_b32_by_offset_calldata(tr_state, blob, 0x31);" : "//No lookups and no permutation"; + reps["$QUOTIENT_COMMITMENT_OFFSET$"] = "0x" + to_hex_string(_placeholder_info.quotient_batch_order * 0x28 + 0x9); + reps["$TEST_NAME$"] = _test_name; + reps["$MODULUS$"] = to_string(PlaceholderParams::field_type::modulus); + reps["$VERIFICATION_KEY1$"] = "0x" + to_string(_common_data.vk.constraint_system_with_params_hash); + reps["$VERIFICATION_KEY2$"] = "0x" + to_string(_common_data.vk.fixed_values_commitment); + reps["$BATCHES_NUM$"] = to_string(_placeholder_info.batches_num); + reps["$EVAL_PROOF_OFFSET$"] = "0x" + to_hex_string(_placeholder_info.batches_num * 0x28 - 0x27); + reps["$SORTED_COLUMNS_NUMBER$"] = to_string(_constraint_system.sorted_lookup_columns_number()); + reps["$LOOKUP_OPTIONS_NUMBER$"] = to_string(_constraint_system.lookup_options_num()); + reps["$LOOKUP_CONSTRAINTS_NUMBER$"] = to_string(_constraint_system.lookup_constraints_num()); + reps["$Z_OFFSET$"] = "0x" + to_hex_string(_z_offset); + reps["$PERMUTATION_SIZE$"] = to_string(_permutation_size); + reps["$SPECIAL_SELECTORS_OFFSET$"] = to_string(_special_selectors_offset); + reps["$TABLE_OFFSET$"] = "0x" + to_hex_string(_table_offset); + reps["$TABLE_END_OFFSET$"] = "0x" + to_hex_string(_table_end_offset); + reps["$PUBLIC_INPUT_OFFSET$"] = to_string(_public_input_offset); + reps["$PERMUTATION_TABLE_OFFSET$"] = to_string(_permutation_offset); + reps["$QUOTIENT_OFFSET$"] = "0x" + to_hex_string(_quotient_offset); + reps["$V_L_OFFSET$"] = "0x" + to_hex_string(_v_l_offset); + reps["$LOOKUP_OFFSET$"] = "0x" + to_hex_string(_lookup_offset); + reps["$SORTED_COMMITMENT_OFFSET$"] = "0x" + to_hex_string(_placeholder_info.lookup_batch_order * 0x28 + 0x9); + reps["$ROWS_AMOUNT$"] = to_string(_desc.rows_amount); + reps["$OMEGA$"] = to_string(_common_data.basic_domain->get_domain_element(1)); + reps["$ZERO_INDICES$"] = permuted_indices_to_hex_str(_placeholder_info.permuted_zero_indices); + reps["$GATE_ARGUMENT_COMPUTATION$"] = gate_argument; + reps["$GATE_INCLUDES$"] = _gate_includes; + reps["$LOOKUP_INCLUDES$"] = _lookup_includes; + reps["$LOOKUP_ARGUMENT_COMPUTATION$"] = lookup_argument; + reps["$COMMITMENT_CODE$"] = commitment_code; + reps["$ETA_VALUES_VERIFICATION$"] = eta_point_verification_code(); + reps["$QUOTIENT_SIZE$"] = to_string(_placeholder_info.quotient_size); + reps["$PERMUTATION_PARTS$"] = to_string(_placeholder_info.permutation_poly_amount); + reps["$LOOKUP_PARTS_AMOUNT$"] = to_string(_placeholder_info.lookup_poly_amount); + reps["$LOOKUP_PARTS$"] = lookup_parts_hex_string(_constraint_system.lookup_parts(_common_data.max_quotient_chunks)); + reps["$MAX_QUOTIENT_CHUNKS$"] = to_string(_common_data.max_quotient_chunks); + + std::size_t _lookup_degree = _constraint_system.lookup_poly_degree_bound(); + std::size_t _rows_amount = _desc.rows_amount; + + commitment_scheme_replaces( + _placeholder_info, + _desc, + reps, _common_data, _fri_params, _permutation_size, _placeholder_info.quotient_size, + _use_lookups?_constraint_system.sorted_lookup_columns_number():0, _use_lookups); + + replace_and_print(modular_verifier_template, reps, _folder_name + "/modular_verifier.sol"); + if( _placeholder_info.permutation_poly_amount == 1 ){ + replace_and_print(modular_permutation_argument_library_template, reps, _folder_name + "/permutation_argument.sol"); + } else { + replace_and_print(modular_permutation_argument_chunked_library_template, reps, _folder_name + "/permutation_argument.sol"); + } + replace_and_print(modular_gate_argument_library_template, reps, _folder_name + "/gate_argument.sol"); + replace_and_print(modular_commitment_library_template, reps, _folder_name + "/commitment.sol"); + if(_use_lookups){ + if( _placeholder_info.lookup_poly_amount == 1) + replace_and_print(modular_lookup_argument_library_template, reps, _folder_name + "/lookup_argument.sol"); + else{ + replace_and_print(modular_lookup_argument_chunked_library_template, reps, _folder_name + "/lookup_argument.sol"); + } + } else + replace_and_print(modular_dummy_lookup_argument_library_template, reps, _folder_name + "/lookup_argument.sol"); + } + + private: + const zk::snark::plonk_table_description _desc; + const typename PlaceholderParams::constraint_system_type &_constraint_system; + const common_data_type &_common_data; + const typename PlaceholderParams::commitment_scheme_type::params_type &_fri_params; + std::size_t _permutation_size; + std::string _folder_name; + std::string _test_name; + bool _use_lookups; + bool _use_permutations; + std::size_t _z_offset; + std::size_t _special_selectors_offset; + std::size_t _table_offset; + std::size_t _variable_values_offset; + std::size_t _table_end_offset; + std::size_t _permutation_offset; + std::size_t _v_l_offset; + std::size_t _quotient_offset; + std::size_t _lookup_offset; + std::size_t _public_input_offset; + typename nil::crypto3::zk::snark::placeholder_info::variable_indices_type _var_indices; + nil::crypto3::zk::snark::placeholder_info _placeholder_info; + + bool _deduce_horner; + + bool _optimize_powers; + std::unordered_set _term_powers; + + std::string _gate_includes; + std::string _lookup_includes; + std::size_t _gates_contract_size_threshold; + std::size_t _lookups_contract_size_threshold; + std::size_t _lookups_library_size_threshold; + }; + } +} + +#endif //__MODULAR_CONTRACTS_TEMPLATES_HPP__ \ No newline at end of file diff --git a/libs/transpiler/include/nil/blueprint/transpiler/gate_argument_template.hpp b/libs/transpiler/include/nil/blueprint/transpiler/gate_argument_template.hpp new file mode 100644 index 000000000..6fb565c55 --- /dev/null +++ b/libs/transpiler/include/nil/blueprint/transpiler/gate_argument_template.hpp @@ -0,0 +1,394 @@ +#ifndef __GATE_ARGUMENT_TEMPLATE_HPP__ +#define __GATE_ARGUMENT_TEMPLATE_HPP__ + +#include + +namespace nil { + namespace blueprint { +// Functions for columns with non-zero columns rotations +std::string field_rotated_witness_evaluations = "\t\tuint256[][] witness_evaluations;\n"; +std::string load_rotated_witness_evaluations = R"( + local_vars.witness_evaluations = new uint256[][](ar_params.witness_columns); + for (uint256 i = 0; i < ar_params.witness_columns;) { + local_vars.witness_evaluations[i] = new uint256[](columns_rotations[i].length); + for (uint256 j = 0; j < columns_rotations[i].length;) { + local_vars.witness_evaluations[i][j] = batched_lpc_verifier.get_variable_values_z_i_j_from_proof_be( + blob, eval_proof_combined_value_offset, i, j + ); + unchecked{j++;} + } + unchecked{i++;} + } +)"; + +std::string field_rotated_public_input_evaluations = "\t\tuint256[][] public_input_evaluations;\n"; +std::string load_rotated_public_input_evaluations = R"( + local_vars.public_input_evaluations = new uint256[][](ar_params.public_input_columns); + for (uint256 i = 0; i < ar_params.public_input_columns;) { + local_vars.public_input_evaluations[i] = new uint256[](columns_rotations[ar_params.withess_columns + i].length); + for (uint256 j = 0; j < columns_rotations[ar_params.withess_columns + i].length;) { + local_vars.public_input_evaluations[i][j] = batched_lpc_verifier.get_variable_values_z_i_j_from_proof_be( + blob, eval_proof_combined_value_offset, ar_params.withess_columns + i, j + ); + unchecked{j++;} + } + unchecked{i++;} + } +)"; + +std::string field_rotated_constant_evaluations = "\t\tuint256[][] constant_evaluations;\n"; +std::string load_rotated_constant_evaluations = R"( + local_vars.constant_evaluations = new uint256[][](ar_params.constant_columns); + for (uint256 i = 0; i < ar_params.constant_columns;) { + local_vars.constant_evaluations[i] = new uint256[](columns_rotations[ar_params.witness_colunms + ar_params.public_input_columns +i].length); + for (uint256 j = 0; j < columns_rotations[ar_params.witness_colunms + ar_params.public_input_columns + i].length;) { + local_vars.constant_evaluations[i][j] = batched_lpc_verifier.get_fixed_values_z_i_j_from_proof_be( + blob, eval_proof_combined_value_offset, ar_params.permutation_columns + ar_params.permutation_columns + i, j + ); + unchecked{j++;} + } + unchecked{i++;} + } +)"; + +std::string field_rotated_selector_evaluations = "\t\tuint256[][] selector_evaluations;\n"; +std::string load_rotated_selector_evaluations = R"( + local_vars.selector_evaluations = new uint256[][](ar_params.selector_columns); + for (uint256 i = 0; i < ar_params.selector_columns;) { + local_vars.selector_evaluations[i] = new uint256[](columns_rotations[ar_params.witness_colunms + ar_params.public_input_columns + ar_params.constant_columns + i].length); + for (uint256 j = 0; j < columns_rotations[ar_params.witness_colunms + ar_params.public_input_columns + ar_params.constant_columns + i].length;) { + local_vars.selector_evaluations[i][j] = batched_lpc_verifier.get_variable_values_z_i_j_from_proof_be( + blob, eval_proof_combined_value_offset, ar_params.permutation_columns + ar_params.permutation_columns + i, j + ); + unchecked{j++;} + } + unchecked{i++;} + } +)"; + +// Functions for columns with zero columns rotations +std::string field_witness_evaluations = "\t\tuint256[] witness_evaluations;\n"; +std::string load_witness_evaluations = R"( + local_vars.witness_evaluations = new uint256[](ar_params.witness_columns); + for (uint256 i = 0; i < ar_params.witness_columns;) { + local_vars.witness_evaluations[i] = batched_lpc_verifier.get_variable_values_z_i_j_from_proof_be( + blob, eval_proof_combined_value_offset, i, 0 + ); + unchecked{i++;} + } +)"; +std::string field_public_input_evaluations = "\t\tuint256[] public_input_evaluations;\n"; +std::string load_public_input_evaluations = R"( + local_vars.public_input_evaluations = new uint256[](ar_params.public_input_columns); + for (uint256 i = 0; i < ar_params.public_input_columns;) { + local_vars.public_input_evaluations[i] = batched_lpc_verifier.get_variable_values_z_i_j_from_proof_be( + blob, eval_proof_combined_value_offset, i, 0 + ); + unchecked{i++;} + } +)"; +std::string field_constant_evaluations = "\t\tuint256[] constant_evaluations;\n"; +std::string load_constant_evaluations = R"( + local_vars.constant_evaluations = new uint256[](ar_params.constant_columns); + for (uint256 i = 0; i < ar_params.constant_columns;) { + local_vars.constant_evaluations[i] = batched_lpc_verifier.get_fixed_values_z_i_j_from_proof_be( + blob, eval_proof_combined_value_offset, ar_params.permutation_columns + ar_params.permutation_columns + i, 0 + ); + + unchecked{i++;} + } +)"; +std::string field_selector_evaluations = "\t\tuint256[] selector_evaluations;\n"; +std::string load_selector_evaluations = R"( + local_vars.selector_evaluations = new uint256[](ar_params.selector_columns); + for (uint256 i = 0; i < ar_params.selector_columns;) { + local_vars.selector_evaluations[i] = batched_lpc_verifier.get_fixed_values_z_i_j_from_proof_be( + blob, eval_proof_combined_value_offset, ar_params.permutation_columns + ar_params.permutation_columns + ar_params.constant_columns + i, 0 + ); + unchecked{i++;} + } +)"; + +std::string main_sol_file_template = R"( +// SPDX-License-Identifier: Apache-2.0. +//---------------------------------------------------------------------------// +// Copyright (c) 2022 Mikhail Komarov +// Copyright (c) 2022 Aleksei Moskvin +// Copyright (c) 2023 Elena Tatuzova +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//---------------------------------------------------------------------------// +pragma solidity >=0.8.4; + +import "../../../contracts/types.sol"; +import "../../../contracts/basic_marshalling.sol"; +import "../../../contracts/commitments/batched_lpc_verifier.sol"; +import "../../../contracts/interfaces/gate_argument.sol"; + +$GATES_IMPORTS$ + +contract $TEST_ID$_gate_argument_split_gen is IGateArgument{ + uint256 constant GATES_N = $GATES_NUMBER$; + + struct local_vars_type{ + // 0x0 + uint256 constraint_eval; + // 0x20 + uint256 gate_eval; + // 0x40 + uint256 gates_evaluation; + // 0x60 + uint256 theta_acc; + +$GATES_LOCAL_VARS_EVALUATION_FIELDS$ + } + + // TODO: columns_rotations could be hard-coded + function evaluate_gates_be( + bytes calldata blob, + uint256 eval_proof_combined_value_offset, + types.gate_argument_params memory gate_params, + types.arithmetization_params memory ar_params, + int256[][] calldata columns_rotations + ) external pure returns (uint256 gates_evaluation) { + local_vars_type memory local_vars; + +$GATES_LOAD_EVALUATIONS$ + + local_vars.theta_acc = 1; + local_vars.gates_evaluation = 0; + +$GATES_EXECUTION$ + + gates_evaluation = local_vars.gates_evaluation; + } +} +)"; + +// Functions for extracting evaluations for rotated columns +std::string get_rotated_witness = R"( + function get_witness_i_by_rotation_idx(idx, rot_idx, ptr) -> result { + result := mload( + add( + add(mload(add(add(mload(add(ptr, WITNESS_EVALUATIONS_OFFSET)), 0x20), mul(0x20, idx))), 0x20), + mul(0x20, rot_idx) + ) + ) + } +)"; +std::string get_rotated_witness_call = "get_witness_i_by_rotation_idx"; + +std::string get_rotated_public_input = R"( + function get_public_input_i_by_rotation_idx(idx, rot_idx, ptr) -> result { + result := mload( + add( + add(mload(add(add(mload(add(ptr, PUBLIC_INPUT_EVALUATIONS_OFFSET)), 0x20), mul(0x20, idx))), 0x20), + mul(0x20, rot_idx) + ) + ) + } +)"; +std::string get_rotated_public_input_call = "get_public_input_i_by_rotation_idx"; + +std::string get_rotated_constant = R"( + function get_constant_i_by_rotation_idx(idx, rot_idx, ptr) -> result { + result := mload( + add( + add(mload(add(add(mload(add(ptr, CONSTANT_EVALUATIONS_OFFSET)), 0x20), mul(0x20, idx))), 0x20), + mul(0x20, rot_idx) + ) + ) + } +)"; +std::string get_rotated_constant_call = "get_constant_i_by_rotation_idx"; + + +std::string get_rotated_selector = R"( + function get_selector_i_by_rotation_idx(idx, rot_idx, ptr) -> result { + result := mload( + add( + add(mload(add(add(mload(add(ptr, SELECTOR_EVALUATIONS_OFFSET)), 0x20), mul(0x20, idx))), 0x20), + mul(0x20, rot_idx) + ) + ) + } +)"; +std::string get_rotated_selector_call = "get_selector_i_by_rotation_idx"; + +// Functions for extracting evaluations for non-rotated columns +std::string get_witness = R"( + function get_witness_i(idx, ptr) -> result { + result := mload(add(add(mload(add(ptr, WITNESS_EVALUATIONS_OFFSET)), 0x20), mul(0x20, idx))) + } +)"; +std::string get_witness_call = "get_witness_i"; + + +std::string get_public_input = R"( + function get_public_input_i(idx, ptr) -> result { + result := mload(add(add(mload(add(ptr, PUBLIC_INPUT_EVALUATIONS_OFFSET)), 0x20), mul(0x20, idx))) + } +)"; +std::string get_public_input_call = "get_public_input_i"; + +std::string get_constant = R"( + function get_constant_i(idx, ptr) -> result { + result := mload(add(add(mload(add(ptr, CONSTANT_EVALUATIONS_OFFSET)), 0x20), mul(0x20, idx))) + } +)"; +std::string get_constant_call = "get_constant_i"; + +std::string get_selector = R"( + function get_selector_i(idx, ptr) -> result { + result := mload(add(add(mload(add(ptr, SELECTOR_EVALUATIONS_OFFSET)), 0x20), mul(0x20, idx))) + } +)"; +std::string get_selector_call = "get_selector_i"; + +std::string gate_sol_file_template = R"( +// SPDX-License-Identifier: Apache-2.0. +//---------------------------------------------------------------------------// +// Copyright (c) 2022 Mikhail Komarov +// Copyright (c) 2022 Ilias Khairullin +// Copyright (c) 2022 Aleksei Moskvin +// Copyright (c) 2022-2023 Elena Tatuzova +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//---------------------------------------------------------------------------// +pragma solidity >=0.8.4; + +import "../../../contracts/types.sol"; +import "./gate_argument.sol"; + +library $TEST_ID$_gate$CONTRACT_NUMBER${ + uint256 constant MODULUS_OFFSET = 0x0; + uint256 constant THETA_OFFSET = 0x20; + + uint256 constant CONSTRAINT_EVAL_OFFSET = 0x00; + uint256 constant GATE_EVAL_OFFSET = 0x20; + uint256 constant GATES_EVALUATIONS_OFFSET = 0x40; + uint256 constant THETA_ACC_OFFSET = 0x60; + +$GATE_ARGUMENT_LOCAL_VARS_OFFSETS$ + + function evaluate_gate_be( + types.gate_argument_params memory gate_params, + $TEST_ID$_gate_argument_split_gen.local_vars_type memory local_vars + ) external pure returns (uint256 gates_evaluation, uint256 theta_acc) { + gates_evaluation = local_vars.gates_evaluation; + theta_acc = local_vars.theta_acc; + uint256 terms; + assembly { + let modulus := mload(gate_params) + let theta := mload(add(gate_params, THETA_OFFSET)) + + mstore(add(local_vars, GATE_EVAL_OFFSET), 0) +$GATES_GET_EVALUATIONS_FUNCTIONS$ +$GATES_ASSEMBLY_CODE$ + } + } +} +)"; + +std::string single_sol_file_template = R"( +// SPDX-License-Identifier: Apache-2.0. +//---------------------------------------------------------------------------// +// Copyright (c) 2022 Mikhail Komarov +// Copyright (c) 2022 Aleksei Moskvin +// Copyright (c) 2023 Elena Tatuzova +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//---------------------------------------------------------------------------// +pragma solidity >=0.8.4; + +import "../../../contracts/types.sol"; +import "../../../contracts/basic_marshalling.sol"; +import "../../../contracts/commitments/batched_lpc_verifier.sol"; +import "../../../contracts/interfaces/gate_argument.sol"; + +contract $TEST_ID$_gate_argument_split_gen is IGateArgument{ + uint256 constant GATES_N = $GATES_NUMBER$; + + struct local_vars_type{ + // 0x0 + uint256 constraint_eval; + // 0x20 + uint256 gate_eval; + // 0x40 + uint256 gates_evaluation; + // 0x60 + uint256 theta_acc; + +$GATES_LOCAL_VARS_EVALUATION_FIELDS$ + } + + uint256 constant MODULUS_OFFSET = 0x0; + uint256 constant THETA_OFFSET = 0x20; + + uint256 constant CONSTRAINT_EVAL_OFFSET = 0x00; + uint256 constant GATE_EVAL_OFFSET = 0x20; + uint256 constant GATES_EVALUATIONS_OFFSET = 0x40; + uint256 constant THETA_ACC_OFFSET = 0x60; +$GATE_ARGUMENT_LOCAL_VARS_OFFSETS$ + + function evaluate_gates_be( + bytes calldata blob, + uint256 eval_proof_combined_value_offset, + types.gate_argument_params memory gate_params, + types.arithmetization_params memory ar_params, + int256[][] calldata columns_rotations + ) external pure returns (uint256 gates_evaluation) { + local_vars_type memory local_vars; + +$GATES_LOAD_EVALUATIONS$ + + local_vars.theta_acc = 1; + local_vars.gates_evaluation = 0; + + uint256 theta_acc = local_vars.theta_acc; + + uint256 terms; + assembly { + let modulus := mload(gate_params) + let theta := mload(add(gate_params, THETA_OFFSET)) + +$GATES_GET_EVALUATIONS_FUNCTIONS$ +$GATES_EXECUTION$ + } + } +} +)"; + } +} + +#endif //__GATE_ARGUMENT_TEMPLATE_HPP__ \ No newline at end of file diff --git a/libs/transpiler/include/nil/blueprint/transpiler/lpc_scheme_gen.hpp b/libs/transpiler/include/nil/blueprint/transpiler/lpc_scheme_gen.hpp new file mode 100644 index 000000000..40dcbc1a5 --- /dev/null +++ b/libs/transpiler/include/nil/blueprint/transpiler/lpc_scheme_gen.hpp @@ -0,0 +1,152 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2023 Elena Tatuzova +// +// 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 unified addition component. +//---------------------------------------------------------------------------// +#ifndef __LPC_SCHEME_GEN_HPP__ +#define __LPC_SCHEME_GEN_HPP__ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace nil { + namespace blueprint { + template + using common_data_type = typename nil::crypto3::zk::snark::placeholder_public_preprocessor< + typename PlaceholderParams::field_type, + PlaceholderParams + >::preprocessed_data_type::common_data_type; + + template + void commitment_scheme_replaces( + const zk::snark::placeholder_info &placeholder_info, + zk::snark::plonk_table_description desc, + transpiler_replacements& replacements, + const common_data_type &common_data, + const typename PlaceholderParams::commitment_scheme_type& lpc_scheme, + std::size_t permutation_size, + std::size_t quotient_polys, + std::size_t lookup_polys, + bool use_lookups + ){ + std::set unique_points; + std::vector points; + + auto [z_points_indices, singles_strs, singles_map, poly_ids] = calculate_unique_points>( + placeholder_info, + desc, + common_data, permutation_size, quotient_polys, lookup_polys, + "evm" // Generator mode + ); + + std::stringstream points_initializer; + std::size_t i = 0; + + for(const auto& point: singles_strs){ + points_initializer << "\t\tresult[" << i << "] = " << point << ";" << std::endl; + i++; + } + + std::stringstream points_ids; + for( const auto& point_id: z_points_indices){ + points_ids << std::hex << std::setw(2) << std::setfill('0') << point_id; + } + + std::stringstream poly_ids_str; + std::stringstream poly_points_num; + for(i = 0; i < poly_ids.size(); i++){ + poly_points_num << std::hex << std::setw(4) << std::setfill('0') << poly_ids[i].size(); + for(std::size_t j = 0; j < poly_ids[i].size(); j++){ + poly_ids_str << std::hex << std::setw(4) << std::setfill('0') << poly_ids[i][j] * 0x40; + } + } + + std::string eta_point_U; + std::vector eta_points; + for( const auto &it:common_data.commitment_scheme_data){ + for( std::size_t i = 0; i < it.second.size(); i++ ) + eta_points.push_back(it.second[i]); + } + for( std::size_t i = 0; i < eta_points.size(); i++){ + eta_point_U += "\t\tresult = addmod(0x" +to_hex_string(eta_points[eta_points.size() - i - 1]) + ", mulmod(result, theta, modulus), modulus);\n"; + } + + std::vector init_blob = {}; + nil::crypto3::zk::transcript::fiat_shamir_heuristic_sequential transcript(init_blob); + transcript(common_data.vk.constraint_system_with_params_hash); + transcript(common_data.vk.fixed_values_commitment); + auto etha = transcript.template challenge(); + + auto fri_params = lpc_scheme.get_commitment_params(); + replacements["$R$"] = to_string(fri_params.r); + replacements["$LAMBDA$"] = to_string(fri_params.lambda); + replacements["$D0_SIZE$"] = to_string(fri_params.D[0]->m); + replacements["$D0_LOG$"] = to_string(log2(fri_params.D[0]->m)); + replacements["$D0_OMEGA$"] = to_string(fri_params.D[0]->get_domain_element(1)); + replacements["$MAX_DEGREE$"] = to_string(fri_params.max_degree); + replacements["$UNIQUE_POINTS$"] = to_string(singles_strs.size()); + replacements["$DIFFERENT_POINTS$"] = to_string(singles_strs.size()); + replacements["$POINTS_IDS$"] = points_ids.str(); + replacements["$POLY_IDS$"] = poly_ids_str.str(); + replacements["$POLY_POINTS_NUM$"] = poly_points_num.str(); + replacements["$POINTS_INITIALIZATION$"] = points_initializer.str(); + replacements["$ETA$"] = to_string(etha); + replacements["$ETA_POINT_U$"] = eta_point_U; + replacements["$FIXED_BATCH_SIZE$"] = to_string(placeholder_info.batches_sizes[0]); +/* if( fri_params.use_grinding){ + auto params = PlaceholderParams::commitment_scheme_type::fri_type::grinding_type::get_params(); + uint32_t mask_value = params.template get("mask", 0); + std::stringstream mask_value_hex; + mask_value_hex << std::hex << std::showbase << std::setw(8) << std::setfill('0') << mask_value; + replacements["$GRINDING_CHECK$"] = modular_commitment_grinding_check_template; + replacements["$GRINDING_MASK$"] = mask_value_hex.str(); + } else {*/ + replacements["$GRINDING_CHECK$"] = ""; +// } + } + + template + std::string generate_commitment_scheme_code( + const common_data_type &common_data, + const typename PlaceholderParams::commitment_scheme_type::params_type& fri_params + ){ + BOOST_ASSERT(fri_params.step_list.size() == fri_params.r); + for(std::size_t i = 0; i < fri_params.step_list.size(); i++){ + BOOST_ASSERT(fri_params.step_list[i] == 1); + } + std::stringstream out; + + return out.str(); + } + } +} + +#endif //__MODULAR_CONTRACTS_TEMPLATES_HPP__ \ No newline at end of file diff --git a/libs/transpiler/include/nil/blueprint/transpiler/minimized_profiling_plonk_circuit.hpp b/libs/transpiler/include/nil/blueprint/transpiler/minimized_profiling_plonk_circuit.hpp new file mode 100644 index 000000000..5d05f05be --- /dev/null +++ b/libs/transpiler/include/nil/blueprint/transpiler/minimized_profiling_plonk_circuit.hpp @@ -0,0 +1,719 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2021 Mikhail Komarov +// Copyright (c) 2021-2023 Nikita Kaskov +// Copyright (c) 2022-2023 Polina Chernyshova +// Copyright (c) 2022-2023 Elena Tatuzova +// +// 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 unified addition component. +//---------------------------------------------------------------------------// + +#ifndef CRYPTO3_MINIMIZED_PROFILING_PLONK_CIRCUIT_HPP +#define CRYPTO3_MINIMIZED_PROFILING_PLONK_CIRCUIT_HPP + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +namespace nil { + namespace blueprint { + template + struct minimized_profiling_plonk_circuit { + static const std::size_t MAX_LINES = 1200; + static const std::size_t ONE_FILE_GATES_MAX_LINES = 1000; + + const zk::snark::plonk_table_description desc; + + using columns_rotations_type = std::vector>; + using ArithmetizationType = nil::crypto3::zk::snark::plonk_constraint_system; + using TableDescriptionType = nil::crypto3::zk::snark::plonk_table_description; + using GateType = nil::crypto3::zk::snark::plonk_gate>; + + + + struct profiling_params_type { + bool optimize_gates; + + bool need_witness; + bool need_public_input; + bool need_constant; + bool need_selector; + + bool rotated_witness; + bool rotated_constant; + bool rotated_public_input; + bool rotated_selector; + + std::size_t offset_witness; + std::size_t offset_public_input; + std::size_t offset_constant; + std::size_t offset_selector; + + bool one_file_gates; + std::vector gates_lines; + std::vector gates_first; + std::vector gates_num; + + std::string evaluation_fields; + std::string load_evaluation_fields; + std::string evals_offsets; + std::string get_evals_functions; + + profiling_params_type( + ArithmetizationType &bp, + bool optimize_gates = true + ){ + auto gates = bp.gates(); + + this->optimize_gates = optimize_gates; + this->need_witness = false; + this->need_public_input = false; + this->need_constant = false; + this->need_selector = true; + this->rotated_witness = false; + this->rotated_public_input = false; + this->rotated_constant = false; + this->rotated_selector = false; + + using variable_type = nil::crypto3::zk::snark::plonk_variable; + std::size_t offset = 0x80; + + // compute needed and rotated vars + for (const auto& gate: gates) { + // constraint + // gate_evaluation + // theta_acc + for (const auto& constraint: gate.constraints) { + crypto3::math::expression_for_each_variable_visitor visitor( + [this](const variable_type& var){ + if (var.type == variable_type::witness) { + this->need_witness = true; + if( var.rotation != 0){ this->rotated_witness = true; } + } + if (var.type == variable_type::public_input) { + this->need_public_input = true; + if( var.rotation != 0){ this->rotated_public_input = true; } + } + if (var.type == variable_type::constant) { + this->need_constant = true; + if( var.rotation != 0) { this->rotated_constant = true; } + } + if (var.type == variable_type::selector) { + if( var.rotation != 0) { this->rotated_selector = true; } + } + }); + visitor.visit(constraint); + } + } + + for (const auto& gate: gates) { + std::size_t gate_lines = 2; + for (const auto& constraint: gate.constraints) { + gate_lines += 2; + // Convert constraint expression to non_linear_combination. + crypto3::math::expression_to_non_linear_combination_visitor visitor; + auto comb = visitor.convert(constraint); + + for (std::size_t t_index = 0; t_index < comb.terms.size(); t_index++) { + if (!comb.terms[t_index].get_coeff().is_one()) + gate_lines += 1; + gate_lines += comb.terms[t_index].get_vars().size(); + gate_lines += 1; + } + gate_lines += 1; + } + gate_lines += 2; + this->gates_lines.push_back(gate_lines); + } + + std::size_t sum = 0; + std::size_t total = 0; + std::size_t cur = 0; + this->gates_num.push_back(0); + this->gates_first.push_back(0); + for( std::size_t i =0; i < this->gates_lines.size(); i++ ){ + BOOST_ASSERT( this->gates_lines[i] < MAX_LINES ); + if( sum + this->gates_lines[i] < MAX_LINES ){ + sum += this->gates_lines[i]; + total += this->gates_lines[i]; + this->gates_num[cur]++; + continue; + } + cur++; + this->gates_num.push_back(1); + sum = this->gates_lines[i]; + this->gates_first.push_back(i); + } + this->one_file_gates = (total < ONE_FILE_GATES_MAX_LINES); + + if( this->need_witness ){ + this->offset_witness = offset; + offset += 0x20; + } + if( this->need_public_input ){ + this->offset_public_input = offset; + offset += 0x20; + } + if( this->need_constant ){ + this->offset_constant = offset; + offset += 0x20; + } + if( this->need_selector ){ + this->offset_selector = offset; + offset += 0x20; + } + this->process(); + } + + void process(){ + std::stringstream evaluation_fields_str; + std::stringstream load_evaluation_fields_str; + std::stringstream evals_offsets_str; + std::stringstream get_evals_functions_str; + + if( this->need_witness ){ + evals_offsets_str << "\tuint256 constant WITNESS_EVALUATIONS_OFFSET = 0x" << std::hex + << this->offset_witness << std::dec << ";" << std::endl; + evaluation_fields_str << "\t\t//0x" << std::hex << this->offset_witness << std::dec << std::endl; + if(this->rotated_witness){ + get_evals_functions_str << get_rotated_witness; + evaluation_fields_str << field_rotated_witness_evaluations; + load_evaluation_fields_str << load_rotated_witness_evaluations; + } else { + evaluation_fields_str << field_witness_evaluations; + load_evaluation_fields_str << load_witness_evaluations; + get_evals_functions_str << get_witness; + } + } + + if( this->need_public_input ){ + evaluation_fields_str << "\t\t//0x" << std::hex << this->offset_public_input << std::dec << std::endl; + evals_offsets_str << "\tuint256 constant PUBLIC_INPUT_EVALUATIONS_OFFSET = 0x" << std::hex + << this->offset_public_input << std::dec << ";" << std::endl; + if(this->rotated_public_input){ + get_evals_functions_str << get_rotated_public_input; + evaluation_fields_str << field_rotated_public_input_evaluations; + load_evaluation_fields_str << load_rotated_public_input_evaluations; + } else { + evaluation_fields_str << field_public_input_evaluations; + load_evaluation_fields_str << load_public_input_evaluations; + get_evals_functions_str << get_public_input; + } + } + + if( this->need_constant ){ + evaluation_fields_str << "\t\t//" << std::hex << this->offset_constant << std::dec << std::endl; + evals_offsets_str << "\tuint256 constant CONSTANT_EVALUATIONS_OFFSET = 0x" << std::hex + << this->offset_constant << std::dec << ";" << std::endl; + if(this->rotated_constant){ + evaluation_fields_str << field_rotated_constant_evaluations; + load_evaluation_fields_str << load_rotated_constant_evaluations; + get_evals_functions_str << get_rotated_constant; + } else { + get_evals_functions_str << get_constant; + evaluation_fields_str << field_constant_evaluations; + load_evaluation_fields_str << load_constant_evaluations; + } + } + + if( this->need_selector ){ + evaluation_fields_str << "\t\t//" << std::hex << this->offset_selector << std::dec << std::endl; + evals_offsets_str << "\tuint256 constant SELECTOR_EVALUATIONS_OFFSET = 0x" << std::hex + << this->offset_selector << std::dec << ";" << std::endl; + if(this->rotated_selector){ + evaluation_fields_str << field_rotated_selector_evaluations; + load_evaluation_fields_str << load_rotated_selector_evaluations; + get_evals_functions_str << get_rotated_selector; + } else { + evaluation_fields_str << field_selector_evaluations; + load_evaluation_fields_str << load_selector_evaluations; + get_evals_functions_str << get_selector; + } + } + + this->get_evals_functions = get_evals_functions_str.str(); + this->evals_offsets = evals_offsets_str.str(); + this->evaluation_fields = evaluation_fields_str.str(); + this->load_evaluation_fields = load_evaluation_fields_str.str(); + } + }; + + columns_rotations_type columns_rotations( + ArithmetizationType &constraint_system, const TableDescriptionType &table_description + ) { + using variable_type = nil::crypto3::zk::snark::plonk_variable; + + columns_rotations_type result; + for (const auto& gate: constraint_system.gates()) { + for (const auto& constraint: gate.constraints) { + crypto3::math::expression_for_each_variable_visitor visitor( + [&table_description, &result](const variable_type& var) { + if (var.relative) { + std::size_t column_index = table_description.global_index(var); + result[column_index].insert(var.rotation); + } + }); + visitor.visit(constraint); + } + } +/* + for (const auto& gate: constraint_system.lookup_gates()) { + for (const auto& constraint: gate.constraints) { + for (const auto& lookup_input: constraint.lookup_input) { + const auto& var = lookup_input.get_vars()[0]; + if (var.relative) { + std::size_t column_index = table_description.global_index(var); + result[column_index].insert(var.rotation); + } + } + } + } +*/ + for (std::size_t i = 0; i < desc.witness_columns + desc.public_input_columns + desc.constant_columns + desc.selector_columns; i++) { + result[i].insert(0); + } + + return result; + } + + template + static bool is_last_element(const Container &c, ContainerIt it) { + return it == (std::cend(c) - 1); + } + + std::string generate_variable( + const profiling_params_type &profiling_params, + const nil::crypto3::zk::snark::plonk_variable &var, + columns_rotations_type &columns_rotations + ) { + using variable_type = nil::crypto3::zk::snark::plonk_variable; + + std::stringstream res; + std::size_t index = var.index; + std::size_t global_index; + + // Define global index in columns_rotations + if (var.type == variable_type::witness) { + global_index = var.index; + } + if (var.type == variable_type::public_input) { + global_index = var.index + desc.witness_columns; + } + if (var.type == variable_type::constant) { + global_index = var.index + + desc.witness_columns + + desc.public_input_columns; + } + if (var.type == variable_type::selector) { + global_index = var.index + + desc.witness_columns + + desc.public_input_columns + + desc.constant_columns; + } + + // Find out rotation_idx + std::size_t rotation_idx = std::distance( + columns_rotations.at(global_index).begin(), + columns_rotations.at(global_index).find(var.rotation) + ); + + if (var.type == variable_type::witness) { + if( profiling_params.rotated_witness ) + res << get_rotated_witness_call << "("<< index << "," << rotation_idx << ", local_vars)"; + else + res << get_witness_call << "("<< index << ", local_vars)"; + } + if (var.type == variable_type::public_input) { + if( profiling_params.rotated_public_input ) + res << get_rotated_public_input_call << "("<< index << ","<< rotation_idx << ", local_vars)"; + else + res << get_public_input_call << "("<< index << ", local_vars)"; + } + if (var.type == variable_type::constant) { + if( profiling_params.rotated_public_input ) + res << get_rotated_constant_call << "("<< index << ","<< rotation_idx << ", local_vars)"; + else + res << get_constant_call << "("<< index << ", local_vars)"; + } + if (var.type == variable_type::selector) { + if( profiling_params.rotated_selector ) + res << get_rotated_selector_call << "("<< index << ","<< rotation_idx << ", local_vars)"; + else + res << get_selector_call << "("<< index << ", local_vars)"; + } + return res.str(); + } + + template + std::string generate_term( + const profiling_params_type &profiling_params, + const Vars &vars, + columns_rotations_type &columns_rotations, + bool coeff_one = false + ) { + std::stringstream res; + bool first = true; + + for( auto it = std::cbegin(vars); it != std::end(vars); it++){ + if( first ){ + first = false; + if(coeff_one){ + res << "\t\t\tterms:=" << generate_variable(profiling_params, *it, columns_rotations) << std::endl; + continue; + } + } + res << "\t\t\tterms:=mulmod(terms, "; + res << generate_variable(profiling_params, *it, columns_rotations); + res << ", modulus)" << std::endl; + } + return res.str(); + } + + template + std::string generate_terms( + const profiling_params_type &profiling_params, + const Terms &terms, + columns_rotations_type &columns_rotations + ) { + std::stringstream res; + for( auto it = std::cbegin(terms); it != std::cend(terms); it++ ){ + if(it->get_coeff().is_one()) + res << generate_term(profiling_params, it->get_vars(), columns_rotations, true); + else { + res << "\t\t\tterms:=0x" << std::hex << it->get_coeff().data << std::dec << std::endl; + res << generate_term(profiling_params, it->get_vars(), columns_rotations, false); + } + res << "\t\t\tmstore(" + "add(local_vars, CONSTRAINT_EVAL_OFFSET)," + "addmod(" + "mload(add(local_vars, CONSTRAINT_EVAL_OFFSET)),"; + res << "terms"; + res << ",modulus))" << std::endl; + } + return res.str(); + } + + + std::string generate_constraint( + const profiling_params_type &profiling_params, + const typename nil::crypto3::zk::snark::plonk_constraint &constraint, + columns_rotations_type &columns_rotations + ) { + using variable_type = nil::crypto3::zk::snark::plonk_variable; + + std::stringstream res; + res << "\t\t\tmstore(add(local_vars, CONSTRAINT_EVAL_OFFSET), 0)" << std::endl; + + // Convert constraint expression to non_linear_combination. + crypto3::math::expression_to_non_linear_combination_visitor visitor; + auto comb = visitor.convert(constraint); + res << generate_terms(profiling_params, comb.terms, columns_rotations); + return res.str(); + } + + static std::string generate_gate_evaluation() { + return "\t\t\tmstore(" + "add(local_vars, GATE_EVAL_OFFSET)," + "addmod(" + "mload(add(local_vars, GATE_EVAL_OFFSET))," + "mulmod(" + "mload(add(local_vars, CONSTRAINT_EVAL_OFFSET))," + "theta_acc," + "modulus" + ")," + "modulus" + ")" + ")\n"; + } + + static std::string generate_theta_acc() { + return "\t\t\ttheta_acc := mulmod(theta_acc, theta, modulus)\n"; + } + + static std::string generate_selector( + const nil::crypto3::zk::snark::plonk_gate< + FieldType, nil::crypto3::zk::snark::plonk_constraint> &gate + ) { + std::stringstream res; + + res << "\t\t\tmstore(" + "add(local_vars, GATE_EVAL_OFFSET)," + "mulmod(" + "mload(add(local_vars, GATE_EVAL_OFFSET))," + "get_selector_i(" + << gate.selector_index + << "," + "local_vars" + ")," + "modulus" + ")" + ")" + << std::endl; + return res.str(); + } + + static std::string generate_gate_argument_evaluation() { + return "\t\t\tgates_evaluation := addmod(" + "gates_evaluation," + "mload(add(local_vars, GATE_EVAL_OFFSET))," + "modulus" + ")\n"; + } + + std::string generate_gate_assembly_code( + const profiling_params_type &profiling_params, + int gate_ind, const GateType &gate, + columns_rotations_type &columns_rotations + ) { + std::stringstream res; + res << "\t\t\t//Gate" << gate_ind << std::endl; + res << "\t\t\tmstore(add(local_vars, GATE_EVAL_OFFSET), 0)" << std::endl; + for (auto &constraint : gate.constraints) { + res << generate_constraint(profiling_params, constraint, columns_rotations); + res << generate_gate_evaluation(); + res << generate_theta_acc(); + } + res << generate_selector(gate); + res << generate_gate_argument_evaluation(); + return res.str(); + } + + void print_gate_file( + int gate_ind, std::ostream &gate_out, + std::string id, + const profiling_params_type &profiling_params, + std::string gate_sol_file_template, + const GateType &gate, + columns_rotations_type &columns_rotations + ) { + std::string result = gate_sol_file_template; + + boost::replace_all(result, "$TEST_ID$", id); + boost::replace_all(result, "$GATE_ARGUMENT_LOCAL_VARS_OFFSETS$", profiling_params.evals_offsets); + boost::replace_all(result, "$GATES_GET_EVALUATIONS_FUNCTIONS$", profiling_params.get_evals_functions); + boost::replace_all(result, "$CONTRACT_NUMBER$", std::to_string(gate_ind)); + boost::replace_all(result, "$GATES_ASSEMBLY_CODE$", generate_gate_assembly_code(profiling_params, gate_ind, gate, columns_rotations)); + gate_out << result; + } + + void print_multiple_gates_file( + int file_ind, std::ostream &gate_out, + std::string id, + const profiling_params_type &profiling_params, + std::string gate_sol_file_template, + const ArithmetizationType &bp, + columns_rotations_type &columns_rotations + ) { + std::string assembly_code; + for(std::size_t i = profiling_params.gates_first[file_ind]; + i < profiling_params.gates_first[file_ind] + profiling_params.gates_num[file_ind]; + i++ + ){ + assembly_code += generate_gate_assembly_code(profiling_params, i, bp.gates()[i], columns_rotations); + assembly_code += "\n"; + } + + std::string result = gate_sol_file_template; + + boost::replace_all(result, "$TEST_ID$", id); + boost::replace_all(result, "$GATE_ARGUMENT_LOCAL_VARS_OFFSETS$", profiling_params.evals_offsets); + boost::replace_all(result, "$GATES_GET_EVALUATIONS_FUNCTIONS$", profiling_params.get_evals_functions); + boost::replace_all(result, "$CONTRACT_NUMBER$", std::to_string(profiling_params.gates_first[file_ind])); + boost::replace_all(result, "$GATES_ASSEMBLY_CODE$", assembly_code); + gate_out << result; + } + + static void print_main_file( + std::ostream &out, + std::string id, + profiling_params_type &profiling_params, + std::string main_file_template, + std::string includes, + std::size_t gates_number, + std::string executions + ) { + std::string result = main_file_template; + boost::replace_all(result, "$GATES_IMPORTS$", includes ); + boost::replace_all(result, "$GATES_NUMBER$", std::to_string(gates_number)); + boost::replace_all(result, "$GATES_EXECUTION$", executions); + boost::replace_all(result, "$GATES_LOCAL_VARS_EVALUATION_FIELDS$", profiling_params.evaluation_fields); + boost::replace_all(result, "$GATES_LOAD_EVALUATIONS$", profiling_params.load_evaluation_fields); + boost::replace_all(result, "$TEST_ID$", id ); + out << result; + } + + void print_single_sol_file( + std::ostream &out, + std::string id, + profiling_params_type &profiling_params, + columns_rotations_type columns_rotations, + std::string single_file_template, + ArithmetizationType &bp + ) { + std::stringstream gates_execution_str; + for(std::size_t i = 0; i < bp.gates().size(); i++){ + gates_execution_str << generate_gate_assembly_code( + profiling_params, i, bp.gates()[i], columns_rotations + ); + gates_execution_str << std::endl; + } + + std::string result = single_file_template; + boost::replace_all(result, "$TEST_ID$", id); + boost::replace_all(result, "$GATES_NUMBER$", std::to_string(bp.gates().size())); + boost::replace_all(result, "$GATES_LOCAL_VARS_EVALUATION_FIELDS$", profiling_params.evaluation_fields); + boost::replace_all(result, "$GATES_LOAD_EVALUATIONS$", profiling_params.load_evaluation_fields); + + boost::replace_all(result, "$GATE_ARGUMENT_LOCAL_VARS_OFFSETS$", profiling_params.evals_offsets); + boost::replace_all(result, "$GATES_GET_EVALUATIONS_FUNCTIONS$", profiling_params.get_evals_functions); + boost::replace_all(result, "$GATES_EXECUTION$", gates_execution_str.str()); + out << result; + } + + static void print_linked_libraries_list(std::ostream &out, std::string id, const profiling_params_type &profiling_params) { + bool first = true; + if(!profiling_params.optimize_gates){ + out << "[" << std::endl; + for (size_t i = 0; i < profiling_params.gates_lines.size(); i++) { + if (first) + first = false; + else + out << "," << std::endl; + out << "\""<< id << "_gate" << i << "\""; + } + out << std::endl << "]" << std::endl; + return; + } + + if(profiling_params.one_file_gates){ + out << "[]" << std::endl; + return; + } + + out << "[" << std::endl; + for (size_t i = 0; i < profiling_params.gates_first.size(); i++) { + if (first) + first = false; + else + out << "," << std::endl; + out << "\""<< id << "_gate" << profiling_params.gates_first[i] << "\""; + } + out << std::endl << "]" << std::endl; + } + + + void process_split( + std::string main_file_template, + std::string gate_file_template, + ArithmetizationType &bp, + columns_rotations_type &columns_rotations, + std::string out_folder_path = ".", + bool optimize_gates = false + ) { + auto id = out_folder_path.substr(out_folder_path.rfind("/") + 1); + + profiling_params_type profiling_params(bp, optimize_gates); + + if( profiling_params.optimize_gates && profiling_params.one_file_gates ){ + std::ofstream json_out; + json_out.open(out_folder_path + "/linked_libs_list.json"); + print_linked_libraries_list(json_out,id, profiling_params); + json_out.close(); + + std::ofstream gate_argument_out; + gate_argument_out.open(out_folder_path + "/gate_argument.sol"); + print_single_sol_file( + gate_argument_out, + id, + profiling_params, + columns_rotations, + single_sol_file_template, + bp + ); + gate_argument_out.close(); + }else{ + std::ofstream json_out; + json_out.open(out_folder_path + "/linked_libs_list.json"); + print_linked_libraries_list(json_out, id, profiling_params); + json_out.close(); + + size_t i = 0; + + std::stringstream imports; + std::stringstream executions; + + if(!profiling_params.optimize_gates){ + for (const auto &gate : bp.gates()) { + imports << "import \"./gate" << i << ".sol\";" << std::endl; + executions << "\t\t(local_vars.gates_evaluation, local_vars.theta_acc) = "<< id <<"_gate"<< i <<".evaluate_gate_be(gate_params, local_vars);" << std::endl; + std::ofstream gate_out; + gate_out.open(out_folder_path + "/gate" + std::to_string(i) + ".sol"); + print_gate_file(i, gate_out, id, profiling_params, gate_file_template, gate, columns_rotations); + gate_out.close(); + i++; + } + } else { + for (std::size_t i = 0; i < profiling_params.gates_first.size(); i++) { + imports << "import \"./gate" << profiling_params.gates_first[i] << ".sol\";" << std::endl; + executions << "\t\t(local_vars.gates_evaluation, local_vars.theta_acc) = " << id << "_gate"<< profiling_params.gates_first[i] <<".evaluate_gate_be(gate_params, local_vars);" << std::endl; + std::ofstream gate_out; + gate_out.open(out_folder_path + "/gate" + std::to_string(profiling_params.gates_first[i]) + ".sol"); + print_multiple_gates_file(i, gate_out, id, profiling_params, gate_file_template, bp, columns_rotations); + gate_out.close(); + } + } + + std::ofstream gate_argument_out; + gate_argument_out.open(out_folder_path + "/gate_argument.sol"); + print_main_file( + gate_argument_out, + id, + profiling_params, + main_file_template, + imports.str(), + bp.gates().size(), + executions.str() + ); + gate_argument_out.close(); + } + } + + minimized_profiling_plonk_circuit(crypto3::zk::snark::plonk_table_description desc) : desc(desc) {} + + }; + } // namespace blueprint +} // namespace nil + +#endif // CRYPTO3_MINIMIZED_PROFILING_PLONK_CIRCUIT_HPP diff --git a/libs/transpiler/include/nil/blueprint/transpiler/public_input.hpp b/libs/transpiler/include/nil/blueprint/transpiler/public_input.hpp new file mode 100644 index 000000000..2eeb105a2 --- /dev/null +++ b/libs/transpiler/include/nil/blueprint/transpiler/public_input.hpp @@ -0,0 +1,61 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2021 Mikhail Komarov +// Copyright (c) 2021-2023 Nikita Kaskov +// Copyright (c) 2022-2023 Polina Chernyshova +// Copyright (c) 2022-2023 Elena Tatuzova +// +// 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 unified addition component. +//---------------------------------------------------------------------------// + +#ifndef CRYPTO3_TRANSPILER_PUBLIC_INPUT_HPP +#define CRYPTO3_TRANSPILER_PUBLIC_INPUT_HPP + + + +namespace nil { + namespace blueprint { + template + std::string convert_numeric_public_input_to_json(std::string path){ + std::ifstream in(path); + std::stringstream result; + + result << "[" << std::endl; + std::size_t i = 0; + if( i != 0 ){ + result << "," << std::endl; + } + for (std::string line; std::getline(in, line); i++) + { + if( i != 0 ){ + result << "," << std::endl; + } + result << line; + } + result << std::endl << "]"; + + return result.str(); + } + } +} + +#endif // CRYPTO3_MINIMIZED_PROFILING_PLONK_CIRCUIT_HPP \ No newline at end of file diff --git a/libs/transpiler/include/nil/blueprint/transpiler/recursive_verifier_generator.hpp b/libs/transpiler/include/nil/blueprint/transpiler/recursive_verifier_generator.hpp new file mode 100644 index 000000000..67eacae36 --- /dev/null +++ b/libs/transpiler/include/nil/blueprint/transpiler/recursive_verifier_generator.hpp @@ -0,0 +1,1096 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2023 Elena Tatuzova +// +// 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 unified addition component. +//---------------------------------------------------------------------------// + +#ifndef CRYPTO3_RECURSIVE_VERIFIER_GENERATOR_HPP +#define CRYPTO3_RECURSIVE_VERIFIER_GENERATOR_HPP + +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include + +namespace nil { + namespace blueprint { + template + struct recursive_verifier_generator{ + using field_type = typename PlaceholderParams::field_type; + using proof_type = ProofType; + using common_data_type = CommonDataType; + using verification_key_type = typename common_data_type::verification_key_type; + using commitment_scheme_type = typename PlaceholderParams::commitment_scheme_type; + using constraint_system_type = typename PlaceholderParams::constraint_system_type; + using columns_rotations_type = std::vector>; + using variable_type = typename constraint_system_type::variable_type; + using variable_indices_type = std::map; + using degree_visitor_type = typename constraint_system_type::degree_visitor_type; + using expression_type = typename constraint_system_type::expression_type; + using term_type = typename constraint_system_type::term_type; + using binary_operation_type = typename constraint_system_type::binary_operation_type; + using pow_operation_type = typename constraint_system_type::pow_operation_type; + using assignment_table_type = typename PlaceholderParams::assignment_table_type; + + std::vector zero_indices(const columns_rotations_type &col_rotations, std::size_t permutation_size){ + std::vector zero_indices; + std::uint16_t fixed_values_points = 0; + std::stringstream result; + + for(std::size_t i= 0; i < desc.constant_columns + desc.selector_columns; i++){ + fixed_values_points += col_rotations[i + desc.witness_columns + desc.public_input_columns].size(); + } + + for(std::size_t i= 0; i < desc.witness_columns + desc.public_input_columns + desc.constant_columns + desc.selector_columns; i++){ + std::size_t j = 0; + for(auto& rot: col_rotations[i]){ + if(rot == 0){ + zero_indices.push_back(j); + break; + } + j++; + } + } + + std::uint16_t sum = fixed_values_points; + std::size_t i = 0; + for(; i < desc.witness_columns + desc.public_input_columns; i++){ + zero_indices[i] = sum + zero_indices[i] + 2 * permutation_size + 4; + sum += col_rotations[i].size(); + } + + sum = 0; + for(; i < desc.witness_columns + desc.public_input_columns + desc.constant_columns + desc.selector_columns; i++){ + zero_indices[i] = sum + zero_indices[i] + 2 * permutation_size + 4; + sum += col_rotations[i].size(); + } + + return zero_indices; + } + + static std::string generate_field_array2_from_64_hex_string(std::string str){ + BOOST_ASSERT_MSG(str.size() == 64, "input string must be 64 hex characters long"); + std::string first_half = str.substr(0, 32); + std::string second_half = str.substr(32, 32); + return "{\"vector\": [{\"field\": \"0x" + first_half + "\"},{\"field\": \"0x" + second_half + "\"}]}"; + } + + template + static inline std::string generate_hash(typename HashType::digest_type hashed_data){ + if constexpr(std::is_same>::value){ + std::stringstream out; + out << hashed_data; + return generate_field_array2_from_64_hex_string(out.str()); + } else if constexpr(std::is_same>::value){ + std::stringstream out; + out << hashed_data; + return generate_field_array2_from_64_hex_string(out.str()); + } else { + std::stringstream out; + out << "{\"field\": \"" << hashed_data << "\"}"; + return out.str(); + } + BOOST_ASSERT_MSG(false, "unsupported merkle hash type"); + return "unsupported merkle hash type"; + } + + template + static inline std::string generate_commitment(typename CommitmentSchemeType::commitment_type commitment) { + return generate_hash(commitment); + } + + static inline std::string generate_lookup_options_amount_list( + const constraint_system_type &constraint_system + ) { + std::string result; + for(std::size_t i = 0; i < constraint_system.lookup_tables().size(); i++){ + if( i != 0 ) result += ", "; + result += to_string(constraint_system.lookup_tables()[i].lookup_options.size()); + } + return result; + } + + static inline std::string generate_lookup_columns_amount_list( + const constraint_system_type &constraint_system + ) { + std::string result; + for(std::size_t i = 0; i < constraint_system.lookup_tables().size(); i++){ + if( i != 0 ) result += ", "; + result += to_string(constraint_system.lookup_tables()[i].lookup_options[0].size()); + } + return result; + } + + static inline std::string generate_lookup_constraints_amount_list( + const constraint_system_type &constraint_system + ) { + std::string result; + for(std::size_t i = 0; i < constraint_system.lookup_gates().size(); i++){ + if( i != 0 ) result += ", "; + result += to_string(constraint_system.lookup_gates()[i].constraints.size()); + } + return result; + } + + static inline std::string generate_lookup_constraint_table_ids_list( + const constraint_system_type &constraint_system + ){ + std::string result; + for(std::size_t i = 0; i < constraint_system.lookup_gates().size(); i++){ + for(std::size_t j = 0; j < constraint_system.lookup_gates()[i].constraints.size(); j++){ + if( i != 0 || j!=0 ) result += ", "; + result += to_string(constraint_system.lookup_gates()[i].constraints[j].table_id); + } + } + return result; + } + + static inline std::string generate_lookup_expressions_amount_list( + const constraint_system_type &constraint_system + ) { + std::string result; + for(std::size_t i = 0; i < constraint_system.lookup_gates().size(); i++){ + for(std::size_t j = 0; j < constraint_system.lookup_gates()[i].constraints.size(); j++){ + if( i != 0 || j != 0) result += ", "; + result += to_string(constraint_system.lookup_gates()[i].constraints[j].lookup_input.size()); + } + } + return result; + } + + static inline std::string generate_lookup_expressions_computation( + const constraint_system_type &constraint_system + ){ + return ""; + } + + template + static inline std::string generate_eval_proof(typename CommitmentSchemeType::proof_type eval_proof) { + std::stringstream out; + out << "\t\t{\"array\":[" << std::endl; + auto batch_info = eval_proof.z.get_batch_info(); + std::size_t sum = 0; + std::size_t poly_num = 0; + for(const auto& [k, v]: batch_info){ + for(std::size_t i = 0; i < v; i++){ + poly_num++; + BOOST_ASSERT(eval_proof.z.get_poly_points_number(k, i) != 0); + for(std::size_t j = 0; j < eval_proof.z.get_poly_points_number(k, i); j++){ + if( sum != 0 ) out << "," << std::endl; + out << "\t\t\t{\"field\":\"" << eval_proof.z.get(k, i, j) << "\"}"; + sum++; + } + } + } + out << std::endl << "\t\t]}," << std::endl; + out << "\t\t{\"array\": [" << std::endl; + for( std::size_t i = 0; i < eval_proof.fri_proof.fri_roots.size(); i++){ + if(i != 0) out << "," << std::endl; + out << "\t\t\t" << generate_commitment( + eval_proof.fri_proof.fri_roots[i] + ); + } + out << std::endl << "\t\t]}," << std::endl; + out << "\t\t{\"array\": [" << std::endl; + for( std::size_t i = 0; i < eval_proof.fri_proof.query_proofs.size(); i++){ + if(i != 0) out << "," << std::endl; + out << "\t\t\t{\"array\":[" << std::endl; + std::size_t cur = 0; + for( const auto &[j, initial_proof]: eval_proof.fri_proof.query_proofs[i].initial_proof){ + for( std::size_t k = 0; k < initial_proof.values.size(); k++){ + if(cur != 0) out << "," << std::endl; + BOOST_ASSERT_MSG(initial_proof.values[k].size() == 1, "Unsupported step_list[0] value"); + out << "\t\t\t\t{\"field\":\"" << initial_proof.values[k][0][0] << "\"}," << std::endl; + out << "\t\t\t\t{\"field\":\"" << initial_proof.values[k][0][1] << "\"}"; + cur++; + cur++; + } + } + out << "\n\t\t\t]}"; + } + out << std::endl << "\n\t\t]}," << std::endl; + out << "\t\t{\"array\": [" << std::endl; + std::size_t cur = 0; + for( std::size_t i = 0; i < eval_proof.fri_proof.query_proofs.size(); i++){ + if(i != 0) out << "," << std::endl; + out << "\t\t\t{\"array\": [" << std::endl; + cur = 0; + for( std::size_t j = 0; j < eval_proof.fri_proof.query_proofs[i].round_proofs.size(); j++){ + const auto &round_proof = eval_proof.fri_proof.query_proofs[i].round_proofs[j]; + if(cur != 0) out << "," << std::endl; + BOOST_ASSERT_MSG(round_proof.y.size() == 1, "Unsupported step_lis value"); + out << "\t\t\t\t{\"field\":\"" << round_proof.y[0][0] << "\"}," << std::endl; + out << "\t\t\t\t{\"field\":\"" << round_proof.y[0][1] << "\"}"; + cur++; + cur++; + } + out << std::endl << "\t\t\t]}"; + } + out << std::endl << "\t\t]}," << std::endl; + + out << "\t\t{\"array\": [" << std::endl; + for( std::size_t i = 0; i < eval_proof.fri_proof.query_proofs.size(); i++){ + if( i!= 0 ) out << "," << std::endl; + out << "\t\t\t{\"array\":[" << std::endl; + std::size_t cur = 0; + for( const auto &[j, initial_proof]: eval_proof.fri_proof.query_proofs[i].initial_proof){ + for( std::size_t k = 0; k < initial_proof.p.path().size(); k++){ + if(cur != 0) out << "," << std::endl; + out << "\t\t\t\t{\"int\":" << initial_proof.p.path()[k][0].position() << "}"; + cur ++; + } + break; + } + out << std::endl << "\t\t\t]}"; + } + out << std::endl << "\t\t]}," << std::endl; + + out << "\t\t{\"array\": [" << std::endl; + for( std::size_t i = 0; i < eval_proof.fri_proof.query_proofs.size(); i++){ + if( i!= 0 ) out << "," << std::endl; + out << "\t\t\t{\"array\":[" << std::endl; + std::size_t cur = 0; + for( const auto &[j, initial_proof]: eval_proof.fri_proof.query_proofs[i].initial_proof){ + for( std::size_t k = 0; k < initial_proof.p.path().size(); k++){ + if(cur != 0) out << "," << std::endl; + out << "\t\t\t\t" << generate_hash( + initial_proof.p.path()[k][0].hash() + ); + cur ++; + } + } + out << std::endl << "\t\t\t]}"; + } + out << std::endl << "\t\t]}," << std::endl; + + out << "\t\t{\"array\": [" << std::endl; + for( std::size_t i = 0; i < eval_proof.fri_proof.query_proofs.size(); i++){ + if(i != 0) out << "," << std::endl; + out << "\t\t\t{\"array\": [" << std::endl; + cur = 0; + for( std::size_t j = 0; j < eval_proof.fri_proof.query_proofs[i].round_proofs.size(); j++){ + const auto& p = eval_proof.fri_proof.query_proofs[i].round_proofs[j].p; + for( std::size_t k = 0; k < p.path().size(); k++){ + if(cur != 0) out << "," << std::endl; + out << "\t\t\t\t{\"int\": " << p.path()[k][0].position() << "}"; + cur++; + } + } + out << std::endl << "\t\t\t]}"; + } + out << std::endl << "\t\t]}," << std::endl; + + out << "\t\t{\"array\": [" << std::endl; + for( std::size_t i = 0; i < eval_proof.fri_proof.query_proofs.size(); i++){ + if(i != 0) out << "," << std::endl; + out << "\t\t\t{\"array\": [" << std::endl; + cur = 0; + for( std::size_t j = 0; j < eval_proof.fri_proof.query_proofs[i].round_proofs.size(); j++){ + const auto& p = eval_proof.fri_proof.query_proofs[i].round_proofs[j].p; + for( std::size_t k = 0; k < p.path().size(); k++){ + if(cur != 0) out << "," << std::endl; + out << "\t\t\t\t" << generate_hash( + p.path()[k][0].hash() + ); + cur++; + } + } + out << std::endl << "\t\t\t]}"; + } + out << std::endl << "\t\t]}," << std::endl; + + cur = 0; + out << "\t\t{\"array\": [" << std::endl; + for( std::size_t i = 0; i < eval_proof.fri_proof.final_polynomial.size(); i++){ + if(cur != 0) out << "," << std::endl; + out << "\t\t\t{\"field\": \"" << eval_proof.fri_proof.final_polynomial[i] << "\"}"; + cur++; + } + out << std::endl << "\t\t]}"; + + return out.str(); + BOOST_ASSERT_MSG(false, "unsupported commitment scheme type"); + return "unsupported commitment scheme type"; + } + + inline std::string generate_input( + const typename assignment_table_type::public_input_container_type &public_inputs, + const proof_type &proof, + const std::vector public_input_sizes + ){ + BOOST_ASSERT(public_input_sizes.size() == desc.public_input_columns); + std::stringstream out; + out << "[" << std::endl; + + if(desc.public_input_columns != 0){ + out << "\t{\"array\":[" << std::endl; + std::size_t cur = 0; + for(std::size_t i = 0; i < desc.public_input_columns; i++){ + std::size_t max_non_zero = 0; + for(std::size_t j = 0; j < public_inputs[i].size(); j++){ + if( public_inputs[i][j] != 0 ) max_non_zero = j; + } + if( max_non_zero + 1 > public_input_sizes[i] ) { + std::cout << "Public input size is larger than reserved. Real size = " << max_non_zero + 1 << " reserved = " << public_input_sizes[i] << std::endl; + exit(1); + } + BOOST_ASSERT(max_non_zero <= public_input_sizes[i]); + for(std::size_t j = 0; j < public_input_sizes[i]; j++){ + if(cur != 0) out << "," << std::endl; + if( j >= public_inputs[i].size() ) + out << "\t\t{\"field\": \"" << typename field_type::value_type(0) << "\"}"; + else + out << "\t\t{\"field\": \"" << public_inputs[i][j] << "\"}"; + cur++; + } + } + out << std::endl << "\t]}," << std::endl; + } + + out << "\t{\"struct\":[" << std::endl; + out << "\t\t{\"array\":[" << std::endl; + bool first = true; + for( const auto &it: proof.commitments ){ + if( !first ) out << "," << std::endl; else first = false; + out << "\t\t\t" << generate_commitment(proof.commitments.at(it.first));//(nil::crypto3::zk::snark::VARIABLE_VALUES_BATCH) + } + out << "\t\t]}," << std::endl; + + out << "\t\t{\"field\": \"" << proof.eval_proof.challenge << "\"}," << std::endl; + out << generate_eval_proof( + proof.eval_proof.eval_proof + ) << std::endl; + out << "\t]}" << std::endl; + + out << "]" << std::endl; + return out.str(); + } + + // TODO move logic to utils.hpp to prevent code duplication + inline variable_indices_type get_plonk_variable_indices(const columns_rotations_type &col_rotations, std::size_t start_index){ + std::map result; + std::size_t j = 0; + for(std::size_t i = 0; i < desc.constant_columns; i++){ + for(auto& rot: col_rotations[i + desc.witness_columns + desc.public_input_columns]){ + variable_type v(i, rot, true, variable_type::column_type::constant); + result[v] = j + start_index; + j++; + } + } + for(std::size_t i = 0; i < desc.selector_columns; i++){ + for(auto& rot: col_rotations[i + desc.witness_columns + desc.public_input_columns + desc.constant_columns]){ + variable_type v(i, rot, true, variable_type::column_type::selector); + result[v] = j + start_index; + j++; + } + } + for(std::size_t i = 0; i < desc.witness_columns; i++){ + for(auto& rot: col_rotations[i]){ + variable_type v(i, rot, true, variable_type::column_type::witness); + result[v] = j + start_index; + j++; + } + } + for(std::size_t i = 0; i < desc.public_input_columns; i++){ + for(auto& rot: col_rotations[i + desc.witness_columns]){ + variable_type v(i, rot, true, variable_type::column_type::public_input); + result[v] = j + start_index; + j++; + } + } + return result; + } + + template + class expression_gen_code_visitor : public boost::static_visitor { + const variable_indices_type &_indices; + public: + expression_gen_code_visitor(const variable_indices_type &var_indices) :_indices(var_indices){} + + std::string generate_expression(const expression_type& expr) { + return boost::apply_visitor(*this, expr.get_expr()); + } + + std::string operator()(const term_type& term) { + std::string result; + std::vector v; + if( term.get_coeff() != field_type::value_type::one() || term.get_vars().size() == 0) + v.push_back("pallas::base_field_type::value_type(0x" + to_hex_string(term.get_coeff()) + "_cppui_modular255)"); + for(auto& var: term.get_vars()){ + v.push_back("z[" + to_string(_indices.at(var)) + "]"); + } + for(std::size_t i = 0; i < v.size(); i++){ + if(i != 0) result += " * "; + result += v[i]; + } + return result; + } + + std::string operator()( + const pow_operation_type& pow) { + std::string result = boost::apply_visitor(*this, pow.get_expr().get_expr()); + return "pow" + to_string(pow.get_power()) + "(" + result +")"; + } + + std::string operator()( + const binary_operation_type& op) { + std::string left = boost::apply_visitor(*this, op.get_expr_left().get_expr()); + std::string right = boost::apply_visitor(*this, op.get_expr_right().get_expr()); + switch (op.get_op()) { + case binary_operation_type::ArithmeticOperatorType::ADD: + return "(" + left + " + " + right + ")"; + case binary_operation_type::ArithmeticOperatorType::SUB: + return "(" + left + " - " + right + ")"; + case binary_operation_type::ArithmeticOperatorType::MULT: + return "(" + left + " * " + right + ")"; + } + return ""; + } + }; + + static inline std::string rot_string (int j){ + if(j == 0) return "xi"; else + if(j == 1 ) return "xi*omega"; else + if(j == -1) return "xi/omega"; else + if(j > 0) return "xi*pow<" + to_string(j) + ">(omega)"; else + if(j < 0) return "xi/pow<" + to_string(-j) + ">(omega)"; + return ""; + } + + static inline std::vector split_point_string(std::string point){ + std::vector result; + std::size_t found = point.find("& "); + std::size_t j = 0; + std::size_t prev = 0; + while (found!=std::string::npos){ + result.push_back(point.substr(prev, found-prev)); + prev = found + 2; + found = point.find("& ",prev); + j++; + } + return result; + } + + std::string generate_recursive_verifier( + const constraint_system_type &constraint_system, + const common_data_type &common_data, + const std::vector public_input_sizes + ){ + auto placeholder_info = nil::crypto3::zk::snark::prepare_placeholder_info( + constraint_system, + common_data + ); + + std::size_t permutation_size = common_data.permuted_columns.size(); + const auto &desc = common_data.desc; + BOOST_ASSERT(desc.public_input_columns == public_input_sizes.size()); + std::string result = nil::blueprint::recursive_verifier_template; + bool use_lookups = constraint_system.lookup_gates().size() > 0; + transpiler_replacements lookup_reps; + transpiler_replacements reps; + + auto fri_params = common_data.commitment_params; + std::size_t batches_num = placeholder_info.batches_num; + auto lambda = fri_params.lambda; + + std::size_t round_proof_layers_num = 0; + for(std::size_t i = 0; i < fri_params.r; i++ ){ + round_proof_layers_num += log2(fri_params.D[i]->m) -1; + } + + std::size_t lookup_degree = constraint_system.lookup_poly_degree_bound(); + + std::size_t rows_amount = desc.rows_amount; + std::size_t quotient_polys = placeholder_info.quotient_size; + + std::size_t poly_num = placeholder_info.poly_num; + + std::size_t points_num = placeholder_info.points_num; + std::size_t table_values_num = placeholder_info.table_values_num; + + std::size_t constraints_amount = 0; + std::string gates_sizes = ""; + std::stringstream constraints_body; + std::size_t cur = 0; + auto verifier_indices = get_plonk_variable_indices(common_data.columns_rotations, 2*permutation_size + 4); + + expression_gen_code_visitor visitor(verifier_indices); + for(std::size_t i = 0; i < constraint_system.gates().size(); i++){ + constraints_amount += constraint_system.gates()[i].constraints.size(); + if( i != 0) gates_sizes += ", "; + gates_sizes += to_string(constraint_system.gates()[i].constraints.size()); + for(std::size_t j = 0; j < constraint_system.gates()[i].constraints.size(); j++, cur++){ + constraints_body << "\tconstraints[" << cur << "] = " << visitor.generate_expression(constraint_system.gates()[i].constraints[j]) << ";" << std::endl; + } + } + + std::stringstream lookup_expressions_body; + cur = 0; + for(const auto &lookup_gate: constraint_system.lookup_gates()){ + for(const auto &lookup_constraint: lookup_gate.constraints){ + for( const auto &expr: lookup_constraint.lookup_input){ + lookup_expressions_body << "\texpressions[" << cur << "] = " << visitor.generate_expression(expr) << ";" << std::endl; + cur++; + } + } + } + + std::stringstream lookup_gate_selectors_list; + cur = 0; + for(const auto &lookup_gate: constraint_system.lookup_gates()){ + variable_type var(lookup_gate.tag_index, 0, true, variable_type::column_type::selector); + lookup_gate_selectors_list << "\t\tlookup_gate_selectors[" << cur << "] = proof.z[" << verifier_indices[var] <<"];" << std::endl; + cur++; + } + + std::stringstream lookup_table_selectors_list; + cur = 0; + for(const auto &lookup_table: constraint_system.lookup_tables()){ + variable_type var(lookup_table.tag_index, 0, true, variable_type::column_type::selector); + lookup_table_selectors_list << "\t\tlookup_table_selectors[" << cur << "] = proof.z[" << verifier_indices[var] <<"];" << std::endl; + cur++; + } + + std::stringstream lookup_shifted_table_selectors_list; + cur = 0; + for(const auto &lookup_table: constraint_system.lookup_tables()){ + variable_type var(lookup_table.tag_index, 1, true, variable_type::column_type::selector); + lookup_shifted_table_selectors_list << "\t\tshifted_lookup_table_selectors[" << cur << "] = proof.z[" << verifier_indices[var] <<"];" << std::endl; + cur++; + } + + std::stringstream lookup_options_list; + cur = 0; + for(const auto &lookup_table: constraint_system.lookup_tables()){ + for(const auto &lookup_option: lookup_table.lookup_options){ + for( const auto &column: lookup_option){ + variable_type var(column.index, 0, true, variable_type::column_type::constant); + lookup_options_list << "\t\tlookup_table_lookup_options[" << cur << "] = proof.z[" << verifier_indices[var] <<"];" << std::endl; + cur++; + } + } + } + + std::stringstream lookup_shifted_options_list; + cur = 0; + for(const auto &lookup_table: constraint_system.lookup_tables()){ + for(const auto &lookup_option: lookup_table.lookup_options){ + for( const auto &column: lookup_option){ + variable_type var(column.index, 1, true, variable_type::column_type::constant); + lookup_shifted_options_list << "\t\tshifted_lookup_table_lookup_options[" << cur << "] = proof.z[" << verifier_indices[var] <<"];" << std::endl; + cur++; + } + } + } + + std::stringstream gates_selectors_indices; + cur = 0; + for(const auto &gate: constraint_system.gates()){ + if(cur != 0) gates_selectors_indices << ", "; + gates_selectors_indices << gate.selector_index; + cur++; + } + + auto [z_points_indices, singles_strs, singles_map, poly_ids] = calculate_unique_points( + placeholder_info, + desc, + common_data, permutation_size, quotient_polys, + use_lookups?constraint_system.sorted_lookup_columns_number():0, + "recursive" // Generator mode + ); + + std::string singles_str = ""; + for(const auto &[k, v]: singles_map){ + singles_str+= "\tsingles[" + to_string(v) + "] = " + k + ";\n"; + } + + std::string lpc_poly_ids_const_arrays = ""; + for(std::size_t i = 0; i < poly_ids.size(); i++){ + lpc_poly_ids_const_arrays += "\tconstexpr std::array lpc_poly_ids" + to_string(i) + " = {"; + for(std::size_t j = 0; j < poly_ids[i].size(); j++){ + if(j != 0) lpc_poly_ids_const_arrays += ", "; + lpc_poly_ids_const_arrays += to_string(poly_ids[i][j]); + } + lpc_poly_ids_const_arrays += "};\n"; + } + + std::stringstream prepare_U_V_str; + prepare_U_V_str << "\tpallas::base_field_type::value_type theta_acc = pallas::base_field_type::value_type(1);\n\n"; + for(std::size_t i = 0; i < singles_strs.size();i++){ + prepare_U_V_str << "\tU[" + to_string(i) << "] = pallas::base_field_type::value_type(0);\n"; + for(std::size_t j = 0; j &batches_sizes = placeholder_info.batches_sizes; + + std::size_t start_position = 0; + std::size_t initial_merkle_proofs_position_num = (log2(fri_params.D[0]->m) - 1); + cur = 0; + for(std::size_t i = 0; i < batches_num; i++){ + initial_proof_check_str += "\t\thash_state = calculate_leaf_hash<"+to_string(start_position*2)+"," + to_string(batches_sizes[i]) + ">(proof.initial_proof_values[i]);\n"; + for(std::size_t j = 0; j < initial_merkle_proofs_position_num; j++){ + initial_proof_check_str += "\t\tpos = pallas::base_field_type::value_type(proof.initial_proof_positions[i][" + to_string(j) + "]);"; + initial_proof_check_str += " npos = pallas::base_field_type::value_type(1) - pos;\n"; + initial_proof_check_str += + "\t\thash_state = __builtin_assigner_poseidon_pallas_base({0, pos * hash_state + npos * proof.initial_proof_hashes[i][" + +to_string(cur)+ + "], npos * hash_state + pos * proof.initial_proof_hashes[i][" + +to_string(cur)+ + "]})[2];\n"; + cur++; + } + start_position += batches_sizes[i]; + if( i == 0 ) + initial_proof_check_str += "\t\t__builtin_assigner_exit_check(hash_state == pallas::base_field_type::value_type(0x$VK1$_cppui_modular255));\n\n"; + else + initial_proof_check_str += "\t\t__builtin_assigner_exit_check(hash_state == proof.commitments[" + to_string(i-1) + "]);\n\n"; + } + + std::string placeholder_challenges_str = "\tchallenges.eta = state = __builtin_assigner_poseidon_pallas_base({0, vk0, vk1})[2];\n"; + if(placeholder_info.use_permutations){ + placeholder_challenges_str += "\t// generate permutation argument challenges\n"; + placeholder_challenges_str += "\tchallenges.perm_beta = state = __builtin_assigner_poseidon_pallas_base({state, proof.commitments[0], 0})[2];\n"; + placeholder_challenges_str += "\tchallenges.perm_gamma = state = __builtin_assigner_poseidon_pallas_base({state, 0, 0})[2];\n"; + if( placeholder_info.permutation_poly_amount > 1 ){ + placeholder_challenges_str += "\tfor( std::size_t i = 0; i < " + to_string(placeholder_info.permutation_poly_amount - 1) + "; i++){\n"; + placeholder_challenges_str += "\t\tchallenges.perm_chunk_alphas[i] = state = __builtin_assigner_poseidon_pallas_base({state, 0, 0})[2];\n"; + placeholder_challenges_str += "\t}\n"; + } + } + if(placeholder_info.use_lookups){ + placeholder_challenges_str += "\t// generate permutation argument challenges\n"; + if( placeholder_info.use_permutations ) { + placeholder_challenges_str += "\tchallenges.lookup_theta = state = __builtin_assigner_poseidon_pallas_base({state, 0, 0})[2];\n"; + placeholder_challenges_str += "\tchallenges.lookup_beta = state = __builtin_assigner_poseidon_pallas_base({state, proof.commitments[3], 0})[2];"; + } else { + placeholder_challenges_str += "\tchallenges.lookup_theta = state = __builtin_assigner_poseidon_pallas_base({state, proof.commitments[0], 0})[2];\n"; + placeholder_challenges_str += "\tchallenges.lookup_beta = state = __builtin_assigner_poseidon_pallas_base({state, proof.commitments[3], 0})[2];"; + } + placeholder_challenges_str += "\tchallenges.lookup_gamma = state = __builtin_assigner_poseidon_pallas_base({state, 0, 0})[2];\n"; + if( placeholder_info.lookup_poly_amount > 1 ){ + placeholder_challenges_str += "\tfor( std::size_t i = 0; i < " + to_string(placeholder_info.lookup_poly_amount - 1) + "; i++){\n"; + placeholder_challenges_str += "\t\tchallenges.lookup_chunk_alphas[i] = state = __builtin_assigner_poseidon_pallas_base({state, 0, 0})[2];\n"; + placeholder_challenges_str += "\t}\n"; + } + placeholder_challenges_str += "\tfor( std::size_t i = 0; i < " + to_string(placeholder_info.sorted_poly_amount -1) + "; i++){\n"; + placeholder_challenges_str += "\t\tchallenges.lookup_alphas[i] = state =__builtin_assigner_poseidon_pallas_base({state, 0, 0})[2];\n"; + placeholder_challenges_str += "\t}\n"; + } + if(placeholder_info.use_permutations || placeholder_info.use_lookups){ + placeholder_challenges_str += "\tchallenges.gate_theta = state = __builtin_assigner_poseidon_pallas_base({state, proof.commitments[1], 0})[2];\n"; + } else { + placeholder_challenges_str += "\tchallenges.gate_theta = state = __builtin_assigner_poseidon_pallas_base({state, proof.commitments[0]})[2];\n"; + } + + for( std::size_t i = 0; i < 8; i++){ + placeholder_challenges_str += "\tchallenges.alphas[" + to_string(i) + "] = state = __builtin_assigner_poseidon_pallas_base({state, 0, 0})[2];\n"; + } + + if( placeholder_info.use_permutations || placeholder_info.use_lookups ) + placeholder_challenges_str += "\tchallenges.xi = state = __builtin_assigner_poseidon_pallas_base({state, proof.commitments[2], 0})[2];\n"; + else + placeholder_challenges_str += "\tchallenges.xi = state = __builtin_assigner_poseidon_pallas_base({state, proof.commitments[1], 0})[2];\n"; + + if( placeholder_info.use_lookups ){ + placeholder_challenges_str += "\tstate = __builtin_assigner_poseidon_pallas_base({state, vk1, proof.commitments[0]})[2];\n"; + placeholder_challenges_str += "\tstate = __builtin_assigner_poseidon_pallas_base({state, proof.commitments[1], proof.commitments[2]})[2];\n"; + placeholder_challenges_str += "\tchallenges.lpc_theta = state = __builtin_assigner_poseidon_pallas_base({state, proof.commitments[3], 0})[2];\n"; + } else if (placeholder_info.use_permutations){ + placeholder_challenges_str += "\tstate = __builtin_assigner_poseidon_pallas_base({state, vk1, proof.commitments[0]})[2];\n"; + placeholder_challenges_str += "\tchallenges.lpc_theta = state = __builtin_assigner_poseidon_pallas_base({state, proof.commitments[1], proof.commitments[2]})[2];\n"; + } else { + placeholder_challenges_str += "\tstate = __builtin_assigner_poseidon_pallas_base({state, vk1, proof.commitments[0]})[2];\n"; + placeholder_challenges_str += "\tchallenges.lpc_theta = state = __builtin_assigner_poseidon_pallas_base({state, proof.commitments[1], 0})[2];\n"; + } + + placeholder_challenges_str += "\tfor(std::size_t i = 0; i < fri_roots_num; i++){\n"; + placeholder_challenges_str += "\t\tchallenges.fri_alphas[i] = state = __builtin_assigner_poseidon_pallas_base({state, proof.fri_roots[i], 0})[2];\n"; + placeholder_challenges_str += "\t}\n"; + + placeholder_challenges_str += "\tfor(std::size_t i = 0; i < lambda; i++){\n"; + placeholder_challenges_str += "\t\tchallenges.fri_x_indices[i] = state = __builtin_assigner_poseidon_pallas_base({state, 0, 0})[2];\n"; + placeholder_challenges_str += "\t}\n"; + + std::string batches_size_list; + for( std::size_t i = 0; i < batches_num; i++){ + if( i != 0) batches_size_list += ", "; + batches_size_list += to_string(batches_sizes[i]); + } + + std::string round_proof_check_str = ""; + cur = 0; + for( std::size_t i = 0; i < fri_params.r; i++){ + round_proof_check_str += "\t\tpos = res[" + to_string(i) + "][2]; npos = pallas::base_field_type::value_type(1) - pos;\n"; + if(i == 0) + round_proof_check_str += "\t\trhash = __builtin_assigner_poseidon_pallas_base({0, y0, y1})[2];\n"; + else + round_proof_check_str += "\t\trhash = __builtin_assigner_poseidon_pallas_base({0, proof.round_proof_values[i]["+to_string(i*2-2)+"], proof.round_proof_values[i]["+to_string(i*2-1)+"]})[2];\n"; + for ( std::size_t j = 0; j < log2(fri_params.D[0]->m) - i - 1; j++){ + round_proof_check_str += "\t\tpos = pallas::base_field_type::value_type(proof.round_merkle_proof_positions[i][" + to_string(cur) + "]); npos = pallas::base_field_type::value_type(1) - pos;\n"; + round_proof_check_str += "\t\trhash = __builtin_assigner_poseidon_pallas_base({0, pos * rhash + npos * proof.round_proof_hashes[i]["+to_string(cur)+"], npos * rhash + pos * proof.round_proof_hashes[i]["+to_string(cur)+"]})[2];\n"; + cur++; + } + round_proof_check_str += "\t\t__builtin_assigner_exit_check(rhash == proof.fri_roots["+to_string(i)+"]);\n\n"; + } + + + std::size_t domain_size_log = std::ceil(std::log2(fri_params.D[0]->size())) - 1; + for(std::size_t i = 0; i < fri_params.r; i++){ + if( i == 0){ + round_proof_check_str += "\t\tinterpolant = __builtin_assigner_fri_lin_inter(x_2, y0, y1, challenges.fri_alphas["+to_string(i)+"]);\n"; + round_proof_check_str += "\t\t__builtin_assigner_exit_check_eq_pallas(proof.initial_proof_positions[i][" + to_string(domain_size_log - 1) + "] * (interpolant - proof.round_proof_values[i]["+to_string(2*i)+"]),0);\n"; + round_proof_check_str += "\t\t__builtin_assigner_exit_check_eq_pallas((1 - proof.initial_proof_positions[i][" + to_string(domain_size_log - 1) + "]) * (interpolant - proof.round_proof_values[i]["+to_string(2*i + 1)+"]),0);\n"; + round_proof_check_str += "\t\t\n"; + } + else{ + round_proof_check_str += "\t\tinterpolant = __builtin_assigner_fri_lin_inter(2 * proof.initial_proof_positions[i][" + to_string(domain_size_log - i) + "] * x - x, y0, y1, challenges.fri_alphas["+to_string(i)+"]);\n"; + round_proof_check_str += "\t\t__builtin_assigner_exit_check_eq_pallas(proof.initial_proof_positions[i][" + to_string(domain_size_log - i - 1) + "] * (interpolant - proof.round_proof_values[i]["+to_string(2*i)+"]),0);\n"; + round_proof_check_str += "\t\t__builtin_assigner_exit_check_eq_pallas((1 - proof.initial_proof_positions[i][" + to_string(domain_size_log - i - 1) + "]) * (interpolant - proof.round_proof_values[i]["+to_string(2*i + 1)+"]),0);\n"; + round_proof_check_str += "\t\t\n"; + } + round_proof_check_str += "\t\ty0 = proof.round_proof_values[i]["+to_string(2*i)+"];\n"; + round_proof_check_str += "\t\ty1 = proof.round_proof_values[i]["+to_string(2*i+1)+"];\n"; + round_proof_check_str += "\t\tx = x * x;\n"; + } + round_proof_check_str += "\t\tx = 2 * proof.initial_proof_positions[i][" + to_string(domain_size_log - fri_params.r) + "] * x - x;\n"; + + std::vector selectors_indices; + for(const auto &gate: constraint_system.gates()){ + selectors_indices.push_back(gate.selector_index); + } + + auto zeroes = zero_indices(common_data.columns_rotations, permutation_size); + std::string public_input_sizes_str = ""; + std::string public_input_indices_str = ""; + std::size_t full_public_input_size = 0; + for(std::size_t i = 0; i < public_input_sizes.size(); i++){ + if(i != 0) { + public_input_sizes_str += ", "; + public_input_indices_str += ", "; + } + public_input_sizes_str += to_string(public_input_sizes[i]); + public_input_indices_str += to_string(zeroes[desc.witness_columns + i]); + full_public_input_size += public_input_sizes[i]; + } + + cur = 0; + std::string full_public_input_check_str = ""; + if( desc.public_input_columns != 0){ + full_public_input_check_str += "\tstd::array Omegas ;\n"; + full_public_input_check_str += "\tOmegas[0] = pallas::base_field_type::value_type(1);\n"; + full_public_input_check_str += "\tpallas::base_field_type::value_type result(0);\n"; + for (std::size_t i = 0; i < desc.public_input_columns; i++){ + full_public_input_check_str += "\t{\n"; + full_public_input_check_str += "\tresult = pallas::base_field_type::value_type(0);\n"; + for( std::size_t j = 0; j < public_input_sizes[i]; j++){ + full_public_input_check_str += "\t\tresult += public_input[" + to_string(cur) + "] * Omegas["+to_string(j)+"] / (challenges.xi - Omegas["+to_string(j)+"]);"; + if( j != public_input_sizes[i] - 1) + full_public_input_check_str += " Omegas["+to_string(j+1)+"] = Omegas["+to_string(j)+"] * omega;\n"; + cur++; + } + full_public_input_check_str += "\n\t\t__builtin_assigner_exit_check_eq_pallas(rows_amount * proof.z[public_input_indices[" + to_string(i) + " ]], precomputed_values.Z_at_xi * result);\n"; + full_public_input_check_str += "\t}\n"; + } + } + + std::string perm_arg_str = ""; + if( placeholder_info.use_permutations){ + cur = 0; + std::size_t chunk = 0; + for( std::size_t i = 0; i < permutation_size; i++ ){ + perm_arg_str += "\t\ttmp = challenges.perm_gamma + proof.z["+to_string(zeroes[common_data.permuted_columns[i]])+"];\n"; + perm_arg_str += "\t\tg *= challenges.perm_beta * proof.z["+to_string(i)+"] + tmp;\n"; + perm_arg_str += "\t\th *= challenges.perm_beta * proof.z["+to_string(permutation_size + i)+"] + tmp;\n"; + cur++; + if(common_data.max_quotient_chunks != 0 && cur == common_data.max_quotient_chunks - 1){ + perm_arg_str += "\t\tcurrent_value = proof.z["+to_string(2 * permutation_size + 4 + placeholder_info.table_values_num + 2 + chunk ) +"];\n"; + perm_arg_str += "\t\tF[1] += challenges.perm_chunk_alphas["+to_string(chunk)+"] * (previous_value * g - current_value * h);\n"; + perm_arg_str += "\t\tprevious_value = current_value;\n"; + perm_arg_str += "\t\tg = pallas::base_field_type::value_type(1); h = pallas::base_field_type::value_type(1);\n"; + chunk++; + cur = 0; + } + } + } + + std::string gate_arg_prepare_str = "\t\tpallas::base_field_type::value_type theta_acc(1);\n"; + cur = 0; + for( std::size_t i = 0; i < constraint_system.gates().size(); i++ ){ + for( std::size_t j = 0; j < constraint_system.gates()[i].constraints.size(); j++, cur++){ + gate_arg_prepare_str += "\t\tF[7] += proof.z["+to_string(zeroes[desc.witness_columns + desc.public_input_columns + desc.constant_columns + selectors_indices[i]]) + "] * constraints["+to_string(cur)+"] * theta_acc; theta_acc *= challenges.gate_theta;\n"; + } + gate_arg_prepare_str += "\n"; + } + + std::string lookup_input_loop = ""; + cur = 0; + std::size_t cur_e = 0; + for(std::size_t i=0; i < constraint_system.lookup_gates().size(); i++){ + for(std::size_t j = 0; j < constraint_system.lookup_gates()[i].constraints.size(); j++){ + lookup_input_loop += "\t\tlookup_input["+to_string(cur) + "] = lookup_gate_constraints_table_ids["+to_string(cur)+"];\n"; + lookup_input_loop += "\t\ttheta_acc = theta;\n"; + for(std::size_t k = 0; k < constraint_system.lookup_gates()[i].constraints[j].lookup_input.size(); k++){ + lookup_input_loop += "\t\tlookup_input["+to_string(cur)+"] += lookup_gate_constraints_lookup_inputs["+to_string(cur_e)+"] * theta_acc; theta_acc *= theta;\n"; + cur_e++; + } + lookup_input_loop += "\t\tlookup_input["+to_string(cur) + "] *= lookup_gate_selectors["+to_string(i)+"];\n"; + cur++; + } + } + + std::string lookup_table_loop = ""; + cur = 0; + std::size_t cur_o = 0; + for(std::size_t i = 0; i < constraint_system.lookup_tables().size(); i++){ + for(std::size_t j = 0; j < constraint_system.lookup_tables()[i].lookup_options.size(); j++){ + lookup_table_loop += "\t\ttheta_acc = theta;\n"; + lookup_table_loop += "\t\tlookup_value["+to_string(cur)+"] = lookup_table_selectors["+to_string(i)+"] * pallas::base_field_type::value_type("+to_string(i+1)+");\n"; + lookup_table_loop += "\t\tlookup_shifted_value["+to_string(cur)+"] = shifted_lookup_table_selectors["+to_string(i)+"] * pallas::base_field_type::value_type("+to_string(i+1)+");\n"; + for(std::size_t k = 0; k < constraint_system.lookup_tables()[i].lookup_options[j].size(); k++){ + lookup_table_loop += "\t\tlookup_value["+to_string(cur)+"] += lookup_table_selectors["+to_string(i)+"] * lookup_table_lookup_options["+to_string(cur_o)+"] * theta_acc;\n"; + lookup_table_loop += "\t\tlookup_shifted_value["+to_string(cur)+"] += shifted_lookup_table_selectors["+to_string(i)+"] * shifted_lookup_table_lookup_options["+to_string(cur_o)+"] * theta_acc;\n"; + lookup_table_loop += "\t\ttheta_acc = theta_acc * theta;\n"; + cur_o++; + } + lookup_table_loop += "\t\tlookup_value["+to_string(cur)+"] *= precomputed_values.mask;\n"; + lookup_table_loop += "\t\tlookup_shifted_value["+to_string(cur)+"] *= precomputed_values.shifted_mask;\n"; + cur++; + } + } + + std::string lookup_chunking_code_str = ""; + if( placeholder_info.use_lookups ){ + std::vector lookup_parts = constraint_system.lookup_parts(common_data.max_quotient_chunks); + cur = 0; + std::size_t chunk = 0; + std::size_t v_l_start_index = placeholder_info.use_permutations? 2*permutation_size + 4 + placeholder_info.table_values_num + placeholder_info.permutation_poly_amount + 1:2*permutation_size + 4 + placeholder_info.table_values_num; + for( std::size_t i = 0; i < constraint_system.lookup_constraints_num(); i++ ){ + lookup_chunking_code_str += "\t\tg = g *(pallas::base_field_type::value_type(1)+beta)*(gamma + lookup_input["+to_string(i)+"]);\n"; + lookup_chunking_code_str += "\t\th = h * ((pallas::base_field_type::value_type(1)+beta) * gamma + sorted["+to_string(3*i)+"] + beta * sorted[" + to_string(3*i+1) + "]);\n"; + cur++; + if( common_data.max_quotient_chunks > 0 && cur == lookup_parts[chunk]){ + lookup_chunking_code_str += "\t\tcurrent_value = proof.z["+to_string(v_l_start_index + 2 + chunk)+"];\n"; + lookup_chunking_code_str += "\t\tlookup_argument[2] += challenges.lookup_chunk_alphas[" + to_string(chunk) + "] * (previous_value * g - current_value * h);\n"; + lookup_chunking_code_str += "\t\tprevious_value = current_value;\n"; + lookup_chunking_code_str += "\t\tg = pallas::base_field_type::value_type(1); h = pallas::base_field_type::value_type(1);\n"; + cur = 0; + chunk++; + } + } + for( std::size_t i = 0; i < constraint_system.lookup_options_num(); i++ ){ + lookup_chunking_code_str += "\t\tg = g * ((pallas::base_field_type::value_type(1)+beta) * gamma + lookup_value["+to_string(i)+"] + beta * lookup_shifted_value["+to_string(i)+"]);\n"; + lookup_chunking_code_str += "\t\th = h * ((pallas::base_field_type::value_type(1)+beta) * gamma + sorted["+to_string(3*(i+constraint_system.lookup_constraints_num()))+"] + beta * sorted[" + to_string(3*(i+constraint_system.lookup_constraints_num())+1) + "]);\n"; + cur++; + if( common_data.max_quotient_chunks > 0 && cur == lookup_parts[chunk] && i != constraint_system.lookup_options_num() - 1 ){ + lookup_chunking_code_str += "\t\tcurrent_value = proof.z["+to_string(v_l_start_index + 2 + chunk)+"];\n"; + lookup_chunking_code_str += "\t\tlookup_argument[2] += challenges.lookup_chunk_alphas[" + to_string(chunk) + "] * (previous_value * g - current_value * h);\n"; + lookup_chunking_code_str += "\t\tprevious_value = current_value;\n"; + lookup_chunking_code_str += "\t\tg = pallas::base_field_type::value_type(1); h = pallas::base_field_type::value_type(1);\n"; + cur = 0; + chunk++; + } + } + } + + std::string x_challenge_pow_str = "\t\t"; + typename PlaceholderParams::field_type::integral_type x_power = (PlaceholderParams::field_type::modulus - 1)/fri_params.D[0]->size(); + typename PlaceholderParams::field_type::integral_type mask = 1; + while( mask < x_power ){ mask <<= 1; } + mask >>= 1; + while( mask > 0 ){ + x_challenge_pow_str += "x = x * x;"; + if( mask & x_power ) x_challenge_pow_str += " x = x * x_challenge; "; + mask >>= 1; + } + x_challenge_pow_str += "\n"; + +// for( uint64 j = 0; j < D0_log - 1; j++){ +// state.x_index += (uint64(1 - uint8(blob[state.initial_proof_offset + 0x47 + 0x38 * j])) << j ); +// } + + for( std::size_t i = 0; i < domain_size_log; i++){ + x_challenge_pow_str += "\t\tx_2 = x_2 * x_2; x_2 *= (proof.initial_proof_positions[i]["+ to_string(domain_size_log - i - 1) + "] + (1 - proof.initial_proof_positions[i]["+ to_string(domain_size_log - i - 1) + "]) * D0_omega);\n"; + } + + lookup_reps["$LOOKUP_VARS$"] = use_lookups?lookup_vars:""; + lookup_reps["$LOOKUP_EXPRESSIONS$"] = use_lookups?lookup_expressions:""; + lookup_reps["$LOOKUP_CODE$"] = use_lookups?lookup_code:""; + lookup_reps["$LOOKUP_INPUT_LOOP$"] = use_lookups?lookup_input_loop:""; + lookup_reps["$LOOKUP_TABLE_LOOP$"] = use_lookups?lookup_table_loop:""; + result = replace_all(result, lookup_reps); + + reps["$LOOKUP_CHUNKING_CODE$"] = use_lookups?lookup_chunking_code_str:""; + reps["$USE_LOOKUPS$"] = use_lookups? "true" : "false"; + reps["$BATCHES_NUM$"] = to_string(batches_num); + reps["$COMMITMENTS_NUM$"] = to_string(batches_num - 1); + reps["$POINTS_NUM$"] = to_string(points_num); + reps["$POLY_NUM$"] = to_string(poly_num); + reps["$INITIAL_PROOF_POINTS_NUM$"] = to_string(poly_num * 2); + reps["$ROUND_PROOF_POINTS_NUM$"] = to_string(fri_params.r * 2); + reps["$FRI_ROOTS_NUM$"] = to_string(fri_params.r); + reps["$INITIAL_MERKLE_PROOFS_NUM$"] = to_string(batches_num * lambda); + reps["$INITIAL_MERKLE_PROOFS_POSITION_NUM$"] = to_string(initial_merkle_proofs_position_num); + reps["$INITIAL_MERKLE_PROOFS_HASH_NUM$"] = to_string((log2(fri_params.D[0]->m) - 1) * batches_num); + reps["$INITIAL_PROOF_CHECK$"] = to_string(initial_proof_check_str); + reps["$ROUND_MERKLE_PROOFS_POSITION_NUM$"] = to_string(round_proof_layers_num); + reps["$ROUND_MERKLE_PROOFS_HASH_NUM$"] = to_string(round_proof_layers_num); + reps["$ROUND_PROOF_CHECK$"] = to_string(round_proof_check_str); + reps["$FINAL_POLYNOMIAL_SIZE$"] = to_string(std::pow(2, std::log2(fri_params.max_degree + 1) - fri_params.r + 1) - 2); + reps["$LAMBDA$"] = to_string(lambda); + reps["$PERMUTATION_SIZE$"] = to_string(permutation_size); + reps["$TOTAL_COLUMNS$"] = to_string(desc.table_width()); + reps["$ROWS_LOG$"] = to_string(log2(rows_amount)); + reps["$ROWS_AMOUNT$"] = to_string(rows_amount); + reps["$TABLE_VALUES_NUM$"] = to_string(table_values_num); + reps["$GATES_AMOUNT$"] = to_string(constraint_system.gates().size()); + reps["$CONSTRAINTS_AMOUNT$"] = to_string(constraints_amount); + reps["$GATES_SIZES$"] = gates_sizes; + reps["$GATES_SELECTOR_INDICES$"] = gates_selectors_indices.str(); + reps["$CONSTRAINTS_BODY$"] = constraints_body.str(); + reps["$WITNESS_COLUMNS_AMOUNT$"] = to_string(desc.witness_columns); + reps["$PUBLIC_INPUT_COLUMNS_AMOUNT$"] = to_string(desc.public_input_columns); + reps["$CONSTANT_COLUMNS_AMOUNT$"] = to_string(desc.constant_columns); + reps["$SELECTOR_COLUMNS_AMOUNT$"] = to_string(desc.selector_columns); + reps["$QUOTIENT_POLYS_START$"] = to_string(placeholder_info.quotient_poly_first_index); + reps["$QUOTIENT_POLYS_AMOUNT$"] = to_string(quotient_polys); + reps["$D0_SIZE$"] = to_string(fri_params.D[0]->m); + reps["$D0_LOG$"] = to_string(log2(fri_params.D[0]->m)); + reps["$D0_OMEGA$"] = "pallas::base_field_type::value_type(0x" + to_hex_string(fri_params.D[0]->get_domain_element(1)) + "_cppui_modular255)"; + reps["$OMEGA$"] = "pallas::base_field_type::value_type(0x" + to_hex_string(common_data.basic_domain->get_domain_element(1)) + "_cppui_modular255)"; + reps["$FRI_ROUNDS$"] = to_string(fri_params.r); + reps["$UNIQUE_POINTS$"] = to_string(singles_strs.size()); + reps["$SINGLES_AMOUNT$"] = to_string(singles_strs.size()); + reps["$SINGLES_COMPUTATION$"] = singles_str; + reps["$PREPARE_U_AND_V$"] = prepare_U_V_str.str(); + reps["$SORTED_COLUMNS$"] = to_string(constraint_system.sorted_lookup_columns_number()); + reps["$SORTED_ALPHAS$"] = to_string(use_lookups? constraint_system.sorted_lookup_columns_number() - 1: 0); + reps["$LOOKUP_TABLE_AMOUNT$"] = to_string(constraint_system.lookup_tables().size()); + reps["$LOOKUP_GATE_AMOUNT$"] = to_string(constraint_system.lookup_gates().size()); + reps["$LOOKUP_OPTIONS_AMOUNT$"] = to_string(constraint_system.lookup_options_num()); + reps["$LOOKUP_OPTIONS_AMOUNT_LIST$"] = generate_lookup_options_amount_list(constraint_system); + reps["$LOOKUP_CONSTRAINTS_AMOUNT$"] = to_string(constraint_system.lookup_constraints_num()); + reps["$LOOKUP_CONSTRAINTS_AMOUNT_LIST$"] = generate_lookup_constraints_amount_list(constraint_system); + reps["$LOOKUP_EXPRESSIONS_AMOUNT$"] = to_string(constraint_system.lookup_expressions_num()); + reps["$LOOKUP_EXPRESSIONS_AMOUNT_LIST$"] = generate_lookup_expressions_amount_list(constraint_system); + reps["$LOOKUP_TABLES_COLUMNS_AMOUNT$"] = to_string(constraint_system.lookup_tables_columns_num()); + reps["$LOOKUP_TABLES_COLUMNS_AMOUNT_LIST$"] = generate_lookup_columns_amount_list(constraint_system); + reps["$LOOKUP_EXPRESSIONS_BODY$"] = lookup_expressions_body.str(); + reps["$LOOKUP_CONSTRAINT_TABLE_IDS_LIST$"] = generate_lookup_constraint_table_ids_list(constraint_system); + reps["$LOOKUP_GATE_SELECTORS_LIST$"] = lookup_gate_selectors_list.str(); + reps["$LOOKUP_TABLE_SELECTORS_LIST$"] = lookup_table_selectors_list.str(); + reps["$LOOKUP_SHIFTED_TABLE_SELECTORS_LIST$"] = lookup_shifted_table_selectors_list.str(); + reps["$LOOKUP_OPTIONS_LIST$"] = lookup_options_list.str(); + reps["$LOOKUP_SHIFTED_OPTIONS_LIST$"] = lookup_shifted_options_list.str(); + reps["$LOOKUP_SORTED_START$"] = to_string(2*permutation_size + 4 + table_values_num + (placeholder_info.use_permutations?placeholder_info.permutation_poly_amount+1:0) + (placeholder_info.use_lookups?placeholder_info.lookup_poly_amount+1:0) + quotient_polys); + reps["$BATCHES_AMOUNT_LIST$"] = batches_size_list; + reps["$PUBLIC_INPUT_SIZES$"] = public_input_sizes_str; + reps["$PUBLIC_INPUT_INDICES$"] = public_input_indices_str; + reps["$FULL_PUBLIC_INPUT_SIZE$"] = to_string(full_public_input_size); + reps["$LPC_POLY_IDS_CONSTANT_ARRAYS$"] = lpc_poly_ids_const_arrays; + reps["$LPC_Y_COMPUTATION$"] = lpc_y_computation.str(); + reps["$PUBLIC_INPUT_CHECK$"] = desc.public_input_columns == 0 ? "" :full_public_input_check_str; + reps["$PUBLIC_INPUT_INPUT$"] = desc.public_input_columns == 0 ? "" : public_input_input_str; + reps["$VK0$"] = to_hex_string(common_data.vk.constraint_system_with_params_hash); + reps["$VK1$"] = to_hex_string(common_data.vk.fixed_values_commitment); + reps["$PERM_BODY$"] = placeholder_info.use_permutations? perm_arg_body:""; + reps["$PERM_CODE$"] = placeholder_info.use_permutations? perm_arg_str: ""; + reps["$GATE_ARG_PREPARE$"] = gate_arg_prepare_str; + reps["$PERMUTATION_CHUNK_ALPHAS$"] = to_string(placeholder_info.use_permutations? placeholder_info.permutation_poly_amount - 1: 0); + reps["$LOOKUP_CHUNK_ALPHAS$"] = to_string(placeholder_info.use_lookups? placeholder_info.lookup_poly_amount - 1: 0); + reps["$PLACEHOLDER_CHALLENGES_STR$"] = placeholder_challenges_str; + reps["$V_P_INDEX$"] = placeholder_info.use_permutations? to_string(2*permutation_size + 4 + placeholder_info.table_values_num):"0"; + reps["$V_L_INDEX$"] = placeholder_info.use_permutations? to_string(2*permutation_size + 4 + placeholder_info.table_values_num + placeholder_info.permutation_poly_amount + 1):to_string(2*permutation_size + 4 + placeholder_info.table_values_num); + reps["$X_CHALLENGE_POW$"] = x_challenge_pow_str; + + result = replace_all(result, reps); + result = replace_all(result, reps); + return result; + } + + public: + recursive_verifier_generator( + zk::snark::plonk_table_description _desc) : + desc(_desc) {} + + private: + const zk::snark::plonk_table_description desc; + }; + } +} + +#endif // CRYPTO3_RECURSIVE_VERIFIER_GENERATOR_HPP \ No newline at end of file diff --git a/libs/transpiler/include/nil/blueprint/transpiler/table_profiling.hpp b/libs/transpiler/include/nil/blueprint/transpiler/table_profiling.hpp new file mode 100644 index 000000000..5d0fc333f --- /dev/null +++ b/libs/transpiler/include/nil/blueprint/transpiler/table_profiling.hpp @@ -0,0 +1,178 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2021 Mikhail Komarov +// Copyright (c) 2021-2023 Nikita Kaskov +// Copyright (c) 2022-2023 Polina Chernyshova +// Copyright (c) 2022-2023 Elena Tatuzova +// +// 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 PLONK table profiling util. +//---------------------------------------------------------------------------// + +#ifndef CRYPTO3_BLUEPRINT_TABLE_PROFILING_HPP +#define CRYPTO3_BLUEPRINT_TABLE_PROFILING_HPP + +#include + +#include +#include + +namespace nil { + namespace blueprint { + template + void profiling(std::vector column, std::ostream &out = std::cout) { + for (std::size_t index = 0; index < column.size(); index++) { + out << "\t" << column[index].data; + } + } + + template + void profiling(const crypto3::zk::snark::plonk_assignment_table& assignments, std::ostream &out = std::cout) { + + for (std::size_t row_index = 0; row_index < assignments.rows_amount(); row_index++) { + out << "\t" << row_index; + } + out << std::endl; + + for (std::size_t w_index = 0; w_index < ArithmetizationParams::witness_columns; w_index++) { + out << "W" << w_index << ":"; + profiling(assignments.witness(w_index), out); + out << std::endl; + } + + for (std::size_t pi_index = 0; pi_index < ArithmetizationParams::public_input_columns; pi_index++) { + std::cout << "PI" << pi_index << ":"; + profiling(assignments.public_input(pi_index), out); + out << std::endl; + } + + for (std::size_t c_index = 0; c_index < ArithmetizationParams::constant_columns; c_index++) { + out << "C" << c_index << ":"; + profiling(assignments.constant(c_index), out); + out << std::endl; + } + + for (std::size_t s_index = 0; s_index < ArithmetizationParams::selector_columns; s_index++) { + out << "S" << s_index << ":"; + profiling(assignments.selector(s_index), out); + out << std::endl; + } + } + + + template + void profiling_assignment_table( + const crypto3::zk::snark::plonk_assignment_table& assignments, + std::uint32_t usable_rows, + std::ostream &out = std::cout + ) { + out << usable_rows << std::endl; + out << assignments.rows_amount() << std::endl; + + for (std::size_t w_index = 0; w_index < ArithmetizationParams::witness_columns; w_index++) { + profiling(assignments.witness(w_index), out); + out << std::endl; + } + + for (std::size_t pi_index = 0; pi_index < ArithmetizationParams::public_input_columns; pi_index++) { + profiling(assignments.public_input(pi_index), out); + out << std::endl; + } + + for (std::size_t c_index = 0; c_index < ArithmetizationParams::constant_columns; c_index++) { + profiling(assignments.constant(c_index), out); + out << std::endl; + } + + for (std::size_t s_index = 0; s_index < ArithmetizationParams::selector_columns; s_index++) { + profiling(assignments.selector(s_index), out); + out << std::endl; + } + } + + template + std::tuple> + load_assignment_table(std::istream &istr) { + using PrivateTableType = + nil::crypto3::zk::snark::plonk_private_table; + using PublicTableType = + nil::crypto3::zk::snark::plonk_public_table; + using AssignmentTableType = + nil::crypto3::zk::snark::plonk_table; + std::uint32_t usable_rows; + std::uint32_t rows_amount; + + typename PrivateTableType::witnesses_container_type witness; + typename PublicTableType::public_input_container_type public_input; + typename PublicTableType::constant_container_type constant; + typename PublicTableType::selector_container_type selector; + + istr >> usable_rows; + istr >> rows_amount; + + for (std::size_t i = 0; i < witness.size(); i++) { // witnesses.size() == ArithmetizationParams.WitnessColumns + ColumnType column; + typename BlueprintFieldType::integral_type num; + for (std::uint32_t j = 0; j < rows_amount; j++) { + istr >> num; + column.push_back(typename BlueprintFieldType::value_type(num)); + } + witness[i] = column; + } + + for (std::size_t i = 0; i < public_input.size(); i++) { // witnesses.size() == ArithmetizationParams.WitnessColumns + ColumnType column; + typename BlueprintFieldType::integral_type num; + for (std::uint32_t j = 0; j < rows_amount; j++) { + istr >> num; + column.push_back(typename BlueprintFieldType::value_type(num)); + } + public_input[i] = column; + } + + for (std::size_t i = 0; i < constant.size(); i++) { // witnesses.size() == ArithmetizationParams.WitnessColumns + ColumnType column; + typename BlueprintFieldType::integral_type num; + for (std::uint32_t j = 0; j < rows_amount; j++) { + istr >> num; + column.push_back(typename BlueprintFieldType::value_type(num)); + } + constant[i] = column; + } + for (std::size_t i = 0; i < selector.size(); i++) { // witnesses.size() == ArithmetizationParams.WitnessColumns + ColumnType column; + typename BlueprintFieldType::integral_type num; + for (std::uint32_t j = 0; j < rows_amount; j++) { + istr >> num; + column.push_back(typename BlueprintFieldType::value_type(num)); + } + selector[i] = column; + } + return std::make_tuple( + usable_rows, rows_amount, + AssignmentTableType(PrivateTableType(witness), PublicTableType(public_input, constant, selector))); + } + + } // namespace blueprint +} // namespace nil + +#endif // CRYPTO3_BLUEPRINT_TABLE_PROFILING_HPP diff --git a/libs/transpiler/include/nil/blueprint/transpiler/templates/commitment_scheme.hpp b/libs/transpiler/include/nil/blueprint/transpiler/templates/commitment_scheme.hpp new file mode 100644 index 000000000..ee9f03731 --- /dev/null +++ b/libs/transpiler/include/nil/blueprint/transpiler/templates/commitment_scheme.hpp @@ -0,0 +1,531 @@ +#ifndef __MODULAR_COMMITMENT_SCHEME_CONTRACT_TEMPLATE_HPP__ +#define __MODULAR_COMMITMENT_SCHEME_CONTRACT_TEMPLATE_HPP__ + +#include + +namespace nil { + namespace blueprint { + std::string modular_commitment_grinding_check_template = R"( + bytes calldata proof_of_work = blob[blob.length - 4:]; + transcript.update_transcript(tr_state, proof_of_work); + uint256 p_o_w = transcript.get_integral_challenge_be(tr_state, 4); + if (p_o_w & $GRINDING_MASK$ != 0) return false; +)"; + + std::string modular_commitment_library_template = R"( +// SPDX-License-Identifier: Apache-2.0. +//---------------------------------------------------------------------------// +// Copyright (c) 2023 Generated by ZKLLVM-transpiler +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//---------------------------------------------------------------------------// +pragma solidity >=0.8.4; + +import "../../cryptography/transcript.sol"; +import "../../interfaces/modular_commitment.sol"; +// Move away unused structures from types.sol +import "../../types.sol"; +import "../../basic_marshalling.sol"; +import "../../containers/merkle_verifier.sol"; +import "../../algebra/polynomial.sol"; +import "hardhat/console.sol"; + +library modular_commitment_scheme_$TEST_NAME$ { + uint256 constant modulus = $MODULUS$; + uint64 constant batches_num = $BATCHES_NUM$; + uint256 constant r = $R$; + uint256 constant lambda = $LAMBDA$; + uint256 constant D0_size = $D0_SIZE$; + uint256 constant D0_log = $D0_LOG$; + uint256 constant max_degree = $MAX_DEGREE$; + uint256 constant D0_omega = $D0_OMEGA$; + uint256 constant unique_points = $UNIQUE_POINTS$; + uint256 constant omega = $OMEGA$; + uint256 constant _eta = $ETA$; + uint64 constant fixed_batch_size = $FIXED_BATCH_SIZE$; + bytes constant point_ids = hex"$POINTS_IDS$"; // 1 byte -- point id + bytes constant poly_points_num = hex"$POLY_POINTS_NUM$"; // 2 byte lengths + bytes constant poly_ids = hex"$POLY_IDS$"; // 2 byte poly_id 2 byte + + struct commitment_state{ + bytes leaf_data; + uint256 roots_offset; + uint256 query_proof_offset; + uint256 initial_data_offset; + uint256 initial_proof_offset; + uint256 round_proof_offset; + uint256 round_data_offset; + uint256[r] alphas; + uint64[batches_num] batch_sizes; + uint64 poly_num; + uint256 points_num; + uint256 theta; + uint256 x_index; + uint256 x; + uint256 max_batch; + uint256 domain_size; + uint256[] final_polynomial; + uint256 leaf_length; + uint256[2][unique_points+1] denominators; + uint256[unique_points+1] U; + uint256[unique_points] unique_eval_points; + uint256[unique_points+1] theta_factors; + uint256[2] y; + uint256[2] Q; + uint256 j; + uint256 offset; + uint256 interpolant; + uint16[][unique_points] poly_inds; + } + + + function prepare_eval_points(uint256[unique_points] memory result, uint256 xi) internal view { + uint256 inversed_omega = field.inverse_static(omega, modulus); +$POINTS_INITIALIZATION$ + } + + function prepare_Y(bytes calldata blob, uint256 offset, commitment_state memory state) internal pure { + unchecked{ + state.y[0] = 0; + state.y[1] = 0; + for(uint256 cur_point = unique_points; cur_point > 0; ){ + cur_point--; + for(uint256 cur_poly = state.poly_inds[cur_point].length; cur_poly > 0;){ + cur_poly--; + uint256 cur_offset = state.poly_inds[cur_point][cur_poly]; + cur_offset = state.query_proof_offset + cur_offset; + state.Q[0] = mulmod(state.Q[0], state.theta, modulus); + state.Q[1] = mulmod(state.Q[1], state.theta, modulus); + state.Q[0] = addmod(state.Q[0], basic_marshalling.get_uint256_be(blob, cur_offset), modulus); + state.Q[1] = addmod(state.Q[1], basic_marshalling.get_uint256_be(blob, cur_offset + 0x20), modulus); + } + state.Q[0] = addmod(state.Q[0], modulus - state.U[cur_point], modulus); + state.Q[1] = addmod(state.Q[1], modulus - state.U[cur_point], modulus); + state.Q[0] = mulmod(state.Q[0], state.denominators[cur_point][0], modulus); + state.Q[1] = mulmod(state.Q[1], state.denominators[cur_point][1], modulus); + state.Q[0] = mulmod(state.Q[0], state.theta_factors[cur_point], modulus); + state.Q[1] = mulmod(state.Q[1], state.theta_factors[cur_point], modulus); + state.y[0] = addmod(state.y[0], state.Q[0], modulus); + state.y[1] = addmod(state.y[1], state.Q[1], modulus); + state.Q[0] = 0; + state.Q[1] = 0; + } + for( uint256 cur_poly = fixed_batch_size; cur_poly > 0; ){ + cur_poly--; + uint256 cur_offset = cur_poly * 0x40; + cur_offset = state.query_proof_offset + cur_offset; + state.Q[0] = mulmod(state.Q[0], state.theta, modulus); + state.Q[1] = mulmod(state.Q[1], state.theta, modulus); + state.Q[0] = addmod(state.Q[0], basic_marshalling.get_uint256_be(blob, cur_offset), modulus); + state.Q[1] = addmod(state.Q[1], basic_marshalling.get_uint256_be(blob, cur_offset + 0x20), modulus); + } + state.Q[0] = addmod(state.Q[0], modulus - state.U[unique_points], modulus); + state.Q[1] = addmod(state.Q[1], modulus - state.U[unique_points], modulus); + state.Q[0] = mulmod(state.Q[0], state.denominators[unique_points][0], modulus); + state.Q[1] = mulmod(state.Q[1], state.denominators[unique_points][1], modulus); + state.Q[0] = mulmod(state.Q[0], state.theta_factors[unique_points], modulus); + state.Q[1] = mulmod(state.Q[1], state.theta_factors[unique_points], modulus); + state.y[0] = addmod(state.y[0], state.Q[0], modulus); + state.y[1] = addmod(state.y[1], state.Q[1], modulus); + state.Q[0] = 0; + state.Q[1] = 0; + } + } + + function initialize( + bytes32 tr_state_before + ) internal returns(bytes32 tr_state_after){ + types.transcript_data memory tr_state; + tr_state.current_challenge = tr_state_before; + uint256 eta = transcript.get_field_challenge(tr_state, modulus); + require(eta == _eta, "Wrong eta"); + tr_state_after = tr_state.current_challenge; + } + + function copy_memory_pair_and_check(bytes calldata blob, uint256 proof_offset, bytes memory leaf, uint256[2] memory pair) + internal pure returns(bool b){ + uint256 c = pair[0]; + uint256 d = pair[1]; + assembly{ + mstore( + add(leaf, 0x20), + c + ) + mstore( + add(leaf, 0x40), + d + ) + } + if( !merkle_verifier.parse_verify_merkle_proof_bytes_be(blob, proof_offset, leaf, 0x40 )){ + return false; + } else { + return true; + } + } + + function copy_reverted_memory_pair_and_check(bytes calldata blob, uint256 proof_offset, bytes memory leaf, uint256[2] memory pair) + internal pure returns(bool b){ + uint256 c = pair[0]; + uint256 d = pair[1]; + assembly{ + mstore( + add(leaf, 0x20), + d + ) + mstore( + add(leaf, 0x40), + c + ) + } + if( !merkle_verifier.parse_verify_merkle_proof_bytes_be(blob, proof_offset, leaf, 0x40 )){ + return false; + } else { + return true; + } + } + + function copy_pairs_and_check(bytes calldata blob, uint256 offset, bytes memory leaf, uint256 size, uint256 proof_offset) + internal pure returns(bool b){ + unchecked { + uint256 offset2 = 0x20; + for(uint256 k = 0; k < size;){ + assembly{ + mstore( + add(leaf, offset2), + calldataload(add(blob.offset, offset)) + ) + mstore( + add(leaf, add(offset2, 0x20)), + calldataload(add(blob.offset, add(offset, 0x20))) + ) + } + k++; offset2 += 0x40; offset += 0x40; + } + if( !merkle_verifier.parse_verify_merkle_proof_bytes_be(blob, proof_offset, leaf, offset2 - 0x20 )){ + return false; + } else { + return true; + } + } + } + + function copy_reverted_pairs_and_check(bytes calldata blob, uint256 offset, bytes memory leaf, uint256 size, uint256 proof_offset) + internal pure returns(bool){ + unchecked { + uint256 offset2 = 0x20; + for(uint256 k = 0; k < size;){ + assembly{ + mstore( + add(leaf, offset2), + calldataload(add(blob.offset, add(offset, 0x20))) + ) + mstore( + add(leaf, add(offset2, 0x20)), + calldataload(add(blob.offset, offset)) + ) + } + k++; offset2 += 0x40; offset += 0x40; + } + if( !merkle_verifier.parse_verify_merkle_proof_bytes_be(blob, proof_offset, leaf, offset2 - 0x20 )){ + return false; + } else { + return true; + } + } + } + + function colinear_check(uint256 x, uint256[2] memory y, uint256 alpha, uint256 colinear_value) internal pure returns(bool){ + unchecked { + uint256 tmp; + tmp = addmod(y[0], y[1], modulus); + tmp = mulmod(tmp, x, modulus); + tmp = addmod( + tmp, + mulmod( + alpha, + addmod(y[0], modulus-y[1], modulus), + modulus + ), + modulus + ); + uint256 tmp1 = mulmod(colinear_value , 2, modulus); + tmp1 = mulmod(tmp1 , x, modulus); + if( tmp != tmp1 ){ + return false; + } + return true; + } + } + + function prepare_eta_U(uint256 theta) internal pure returns (uint256 result){ +$ETA_POINT_U$ + } + + function verify_eval( + bytes calldata blob, + uint256[5] memory commitments, + uint256 challenge, + bytes32 transcript_state + ) internal view returns (bool){ +unchecked { + types.transcript_data memory tr_state; + tr_state.current_challenge = transcript_state; + commitment_state memory state; + + { + uint256 offset; + + uint256 challenge2 = transcript.get_field_challenge(tr_state, modulus); + if (challenge!= challenge2) { + console.log("Wrong challenge"); + return false; + } + + for(uint8 i = 0; i < batches_num;){ + transcript.update_transcript_b32(tr_state, bytes32(commitments[i])); + i++; + } + state.theta = transcript.get_field_challenge(tr_state, modulus); + + state.points_num = basic_marshalling.get_length(blob, 0x0); + offset = 0x10 + state.points_num * 0x20; + for(uint8 i = 0; i < batches_num;){ + state.batch_sizes[i] = uint64(uint8(blob[offset + 0x1])); + if( state.batch_sizes[i] > state.max_batch ) state.max_batch = state.batch_sizes[i]; + state.poly_num += state.batch_sizes[i]; + i++; offset +=2; + } + + offset += 0x8; + offset += state.poly_num; + state.roots_offset = offset + 0x8; + offset += 0x8; + + for( uint8 i = 0; i < r;){ + transcript.update_transcript_b32(tr_state, bytes32(basic_marshalling.get_uint256_be(blob, offset + 0x8))); + state.alphas[i] = transcript.get_field_challenge(tr_state, modulus); + i++; offset +=40; + } + + $GRINDING_CHECK$ + + offset += 0x8 + r; + state.initial_data_offset = offset + 0x8; + offset += 0x8 + 0x20*basic_marshalling.get_length(blob, offset); + + state.round_data_offset = offset + 0x8; + offset += 0x8 + 0x20*basic_marshalling.get_length(blob, offset); + offset += 0x8; + + state.initial_proof_offset = offset; + for(uint256 i = 0; i < lambda;){ + for(uint256 j = 0; j < batches_num;){ + if(basic_marshalling.get_uint256_be(blob, offset + 0x10) != commitments[j] ) return false; + offset = merkle_verifier.skip_merkle_proof_be(blob, offset); + j++; + } + i++; + } + offset += 0x8; + state.round_proof_offset = offset; + + for(uint256 i = 0; i < lambda;){ + for(uint256 j = 0; j < r;){ + if(basic_marshalling.get_uint256_be(blob, offset + 0x10) != basic_marshalling.get_uint256_be(blob, state.roots_offset + j * 40 + 0x8) ) return false; + offset = merkle_verifier.skip_merkle_proof_be(blob, offset); + j++; + } + i++; + } + + state.final_polynomial = new uint256[](basic_marshalling.get_length(blob, offset)); + offset += 0x8; + for (uint256 i = 0; i < state.final_polynomial.length;) { + state.final_polynomial[i] = basic_marshalling.get_uint256_be(blob, offset); + i++; offset+=0x20; + } + } + if( state.final_polynomial.length > (( 1 << (field.log2(max_degree + 1) - r + 1) ) ) ){ + console.log("Wrong final poly degree"); + return false; + } + + prepare_eval_points(state.unique_eval_points, challenge); + // Prepare U + { + uint256 sum; + + for(uint256 i = 0; i < state.unique_eval_points.length;){ + state.theta_factors[i] = field.pow_small(state.theta, sum, modulus); + sum += (uint256(uint8(poly_points_num[2*i])) << 8) + uint256(uint8(poly_points_num[2*i + 1])); + i++; + } + state.theta_factors[unique_points] = field.pow_small(state.theta, sum, modulus); + + uint256 off = point_ids.length * 0x20 - 0x18; + for(uint256 i = 0; i < point_ids.length;){ + uint256 p = uint256(uint8(point_ids[point_ids.length - i - 1])); + state.U[p] = mulmod(state.U[p], state.theta, modulus); + state.U[p] = addmod(state.U[p], basic_marshalling.get_uint256_be(blob, off), modulus); + off -= 0x20; + i++; + } + state.U[unique_points] = prepare_eta_U(state.theta); + } + + uint64 cur = 0; + for(uint64 p = 0; p < unique_points; p++){ + state.poly_inds[p] = new uint16[]((uint16(uint8(poly_points_num[2*p])) << 8) + uint16(uint8(poly_points_num[2*p + 1]))); + for(uint64 i = 0; i < state.poly_inds[p].length; i++){ + state.poly_inds[p][i] = (uint16(uint8(poly_ids[cur])) << 8) + uint16(uint8(poly_ids[cur + 1])); + cur+=2; + } + } + + state.leaf_data = new bytes(state.max_batch * 0x40 + 0x40); + for(uint64 i = 0; i < lambda;){ + // Initial proofs + state.query_proof_offset = state.initial_data_offset; + state.x = transcript.get_field_challenge(tr_state, modulus); + state.x = field.pow_small(state.x, (modulus-1) / D0_size , modulus); + state.x_index = 0; + for( uint64 j = 0; j < D0_log - 1; j++){ + state.x_index += (uint64(1 - uint8(blob[state.initial_proof_offset + 0x47 + 0x38 * j])) << j ); + } + { + uint256 tmp = field.pow_small(D0_omega, state.x_index, modulus); + if( tmp != state.x ){ + state.x_index += D0_size/2; + tmp = modulus - tmp; + if( tmp != state.x ){ + console.log("Wrong x_index"); + return false; + } + } + } + state.domain_size = D0_size >> 1; + for(uint64 j = 0; j < batches_num;){ + if(!copy_pairs_and_check(blob, state.initial_data_offset, state.leaf_data, state.batch_sizes[j], state.initial_proof_offset)){ + console.log("Error in initial mekle proof"); + return false; + } + state.leaf_length = state.batch_sizes[j] * 0x40; + state.initial_data_offset += state.batch_sizes[j] * 0x40; + state.initial_proof_offset = merkle_verifier.skip_merkle_proof_be(blob, state.initial_proof_offset); + j++; + } + for( uint64 p = 0; p < unique_points; p++){ + state.denominators[p][0] = addmod(state.x, modulus - state.unique_eval_points[p], modulus); + state.denominators[p][1] = addmod(modulus - state.x, modulus - state.unique_eval_points[p], modulus); + state.denominators[p][0] = field.inverse_static(state.denominators[p][0], modulus); + state.denominators[p][1] = field.inverse_static(state.denominators[p][1], modulus); + } + state.denominators[unique_points][0] = addmod(state.x, modulus - _eta, modulus); + state.denominators[unique_points][1] = addmod(modulus - state.x, modulus - _eta, modulus); + state.denominators[unique_points][0] = field.inverse_static(state.denominators[unique_points][0], modulus); + state.denominators[unique_points][1] = field.inverse_static(state.denominators[unique_points][1], modulus); + + if(state.x_index >= state.domain_size){ + for( uint64 p = 0; p < unique_points + 1; p++ ){ + uint256 tmp; + tmp = state.denominators[p][0]; + state.denominators[p][0] = state.denominators[p][1]; + state.denominators[p][1] = tmp; + } + } + + prepare_Y(blob, state.query_proof_offset, state); + if( !copy_memory_pair_and_check(blob, state.round_proof_offset, state.leaf_data, state.y) ){ + console.log("Not validated!"); + return false; + } + if( state.x_index % (state.domain_size) < state.domain_size/2){ + state.interpolant = basic_marshalling.get_uint256_be(blob,state.round_data_offset); + } else { + state.interpolant = basic_marshalling.get_uint256_be(blob,state.round_data_offset + 0x20); + } + if( state.x_index < state.domain_size ) { + if( !colinear_check(state.x, state.y, state.alphas[0], state.interpolant) ){ + console.log("Colinear check failed"); + return false; + } + } else { + if( !colinear_check(modulus - state.x, state.y, state.alphas[0], state.interpolant) ){ + console.log("Colinear check failed"); + return false; + } + } + + state.round_proof_offset = merkle_verifier.skip_merkle_proof_be(blob, state.round_proof_offset); + for(state.j = 1; state.j < r;){ + state.x_index %= state.domain_size; + state.x = mulmod(state.x, state.x, modulus); + state.domain_size >>= 1; + if(!copy_pairs_and_check(blob, state.round_data_offset, state.leaf_data, 1, state.round_proof_offset)) { + console.log("Error in round mekle proof"); + return false; + } + state.y[0] = basic_marshalling.get_uint256_be(blob, state.round_data_offset); + state.y[1] = basic_marshalling.get_uint256_be(blob, state.round_data_offset + 0x20); + if( state.x_index % (state.domain_size) < state.domain_size/2){ + state.interpolant = basic_marshalling.get_uint256_be(blob,state.round_data_offset + 0x40); + } else { + state.interpolant = basic_marshalling.get_uint256_be(blob,state.round_data_offset + 0x60); + } + if( state.x_index < state.domain_size ) { + if( !colinear_check(state.x, state.y, state.alphas[state.j], state.interpolant) ){ + console.log("Round colinear check failed", state.j); + return false; + } + } else { + if( !colinear_check(modulus - state.x, state.y, state.alphas[state.j], state.interpolant) ){ + console.log("Round colinear check failed", state.j); + return false; + } + } + state.j++; state.round_data_offset += 0x40; + state.round_proof_offset = merkle_verifier.skip_merkle_proof_be(blob, state.round_proof_offset); + } + + state.x = mulmod(state.x, state.x, modulus); + state.x_index = state.x_index%state.domain_size; + if( state.x_index % state.domain_size/2 < state.domain_size/4 ){ + state.y[0] = basic_marshalling.get_uint256_be(blob, state.round_data_offset); + state.y[1] = basic_marshalling.get_uint256_be(blob, state.round_data_offset + 0x20); + } else { + state.y[0] = basic_marshalling.get_uint256_be(blob, state.round_data_offset + 0x20); + state.y[1] = basic_marshalling.get_uint256_be(blob, state.round_data_offset); + } + + if(polynomial.evaluate(state.final_polynomial, state.x, modulus) != state.y[0]) { + console.log("Wrong final poly check", polynomial.evaluate(state.final_polynomial, state.x, modulus)); + console.log(state.y[0]); +// return false; + } + if(polynomial.evaluate(state.final_polynomial, modulus - state.x, modulus) != state.y[1]){ + console.log("Wrong final poly check",polynomial.evaluate(state.final_polynomial, modulus-state.x, modulus)); + console.log(state.y[1]); +// return false; + } + state.round_data_offset += 0x40; + i++; + } + return true; +} + } +} + )"; + } +} + +#endif //__MODULAR_CONTRACT_TEMPLATE_HPP__ diff --git a/libs/transpiler/include/nil/blueprint/transpiler/templates/external_gate.hpp b/libs/transpiler/include/nil/blueprint/transpiler/templates/external_gate.hpp new file mode 100644 index 000000000..356dca8d5 --- /dev/null +++ b/libs/transpiler/include/nil/blueprint/transpiler/templates/external_gate.hpp @@ -0,0 +1,69 @@ +#ifndef __MODULAR_EXTERNAL_GATE_ARGUMENT_TEMPLATE_HPP__ +#define __MODULAR_EXTERNAL_GATE_ARGUMENT_TEMPLATE_HPP__ + +#include + +namespace nil { + namespace blueprint { + std::string gate_evaluation_template = R"( + function evaluate_gate_$GATE_ID$_be( + bytes calldata blob, + uint256 theta, + uint256 theta_acc + ) external pure returns (uint256 F, uint256) { + uint256 sum; + uint256 gate; + uint256 prod; + uint256 x; + +$GATE_ASSEMBLY_CODE$ + + return( F, theta_acc ); + } +)"; + std::string modular_external_gate_library_template = R"( +// SPDX-License-Identifier: Apache-2.0. +//---------------------------------------------------------------------------// +// Copyright (c) 2023 -- Generated by zkllvm-transpiler +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//---------------------------------------------------------------------------// +pragma solidity >=0.8.4; + +import "../../../contracts/basic_marshalling.sol"; +$UTILS_LIBRARY_IMPORT$ + +library gate_$TEST_NAME$_$GATE_LIB_ID${ + uint256 constant modulus = $MODULUS$; + + function evaluate_constraint_series_be( + bytes calldata blob, + uint256 theta, + uint256 theta_acc + ) external pure returns (uint256 F, uint256) { + uint256 sum; + uint256 gate; + uint256 prod; + uint256 x; + +$CONSTRAINT_SERIES_CODE$ + + return( F, theta_acc ); + } + +} + )"; + } +} + +#endif //__EXTERNAL_GATE_ARGUMENT_TEMPLATE_HPP__ diff --git a/libs/transpiler/include/nil/blueprint/transpiler/templates/external_lookup.hpp b/libs/transpiler/include/nil/blueprint/transpiler/templates/external_lookup.hpp new file mode 100644 index 000000000..0f1238d02 --- /dev/null +++ b/libs/transpiler/include/nil/blueprint/transpiler/templates/external_lookup.hpp @@ -0,0 +1,59 @@ +#ifndef __MODULAR_EXTERNAL_LOOKUP_ARGUMENT_TEMPLATE_HPP__ +#define __MODULAR_EXTERNAL_LOOKUP_ARGUMENT_TEMPLATE_HPP__ + +#include + +namespace nil { + namespace blueprint { + std::string lookup_evaluation_template = R"( + function evaluate_lookup_$LOOKUP_ID$_be( + bytes calldata blob, + uint256 theta, + uint256 theta_acc, + uint256 beta, + uint256 gamma + ) external pure returns (uint256 g, uint256) { + uint256 l; + uint256 selector_value; + uint256 sum; + uint256 prod; + + g = 1; + +$LOOKUP_ASSEMBLY_CODE$ + + return( g, theta_acc ); + } +)"; + std::string modular_external_lookup_library_template = R"( +// SPDX-License-Identifier: Apache-2.0. +//---------------------------------------------------------------------------// +// Copyright (c) 2023 -- Generated by zkllvm-transpiler +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//---------------------------------------------------------------------------// +pragma solidity >=0.8.4; + +import "../../../contracts/basic_marshalling.sol"; + +library lookup_$TEST_NAME$_$LOOKUP_LIB_ID${ + uint256 constant modulus = $MODULUS$; + +$LOOKUP_COMPUTATION_CODE$ + +} + )"; + } +} + +#endif //__EXTERNAL_GATE_ARGUMENT_TEMPLATE_HPP__ diff --git a/libs/transpiler/include/nil/blueprint/transpiler/templates/gate_argument.hpp b/libs/transpiler/include/nil/blueprint/transpiler/templates/gate_argument.hpp new file mode 100644 index 000000000..44747c990 --- /dev/null +++ b/libs/transpiler/include/nil/blueprint/transpiler/templates/gate_argument.hpp @@ -0,0 +1,55 @@ +#ifndef __MODULAR_GATE_ARGUMENT_CONTRACT_TEMPLATE_HPP__ +#define __MODULAR_GATE_ARGUMENT_CONTRACT_TEMPLATE_HPP__ + +#include + +namespace nil { + namespace blueprint { + std::string gate_call_template = + "\t\t(eval, theta_acc) = gate_$TEST_NAME$_$GATE_LIB_ID$.evaluate_constraint_series_be( blob, theta, theta_acc);\n" + "\t\tF = addmod(F, eval, modulus);\n"; + + std::string modular_gate_argument_library_template = R"( +// SPDX-License-Identifier: Apache-2.0. +//---------------------------------------------------------------------------// +// Copyright (c) 2023 Generated by ZKLLVM-transpiler +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//---------------------------------------------------------------------------// +pragma solidity >=0.8.4; + +import "../../types.sol"; +import "../../basic_marshalling.sol"; +import "../../interfaces/modular_gate_argument.sol"; +import "hardhat/console.sol"; +$GATE_INCLUDES$ + +contract modular_gate_argument_$TEST_NAME$ is IGateArgument{ + uint256 constant modulus = $MODULUS$; + + // Append commitments + function verify( + bytes calldata blob, + uint256 theta + ) external view returns (uint256 F){ + uint256 theta_acc = 1; + uint256 eval; + uint256 x; + +$GATE_ARGUMENT_COMPUTATION$ + } +} )"; + } +} + +#endif //__MODULAR_CONTRACT_TEMPLATE_HPP__ diff --git a/libs/transpiler/include/nil/blueprint/transpiler/templates/lookup_argument.hpp b/libs/transpiler/include/nil/blueprint/transpiler/templates/lookup_argument.hpp new file mode 100644 index 000000000..c6d068d36 --- /dev/null +++ b/libs/transpiler/include/nil/blueprint/transpiler/templates/lookup_argument.hpp @@ -0,0 +1,200 @@ +#ifndef __MODULAR_LOOKUP_ARGUMENT_CONTRACT_TEMPLATE_HPP__ +#define __MODULAR_LOOKUP_ARGUMENT_CONTRACT_TEMPLATE_HPP__ + +#include + +namespace nil { + namespace blueprint { + std::string lookup_call_template = + "\t\t\t(l, state.theta_acc) = lookup_$TEST_NAME$_$LOOKUP_LIB_ID$.evaluate_lookup_$LOOKUP_ID$_be( blob, state.theta, state.theta_acc, state.beta, state.gamma );\n\t\t\tstate.g = mulmod(state.g, l, modulus);\n" ; + + std::string modular_dummy_lookup_argument_library_template = R"( +// SPDX-License-Identifier: Apache-2.0. +//---------------------------------------------------------------------------// +// Copyright (c) 2023 Generated by ZKLLVM-transpiler +// +// Licensed under the +// License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//---------------------------------------------------------------------------// +pragma solidity >=0.8.4; + +library modular_lookup_argument_$TEST_NAME${ +} +)"; + + std::string modular_lookup_argument_library_template = R"( +// SPDX-License-Identifier: Apache-2.0. +//---------------------------------------------------------------------------// +// Copyright (c) 2023 Generated by ZKLLVM-transpiler +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//---------------------------------------------------------------------------// +pragma solidity >=0.8.4; + +import "../../cryptography/transcript.sol"; +// Move away unused structures from types.sol +import "../../types.sol"; +import "../../basic_marshalling.sol"; +import "../../cryptography/transcript.sol"; +import "../../interfaces/modular_lookup_argument.sol"; +$LOOKUP_INCLUDES$ +import "hardhat/console.sol"; + +contract modular_lookup_argument_$TEST_NAME$ is ILookupArgument{ +//library modular_lookup_argument_$TEST_NAME${ + uint256 constant modulus = $MODULUS$; + uint8 constant tables = 1; + uint8 constant sorted_columns = $SORTED_COLUMNS_NUMBER$; + uint8 constant lookup_options_num = $LOOKUP_OPTIONS_NUMBER$; + uint8 constant lookup_constraints_num = $LOOKUP_CONSTRAINTS_NUMBER$; + + + struct lookup_state{ + uint256 theta; + uint256 beta; + uint256 gamma; + uint256 factor; + uint256 V_L_value; + uint256 V_L_shifted_value; + uint256 q_last; + uint256 q_blind; + uint256 mask; + uint256 shifted_mask; + uint256 selector_value; + uint256 shifted_selector_value; + uint256 theta_acc; + uint256 g; + uint256 h; + uint256 l_shifted; + } + + function verify( + bytes calldata zvalues, // Table values and permutations' values + bytes calldata sorted, // Sorted batch values + uint256 lookup_commitment, + uint256 l0, + bytes32 tr_state_before // It's better than transfer all random values + ) external view returns (uint256[4] memory F, bytes32 tr_state_after){ + bytes calldata blob = zvalues[0x80:]; + lookup_state memory state; + state.V_L_value = basic_marshalling.get_uint256_be(zvalues, 0x80 + $V_L_OFFSET$); + state.V_L_shifted_value = basic_marshalling.get_uint256_be(zvalues, 0x80 + $V_L_OFFSET$ + 0x20); + state.q_last = basic_marshalling.get_uint256_be(zvalues, 0x0); + state.q_blind = basic_marshalling.get_uint256_be(zvalues, 0x40); + state.mask = addmod(1, modulus - addmod(state.q_last , state.q_blind, modulus), modulus); + F[2] = state.mask; + + state.shifted_mask = addmod( + 1, + modulus - addmod(basic_marshalling.get_uint256_be(zvalues,0x20) , basic_marshalling.get_uint256_be(zvalues, 0x60), modulus), + modulus + ); + + types.transcript_data memory tr_state; + tr_state.current_challenge = tr_state_before; + { + state.theta = transcript.get_field_challenge(tr_state, modulus); //theta + uint256 l; + state.g = 1; + state.h = 1; + + transcript.update_transcript_b32(tr_state, bytes32(lookup_commitment)); + state.beta = transcript.get_field_challenge(tr_state, modulus); //beta + state.gamma = transcript.get_field_challenge(tr_state, modulus); //gamma + state.factor = mulmod(addmod(1, state.beta, modulus), state.gamma, modulus); +$LOOKUP_ARGUMENT_COMPUTATION$ + } + { + for(uint64 k = 0; k < $SORTED_COLUMNS_NUMBER$;){ + state.mask = basic_marshalling.get_uint256_be(sorted, k*0x60); + state.shifted_mask = basic_marshalling.get_uint256_be(sorted, k*0x60 + 0x20); + state.h = mulmod( + state.h, + addmod( + addmod( + state.factor, + state.mask, + modulus + ), + mulmod(state.beta, state.shifted_mask , modulus), + modulus + ), + modulus + ); + unchecked{k++;} + } + } + + F[0] = mulmod( + l0, + addmod(1, modulus - state.V_L_value, modulus), + modulus + ); + F[1] = mulmod( + mulmod(state.q_last, state.V_L_value, modulus), + addmod(state.V_L_value, modulus-1, modulus), + modulus + ); + { + F[2] = mulmod( + F[2], + addmod( + mulmod(state.h, state.V_L_shifted_value, modulus), + modulus - mulmod(state.V_L_value, state.g, modulus), + modulus + ), + modulus + ); + } + { + for(uint64 i = 0; i < sorted_columns - 1;){ + state.beta = basic_marshalling.get_uint256_be(sorted, (i+1)*0x60); + state.gamma = modulus - basic_marshalling.get_uint256_be(sorted, (i)*0x60 + 0x40); + F[3] = addmod( + F[3], + mulmod( + mulmod( + transcript.get_field_challenge(tr_state, modulus), //alpha + l0, + modulus + ), + addmod( + state.beta, + state.gamma, + modulus + ), + modulus + ), + modulus + ); + unchecked{i++;} + } + } + tr_state_after = tr_state.current_challenge; + } +} +)"; + } +} + +#endif //__MODULAR_CONTRACT_TEMPLATE_HPP__ diff --git a/libs/transpiler/include/nil/blueprint/transpiler/templates/lookup_argument_chunked.hpp b/libs/transpiler/include/nil/blueprint/transpiler/templates/lookup_argument_chunked.hpp new file mode 100644 index 000000000..ed9be037f --- /dev/null +++ b/libs/transpiler/include/nil/blueprint/transpiler/templates/lookup_argument_chunked.hpp @@ -0,0 +1,174 @@ +#ifndef __MODULAR_LOOKUP_ARGUMENT_CHUNKED_CONTRACT_TEMPLATE_HPP__ +#define __MODULAR_LOOKUP_ARGUMENT_CHUNKED_CONTRACT_TEMPLATE_HPP__ + +#include + +namespace nil { + namespace blueprint { + + std::string modular_lookup_argument_chunked_library_template = R"( +// SPDX-License-Identifier: Apache-2.0. +//---------------------------------------------------------------------------// +// Copyright (c) 2023 Generated by ZKLLVM-transpiler +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//---------------------------------------------------------------------------// +pragma solidity >=0.8.4; + +import "../../cryptography/transcript.sol"; +// Move away unused structures from types.sol +import "../../types.sol"; +import "../../basic_marshalling.sol"; +import "../../cryptography/transcript.sol"; +import "../../interfaces/modular_lookup_argument.sol"; +$LOOKUP_INCLUDES$ +import "hardhat/console.sol"; + +contract modular_lookup_argument_$TEST_NAME$ is ILookupArgument{ +//library modular_lookup_argument_$TEST_NAME${ + uint256 constant modulus = $MODULUS$; + uint8 constant tables = 1; + uint8 constant sorted_columns = $SORTED_COLUMNS_NUMBER$; + uint8 constant lookup_options_num = $LOOKUP_OPTIONS_NUMBER$; + uint8 constant lookup_constraints_num = $LOOKUP_CONSTRAINTS_NUMBER$; + + + struct lookup_state{ + uint256 theta; + uint256 beta; + uint256 gamma; + uint256 factor; + uint256 V_L_value; + uint256 V_L_shifted_value; + uint256 q_last; + uint256 q_blind; + uint256 mask; + uint256 shifted_mask; + uint256 selector_value; + uint256 shifted_selector_value; + uint256 theta_acc; + uint256 g; + uint256 h; + uint256 l_shifted; + } + + function verify( + bytes calldata zvalues, // Table values and permutations' values + bytes calldata sorted, // Sorted batch values + uint256 lookup_commitment, + uint256 l0, + bytes32 tr_state_before // It's better than transfer all random values + ) external view returns (uint256[4] memory F, bytes32 tr_state_after){ + bytes calldata blob = zvalues[0x80:]; + lookup_state memory state; + state.V_L_value = basic_marshalling.get_uint256_be(zvalues, 0x80 + $V_L_OFFSET$); + state.V_L_shifted_value = basic_marshalling.get_uint256_be(zvalues, 0x80 + $V_L_OFFSET$ + 0x40); + state.q_last = basic_marshalling.get_uint256_be(zvalues, 0x0); + state.q_blind = basic_marshalling.get_uint256_be(zvalues, 0x40); + state.mask = addmod(1, modulus - addmod(state.q_last , state.q_blind, modulus), modulus); + F[2] = state.mask; + + state.shifted_mask = addmod( + 1, + modulus - addmod(basic_marshalling.get_uint256_be(zvalues,0x20) , basic_marshalling.get_uint256_be(zvalues, 0x60), modulus), + modulus + ); + + types.transcript_data memory tr_state; + tr_state.current_challenge = tr_state_before; + { + state.theta = transcript.get_field_challenge(tr_state, modulus); //theta + uint256 l; + state.g = 1; + state.h = 1; + + transcript.update_transcript_b32(tr_state, bytes32(lookup_commitment)); + state.beta = transcript.get_field_challenge(tr_state, modulus); //beta + state.gamma = transcript.get_field_challenge(tr_state, modulus); //gamma + state.factor = mulmod(addmod(1, state.beta, modulus), state.gamma, modulus); +$LOOKUP_ARGUMENT_COMPUTATION$ + } + { + for(uint64 k = 0; k < $SORTED_COLUMNS_NUMBER$;){ + state.mask = basic_marshalling.get_uint256_be(sorted, k*0x60); + state.shifted_mask = basic_marshalling.get_uint256_be(sorted, k*0x60 + 0x20); + state.h = mulmod( + state.h, + addmod( + addmod( + state.factor, + state.mask, + modulus + ), + mulmod(state.beta, state.shifted_mask , modulus), + modulus + ), + modulus + ); + unchecked{k++;} + } + } + + F[0] = mulmod( + l0, + addmod(1, modulus - state.V_L_value, modulus), + modulus + ); + F[1] = mulmod( + mulmod(state.q_last, state.V_L_value, modulus), + addmod(state.V_L_value, modulus-1, modulus), + modulus + ); + { + F[2] = mulmod( + F[2], + addmod( + mulmod(state.h, state.V_L_shifted_value, modulus), + modulus - mulmod(state.V_L_value, state.g, modulus), + modulus + ), + modulus + ); + } + { + for(uint64 i = 0; i < sorted_columns - 1;){ + state.beta = basic_marshalling.get_uint256_be(sorted, (i+1)*0x60); + state.gamma = modulus - basic_marshalling.get_uint256_be(sorted, (i)*0x60 + 0x40); + F[3] = addmod( + F[3], + mulmod( + mulmod( + transcript.get_field_challenge(tr_state, modulus), //alpha + l0, + modulus + ), + addmod( + state.beta, + state.gamma, + modulus + ), + modulus + ), + modulus + ); + unchecked{i++;} + } + } + tr_state_after = tr_state.current_challenge; + } +} +)"; + } +} + +#endif //__MODULAR_CONTRACT_TEMPLATE_HPP__ diff --git a/libs/transpiler/include/nil/blueprint/transpiler/templates/modular_verifier.hpp b/libs/transpiler/include/nil/blueprint/transpiler/templates/modular_verifier.hpp new file mode 100644 index 000000000..3a92bc19b --- /dev/null +++ b/libs/transpiler/include/nil/blueprint/transpiler/templates/modular_verifier.hpp @@ -0,0 +1,290 @@ +#ifndef __MODULAR_VERIFIER_CONTRACT_TEMPLATE_HPP__ +#define __MODULAR_VERIFIER_CONTRACT_TEMPLATE_HPP__ + +#include + +namespace nil { + namespace blueprint { + std::string lookup_library_call = R"( + { + uint256 lookup_offset = $LOOKUP_OFFSET$; + uint256[4] memory lookup_argument; + uint256 lookup_commitment = basic_marshalling.get_uint256_be(blob, $SORTED_COMMITMENT_OFFSET$); + ILookupArgument lookup_contract = ILookupArgument(_lookup_argument_address); + (lookup_argument, tr_state.current_challenge) = lookup_contract.verify( + blob[special_selectors_offset: table_offset + quotient_offset], + blob[lookup_offset:lookup_offset + sorted_columns * 0x60], + lookup_commitment, + state.l0, + tr_state.current_challenge + ); + state.F[3] = lookup_argument[0]; + state.F[4] = lookup_argument[1]; + state.F[5] = lookup_argument[2]; + state.F[6] = lookup_argument[3]; + } + )"; + + std::string permutation_call = R"( + { + uint256[3] memory permutation_argument; + (permutation_argument, tr_state.current_challenge) = modular_permutation_argument_$TEST_NAME$.verify( + blob[z_offset:quotient_offset], + state.l0, + tr_state.current_challenge + ); + state.F[0] = permutation_argument[0]; + state.F[1] = permutation_argument[1]; + state.F[2] = permutation_argument[2]; + } + )"; + + std::string modular_verifier_template = R"( +// SPDX-License-Identifier: Apache-2.0. +//---------------------------------------------------------------------------// +// Copyright (c) Generated by zkllvm-transpiler +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//---------------------------------------------------------------------------// +pragma solidity >=0.8.4; + +import "../../cryptography/transcript.sol"; +// Move away unused structures from types.sol +import "../../types.sol"; +import "../../basic_marshalling.sol"; +import "../../interfaces/modular_verifier.sol"; +import "./commitment.sol"; +import "./gate_argument.sol"; +import "./lookup_argument.sol"; +import "./permutation_argument.sol"; +import "hardhat/console.sol"; +import "../../algebra/field.sol"; + +contract modular_verifier_$TEST_NAME$ is IModularVerifier{ + uint256 constant modulus = $MODULUS$; + bytes32 constant vk1 = bytes32($VERIFICATION_KEY1$); + bytes32 constant vk2 = bytes32($VERIFICATION_KEY2$); + bytes32 transcript_state; + address _gate_argument_address; + address _permutation_argument_address; + address _lookup_argument_address; + address _commitment_contract_address; + uint64 constant sorted_columns = $SORTED_COLUMNS_NUMBER$; + uint64 constant f_parts = 8; // Individually on parts + uint64 constant z_offset = $Z_OFFSET$; + uint64 constant table_offset = $TABLE_OFFSET$; + uint64 constant special_selectors_offset = $SPECIAL_SELECTORS_OFFSET$; + uint64 constant table_end_offset = $TABLE_END_OFFSET$; + uint64 constant quotient_offset = $QUOTIENT_OFFSET$; + uint64 constant rows_amount = $ROWS_AMOUNT$; + uint256 constant omega = $OMEGA$; + uint64 constant quotient_size = $QUOTIENT_SIZE$; + + function initialize( +// address permutation_argument_address, + address lookup_argument_address, + address gate_argument_address, + address commitment_contract_address + ) public{ + types.transcript_data memory tr_state; + transcript.init_transcript(tr_state, hex""); + transcript.update_transcript_b32(tr_state, vk1); + transcript.update_transcript_b32(tr_state, vk2); + +// _permutation_argument_address = permutation_argument_address; + _lookup_argument_address = lookup_argument_address; + _gate_argument_address = gate_argument_address; + _commitment_contract_address = commitment_contract_address; + +// ICommitmentScheme commitment_scheme = ICommitmentScheme(commitment_contract_address); +// tr_state.current_challenge = commitment_scheme.initialize(tr_state.current_challenge); + tr_state.current_challenge = modular_commitment_scheme_$TEST_NAME$.initialize(tr_state.current_challenge); + transcript_state = tr_state.current_challenge; + } + + struct verifier_state{ + uint256 xi; + uint256 Z_at_xi; + uint256 l0; + uint256[f_parts] F; + bool b; + } + + // Public input columns + function public_input_direct(bytes calldata blob, uint256[] calldata public_input, verifier_state memory state) internal view + returns (bool check){ + check = true; + + uint256 result = 0; + uint256 Omega = 1; + + for(uint256 i = 0; i < public_input.length;){ + if( public_input[i] != 0){ + uint256 L = mulmod( + Omega, + field.inverse_static( + addmod(state.xi, modulus - Omega, modulus), + modulus + ), + modulus + ); + + result = addmod( + result, + mulmod( + public_input[i], L, modulus + ), + modulus + ); + } + Omega = mulmod(Omega, omega, modulus); + unchecked{i++;} + } + result = mulmod( + result, addmod(field.pow_small(state.xi, rows_amount, modulus), modulus - 1, modulus), modulus + ); + result = mulmod(result, field.inverse_static(rows_amount, modulus), modulus); + + // Input is proof_map.eval_proof_combined_value_offset + if( result != basic_marshalling.get_uint256_be( + blob, $PUBLIC_INPUT_OFFSET$ + )) check = false; + } + + function verify( + bytes calldata blob, + uint256[] calldata public_input + ) public returns (bool result) { + verifier_state memory state; + state.b = true; + state.xi = basic_marshalling.get_uint256_be(blob, $EVAL_PROOF_OFFSET$); + state.Z_at_xi = addmod(field.pow_small(state.xi, rows_amount, modulus), modulus-1, modulus); + state.l0 = mulmod( + state.Z_at_xi, + field.inverse_static(mulmod(addmod(state.xi, modulus - 1, modulus), rows_amount, modulus), modulus), + modulus + ); + + //0. Direct public input check + if(public_input.length > 0) { + if (!public_input_direct(blob[$TABLE_OFFSET$:$TABLE_END_OFFSET$], public_input, state)) { + emit WrongPublicInput(); + state.b = false; + } + } + + //1. Init transcript + types.transcript_data memory tr_state; + tr_state.current_challenge = transcript_state; + + { + //2. Push variable_values commitment to transcript + transcript.update_transcript_b32_by_offset_calldata(tr_state, blob, 0x9); + + //3. Permutation argument + $PERMUTATION_ARGUMENT_CALL$ + } + //4. Lookup library call + $LOOKUP_LIBRARY_CALL$ + + //5. Push permutation batch to transcript + $PERMUTATION_BATCH_TRANSCRIPT_PUSH$ + { + //6. Gate argument + IGateArgument modular_gate_argument = IGateArgument(_gate_argument_address); + uint256 theta = transcript.get_field_challenge(tr_state, modulus); + + state.F[7] = modular_gate_argument.verify(blob[table_offset:table_end_offset], theta); + state.F[7] = mulmod( + state.F[7], + addmod( + 1, + modulus - addmod( + basic_marshalling.get_uint256_be(blob, special_selectors_offset), + basic_marshalling.get_uint256_be(blob, special_selectors_offset + 0x40), + modulus + ), + modulus + ), + modulus + ); +// console.log("F[0] = ", state.F[0]); +// console.log("F[1] = ", state.F[1]); +// console.log("F[2] = ", state.F[2]); +// console.log("F[3] = ", state.F[3]); +// console.log("F[4] = ", state.F[4]); +// console.log("F[5] = ", state.F[5]); +// console.log("F[6] = ", state.F[6]); +// console.log("F[7] = ", state.F[7]); + } + + // No public input gate + + uint256 F_consolidated; + { + //7. Push quotient to transcript + for( uint8 i = 0; i < f_parts;){ + uint256 alpha = transcript.get_field_challenge(tr_state, modulus); + F_consolidated = addmod(F_consolidated, mulmod(state.F[i], alpha, modulus), modulus); + unchecked{i++;} + } + + transcript.update_transcript_b32_by_offset_calldata(tr_state, blob, $QUOTIENT_COMMITMENT_OFFSET$); + } + + //8. Commitment scheme verify_eval + { +// ICommitmentScheme commitment_scheme = ICommitmentScheme(_commitment_contract_address); + uint256[5] memory commitments; + commitments[0] = uint256(vk2); + for(uint16 i = 1; i < $BATCHES_NUM$;){ + commitments[i] = basic_marshalling.get_uint256_be(blob, 0x9 + (i-1)*(0x28)); + unchecked{i++;} + } + if(!modular_commitment_scheme_$TEST_NAME$.verify_eval( + blob[z_offset - 0x8:], commitments, state.xi, tr_state.current_challenge + )) { + emit WrongCommitment(); + state.b = false; + } + } + + //9. Final check + { + uint256 T_consolidated; + uint256 factor = 1; + for(uint64 i = 0; i < quotient_size;){ + T_consolidated = addmod( + T_consolidated, + mulmod(basic_marshalling.get_uint256_be(blob, table_offset + quotient_offset + i *0x20), factor, modulus), + modulus + ); + factor = mulmod(factor, state.Z_at_xi + 1, modulus); + unchecked{i++;} + } + if( F_consolidated != mulmod(T_consolidated, state.Z_at_xi, modulus) ) { + emit ConstraintSystemNotSatisfied(); + state.b = false; + } + } + + emit VerificationResult(state.b); + + result = state.b; + } +} + )"; + } +} + +#endif //__MODULAR_CONTRACT_TEMPLATE_HPP__ diff --git a/libs/transpiler/include/nil/blueprint/transpiler/templates/permutation_argument.hpp b/libs/transpiler/include/nil/blueprint/transpiler/templates/permutation_argument.hpp new file mode 100644 index 000000000..53d61727a --- /dev/null +++ b/libs/transpiler/include/nil/blueprint/transpiler/templates/permutation_argument.hpp @@ -0,0 +1,121 @@ +#ifndef __MODULAR_PERMUTATION_ARGUMENT_CONTRACT_TEMPLATE_HPP__ +#define __MODULAR_PERMUTATION_ARGUMENT_CONTRACT_TEMPLATE_HPP__ + +#include + +namespace nil { + namespace blueprint { + std::string modular_permutation_argument_library_template = R"( +// SPDX-License-Identifier: Apache-2.0. +//---------------------------------------------------------------------------// +// Copyright (c) 2023 Generated by ZKLLVM-transpiler +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//---------------------------------------------------------------------------// +pragma solidity >=0.8.4; + +import "../../cryptography/transcript.sol"; +// Move away unused structures from types.sol +import "../../types.sol"; +import "../../basic_marshalling.sol"; +import "hardhat/console.sol"; + +library modular_permutation_argument_$TEST_NAME${ + uint256 constant modulus = $MODULUS$; + uint256 constant permutation_size = $PERMUTATION_SIZE$; + uint256 constant special_selectors_offset = $PERMUTATION_SIZE$ * 0x40; + uint256 constant table_values_offset = $PERMUTATION_SIZE$ * 0x40 + 0x80; + bytes constant zero_indices = hex"$ZERO_INDICES$"; + uint32 constant max_quotient_chunks = $MAX_QUOTIENT_CHUNKS$; + + struct perm_state{ + uint256 beta; + uint256 gamma; + uint256 V_P_value; + uint256 h; + uint256 g; + uint256 tmp; + } + + function uint16_from_two_bytes(bytes1 b1, bytes1 b2) internal pure returns( uint256 result){ + unchecked{ + result = uint8(b1); + result = result << 8; + result += uint8(b2); + } + } + + // Append commitments + function verify( + bytes calldata blob, + uint256 l0, + bytes32 tr_state_before // It's better than transfer all random values + ) internal view returns (uint256[3] memory F, bytes32 tr_state_after){ + types.transcript_data memory tr_state; + tr_state.current_challenge = tr_state_before; + perm_state memory state; + + state.beta = transcript.get_field_challenge(tr_state, modulus); + state.gamma = transcript.get_field_challenge(tr_state, modulus); + + state.V_P_value = basic_marshalling.get_uint256_be(blob, table_values_offset + $PERMUTATION_TABLE_OFFSET$); + state.h = 1; + state.g = 1; + + for(uint256 i = 0; i < permutation_size;){ + state.tmp = addmod( + state.gamma, + basic_marshalling.get_uint256_be( + blob, table_values_offset + uint16_from_two_bytes(zero_indices[i<<1], zero_indices[(i<<1)+1]) + ), + modulus + ); + + state.g = mulmod(state.g, addmod( + mulmod(state.beta, basic_marshalling.get_uint256_be(blob, (i *0x20 )), modulus), + state.tmp, + modulus + ), modulus); + state.h = mulmod(state.h, addmod( + mulmod(state.beta, basic_marshalling.get_uint256_be(blob, permutation_size * 0x20 + (i *0x20 )), modulus), + state.tmp, + modulus + ), + modulus + ); + unchecked{i++;} + } + + F[0] = mulmod(l0, addmod(1, modulus - state.V_P_value, modulus), modulus); + F[1] = mulmod( + addmod(addmod(1, modulus - basic_marshalling.get_uint256_be(blob, special_selectors_offset), modulus), modulus - basic_marshalling.get_uint256_be(blob, special_selectors_offset + 0x40), modulus), + addmod( + mulmod(basic_marshalling.get_uint256_be(blob, table_values_offset + $PERMUTATION_TABLE_OFFSET$ + 0x20), state.h, modulus), + modulus - mulmod(state.V_P_value, state.g, modulus), + modulus + ), + modulus + ); + F[2] = mulmod( + mulmod(basic_marshalling.get_uint256_be(blob, permutation_size * 0x40), state.V_P_value, modulus), + addmod(state.V_P_value, modulus-1, modulus), + modulus + ); + return (F, tr_state.current_challenge); + } +} + )"; + } +} + +#endif //__MODULAR_CONTRACT_TEMPLATE_HPP__ \ No newline at end of file diff --git a/libs/transpiler/include/nil/blueprint/transpiler/templates/permutation_argument_chunked.hpp b/libs/transpiler/include/nil/blueprint/transpiler/templates/permutation_argument_chunked.hpp new file mode 100644 index 000000000..0844bea3f --- /dev/null +++ b/libs/transpiler/include/nil/blueprint/transpiler/templates/permutation_argument_chunked.hpp @@ -0,0 +1,165 @@ +#ifndef __MODULAR_PERMUTATION_ARGUMENT_CHUNKED_CONTRACT_TEMPLATE_HPP__ +#define __MODULAR_PERMUTATION_ARGUMENT_CHUNKED_CONTRACT_TEMPLATE_HPP__ + +#include + +namespace nil { + namespace blueprint { + std::string modular_permutation_argument_chunked_library_template = R"( +// SPDX-License-Identifier: Apache-2.0. +//---------------------------------------------------------------------------// +// Copyright (c) 2023 Generated by ZKLLVM-transpiler +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//---------------------------------------------------------------------------// +pragma solidity >=0.8.4; + +import "../../cryptography/transcript.sol"; +// Move away unused structures from types.sol +import "../../types.sol"; +import "../../basic_marshalling.sol"; +import "hardhat/console.sol"; + +library modular_permutation_argument_$TEST_NAME${ + uint256 constant modulus = $MODULUS$; + uint256 constant permutation_size = $PERMUTATION_SIZE$; + uint256 constant special_selectors_offset = $PERMUTATION_SIZE$ * 0x40; + uint256 constant table_values_offset = $PERMUTATION_SIZE$ * 0x40 + 0x80; + bytes constant zero_indices = hex"$ZERO_INDICES$"; + uint16 constant max_quotient_chunks = $MAX_QUOTIENT_CHUNKS$; + uint16 constant permutaion_parts = $PERMUTATION_PARTS$; + + struct perm_state{ + uint256 beta; + uint256 gamma; + uint256 V_P_value; + uint256 h; + uint256 g; + uint256 tmp; + uint256 previous_value; + uint256 current_value; + } + + function uint16_from_two_bytes(bytes1 b1, bytes1 b2) internal pure returns( uint256 result){ + unchecked{ + result = uint8(b1); + result = result << 8; + result += uint8(b2); + } + } + + // Append commitments + function verify( + bytes calldata blob, + uint256 l0, + bytes32 tr_state_before // It's better than transfer all random values + ) internal view returns (uint256[3] memory F, bytes32 tr_state_after){ + types.transcript_data memory tr_state; + tr_state.current_challenge = tr_state_before; + perm_state memory state; + + state.beta = transcript.get_field_challenge(tr_state, modulus); + state.gamma = transcript.get_field_challenge(tr_state, modulus); + + state.V_P_value = basic_marshalling.get_uint256_be(blob, table_values_offset + $PERMUTATION_TABLE_OFFSET$); + state.h = 1; + state.g = 1; + + uint32 cur = 0; + uint32 chunk = 0; + state.previous_value = state.V_P_value; + for(uint256 i = 0; i < permutation_size;){ + state.tmp = addmod( + state.gamma, + basic_marshalling.get_uint256_be( + blob, table_values_offset + uint16_from_two_bytes(zero_indices[i<<1], zero_indices[(i<<1)+1]) + ), + modulus + ); + + state.g = mulmod(state.g, addmod( + mulmod(state.beta, basic_marshalling.get_uint256_be(blob, (i *0x20 )), modulus), + state.tmp, + modulus + ), modulus); + state.h = mulmod(state.h, addmod( + mulmod(state.beta, basic_marshalling.get_uint256_be(blob, permutation_size * 0x20 + (i *0x20 )), modulus), + state.tmp, + modulus + ), + modulus + ); + unchecked{cur++;} + if( cur == max_quotient_chunks - 1 ){ + state.current_value = basic_marshalling.get_uint256_be(blob, table_values_offset + $PERMUTATION_TABLE_OFFSET$ + 0x40 + (chunk<<5)); + F[1] = addmod( + F[1], + mulmod( + transcript.get_field_challenge(tr_state, modulus), + addmod( + mulmod(state.previous_value,state.g, modulus), + modulus - mulmod(state.current_value, state.h, modulus), + modulus + ), + modulus + ), + modulus + ); + state.previous_value = state.current_value; + state.g = 1; + state.h = 1; + unchecked{chunk++;} + cur = 0; + } + unchecked{i++;} + } + F[0] = mulmod(l0, addmod(1, modulus - state.V_P_value, modulus), modulus); + + state.previous_value = state.current_value; + state.current_value = basic_marshalling.get_uint256_be(blob, table_values_offset + $PERMUTATION_TABLE_OFFSET$ + 0x20); + F[1] = addmod( + F[1], + addmod( + mulmod(state.previous_value,state.g, modulus), + modulus - mulmod(state.current_value, state.h, modulus), + modulus + ), + modulus + ); + state.tmp = addmod( + addmod( + basic_marshalling.get_uint256_be(blob, special_selectors_offset), + basic_marshalling.get_uint256_be(blob, special_selectors_offset + 0x40), + modulus + ), + modulus - 1, + modulus + ); + F[1] = mulmod( + state.tmp, + F[1], + modulus + ); + F[2] = mulmod( + mulmod(basic_marshalling.get_uint256_be(blob, permutation_size * 0x40), state.V_P_value, modulus), + addmod(state.V_P_value, modulus-1, modulus), + modulus + ); + return (F, tr_state.current_challenge); + } +} + )"; + } +} + +#endif //__MODULAR_CONTRACT_TEMPLATE_HPP__ \ No newline at end of file diff --git a/libs/transpiler/include/nil/blueprint/transpiler/templates/recursive_verifier.hpp b/libs/transpiler/include/nil/blueprint/transpiler/templates/recursive_verifier.hpp new file mode 100644 index 000000000..4611ea046 --- /dev/null +++ b/libs/transpiler/include/nil/blueprint/transpiler/templates/recursive_verifier.hpp @@ -0,0 +1,542 @@ +#ifndef __RECURSIVE_VERIFIER_TEMPLATE_HPP__ +#define __RECURSIVE_VERIFIER_TEMPLATE_HPP__ + +#include + +namespace nil { + namespace blueprint { + std::string lookup_vars = R"( +const size_t lookup_table_amount = $LOOKUP_TABLE_AMOUNT$; +const size_t lookup_gate_amount = $LOOKUP_GATE_AMOUNT$; +constexpr std::array lookup_options_amount_list = {$LOOKUP_OPTIONS_AMOUNT_LIST$}; +constexpr std::array lookup_tables_columns_amount_list = {$LOOKUP_TABLES_COLUMNS_AMOUNT_LIST$}; +constexpr std::size_t lookup_options_amount = $LOOKUP_OPTIONS_AMOUNT$; +constexpr std::size_t lookup_table_columns_amount = $LOOKUP_TABLES_COLUMNS_AMOUNT$; + +constexpr std::array lookup_constraints_amount_list = {$LOOKUP_CONSTRAINTS_AMOUNT_LIST$}; +constexpr std::size_t lookup_constraints_amount = $LOOKUP_CONSTRAINTS_AMOUNT$; +constexpr std::array lookup_expressions_amount_list = {$LOOKUP_EXPRESSIONS_AMOUNT_LIST$}; +constexpr std::size_t lookup_expressions_amount = $LOOKUP_EXPRESSIONS_AMOUNT$; + + +constexpr std::size_t m_parameter = lookup_options_amount + lookup_constraints_amount; +constexpr std::size_t input_size_alphas = m_parameter - 1; + +constexpr std::size_t input_size_lookup_gate_selectors = lookup_gate_amount; +constexpr std::size_t input_size_lookup_gate_constraints_table_ids = lookup_constraints_amount; +constexpr std::size_t input_size_lookup_gate_constraints_lookup_inputs = lookup_expressions_amount; + +constexpr std::size_t input_size_lookup_table_selectors = lookup_table_amount; +constexpr std::size_t input_size_lookup_table_lookup_options = lookup_table_columns_amount; + +constexpr std::size_t input_size_shifted_lookup_table_selectors = lookup_table_amount; +constexpr std::size_t input_size_shifted_lookup_table_lookup_options = lookup_table_columns_amount; + +constexpr std::size_t input_size_sorted = m_parameter * 3 - 1; +$LPC_POLY_IDS_CONSTANT_ARRAYS$ + )"; + + std::string lookup_expressions = R"( +std::array calculate_lookup_expressions(std::array z){ + std::array expressions; +$LOOKUP_EXPRESSIONS_BODY$ + + return expressions; +} + )"; + + std::string lookup_code = R"( + { + std::array lookup_gate_selectors; +$LOOKUP_GATE_SELECTORS_LIST$ + std::array lookup_gate_constraints_table_ids = {$LOOKUP_CONSTRAINT_TABLE_IDS_LIST$}; + std::array lookup_gate_constraints_lookup_inputs = calculate_lookup_expressions(proof.z); + std::array lookup_table_selectors; +$LOOKUP_TABLE_SELECTORS_LIST$ + std::array shifted_lookup_table_selectors; +$LOOKUP_SHIFTED_TABLE_SELECTORS_LIST$ + std::array lookup_table_lookup_options; +$LOOKUP_OPTIONS_LIST$ + std::array shifted_lookup_table_lookup_options; +$LOOKUP_SHIFTED_OPTIONS_LIST$ + + std::array sorted; + for(std::size_t i = 0; i < input_size_sorted; i++){ + sorted[i] = proof.z[lookup_sorted_polys_start + i]; + } + + typename pallas::base_field_type::value_type theta = challenges.lookup_theta; + typename pallas::base_field_type::value_type beta = challenges.lookup_beta; + typename pallas::base_field_type::value_type gamma = challenges.lookup_gamma; + typename pallas::base_field_type::value_type L0 = precomputed_values.l0; + precomputed_values.shifted_mask = pallas::base_field_type::value_type(1) - proof.z[2*permutation_size+1] - proof.z[2*permutation_size + 3]; + + lookup_output_type lookup_argument; + + std::array lookup_input; + pallas::base_field_type::value_type theta_acc; +$LOOKUP_INPUT_LOOP$ + std::array lookup_value; + std::array lookup_shifted_value; + pallas::base_field_type::value_type tab_id = 1; +$LOOKUP_TABLE_LOOP$ + + pallas::base_field_type::value_type g = pallas::base_field_type::value_type(1); + pallas::base_field_type::value_type h = pallas::base_field_type::value_type(1); + pallas::base_field_type::value_type previous_value = proof.z[$V_L_INDEX$]; + pallas::base_field_type::value_type current_value; + lookup_argument[2] = pallas::base_field_type::value_type(0); + +$LOOKUP_CHUNKING_CODE$ + lookup_argument[0] = (pallas::base_field_type::value_type(1) - proof.z[$V_L_INDEX$]) * L0; + lookup_argument[1] = proof.z[2*permutation_size]*(proof.z[$V_L_INDEX$] * proof.z[$V_L_INDEX$] - proof.z[$V_L_INDEX$]); + lookup_argument[2] += (previous_value * g - proof.z[$V_L_INDEX$ + 1] * h); + lookup_argument[2] *= -precomputed_values.mask; + lookup_argument[3] = pallas::base_field_type::value_type(0); + for(std::size_t i = 0; i < input_size_alphas; i++){ + lookup_argument[3] = lookup_argument[3] + challenges.lookup_alphas[i] * (sorted[3*i + 3] - sorted[3*i + 2]); + } + lookup_argument[3] = lookup_argument[3] * L0; + F[3] = lookup_argument[0]; + F[4] = lookup_argument[1]; + F[5] = lookup_argument[2]; + F[6] = lookup_argument[3]; + } + )"; + + std::string public_input_check_str = R"( + //Check public input + pallas::base_field_type::value_type Omega(1); + pallas::base_field_type::value_type result(0); + for( std::size_t j = 0; j < public_input_sizes[i]; j++){ + result += public_input[cur] * Omega / (challenges.xi - Omega); + Omega *= omega; + cur++; + } + __builtin_assigner_exit_check(rows_amount * proof.z[public_input_indices[i]] == precomputed_values.Z_at_xi * result); +)"; + std::string public_input_input_str = "\tstd::array public_input,\n"; + + std::string permutation_challenges_str = R"( + // generate permutation argument challenges + state = challenges.perm_beta = __builtin_assigner_poseidon_pallas_base({state, 0, 0})[2]; + state = challenges.perm_gamma = __builtin_assigner_poseidon_pallas_base({state, 0, 0})[2]; + for( std::size_t i = 0; i < $PERMUTATION_CHUNK_ALPHAS$; i++){ + challenges.perm_chunk_alphas[i] = __builtin_assigner_poseidon_pallas_base({state, 0, 0})[2]; + } +); +)"; + std::string perm_arg_body = R"( + // Call permutation argument + { + pallas::base_field_type::value_type g=1; + pallas::base_field_type::value_type h=1; + pallas::base_field_type::value_type tmp; + pallas::base_field_type::value_type previous_value = proof.z[$V_P_INDEX$]; + pallas::base_field_type::value_type current_value = proof.z[$V_P_INDEX$]; +$PERM_CODE$ + F[0] = precomputed_values.l0 * (1 - proof.z[$V_P_INDEX$]); + F[1] += previous_value * g - proof.z[$V_P_INDEX$ + 1] * h; + F[1] *= -precomputed_values.mask; + F[2] = proof.z[2*permutation_size] * proof.z[$V_P_INDEX$] * (proof.z[$V_P_INDEX$] - 1); + } +)"; + + std::string lookup_challenges_str = R"( +// generate lookup argument challenges + challenges.lookup_theta = state = __builtin_assigner_poseidon_pallas_base({state, 0, 0})[2]; + state = challenges.perm_beta = state = __builtin_assigner_poseidon_pallas_base({state, proof.commitments[3], 0})[2]; + state = challenges.perm_gamma = state = __builtin_assigner_poseidon_pallas_base({state, 0, 0})[2]; + for( std::size_t i = 0; i < $LOOKUP_CHUNK_ALPHAS$; i++){ + challenges.lookup_chunk_alphas[i] = state = __builtin_assigner_poseidon_pallas_base({state, 0, 0})[2]; + } + for(std::size_t i = 0; i < sorted_columns-1; i++){ + challenges.lookup_alphas[i] = state = __builtin_assigner_poseidon_pallas_base({state, 0, 0})[2]; + } +); +)"; + + std::string recursive_verifier_template = R"( +#include +#include +#include + +using namespace nil::crypto3; +using namespace nil::crypto3::algebra::curves; + +namespace placeholder_verifier{ + +const size_t witness_amount = $WITNESS_COLUMNS_AMOUNT$; +const size_t public_input_amount = $PUBLIC_INPUT_COLUMNS_AMOUNT$; +const size_t constant_amount = $CONSTANT_COLUMNS_AMOUNT$; +const size_t selector_amount = $SELECTOR_COLUMNS_AMOUNT$; +const std::array public_input_sizes = {$PUBLIC_INPUT_SIZES$}; +const std::size_t full_public_input_size = $FULL_PUBLIC_INPUT_SIZE$; + +const bool use_lookups = $USE_LOOKUPS$; +const size_t batches_num = $BATCHES_NUM$; +const size_t commitments_num = $COMMITMENTS_NUM$; +const size_t points_num = $POINTS_NUM$; +const size_t poly_num = $POLY_NUM$; +const size_t initial_proof_points_num = $INITIAL_PROOF_POINTS_NUM$; +const size_t round_proof_points_num = $ROUND_PROOF_POINTS_NUM$; +const size_t fri_roots_num = $FRI_ROOTS_NUM$; +const size_t initial_merkle_proofs_num = $INITIAL_MERKLE_PROOFS_NUM$; +const size_t initial_merkle_proofs_position_num = $INITIAL_MERKLE_PROOFS_POSITION_NUM$; +const size_t initial_merkle_proofs_hash_num = $INITIAL_MERKLE_PROOFS_HASH_NUM$; +const size_t round_merkle_proofs_position_num = $ROUND_MERKLE_PROOFS_POSITION_NUM$; +const size_t round_merkle_proofs_hash_num = $ROUND_MERKLE_PROOFS_HASH_NUM$; +const size_t final_polynomial_size = $FINAL_POLYNOMIAL_SIZE$; +const size_t lambda = $LAMBDA$; +const size_t rows_amount = $ROWS_AMOUNT$; +const size_t rows_log = $ROWS_LOG$; +const size_t total_columns = $TOTAL_COLUMNS$; +const size_t sorted_columns = $SORTED_COLUMNS$; +const size_t permutation_size = $PERMUTATION_SIZE$; +const std::array public_input_indices = {$PUBLIC_INPUT_INDICES$}; +const size_t table_values_num = $TABLE_VALUES_NUM$; +const size_t gates_amount = $GATES_AMOUNT$; +constexpr std::array gates_selector_indices = {$GATES_SELECTOR_INDICES$}; +const size_t constraints_amount = $CONSTRAINTS_AMOUNT$; +const size_t quotient_polys_start = $QUOTIENT_POLYS_START$; +const size_t quotient_polys_amount = $QUOTIENT_POLYS_AMOUNT$; +const size_t lookup_sorted_polys_start = $LOOKUP_SORTED_START$; +const size_t D0_size = $D0_SIZE$; +const size_t D0_log = $D0_LOG$; +const pallas::base_field_type::value_type D0_omega = $D0_OMEGA$; +const pallas::base_field_type::value_type omega = $OMEGA$; +const size_t fri_rounds = $FRI_ROUNDS$; +const std::array gates_sizes = {$GATES_SIZES$}; +const size_t unique_points = $UNIQUE_POINTS$; +const size_t singles_amount = $SINGLES_AMOUNT$; +const std::array batches_amount_list = {$BATCHES_AMOUNT_LIST$}; +pallas::base_field_type::value_type vk0 = pallas::base_field_type::value_type(0x$VK0$_cppui_modular255); +pallas::base_field_type::value_type vk1 = pallas::base_field_type::value_type(0x$VK1$_cppui_modular255); + + +$LOOKUP_VARS$ + +struct placeholder_proof_type{ + std::array commitments; + pallas::base_field_type::value_type challenge; + std::array z; + std::array fri_roots; + std::array, lambda> initial_proof_values; + std::array, lambda> round_proof_values; // lambda times + std::array, lambda> initial_proof_positions; + std::array, lambda> initial_proof_hashes; + std::array, lambda> round_merkle_proof_positions; // lambda times + std::array, lambda> round_proof_hashes; // lambda times + std::array final_polynomial; +}; + +struct placeholder_challenges_type { + pallas::base_field_type::value_type eta; + + pallas::base_field_type::value_type perm_beta; + pallas::base_field_type::value_type perm_gamma; + std::array perm_chunk_alphas; + + pallas::base_field_type::value_type lookup_theta; + pallas::base_field_type::value_type lookup_gamma; + pallas::base_field_type::value_type lookup_beta; + std::array lookup_chunk_alphas; + + std::array lookup_alphas; + pallas::base_field_type::value_type gate_theta; + std::array alphas; + std::array fri_alphas; + std::array fri_x_indices; + pallas::base_field_type::value_type lpc_theta; + pallas::base_field_type::value_type xi; +}; + +typedef __attribute__((ext_vector_type(2))) typename pallas::base_field_type::value_type permutation_argument_thetas_type; +typedef __attribute__((ext_vector_type(3))) typename pallas::base_field_type::value_type permutation_argument_output_type; + +struct placeholder_permutation_argument_input_type{ + std::array xi_values; + std::array id_perm; + std::array sigma_perm; + permutation_argument_thetas_type thetas; +}; + +struct transcript_state_type{ + std::array state; + std::size_t cur; +}; + +void transcript(transcript_state_type &tr_state, pallas::base_field_type::value_type value) { + if(tr_state.cur == 3){ + tr_state.state[0] = __builtin_assigner_poseidon_pallas_base({tr_state.state[0],tr_state.state[1],tr_state.state[2]})[2]; + tr_state.state[1] = pallas::base_field_type::value_type(0); + tr_state.state[2] = pallas::base_field_type::value_type(0); + tr_state.cur = 1; + } + tr_state.state[tr_state.cur] = value; + tr_state.cur++; +} + +pallas::base_field_type::value_type transcript_challenge(transcript_state_type &tr_state) { + tr_state.state[0] = __builtin_assigner_poseidon_pallas_base({tr_state.state[0], tr_state.state[1], tr_state.state[2]})[2]; + tr_state.state[1] = pallas::base_field_type::value_type(0); + tr_state.state[2] = pallas::base_field_type::value_type(0); + tr_state.cur = 1; + return tr_state.state[0]; +} + +pallas::base_field_type::value_type pow_rows_amount(pallas::base_field_type::value_type x){ + pallas::base_field_type::value_type result = x; + for(std::size_t i = 0; i < rows_log; i++){ + result = result * result; + } + return result; +} + +pallas::base_field_type::value_type pow2(pallas::base_field_type::value_type x){ + return x*x; +} + +pallas::base_field_type::value_type pow3(pallas::base_field_type::value_type x){ + return x*x*x; +} + +pallas::base_field_type::value_type pow4(pallas::base_field_type::value_type x){ + pallas::base_field_type::value_type result = x * x; + result = result * result; + return result; +} + +pallas::base_field_type::value_type pow5(pallas::base_field_type::value_type x){ + pallas::base_field_type::value_type result = x * x; + result = result * result; + return result * x; +} + +pallas::base_field_type::value_type pow6(pallas::base_field_type::value_type x){ + pallas::base_field_type::value_type result = x * x * x; + result = result * result; + return result; +} + +pallas::base_field_type::value_type pow7(pallas::base_field_type::value_type x){ + pallas::base_field_type::value_type result = x * x * x; + result = result * result; + return result * x; +} + +pallas::base_field_type::value_type pow8(pallas::base_field_type::value_type x){ + pallas::base_field_type::value_type result = x * x; + result = result * result; + return result * result; +} + +pallas::base_field_type::value_type pow9(pallas::base_field_type::value_type x){ + pallas::base_field_type::value_type result = x; + result = result * result; + result = result * result; + result = result * result; + result = result * x; + return result; +} + +template +pallas::base_field_type::value_type pow(pallas::base_field_type::value_type x){ + if constexpr( p == 0 ) return pallas::base_field_type::value_type(1); + if constexpr( p == 1 ) return x; + pallas::base_field_type::value_type result = pow

(x); + result = result * result; + if constexpr( p%2 == 1 ) result = result * x; + return result; +} + +std::array fill_singles( + pallas::base_field_type::value_type xi, + pallas::base_field_type::value_type eta +){ + std::array singles; +$SINGLES_COMPUTATION$; + return singles; +} + +placeholder_challenges_type generate_challenges( + const placeholder_proof_type &proof +){ + placeholder_challenges_type challenges; + pallas::base_field_type::value_type state; +$PLACEHOLDER_CHALLENGES_STR$ + return challenges; +} + +std::pair xi_polys( + pallas::base_field_type::value_type xi +){ + pallas::base_field_type::value_type xi_n = pow_rows_amount(xi) - pallas::base_field_type::value_type(1); + pallas::base_field_type::value_type l0 = (xi - pallas::base_field_type::value_type(1))*pallas::base_field_type::value_type(rows_amount); + l0 = xi_n / l0; + return std::make_pair(l0, xi_n); +} + +std::array calculate_constraints(std::array z){ + std::array constraints; +$CONSTRAINTS_BODY$ + + return constraints; +} + +$LOOKUP_EXPRESSIONS$ + +template +pallas::base_field_type::value_type calculate_leaf_hash( + std::array val +){ + pallas::base_field_type::value_type hash_state = pallas::base_field_type::value_type(0); + for(std::size_t pos = 0; pos < leaf_size*2; pos+=2){ + hash_state = __builtin_assigner_poseidon_pallas_base( + {hash_state, val[start_index + pos], val[start_index + pos+1]} + )[2]; + } + return hash_state; +} + +struct precomputed_values_type{ + pallas::base_field_type::value_type l0; + pallas::base_field_type::value_type Z_at_xi; + pallas::base_field_type::value_type F_consolidated; + pallas::base_field_type::value_type T_consolidated; + pallas::base_field_type::value_type mask; + pallas::base_field_type::value_type shifted_mask; +}; + +constexpr std::size_t L0_IND = 0; +constexpr std::size_t Z_AT_XI_IND = 1; +constexpr std::size_t F_CONSOLIDATED_IND = 2; +constexpr std::size_t T_CONSOLIDATED_IND = 3; + +typedef __attribute__((ext_vector_type(2))) + typename pallas::base_field_type::value_type pair_type; + +typedef __attribute__((ext_vector_type(4))) + typename pallas::base_field_type::value_type lookup_output_type; + +typedef __attribute__((ext_vector_type(2))) + typename pallas::base_field_type::value_type pair_type; + + +[[circuit]] bool placeholder_verifier( + $PUBLIC_INPUT_INPUT$ + placeholder_proof_type proof +) { + placeholder_challenges_type challenges = generate_challenges(proof); + __builtin_assigner_exit_check_eq_pallas(challenges.xi, proof.challenge); + + precomputed_values_type precomputed_values; + std::tie(precomputed_values.l0, precomputed_values.Z_at_xi) = xi_polys(challenges.xi); + precomputed_values.mask = (pallas::base_field_type::value_type(1) - proof.z[2*permutation_size] - proof.z[2*permutation_size + 2]); + + // For loop in for loop removed +$PUBLIC_INPUT_CHECK$ + + std::array F; + F[0] = pallas::base_field_type::value_type(0); + F[1] = pallas::base_field_type::value_type(0); + F[2] = pallas::base_field_type::value_type(0); + F[3] = pallas::base_field_type::value_type(0); + F[4] = pallas::base_field_type::value_type(0); + F[5] = pallas::base_field_type::value_type(0); + F[6] = pallas::base_field_type::value_type(0); + F[7] = pallas::base_field_type::value_type(0); + +$PERM_BODY$ +$LOOKUP_CODE$ + if constexpr( gates_amount > 0) { + std::array constraints; + std::array selectors; + constraints = calculate_constraints(proof.z); + +$GATE_ARG_PREPARE$ + F[7] *= precomputed_values.mask; + } + + precomputed_values.F_consolidated = pallas::base_field_type::value_type(0); + for(std::size_t i = 0; i < 8; i++){ + F[i] *= challenges.alphas[i]; + precomputed_values.F_consolidated += F[i]; + } + + precomputed_values.T_consolidated = pallas::base_field_type::value_type(0); + pallas::base_field_type::value_type factor = pallas::base_field_type::value_type(1); + for(std::size_t i = 0; i < quotient_polys_amount; i++){ + precomputed_values.T_consolidated += proof.z[quotient_polys_start + i] * factor; + factor *= (precomputed_values.Z_at_xi + pallas::base_field_type::value_type(1)); + } + __builtin_assigner_exit_check(precomputed_values.F_consolidated == precomputed_values.T_consolidated * precomputed_values.Z_at_xi); + + // Commitment scheme + std::array singles = fill_singles(challenges.xi, challenges.eta); + std::array U{pallas::base_field_type::value_type(0)}; + +$PREPARE_U_AND_V$ + + + std::array, D0_log> res; + std::size_t round_proof_ind = 0; + std::size_t initial_proof_ind = 0; + std::size_t initial_proof_hash_ind = 0; + pallas::base_field_type::value_type interpolant; + std::size_t cur_val = 0; + std::size_t round_proof_hash_ind = 0; + + for(std::size_t i = 0; i < lambda; i++){ + cur_val = 0; + pallas::base_field_type::value_type x(1); + pallas::base_field_type::value_type x_challenge = challenges.fri_x_indices[i]; + pallas::base_field_type::value_type x_2(1); +$X_CHALLENGE_POW$ + __builtin_assigner_exit_check(x == x_2 || x == -x_2); + + pallas::base_field_type::value_type hash_state; + pallas::base_field_type::value_type pos; + pallas::base_field_type::value_type npos; +$INITIAL_PROOF_CHECK$ + pallas::base_field_type::value_type y0; + pallas::base_field_type::value_type y1; + y0 = pallas::base_field_type::value_type(0); + y1 = pallas::base_field_type::value_type(0); + theta_acc = pallas::base_field_type::value_type(1); + pallas::base_field_type::value_type Q0; + pallas::base_field_type::value_type Q1; + +$LPC_Y_COMPUTATION$ + + std::size_t D = D0_log - 1; + pallas::base_field_type::value_type rhash; + +$ROUND_PROOF_CHECK$ + + interpolant = pallas::base_field_type::value_type(0); + pallas::base_field_type::value_type factor = pallas::base_field_type::value_type(1); + for(std::size_t j = 0; j < final_polynomial_size; j++){ + interpolant = interpolant + proof.final_polynomial[j] * factor; + factor = factor * x; + } + __builtin_assigner_exit_check(interpolant == y0); + + x = -x; + interpolant = pallas::base_field_type::value_type(0); + factor = pallas::base_field_type::value_type(1); + for(std::size_t j = 0; j < final_polynomial_size; j++){ + interpolant = interpolant + proof.final_polynomial[j] * factor; + factor = factor * x; + } + __builtin_assigner_exit_check(interpolant == y1); + } + return true; +} + +} + )"; + } +} + +#endif //__RECURSIVE_VERIFIER_TEMPLATE_HPP__ diff --git a/libs/transpiler/include/nil/blueprint/transpiler/templates/utils_template.hpp b/libs/transpiler/include/nil/blueprint/transpiler/templates/utils_template.hpp new file mode 100644 index 000000000..9612d89e0 --- /dev/null +++ b/libs/transpiler/include/nil/blueprint/transpiler/templates/utils_template.hpp @@ -0,0 +1,39 @@ +#ifndef __MODULAR_UTILS_TEMPLATE_HPP__ +#define __MODULAR_UTILS_TEMPLATE_HPP__ + +#include + +namespace nil { + namespace blueprint { + std::string utils_library_template = R"( +// SPDX-License-Identifier: Apache-2.0. +//---------------------------------------------------------------------------// +// Copyright (c) 2023 Generated by ZKLLVM-transpiler +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//---------------------------------------------------------------------------// +pragma solidity >=0.8.4; + +import "hardhat/console.sol"; + +library modular_utils_$TEST_NAME$ { + uint256 constant modulus = $MODULUS$; + + $POWER_FUNCTIONS$ + +} +)"; + } +} + +#endif //__MODULAR_CONTRACT_TEMPLATE_HPP__ diff --git a/libs/transpiler/include/nil/blueprint/transpiler/util.hpp b/libs/transpiler/include/nil/blueprint/transpiler/util.hpp new file mode 100644 index 000000000..b7804f00e --- /dev/null +++ b/libs/transpiler/include/nil/blueprint/transpiler/util.hpp @@ -0,0 +1,265 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2023 Elena Tatuzova +// +// 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 unified addition component. +//---------------------------------------------------------------------------// +#ifndef __TRANSPILER_UTIL_HPP__ +#define __TRANSPILER_UTIL_HPP__ + +#include +#include +#include +#include +#include +//#include + +#include + +namespace nil { + namespace blueprint { + using transpiler_replacements = std::map; + + template std::string to_string(T val) { + std::stringstream strstr; + strstr << val; + return strstr.str(); + } + + template std::string to_hex_string(T val) { + std::stringstream strstr; + strstr << std::hex << val << std::dec; + return strstr.str(); + } + + static inline std::string rot_string (int j, std::size_t rows_amount, std::string mode){ + int abs_j = j>0? j: -j; + int other_j = rows_amount - abs_j; + if(other_j < abs_j) { + j = j > 0? -other_j: other_j; + } + + if( mode == "recursive"){ + if(j == 0) return "xi"; else + if(j == 1 ) return "xi*omega"; else + if(j == -1) return "xi/omega"; else + if(j > 0) return "xi*pow< " + to_string(j) + ">(omega)"; else + if(j < 0) return "xi/pow< " + to_string(-j) + ">(omega)"; + } else if(mode == "evm") { + if(j == 0) return "xi"; else + if(j == 1 ) return "mulmod(xi, omega, modulus)"; else + if(j == -1) return "mulmod(xi, inversed_omega, modulus)"; else + if(j > 0) return "mulmod(xi, field.pow_small(omega, " + to_string(j) + ", modulus), modulus)"; else + if(j < 0) return "mulmod(xi, field.pow_small(inversed_omega, " + to_string(-j) + ", modulus), modulus)"; + } + return ""; + } + + void replace_and_print(std::string input, transpiler_replacements reps, std::string output_file_name){ + std::string code = input; + + for(const auto&[k,v]: reps){ + boost::replace_all(code, k, v); + } + for(const auto&[k,v]: reps){ + boost::replace_all(code, k, v); + } + std::ofstream out; + out.open(output_file_name); + out << code; + out.close(); + } + + std::string replace_all(std::string input, transpiler_replacements reps){ + std::string code = input; + + for(const auto&[k,v]: reps){ + boost::replace_all(code, k, v); + } + + return code; + } + + + // Tuple of singles, poly ids with singles> + template + static std::tuple, std::vector, std::map, std::vector>> + calculate_unique_points( + const zk::snark::placeholder_info &placeholder_info, + zk::snark::plonk_table_description desc, + const CommonDataType &common_data, + std::size_t permutation_size, + std::size_t quotient_size, + std::size_t sorted_size, + std::string mode + ){ + std::vector z_points_indices; + std::vector singles; + std::map singles_map; + std::vector> poly_ids; + std::size_t rows_amount = common_data.desc.rows_amount; + + singles.push_back(rot_string(0, rows_amount, mode)); + singles_map[rot_string(0, rows_amount, mode)] = singles_map.size(); + poly_ids.resize(singles.size()); + + // Sigma and permutation polys + std::size_t count = 0; + for( std::size_t i = 0; i < placeholder_info.permutation_size; i++){ + poly_ids[singles_map[rot_string(0, rows_amount, mode)]].push_back(count); + z_points_indices.push_back(singles_map[rot_string(0, rows_amount, mode)]); + poly_ids[singles_map[rot_string(0, rows_amount, mode)]].push_back(count+1); + z_points_indices.push_back(singles_map[rot_string(0, rows_amount, mode)]); + count += 2; + } + + // Special selectors + singles.push_back(rot_string(1, rows_amount, mode)); + singles_map[rot_string(1, rows_amount, mode)] = singles_map.size(); + poly_ids.resize(singles.size()); + + poly_ids[singles_map[rot_string(0, rows_amount, mode)]].push_back(count); + poly_ids[singles_map[rot_string(1, rows_amount, mode)]].push_back(count); + z_points_indices.push_back(singles_map[rot_string(0, rows_amount, mode)]); + z_points_indices.push_back(singles_map[rot_string(1, rows_amount, mode)]); + count++; + poly_ids[singles_map[rot_string(0, rows_amount, mode)]].push_back(count); + poly_ids[singles_map[rot_string(1, rows_amount, mode)]].push_back(count); + z_points_indices.push_back(singles_map[rot_string(0, rows_amount, mode)]); + z_points_indices.push_back(singles_map[rot_string(1, rows_amount, mode)]); + count++; + + for(std::size_t i = 0; i < desc.constant_columns; i++){ + std::stringstream str; + for(auto j:common_data.columns_rotations[i + desc.witness_columns + desc.public_input_columns]){ + if(singles_map.find(rot_string(j, rows_amount, mode)) == singles_map.end()){ + singles_map[rot_string(j, rows_amount, mode)] = singles_map.size(); + singles.push_back(rot_string(j, rows_amount, mode)); + poly_ids.resize(singles.size()); + } + poly_ids[singles_map[rot_string(j, rows_amount, mode)]].push_back(count); + z_points_indices.push_back(singles_map[rot_string(j, rows_amount, mode)]); + } + count++; + } + + for(std::size_t i = 0; i < desc.selector_columns; i++){ + std::stringstream str; + for(auto j:common_data.columns_rotations[i + desc.witness_columns + desc.public_input_columns + desc.constant_columns]){ + if(singles_map.find(rot_string(j, rows_amount, mode)) == singles_map.end()){ + singles_map[rot_string(j, rows_amount, mode)] = singles_map.size(); + singles.push_back(rot_string(j, rows_amount, mode)); + poly_ids.resize(singles.size()); + } + poly_ids[singles_map[rot_string(j, rows_amount, mode)]].push_back(count); + z_points_indices.push_back(singles_map[rot_string(j, rows_amount, mode)]); + } + count++; + } + + for(std::size_t i = 0; i < desc.witness_columns; i++){ + std::stringstream str; + for(auto j:common_data.columns_rotations[i]){ + if(singles_map.find(rot_string(j, rows_amount, mode)) == singles_map.end()){ + singles_map[rot_string(j, rows_amount, mode)] = singles_map.size(); + singles.push_back(rot_string(j, rows_amount, mode)); + poly_ids.resize(singles.size()); + } + poly_ids[singles_map[rot_string(j, rows_amount, mode)]].push_back(count); + z_points_indices.push_back(singles_map[rot_string(j, rows_amount, mode)]); + } + count++; + } + + for(std::size_t i = 0; i < desc.public_input_columns; i++){ + std::stringstream str; + for(auto j:common_data.columns_rotations[i + desc.witness_columns]){ + if(singles_map.find(rot_string(j, rows_amount, mode)) == singles_map.end()){ + singles_map[rot_string(j, rows_amount, mode)] = singles_map.size(); + singles.push_back(rot_string(j, rows_amount, mode)); + poly_ids.resize(singles.size()); + } + poly_ids[singles_map[rot_string(j, rows_amount, mode)]].push_back(count); + z_points_indices.push_back(singles_map[rot_string(j, rows_amount, mode)]); + } + count++; + } + + // Permutation argument + if( placeholder_info.use_permutations ){ + poly_ids[singles_map[rot_string(0, rows_amount, mode)]].push_back(count); + poly_ids[singles_map[rot_string(1, rows_amount, mode)]].push_back(count); + z_points_indices.push_back(singles_map[rot_string(0, rows_amount, mode)]); + z_points_indices.push_back(singles_map[rot_string(1, rows_amount, mode)]); + count++; + for(std::size_t i = 0; i < placeholder_info.permutation_poly_amount - 1; i++ ){ + poly_ids[singles_map[rot_string(0, rows_amount, mode)]].push_back(count); + z_points_indices.push_back(singles_map[rot_string(0, rows_amount, mode)]); + count++; + } + } + + // Lookup permutation + if(placeholder_info.use_lookups){ + poly_ids[singles_map[rot_string(0, rows_amount, mode)]].push_back(count); + poly_ids[singles_map[rot_string(1, rows_amount, mode)]].push_back(count); + z_points_indices.push_back(singles_map[rot_string(0, rows_amount, mode)]); + z_points_indices.push_back(singles_map[rot_string(1, rows_amount, mode)]); + count++; + for(std::size_t i = 0; i < placeholder_info.lookup_poly_amount - 1; i++ ){ + poly_ids[singles_map[rot_string(0, rows_amount, mode)]].push_back(count); + z_points_indices.push_back(singles_map[rot_string(0, rows_amount, mode)]); + count++; + } + } + + // Quotient + for(std::size_t i = 0; i < placeholder_info.quotient_size; i++){ + poly_ids[singles_map[rot_string(0, rows_amount, mode)]].push_back(count); + z_points_indices.push_back(singles_map[rot_string(0, rows_amount, mode)]); + count++; + } + + // Lookup batch + if(placeholder_info.use_lookups){ + if(singles_map.find(rot_string(common_data.desc.usable_rows_amount, rows_amount, mode)) == singles_map.end()){ + singles_map[rot_string(common_data.desc.usable_rows_amount, rows_amount, mode)] = singles.size(); + singles.push_back(rot_string(common_data.desc.usable_rows_amount, rows_amount, mode)); + poly_ids.resize(singles.size()); + } + for( std::size_t i = 0; i < sorted_size; i++ ){ + poly_ids[singles_map[rot_string(0, rows_amount, mode)]].push_back(count); + z_points_indices.push_back(singles_map[rot_string(0, rows_amount, mode)]); + poly_ids[singles_map[rot_string(1, rows_amount, mode)]].push_back(count); + z_points_indices.push_back(singles_map[rot_string(1, rows_amount, mode)]); + poly_ids[singles_map[rot_string(common_data.desc.usable_rows_amount, rows_amount, mode)]].push_back(count); + z_points_indices.push_back(singles_map[rot_string(common_data.desc.usable_rows_amount, rows_amount, mode)]); + count++; + } + } + + return std::make_tuple(z_points_indices, singles, singles_map, poly_ids); + } + } +} + +#endif //__MODULAR_CONTRACTS_TEMPLATES_HPP__ \ No newline at end of file diff --git a/libs/transpiler/test/CMakeLists.txt b/libs/transpiler/test/CMakeLists.txt new file mode 100644 index 000000000..ea2d41e70 --- /dev/null +++ b/libs/transpiler/test/CMakeLists.txt @@ -0,0 +1,57 @@ +#---------------------------------------------------------------------------# +# Copyright (c) 2018-2020 Mikhail Komarov +# +# Distributed under the Boost Software License, Version 1.0 +# See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt +#---------------------------------------------------------------------------# + +include(CMTest) + +cm_test_link_libraries(${CMAKE_WORKSPACE_NAME}_${CURRENT_PROJECT_NAME} + crypto3::algebra + crypto3::math + crypto3::multiprecision + crypto3::zk + ${Boost_LIBRARIES}) + +add_custom_target(compile_and_run_transpiler_tests) + +macro(define_transpiler_test name) + cm_test(NAME transpiler_${name}_test SOURCES ${name}.cpp) + + if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + target_compile_options(transpiler_${name}_test PRIVATE "-fconstexpr-steps=2147483647") + elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + target_compile_options(transpiler_${name}_test PRIVATE "-fconstexpr-ops-limit=4294967295") + endif() + + target_include_directories(transpiler_${name}_test PRIVATE + "$" + "$" + + ${Boost_INCLUDE_DIRS}) + + set_target_properties(transpiler_${name}_test PROPERTIES CXX_STANDARD 17) + + get_target_property(target_type Boost::unit_test_framework TYPE) + if(target_type STREQUAL "SHARED_LIB") + target_compile_definitions(transpiler_${name}_test PRIVATE BOOST_TEST_DYN_LINK) + elseif(target_type STREQUAL "STATIC_LIB") + + endif() + add_custom_target(transpiler_${name}_test_run + COMMAND $ + DEPENDS transpiler_${name}_test $ + ) + add_dependencies(compile_and_run_transpiler_tests transpiler_${name}_test_run) + +endmacro() + +set(TESTS_NAMES + "transpiler" +) + +foreach(TEST_NAME ${TESTS_NAMES}) + define_transpiler_test(${TEST_NAME}) +endforeach() diff --git a/libs/transpiler/test/detail/circuits.hpp b/libs/transpiler/test/detail/circuits.hpp new file mode 100644 index 000000000..fa6471299 --- /dev/null +++ b/libs/transpiler/test/detail/circuits.hpp @@ -0,0 +1,1062 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2022 Mikhail Komarov +// Copyright (c) 2022 Nikita Kaskov +// Copyright (c) 2022 Ilia Shirobokov +// Copyright (c) 2022 Alisa Cherniaeva +// Copyright (c) 2023 Elena Tatuzova +// +// MIT License +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +//---------------------------------------------------------------------------// + +#ifndef CRYPTO3_ZK_TEST_PLONK_CIRCUITS_HPP +#define CRYPTO3_ZK_TEST_PLONK_CIRCUITS_HPP + +#define _RND_ algebra::random_element(); + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace nil { + namespace crypto3 { + namespace zk { + namespace snark { + template + class circuit_description { + typedef zk::snark::detail::placeholder_policy policy_type; + + constexpr static const std::size_t witness_columns = ParamsType::witness_columns; + constexpr static const std::size_t public_columns = ParamsType::public_input_columns; + + public: + std::size_t table_rows; + std::size_t usable_rows = usable_rows_amount; + + typename policy_type::variable_assignment_type table; + + std::vector>> gates; + std::vector> copy_constraints; + std::vector>> lookup_gates; + std::vector> lookup_tables; + std::vector public_input_sizes; + + circuit_description() : table_rows(0){ + } + }; + + //---------------------------------------------------------------------------// + // Test circuit 1 -- gate argument without rotations + // i | GATE | w_0 | w_1 | w_2 | q_add | q_mul | + // 0 | -- | x | y | z | 0 | 0 | + // 1 | ADD | x | y | z | 1 | 0 | + // ... | ADD | x | y | z | 1 | 0 | + // k-2 | MUL | x | y | z | 0 | 1 | + // k-1 | MUL | x | y | z | 0 | 1 | + // + // ADD: x + y = z + // MUL: x * y = z + //---------------------------------------------------------------------------// + const std::size_t witness_columns_1 = 3; + const std::size_t public_columns_1 = 1; + const std::size_t constant_columns_1 = 0; + const std::size_t selector_columns_1 = 2; + const std::size_t rows_amount_1 = 13; + + template + circuit_description, rows_amount_1> circuit_test_1( + typename nil::crypto3::random::algebraic_engine alg_rnd = nil::crypto3::random::algebraic_engine(), + boost::random::mt11213b rnd = boost::random::mt11213b() + ) { + using assignment_type = typename FieldType::value_type; + + constexpr static const std::size_t usable_rows = rows_amount_1; + + constexpr static const std::size_t witness_columns = witness_columns_1; + constexpr static const std::size_t public_columns = public_columns_1; + constexpr static const std::size_t constant_columns = constant_columns_1; + constexpr static const std::size_t selector_columns = selector_columns_1; + constexpr static const std::size_t table_columns = + witness_columns + public_columns + constant_columns; + + typedef placeholder_circuit_params circuit_params; + circuit_description test_circuit; + std::vector> table(table_columns); + + std::vector q_add(test_circuit.usable_rows); + std::vector q_mul(test_circuit.usable_rows); + for (std::size_t j = 0; j < table_columns; j++) { + table[j].resize(test_circuit.usable_rows); + } + + // init values + typename FieldType::value_type one = FieldType::value_type::one(); + table[0][0] = alg_rnd(); + table[1][0] = alg_rnd(); + table[2][0] = alg_rnd(); +// table[3][0] = algebra::random_element(); + q_add[0] = FieldType::value_type::zero(); + q_mul[0] = FieldType::value_type::zero(); + + // fill rows with ADD gate + for (std::size_t i = 1; i < test_circuit.usable_rows - 5; i++) { + table[0][i] = alg_rnd(); + table[1][i] = alg_rnd(); + table[2][i] = table[0][i] + table[1][i]; +// table[3][i] = FieldType::value_type::zero(); + q_add[i] = one; + q_mul[i] = FieldType::value_type::zero(); + + plonk_variable x(1, i, false, + plonk_variable::column_type::witness); + plonk_variable y(2, i - 1, false, + plonk_variable::column_type::witness); + //test_circuit.copy_constraints.push_back(plonk_copy_constraint(x, y)); + } + + // fill rows with MUL gate + for (std::size_t i = test_circuit.table_rows - 5; i < test_circuit.table_rows; i++) { + table[0][i] = alg_rnd(); + table[1][i] = alg_rnd(); + table[2][i] = table[0][i] * table[1][i]; + table[3][i] = FieldType::value_type::zero(); + q_add[i] = FieldType::value_type::zero(); + q_mul[i] = one; + + plonk_variable x(1, i, false, + plonk_variable::column_type::witness); + plonk_variable y(0, 0, false, + plonk_variable::column_type::public_input); + test_circuit.copy_constraints.push_back(plonk_copy_constraint(x, y)); + } + + std::vector> private_assignment(witness_columns); + for (std::size_t i = 0; i < witness_columns; i++) { + private_assignment[i] = table[i]; + } + + std::vector> selectors_assignment(selector_columns); + std::vector> public_input_assignment(public_columns); + std::vector> constant_assignment(constant_columns); + + selectors_assignment[0] = q_add; + selectors_assignment[1] = q_mul; + + for (std::size_t i = 0; i < public_columns; i++) { + public_input_assignment[i] = table[witness_columns + i]; + } + test_circuit.table = plonk_assignment_table( + plonk_private_assignment_table(private_assignment), + plonk_public_assignment_table( + public_input_assignment, constant_assignment, selectors_assignment)); + + test_circuit.table_rows = zk_padding>(test_circuit.table, alg_rnd); + + plonk_variable w0(0, 0, true, plonk_variable::column_type::witness); + plonk_variable w1(1, 0, true, plonk_variable::column_type::witness); + plonk_variable w2(2, 0, true, plonk_variable::column_type::witness); + + plonk_constraint add_constraint; + add_constraint += w0; + add_constraint += w1; + add_constraint -= w2; + + std::vector> add_gate_costraints {add_constraint}; + plonk_gate> add_gate(0, add_gate_costraints); + test_circuit.gates.push_back(add_gate); + + plonk_constraint mul_constraint; + typename plonk_constraint::term_type w0_term(w0); + typename plonk_constraint::term_type w1_term(w1); + mul_constraint += w0_term * w1_term; + mul_constraint -= w2; + + std::vector> mul_gate_costraints {mul_constraint}; + plonk_gate> mul_gate(1, mul_gate_costraints); + test_circuit.gates.push_back(mul_gate); + + return test_circuit; + } + + //---------------------------------------------------------------------------// + // Test circuit 2 (with rotations) + // i | GATE | w_0 | w_1 | w_2 | public | q_add | q_mul | + // 0 | -- | x | y | z | p1 | 0 | 0 | + // 1 | ADD | x | y | z | 0 | 1 | 0 | + // ... | ADD | x | y | z | 0 | 1 | 0 | + // k-2 | MUL | x | y | z | 0 | 0 | 1 | + // k-1 | MUL | x | y | z | 0 | 0 | 1 | + // + // ADD: x + y = z, copy(prev(z), y) + // MUL: x * y + prev(x) = z, copy(p1, y) + //---------------------------------------------------------------------------// + constexpr static const std::size_t witness_columns_t = 3; + constexpr static const std::size_t public_columns_t = 1; + constexpr static const std::size_t constant_columns_t = 0; + constexpr static const std::size_t selector_columns_t = 2; + constexpr static const std::size_t usable_rows_t = 5; + + template + circuit_description, usable_rows_t> + circuit_test_t( + typename FieldType::value_type pi0 = 0, + typename nil::crypto3::random::algebraic_engine alg_rnd = nil::crypto3::random::algebraic_engine(), + boost::random::mt11213b rnd = boost::random::mt11213b() + ) { + using assignment_type = typename FieldType::value_type; + + constexpr static const std::size_t usable_rows = usable_rows_t; + constexpr static const std::size_t witness_columns = witness_columns_t; + constexpr static const std::size_t public_columns = public_columns_t; + constexpr static const std::size_t constant_columns = constant_columns_t; + constexpr static const std::size_t selector_columns = selector_columns_t; + constexpr static const std::size_t table_columns = + witness_columns + public_columns + constant_columns; + + typedef placeholder_circuit_params circuit_params; + + circuit_description test_circuit; + test_circuit.public_input_sizes = {3}; + + std::vector> table(table_columns); + + std::vector q_mul(test_circuit.usable_rows); + std::vector q_add(test_circuit.usable_rows); + for (std::size_t j = 0; j < table_columns; j++) { + table[j].resize(test_circuit.usable_rows); + } + + // init values + typename FieldType::value_type one = FieldType::value_type::one(); + table[0][0] = alg_rnd(); + table[1][0] = alg_rnd(); + table[2][0] = alg_rnd(); + table[3][0] = pi0; + q_add[0] = FieldType::value_type::zero(); + q_mul[0] = FieldType::value_type::zero(); + + // fill rows with ADD gate + for (std::size_t i = 1; i < 3; i++) { + table[0][i] = alg_rnd(); + table[1][i] = table[2][i - 1]; + table[2][i] = table[0][i] + table[1][i]; + table[3][i] = FieldType::value_type::zero(); + q_add[i] = one; + q_mul[i] = FieldType::value_type::zero(); + + plonk_variable x(1, i, false, + plonk_variable::column_type::witness); + plonk_variable y(2, i - 1, false, + plonk_variable::column_type::witness); + test_circuit.copy_constraints.push_back(plonk_copy_constraint(x, y)); + } + + // fill rows with MUL gate + for (std::size_t i = 3; i < 5; i++) { + table[0][i] = alg_rnd(); + table[1][i] = table[3][0]; + table[2][i] = table[0][i] * table[1][i] + table[0][i - 1]; + table[3][i] = FieldType::value_type::zero(); + q_add[i] = FieldType::value_type::zero(); + q_mul[i] = one; + + plonk_variable x(1, i, false, + plonk_variable::column_type::witness); + plonk_variable y(0, 0, false, + plonk_variable::column_type::public_input); + test_circuit.copy_constraints.push_back(plonk_copy_constraint(x, y)); + } + table[3][1] = FieldType::value_type::zero(); + table[3][2] = FieldType::value_type::one(); + + std::vector> private_assignment(witness_columns); + for (std::size_t i = 0; i < witness_columns; i++) { + private_assignment[i] = table[i]; + } + + std::vector> selectors_assignment(selector_columns); + std::vector> public_input_assignment(public_columns); + std::vector> constant_assignment(constant_columns); + + selectors_assignment[0] = q_add; + selectors_assignment[1] = q_mul; + + for (std::size_t i = 0; i < public_columns; i++) { + public_input_assignment[i] = table[witness_columns + i]; + } + test_circuit.table = plonk_assignment_table( + plonk_private_assignment_table(private_assignment), + plonk_public_assignment_table( + public_input_assignment, constant_assignment, selectors_assignment)); + test_circuit.table_rows = zk_padding>(test_circuit.table, alg_rnd); + + plonk_variable w0(0, 0, true, + plonk_variable::column_type::witness); + plonk_variable w1(1, 0, true, + plonk_variable::column_type::witness); + plonk_variable w2(2, 0, true, + plonk_variable::column_type::witness); + plonk_variable w0_prev(0, -1, true, + plonk_variable::column_type::witness); + + plonk_constraint add_constraint; + add_constraint += w0; + add_constraint += w1; + add_constraint -= w2; + + std::vector> add_gate_costraints {add_constraint}; + plonk_gate> add_gate(0, add_gate_costraints); + test_circuit.gates.push_back(add_gate); + + plonk_constraint mul_constraint; + typename plonk_constraint::term_type w0_term(w0); + typename plonk_constraint::term_type w1_term(w1); + mul_constraint += w0_term * w1_term; + mul_constraint -= w2; + mul_constraint += w0_prev; + + std::vector> mul_gate_costraints {mul_constraint}; + plonk_gate> mul_gate(1, mul_gate_costraints); + //test_circuit.gates.push_back(mul_gate); + + return test_circuit; + } + + + constexpr static const std::size_t witness_columns_3 = 3; + constexpr static const std::size_t public_columns_3 = 0; + constexpr static const std::size_t constant_columns_3 = 3; + constexpr static const std::size_t selector_columns_3 = 2; + constexpr static const std::size_t usable_rows_3 = 4; + + template + circuit_description, usable_rows_3> circuit_test_3( + typename nil::crypto3::random::algebraic_engine alg_rnd = nil::crypto3::random::algebraic_engine(), + boost::random::mt11213b rnd = boost::random::mt11213b() + ) { + using assignment_type = typename FieldType::value_type; + + constexpr static const std::size_t witness_columns = witness_columns_3; + constexpr static const std::size_t public_columns = public_columns_3; + constexpr static const std::size_t constant_columns = constant_columns_3; + constexpr static const std::size_t selector_columns = selector_columns_3; + constexpr static const std::size_t table_columns = + witness_columns + public_columns + constant_columns; + constexpr static const std::size_t usable_rows = usable_rows_3; + + typedef placeholder_circuit_params circuit_params; + + circuit_description test_circuit; + + std::vector> table(table_columns); + for (std::size_t j = 0; j < table_columns; j++) { + table[j].resize(test_circuit.usable_rows); + } + + // lookup inputs + table[0] = {1, 0, 0, 0}; // Witness 1 + table[1] = {0, 0, 0, 0}; + table[2] = {0, 0, 0, 0}; + + table[3] = {0, 1, 0, 1}; //Lookup values + table[4] = {0, 0, 1, 0}; //Lookup values + table[5] = {0, 1, 0, 0}; //Lookup values + + std::vector> private_assignment(witness_columns); + for (std::size_t i = 0; i < witness_columns; i++) { + private_assignment[i] = table[i]; + } + + std::vector> public_input_assignment(public_columns); + std::vector> selectors_assignment(selector_columns); + std::vector> constant_assignment(constant_columns); + + std::vector sel_lookup(test_circuit.table_rows); + sel_lookup = {1, 0, 0, 0}; + selectors_assignment[0] = sel_lookup; + + std::vector sel_lookup_table(test_circuit.table_rows); + sel_lookup_table = {0, 1, 1, 1}; + selectors_assignment[1] = sel_lookup_table; + + for (std::size_t i = 0; i < constant_columns; i++) { + constant_assignment[i] = table[witness_columns + i]; + } + test_circuit.table = plonk_assignment_table( + plonk_private_assignment_table(private_assignment), + plonk_public_assignment_table( + public_input_assignment, constant_assignment, selectors_assignment)); + test_circuit.table_rows = zk_padding(test_circuit.table, alg_rnd); + + plonk_variable w0(0, 0, true, plonk_variable::column_type::witness); + plonk_variable w1(1, 0, true, plonk_variable::column_type::witness); + plonk_variable w2(2, 0, true, plonk_variable::column_type::witness); + + plonk_variable c0(0, 0, true, plonk_variable::column_type::constant); + plonk_variable c1(1, 0, true, plonk_variable::column_type::constant); + plonk_variable c2(2, 0, true, plonk_variable::column_type::constant); + + + plonk_lookup_constraint lookup_constraint; + lookup_constraint.lookup_input.push_back(w0); + lookup_constraint.lookup_input.push_back(w1); + lookup_constraint.lookup_input.push_back(w2); + lookup_constraint.table_id = 1; + + std::vector> lookup_constraints = {lookup_constraint}; + plonk_lookup_gate> lookup_gate(0, lookup_constraints); + test_circuit.lookup_gates.push_back(lookup_gate); + + // Add constructor for lookup table + plonk_lookup_table table1(3, 1); // 1 -- selector_id, 3 -- number of columns; + table1.append_option({c0, c1, c2}); + + test_circuit.lookup_tables.push_back(table1); + return test_circuit; + } + + // Binary multiplication. + // b_i -- random binaries, + // r_i ordinary random numbers. + // One gate: w1*w2 - w3 = 0 + // ---------------------------------------------------------------------------------- + // | Selector Gate| Selector Lookup| W1 | W2 | W3 | Lookup_tag | L1 | L2 | L3 | + // ------------------------------------------------------------------- + // | 1 | 1 | b1 | b2 | b1*b2 | 0 | 0 | 0 | 0 | -- reserved for unselected rows + // | 1 | 1 | b3 | b4 | b3*b4 | 1 | 0 | 0 | 0 | + // | 1 | 0 | r1 | r2 | r1*r2 | 1 | 0 | 1 | 0 | -- unselected for lookups + // | 1 | 1 | b5 | b6 | b5*b6 | 1 | 1 | 0 | 0 | + // | 1 | 1 | b7 | b8 | b7*b8 | 1 | 1 | 1 | 1 | + // ---------------------------------------------------------------------------------- + + constexpr static const std::size_t witness_columns_4= 3; + constexpr static const std::size_t public_columns_4 = 0; + constexpr static const std::size_t constant_columns_4 = 3; + constexpr static const std::size_t selector_columns_4 = 3; + + template + circuit_description, 5> circuit_test_4( + typename nil::crypto3::random::algebraic_engine alg_rnd = nil::crypto3::random::algebraic_engine(), + boost::random::mt11213b rnd = boost::random::mt11213b() + ) { + using assignment_type = typename FieldType::value_type; + + constexpr static const std::size_t rows_log = 3; + + constexpr static const std::size_t witness_columns = witness_columns_4; + constexpr static const std::size_t public_columns = public_columns_4; + constexpr static const std::size_t constant_columns = constant_columns_4; + constexpr static const std::size_t selector_columns = selector_columns_4; + constexpr static const std::size_t table_columns = + witness_columns + public_columns + constant_columns; + + typedef placeholder_circuit_params circuit_params; + + circuit_description test_circuit; + test_circuit.table_rows = 1 << rows_log; + + std::vector> table(table_columns); + for (std::size_t j = 0; j < table_columns; j++) { + table[j].resize(test_circuit.table_rows); + } + + // lookup inputs + table[0] = {rnd() % 2, rnd() % 2, rnd(), rnd() % 2, rnd() % 2, 0, 0, 0}; + table[1] = {rnd() % 2, rnd() % 2, rnd(), rnd() % 2, rnd() % 2, 0, 0, 0};; + table[2] = {table[0][0] * table[1][0], table[0][1] * table[1][1], table[0][2] * table[1][2], table[0][3] * table[1][3], table[0][4] * table[1][4], 0, 0, 0}; + + + //lookup values + // Reserved zero row for unselected lookup input rows + table[3] = {0, 0, 0, 1, 1, 0, 0, 0}; + table[4] = {0, 0, 1, 0, 1, 0, 0, 0}; + table[5] = {0, 0, 0, 0, 1, 0, 0, 0}; + + std::vector> private_assignment(witness_columns); + for (std::size_t i = 0; i < witness_columns; i++) { + private_assignment[i] = table[i]; + } + + std::vector> selectors_assignment(selector_columns); + std::vector> public_input_assignment(public_columns); + std::vector> constant_assignment(constant_columns); + + selectors_assignment[0] = {1, 1, 0, 1, 1, 0, 0, 0}; + selectors_assignment[1] = {1, 1, 1, 1, 1, 0, 0, 0}; + selectors_assignment[2] = {0, 1, 1, 1, 1, 0, 0, 0}; + + for (std::size_t i = 0; i < constant_columns; i++) { + constant_assignment[i] = table[witness_columns + i]; + } + test_circuit.table = plonk_assignment_table( + plonk_private_assignment_table(private_assignment), + plonk_public_assignment_table( + public_input_assignment, constant_assignment, selectors_assignment)); + + + plonk_variable w0(0, 0, true, plonk_variable::column_type::witness); + plonk_variable w1(1, 0, true, plonk_variable::column_type::witness); + plonk_variable w2(2, 0, true, plonk_variable::column_type::witness); + + plonk_variable c0(0, 0, true, plonk_variable::column_type::constant); + plonk_variable c1(1, 0, true, plonk_variable::column_type::constant); + plonk_variable c2(2, 0, true, plonk_variable::column_type::constant); + + plonk_constraint mul_constraint; + typename plonk_constraint::term_type w0_term(w0); + typename plonk_constraint::term_type w1_term(w1); + mul_constraint += w0_term * w1_term; + mul_constraint -= w2; + + std::vector> mul_gate_costraints {mul_constraint}; + plonk_gate> mul_gate(1, mul_gate_costraints); + test_circuit.gates.push_back(mul_gate); + + plonk_lookup_constraint lookup_constraint; + lookup_constraint.lookup_input.push_back(w0); + lookup_constraint.lookup_input.push_back(w1); + lookup_constraint.lookup_input.push_back(w2); + lookup_constraint.table_id = 1; + + std::vector> lookup_constraints = {lookup_constraint}; + plonk_lookup_gate> lookup_gate(0, lookup_constraints); + test_circuit.lookup_gates.push_back(lookup_gate); + + // Add constructor for lookup table + plonk_lookup_table table1(3, 2); // 2 -- selector_id, 3 -- number of columns; + table1.append_option({c0, c1, c2}); + + test_circuit.lookup_tables.push_back(table1); + return test_circuit; + } + + //---------------------------------------------------------------------------// + // Test circuit 5 (wide table) + // i | GATE | w_0 | w_1 | w_2 | ... | w135 | public | q_mul | + // 0 | -- | p_0 | p_1 | p_2 | | p135 | p0 | 0 | + // 1 | | q0 | q1 | q2 | | q135 | p1 | 1 | + // 2 | | r0 | r1 | r2 | | r135 | ... | 0 | + // ...| ... | | | | | 0 | p135 | 0 | + // + // MUL: w_{i-1} - w_{i} * w_{i+1} = 0 + //---------------------------------------------------------------------------// + constexpr static const std::size_t witness_columns_5 = 30; + constexpr static const std::size_t public_columns_5 = 1; + constexpr static const std::size_t constant_columns_5 = 0; + constexpr static const std::size_t selector_columns_5 = 1; + constexpr static const std::size_t usable_rows_5 = 30; + + template + circuit_description, usable_rows_5> + circuit_test_5( + typename nil::crypto3::random::algebraic_engine alg_rnd = nil::crypto3::random::algebraic_engine(), + boost::random::mt11213b rnd = boost::random::mt11213b() + ) { + using assignment_type = typename FieldType::value_type; + + constexpr static const std::size_t usable_rows = usable_rows_5; + constexpr static const std::size_t witness_columns = witness_columns_5; + constexpr static const std::size_t public_input_columns = public_columns_5; + constexpr static const std::size_t constant_columns = constant_columns_5; + constexpr static const std::size_t selector_columns = selector_columns_5; + constexpr static const std::size_t table_columns = + witness_columns + public_input_columns + constant_columns; + + typedef placeholder_circuit_params circuit_params; + + circuit_description test_circuit; + test_circuit.public_input_sizes = {witness_columns}; + + std::vector> private_assignment(witness_columns); + std::vector> public_input_assignment(public_input_columns); + std::vector> constant_assignment(constant_columns); + std::vector> selectors_assignment(selector_columns); + + public_input_assignment[0].resize(test_circuit.usable_rows); + selectors_assignment[0].resize(test_circuit.usable_rows); + for(std::size_t i = 0; i < witness_columns; i++) { + private_assignment[i].resize(test_circuit.usable_rows); + private_assignment[i][0] = private_assignment[i][2] = public_input_assignment[0][i] = typename FieldType::value_type(rnd() % witness_columns); + private_assignment[i][1] = 1; + plonk_variable pi(0, i, false, plonk_variable::column_type::public_input); + plonk_variable wi(i, 0, false, plonk_variable::column_type::witness); + test_circuit.copy_constraints.push_back(plonk_copy_constraint({pi, wi})); + } + selectors_assignment[0][1] = 1; + + test_circuit.table = plonk_assignment_table( + plonk_private_assignment_table(private_assignment), + plonk_public_assignment_table( + public_input_assignment, constant_assignment, selectors_assignment)); + test_circuit.table_rows = zk_padding>(test_circuit.table, alg_rnd); + + std::vector> mul_gate_constraints; + for( std::size_t i = 0; i < witness_columns; i++){ + plonk_variable w0(i, -1, true, plonk_variable::column_type::witness); + plonk_variable w1(i, 0, true, plonk_variable::column_type::witness); + plonk_variable w2(i, 1, true, plonk_variable::column_type::witness); + mul_gate_constraints.push_back(w0 - w1 * w2); + } + + plonk_gate> mul_gate(0, mul_gate_constraints); + test_circuit.gates.push_back(mul_gate); + + return test_circuit; + } + + //---------------------------------------------------------------------------// + // Test fibonacci circuit + // i | GATE | w_0 | public | q_add | + // 0 | -- | f(0) | a | 0 | + // 1 | FIB | f(1) | b | 1 | + // ... | FIB | | 0 | 1 | + // k-2 | FIB | f(k-2) | 0 | 0 | + // k-1 | -- | f(k-1) | 0 | 0 | + // + // public input is copy constrainted to f(0) and f(1) + // FIB: w_0(i-1) + w_0(i) == w_0(i+1) + //---------------------------------------------------------------------------// + constexpr static const std::size_t witness_columns_fib = 1; + constexpr static const std::size_t public_columns_fib = 1; + constexpr static const std::size_t constant_columns_fib = 0; + constexpr static const std::size_t selector_columns_fib = 1; + + template + circuit_description, usable_rows> + circuit_test_fib( + typename nil::crypto3::random::algebraic_engine alg_rnd = nil::crypto3::random::algebraic_engine() + ) { + using assignment_type = typename FieldType::value_type; + + constexpr static const std::size_t witness_columns = witness_columns_fib; + constexpr static const std::size_t public_columns = public_columns_fib; + constexpr static const std::size_t constant_columns = constant_columns_fib; + constexpr static const std::size_t selector_columns = selector_columns_fib; + constexpr static const std::size_t table_columns = + witness_columns + public_columns + selector_columns; + + typedef placeholder_circuit_params circuit_params; + + circuit_description test_circuit; + std::vector> table(table_columns); + + std::vector q_add(test_circuit.usable_rows); + std::vector q_mul(test_circuit.usable_rows); + for (std::size_t j = 0; j < table_columns; j++) { + table[j].resize(test_circuit.usable_rows); + } + // init values + typename FieldType::value_type zero = FieldType::value_type::zero(); + typename FieldType::value_type one = FieldType::value_type::one(); + // witness + table[0][0] = one; + table[0][1] = one; + + // public input + table[1][0] = one; + table[1][1] = one; + + // selector + table[2][0] = zero; + table[2][1] = one; + + plonk_variable x0(0, 0, false, plonk_variable::column_type::witness); + plonk_variable x1(0, 1, false, plonk_variable::column_type::witness); + plonk_variable p0(1, 0, false, plonk_variable::column_type::public_input); + plonk_variable p1(1, 1, false, plonk_variable::column_type::public_input); + +// test_circuit.copy_constraints.push_back(plonk_copy_constraint(x0, p0)); +// test_circuit.copy_constraints.push_back(plonk_copy_constraint(x1, p1)); + + for (std::size_t i = 2; i < test_circuit.usable_rows - 1; i++) { + table[0][i] = table[0][i-2] + table[0][i-1]; + table[1][i] = zero; + table[2][i-1] = one; + } + + std::vector> private_assignment(witness_columns); + private_assignment[0] = table[0]; + + std::vector> selectors_assignment(selector_columns); + std::vector> public_input_assignment(public_columns); + std::vector> constant_assignment(constant_columns); + + selectors_assignment[0] = table[2]; + + public_input_assignment[0] = table[1]; + selectors_assignment[0] = table[2]; + + + test_circuit.table = plonk_assignment_table( + plonk_private_assignment_table(private_assignment), + plonk_public_assignment_table( + public_input_assignment, constant_assignment, selectors_assignment)); + test_circuit.table_rows = zk_padding>(test_circuit.table, alg_rnd); + + plonk_variable w0(0, -1, true, plonk_variable::column_type::witness); + plonk_variable w1(0, 0, true, plonk_variable::column_type::witness); + plonk_variable w2(0, 1, true, plonk_variable::column_type::witness); + + typename plonk_constraint::term_type w0_term(w0); + typename plonk_constraint::term_type w1_term(w1); + typename plonk_constraint::term_type w2_term(w2); + + plonk_constraint fib_constraint; + fib_constraint += w0_term; + fib_constraint += w1_term; + fib_constraint -= w2_term; + + std::vector> fib_costraints {fib_constraint}; + plonk_gate> fib_gate(0, fib_costraints); + test_circuit.gates.push_back(fib_gate); + + return test_circuit; + } + + // Long range check: + // Table 1: Selector LT1 options L1 + // Table 2: Selector LT1 options L1 || L2 || L3 + // Lookup gate1: + // w1 \in Table 1 + // W2 \in Table 2 + // Lookup gate2: + // w1{-1} + w1 \in Table 2 + // --------------------------------------------------------------------------------- + // | s1 | s2 | W1 | W2 | LT1 | L1 | L2 | L3 | + // --------------------------------------------------------------------------------- + // | 1 | 0 | r1 | 7 | 0 | 0 | 0 | 0 | -- reserved for unselected rows + // | 1 | 1 | r2 | r1+r2 | 1 | 2 | 7 | 12 | -- reserved for unselected rows + // | 1 | 1 | r3 | r2+r3 | 1 | 3 | 8 | 12 | + // | 1 | 1 | r4 | r3+r4 | 1 | 4 | 9 | 12 | -- unselected for lookups + // | 1 | 1 | r5 | r4+r5 | 1 | 5 | 10 | 12 | + // | 1 | 1 | r6 | r5+r6 | 1 | 6 | 11 | 12 | + // --------------------------------------------------------------------------------- + + constexpr static const std::size_t witness_columns_6= 2; + constexpr static const std::size_t public_columns_6 = 0; + constexpr static const std::size_t constant_columns_6 = 3; + constexpr static const std::size_t selector_columns_6 = 3; + constexpr static const std::size_t usable_rows_6 = 6; + + template + circuit_description, usable_rows_6> circuit_test_6( + typename nil::crypto3::random::algebraic_engine alg_rnd = nil::crypto3::random::algebraic_engine(), + boost::random::mt11213b rnd = boost::random::mt11213b() + ) { + using assignment_type = typename FieldType::value_type; + + constexpr static const std::size_t witness_columns = witness_columns_6; + constexpr static const std::size_t public_columns = public_columns_6; + constexpr static const std::size_t constant_columns = constant_columns_6; + constexpr static const std::size_t selector_columns = selector_columns_6; + constexpr static const std::size_t table_columns = + witness_columns + public_columns + constant_columns + selector_columns; + + typedef placeholder_circuit_params circuit_params; + + circuit_description test_circuit; + + std::vector> table(table_columns); + for (std::size_t j = 0; j < table_columns; j++) { + table[j].resize(test_circuit.usable_rows); + } + + // lookup inputs + table[0] = {rnd() % 5 + 2, rnd() % 5 + 2, rnd() % 5 + 2, rnd() % 5 + 2, rnd() % 5 + 2, rnd() % 5 + 2}; + table[1] = {7, table[0][0] + table[0][1], table[0][1] + table[0][2], table[0][2] + table[0][3], table[0][3] + table[0][4], table[0][4] + table[0][5]}; + + + // selectors + // Reserved zero row for unselected lookup input rows + table[2] = {0, 1, 1, 1, 1, 1}; // LT1 + table[3] = {1, 1, 1, 1, 1, 1}; // For the first lookup gate + table[4] = {0, 1, 1, 1, 1, 1}; // For the second lookup gate + + // Lookup values + table[5] = {0, 2, 3, 4, 5, 6}; // L1 + table[6] = {0, 7, 8, 9, 10, 11}; // L2 + table[7] = {0, 12, 12, 12, 12, 12}; // L3 + + std::vector> private_assignment(witness_columns); + for (std::size_t i = 0; i < witness_columns; i++) { + private_assignment[i] = table[i]; + } + + std::vector> selectors_assignment(selector_columns); + std::vector> public_input_assignment(public_columns); + std::vector> constant_assignment(constant_columns); + + selectors_assignment[0] = table[2]; + selectors_assignment[1] = table[3]; + selectors_assignment[2] = table[4]; + + for (std::size_t i = 0; i < constant_columns; i++) { + constant_assignment[i] = table[witness_columns + selector_columns + i]; + } + test_circuit.table = plonk_assignment_table( + plonk_private_assignment_table(private_assignment), + plonk_public_assignment_table( + public_input_assignment, constant_assignment, selectors_assignment)); + test_circuit.table_rows = zk_padding(test_circuit.table, alg_rnd); + + plonk_variable w0( 0, 0, true, plonk_variable::column_type::witness); + plonk_variable w0_1(0,-1, true, plonk_variable::column_type::witness); + plonk_variable w1( 1, 0, true, plonk_variable::column_type::witness); + + plonk_variable c0(0, 0, true, plonk_variable::column_type::constant); + plonk_variable c1(1, 0, true, plonk_variable::column_type::constant); + plonk_variable c2(2, 0, true, plonk_variable::column_type::constant); + + plonk_lookup_constraint lookup_constraint1; + lookup_constraint1.lookup_input.push_back(w0); + lookup_constraint1.table_id = 1; + + plonk_lookup_constraint lookup_constraint2; + lookup_constraint2.lookup_input.push_back(w1); + lookup_constraint2.table_id = 2; + + std::vector> lookup_constraints = {lookup_constraint1, lookup_constraint2}; + plonk_lookup_gate> lookup_gate(1, lookup_constraints); + test_circuit.lookup_gates.push_back(lookup_gate); + + + plonk_lookup_constraint lookup_constraint3; + plonk_constraint add_constraint; + add_constraint += w0_1; + add_constraint += w0; + lookup_constraint3.lookup_input.push_back(add_constraint); + lookup_constraint3.table_id = 2; + + std::vector> lookup_constraints2 = {lookup_constraint3}; + plonk_lookup_gate> lookup_gate2(2, lookup_constraints2); + test_circuit.lookup_gates.push_back(lookup_gate2); + + // Add constructor for lookup table + plonk_lookup_table table1(1, 0); // 2 -- selector_id, 3 -- number of columns; + table1.append_option({c0}); + test_circuit.lookup_tables.push_back(table1); + + plonk_lookup_table table2(1, 0); // 2 -- selector_id, 3 -- number of columns; + table2.append_option({c0}); + table2.append_option({c1}); + table2.append_option({c2}); + test_circuit.lookup_tables.push_back(table2); + + return test_circuit; + } + + // Big columns rotations check: + // Table 1: LT1 options: {L1, L2, L3, L4, L5, L6, L7} + // Table 2: LT2 options: {L1, L2} || { L3, L4 } + // Table 3: LT2 options: {L5} || {L6} || {L7} + // Lookup gate1: + // w1{-3}, w1{-2}, w1{-1}, w1, w1{+1}, w1{+2},w1{+3}, \in Table 1 selector s2 + // w1, w2 \in Table 2 selector s0 + // w2{-1} * w2 \in Table 3 selector s3 + // Gate1 + // w1{+7} - w1 = 0 + // ---------------------------------------------------------------------------------------- + // | s0 | s1 | s2 | s3 | W1 | W2 | LT1 | LT2 | L1 | L2 | L3 | L4 | L5 | L6 | L7 + // ---------------------------------------------------------------------------------------- + // | 1 | 1 | 0 | 0 | 1 | 2^w1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 -- reserved for unselected rows + // | 1 | 1 | 0 | 1 | 2 | 2^w1 | 1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 + // | 1 | 1 | 0 | 1 | 3 | 2^w1 | 1 | 0 | 0 | 2 | 3 | 4 | 5 | 6 | 7 + // | 1 | 1 | 1 | 1 | 4 | 2^w1 | 1 | 0 | 0 | 1 | 3 | 4 | 5 | 6 | 7 -- unselected for lookups + // | 1 | 1 | 1 | 1 | 5 | 2^w1 | 1 | 0 | 0 | 1 | 2 | 4 | 5 | 6 | 7 + // | 1 | 1 | 1 | 1 | 6 | 2^w1 | 1 | 0 | 0 | 1 | 2 | 3 | 4 | 6 | 7 + // | 1 | 0 | 1 | 1 | 7 | 2^w1 | 1 | 0 | 0 | 1 | 2 | 3 | 4 | 5 | 7 + // | 1 | 0 | 1 | 1 | 0 | 2^w1 | 1 | 0 | 0 | 1 | 2 | 3 | 4 | 5 | 6 + // | 1 | 0 | 1 | 1 | 1 | 2^w1 | 0 | 1 | 0 | 1 | 6 | 64| 1 | 64 |4096 + // | 1 | 0 | 1 | 1 | 2 | 2^w1 | 0 | 1 | 1 | 2 | 7 | 128| 2 |128 |8192 + // | 1 | 0 | 1 | 1 | 3 | 2^w1 | 0 | 1 | 2 | 4 | 7 | 128| 4 |256 |16384 + // | 1 | 0 | 0 | 1 | 4 | 2^w1 | 0 | 1 | 3 | 8 | 7 | 128| 8 |512 |16384 + // | 1 | 0 | 0 | 1 | 5 | 2^w1 | 0 | 1 | 4 | 16 | 7 | 128| 16 |1024|16384 + // | 1 | 0 | 0 | 1 | 6 | 2^w1 | 0 | 1 | 5 | 32 | 7 | 128| 32 |2048|16384 + // --------------------------------------------------------------------------------- + constexpr static const std::size_t witness_columns_7= 2; + constexpr static const std::size_t public_columns_7 = 0; + constexpr static const std::size_t constant_columns_7 = 7; + constexpr static const std::size_t selector_columns_7 = 6; + constexpr static const std::size_t usable_rows_7 = 14; + + template + circuit_description, usable_rows_7> circuit_test_7( + typename nil::crypto3::random::algebraic_engine alg_rnd = nil::crypto3::random::algebraic_engine(), + boost::random::mt11213b rnd = boost::random::mt11213b() + ) { + using assignment_type = typename FieldType::value_type; + + constexpr static const std::size_t witness_columns = witness_columns_7; + constexpr static const std::size_t public_columns = public_columns_7; + constexpr static const std::size_t constant_columns = constant_columns_7; + constexpr static const std::size_t selector_columns = selector_columns_7; + constexpr static const std::size_t table_columns = + witness_columns + public_columns + constant_columns + selector_columns; + + typedef placeholder_circuit_params circuit_params; + + circuit_description test_circuit; + + std::vector> table(table_columns); + for (std::size_t j = 0; j < table_columns; j++) { + table[j].resize(test_circuit.usable_rows); + } + + // lookup inputs + auto r = rnd() % 7; + table[0] = std::vector(16); + std::size_t j = 0; + for( std::size_t i = 0; i < 7; i++){ + if( j == r ) j++; + table[0][i] = j; + table[1][i] = (typename FieldType::value_type(2)).pow(j); + j++; + } + for( std::size_t i = 7; i < 14; i++){ + table[0][i]=table[0][i-7]; + table[1][i]=table[1][i-7]; + } + + // selectors + // Reserved zero row for unselected lookup input rows + std::vector> selectors_assignment(selector_columns); + selectors_assignment[0] = {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1 }; // Selector for single gate + selectors_assignment[1] = {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }; // Selector lookup gate with multiple rotations + selectors_assignment[2] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; // Selector for gate w1 = 2^w0 + selectors_assignment[3] = {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; // Selector for gate w1_{-1} * w1 \in Table 3 + selectors_assignment[4] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1 }; // Selector for lookup tables 2, 3 + selectors_assignment[5] = {0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0 }; // Selector for lookup table with 7 columns + + // Lookup values + std::vector> constant_assignment(constant_columns); + constant_assignment[0] = {0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5 }; // Lookup tables + constant_assignment[1] = {0, 2, 2, 1, 1, 1, 1, 1, 1, 2, 4, 8, 16, 32 }; // Lookup tables + constant_assignment[2] = {0, 3, 3, 3, 2, 2, 2, 2, 6, 7, 7, 7, 7, 7 }; // Lookup tables + constant_assignment[3] = {0, 4, 4, 4, 4, 3, 3, 3, 64, 128, 128, 128, 128, 128 }; // Lookup tables + constant_assignment[4] = {0, 5, 5, 5, 5, 5, 4, 4, 1, 2, 4, 8, 16, 32 }; // Lookup tables + constant_assignment[5] = {0, 6, 6, 6, 6, 6, 6, 5, 64, 128, 256, 512, 1024, 2048 }; // Lookup tables + constant_assignment[6] = {0, 7, 7, 7, 7, 7, 7, 7,4096,8192,16384,16384,16384,16384 }; // Lookup tables + + std::vector> private_assignment(witness_columns); + for (std::size_t i = 0; i < witness_columns; i++) { + private_assignment[i] = table[i]; + } + + std::vector> public_input_assignment(public_columns); + + test_circuit.table = plonk_assignment_table( + plonk_private_assignment_table(private_assignment), + plonk_public_assignment_table( + public_input_assignment, constant_assignment, selectors_assignment)); + test_circuit.table_rows = zk_padding(test_circuit.table, alg_rnd); + + plonk_variable w0( 0, 0, true, plonk_variable::column_type::witness); + plonk_variable w0__7(0,-7, true, plonk_variable::column_type::witness); + + plonk_constraint add_constraint; + add_constraint += w0; + add_constraint -= w0__7; + + std::vector> add_gate_costraints {add_constraint}; + plonk_gate> add_gate(0, add_gate_costraints); + test_circuit.gates.push_back(add_gate); + + plonk_variable w0__3( 0,-3, true, plonk_variable::column_type::witness); + plonk_variable w0__2( 0,-2, true, plonk_variable::column_type::witness); + plonk_variable w0__1( 0,-1, true, plonk_variable::column_type::witness); + plonk_variable w0_1 ( 0, 1, true, plonk_variable::column_type::witness); + plonk_variable w0_2 ( 0, 2, true, plonk_variable::column_type::witness); + plonk_variable w0_3 ( 0, 3, true, plonk_variable::column_type::witness); + + + plonk_variable c0 ( 0, 0, true, plonk_variable::column_type::constant); + plonk_variable c1 ( 1, 0, true, plonk_variable::column_type::constant); + plonk_variable c2 ( 2, 0, true, plonk_variable::column_type::constant); + plonk_variable c3 ( 3, 0, true, plonk_variable::column_type::constant); + plonk_variable c4 ( 4, 0, true, plonk_variable::column_type::constant); + plonk_variable c5 ( 5, 0, true, plonk_variable::column_type::constant); + plonk_variable c6 ( 6, 0, true, plonk_variable::column_type::constant); + + plonk_lookup_constraint lookup_constraint1; + lookup_constraint1.lookup_input = {w0__3, w0__2, w0__1, w0, w0_1, w0_2, w0_3}; + lookup_constraint1.table_id = 1; + + std::vector> lookup_constraints = {lookup_constraint1}; + plonk_lookup_gate> lookup_gate(1, lookup_constraints); + test_circuit.lookup_gates.push_back(lookup_gate); + + plonk_variable w1( 1, 0, true, plonk_variable::column_type::witness); + plonk_lookup_constraint lookup_constraint2; + lookup_constraint2.lookup_input = {w0, w1}; + lookup_constraint2.table_id = 2; + + std::vector> lookup_constraints2 = {lookup_constraint2}; + plonk_lookup_gate> lookup_gate2(2, lookup_constraints2); + test_circuit.lookup_gates.push_back(lookup_gate2); + + plonk_variable w1__1( 1, -1, true, plonk_variable::column_type::witness); + plonk_lookup_constraint lookup_constraint3; + typename plonk_constraint::term_type w1__1_term(w1__1); + typename plonk_constraint::term_type w1_term(w1); + lookup_constraint3.lookup_input = {w1__1_term* w1_term}; + lookup_constraint3.table_id = 3; + + std::vector> lookup_constraints3 = {lookup_constraint3}; + plonk_lookup_gate> lookup_gate3(3, lookup_constraints3); + test_circuit.lookup_gates.push_back(lookup_gate3); + + plonk_lookup_table lookup_table(7, 5); // 5 -- selector_id, 7 -- number of columns; + lookup_table.append_option({c0, c1, c2, c3, c4, c5, c6}); + test_circuit.lookup_tables.push_back(lookup_table); + + plonk_lookup_table lookup_table2(2, 4); // 4 -- selector_id, 2 -- number of columns; + lookup_table2.append_option({c0, c1}); + lookup_table2.append_option({c2, c3}); + test_circuit.lookup_tables.push_back(lookup_table2); + + plonk_lookup_table lookup_table3(1, 4); // 4 -- selector_id, 1 -- number of columns; + lookup_table3.append_option({c4}); + lookup_table3.append_option({c5}); + lookup_table3.append_option({c6}); + test_circuit.lookup_tables.push_back(lookup_table3); + + return test_circuit; + } + } // namespace snark + } // namespace zk + } // namespace crypto3 +} // namespace nil + +#endif // CRYPTO3_ZK_TEST_PLONK_CIRCUITS_HPP diff --git a/libs/transpiler/test/transpiler.cpp b/libs/transpiler/test/transpiler.cpp new file mode 100644 index 000000000..d0683f921 --- /dev/null +++ b/libs/transpiler/test/transpiler.cpp @@ -0,0 +1,1750 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2023 Elena Tatuzova +// +// 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 transpiler_test + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "./detail/circuits.hpp" + +using namespace nil; +using namespace nil::crypto3; +using namespace nil::crypto3::zk; +using namespace nil::crypto3::zk::snark; + +inline std::vector generate_random_step_list(const std::size_t r, const int max_step) { + using dist_type = std::uniform_int_distribution; + static std::random_device random_engine; + + std::vector step_list; + std::size_t steps_sum = 0; + while (steps_sum != r) { + if (r - steps_sum <= max_step) { + while (r - steps_sum != 1) { + step_list.emplace_back(r - steps_sum - 1); + steps_sum += step_list.back(); + } + step_list.emplace_back(1); + steps_sum += step_list.back(); + } else { + step_list.emplace_back(dist_type(1, max_step)(random_engine)); + steps_sum += step_list.back(); + } + } + return step_list; +} + +// ******************************************************************************* +// * Randomness setup +// *******************************************************************************/ +using dist_type = std::uniform_int_distribution; +std::size_t test_global_seed = 0; +boost::random::mt11213b test_global_rnd_engine; +template +nil::crypto3::random::algebraic_engine test_global_alg_rnd_engine; + +struct test_initializer { + // Enumerate all fields used in tests; + using field1_type = algebra::curves::pallas::base_field_type; + using field2_type = algebra::curves::bls12<381>::scalar_field_type; + test_initializer() { + test_global_seed = 0; + + for (std::size_t i = 0; i < boost::unit_test::framework::master_test_suite().argc - 1; i++) { + if (std::string(boost::unit_test::framework::master_test_suite().argv[i]) == "--seed") { + if (std::string(boost::unit_test::framework::master_test_suite().argv[i + 1]) == "random") { + std::random_device rd; + test_global_seed = rd(); + std::cout << "Random seed = " << test_global_seed << std::endl; + break; + } + if (std::regex_match(boost::unit_test::framework::master_test_suite().argv[i + 1], + std::regex(("((\\+|-)?[[:digit:]]+)(\\.(([[:digit:]]+)?))?")))) { + test_global_seed = atoi(boost::unit_test::framework::master_test_suite().argv[i + 1]); + break; + } + } + } + + BOOST_TEST_MESSAGE("test_global_seed = " << test_global_seed); + test_global_rnd_engine = boost::random::mt11213b(test_global_seed); + test_global_alg_rnd_engine = nil::crypto3::random::algebraic_engine(test_global_seed); + test_global_alg_rnd_engine = nil::crypto3::random::algebraic_engine(test_global_seed); + } + + void setup() { + } + + void teardown() { + } + + ~test_initializer() { + } +}; + +BOOST_AUTO_TEST_SUITE(placeholder_circuit1) + using Endianness = nil::marshalling::option::big_endian; + using TTypeBase = nil::marshalling::field_type; + + using curve_type = algebra::curves::pallas; + using field_type = typename curve_type::base_field_type; + + using merkle_hash_type = hashes::keccak_1600<256>; + using transcript_hash_type = hashes::keccak_1600<256>; + + struct placeholder_test_params { + constexpr static const std::size_t witness_columns = witness_columns_1; + constexpr static const std::size_t public_input_columns = public_columns_1; + constexpr static const std::size_t constant_columns = constant_columns_1; + constexpr static const std::size_t selector_columns = selector_columns_1; + + constexpr static const std::size_t lambda = 10; + constexpr static const std::size_t m = 2; + }; + typedef placeholder_circuit_params circuit_params; + using transcript_type = typename transcript::fiat_shamir_heuristic_sequential; + + using lpc_params_type = commitments::list_polynomial_commitment_params< + merkle_hash_type, + transcript_hash_type, + placeholder_test_params::m + >; + + using lpc_type = commitments::list_polynomial_commitment; + using lpc_scheme_type = typename commitments::lpc_commitment_scheme; + using lpc_placeholder_params_type = nil::crypto3::zk::snark::placeholder_params; + using policy_type = zk::snark::detail::placeholder_policy; + +BOOST_FIXTURE_TEST_CASE(transpiler_test, test_initializer) { + auto circuit = circuit_test_1(test_global_alg_rnd_engine); + + plonk_table_description desc( + placeholder_test_params::witness_columns, + placeholder_test_params::public_input_columns, + placeholder_test_params::constant_columns, + placeholder_test_params::selector_columns + ); + + desc.rows_amount = circuit.table_rows; + desc.usable_rows_amount = circuit.usable_rows; + std::size_t table_rows_log = std::ceil(std::log2(circuit.table_rows)); + + typename policy_type::constraint_system_type constraint_system( + circuit.gates, + circuit.copy_constraints, + circuit.lookup_gates, + circuit.lookup_tables + ); + typename policy_type::variable_assignment_type assignments = circuit.table; + + typename lpc_type::fri_type::params_type fri_params( + 1, table_rows_log, placeholder_test_params::lambda, 4, false + ); + lpc_scheme_type lpc_scheme(fri_params); + + typename placeholder_public_preprocessor::preprocessed_data_type + lpc_preprocessed_public_data = placeholder_public_preprocessor::process( + constraint_system, assignments.public_table(), desc, lpc_scheme + ); + + auto printer = nil::blueprint::evm_verifier_printer( + constraint_system, + lpc_preprocessed_public_data.common_data, + "circuit1", + 26, // gates library size threshold + 60, // lookups library size threshold + 13, // gates inline size threshold + 15 // lookups inline size threshold + ); + printer.print(); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(placeholder_circuit2) + using Endianness = nil::marshalling::option::big_endian; + using TTypeBase = nil::marshalling::field_type; + + using curve_type = algebra::curves::bls12<381>; + using field_type = typename curve_type::scalar_field_type; + + struct placeholder_test_params { + using BlueprintFieldType = algebra::curves::pallas::base_field_type; + using merkle_hash_type = hashes::keccak_1600<256>; + using transcript_hash_type = hashes::keccak_1600<256>; + + constexpr static const std::size_t witness_columns = 3; + constexpr static const std::size_t public_input_columns = 1; + constexpr static const std::size_t constant_columns = 0; + constexpr static const std::size_t selector_columns = 2; + + constexpr static const std::size_t lambda = 1; + constexpr static const std::size_t m = 2; + }; + using circuit_t_params = placeholder_circuit_params< + field_type + >; + + using transcript_type = typename transcript::fiat_shamir_heuristic_sequential; + + using lpc_params_type = commitments::list_polynomial_commitment_params< + typename placeholder_test_params::merkle_hash_type, + typename placeholder_test_params::transcript_hash_type, + placeholder_test_params::m + >; + + using lpc_type = commitments::list_polynomial_commitment; + using lpc_scheme_type = typename commitments::lpc_commitment_scheme; + using lpc_placeholder_params_type = nil::crypto3::zk::snark::placeholder_params; + + using policy_type = zk::snark::detail::placeholder_policy; + +BOOST_FIXTURE_TEST_CASE(transpiler_test, test_initializer) { + auto pi0 = test_global_alg_rnd_engine(); + auto circuit = circuit_test_t(pi0, test_global_alg_rnd_engine, test_global_rnd_engine); + + plonk_table_description desc( + placeholder_test_params::witness_columns, + placeholder_test_params::public_input_columns, + placeholder_test_params::constant_columns, + placeholder_test_params::selector_columns + ); + + desc.rows_amount = circuit.table_rows; + desc.usable_rows_amount = circuit.usable_rows; + std::size_t table_rows_log = std::ceil(std::log2(circuit.table_rows)); + + typename policy_type::constraint_system_type constraint_system( + circuit.gates, + circuit.copy_constraints, + circuit.lookup_gates, + circuit.lookup_tables + ); + typename policy_type::variable_assignment_type assignments = circuit.table; + + bool verifier_res; + + // LPC commitment scheme + typename lpc_type::fri_type::params_type fri_params( + 1, table_rows_log, placeholder_test_params::lambda, 4 + ); + lpc_scheme_type lpc_scheme(fri_params); + + typename placeholder_public_preprocessor::preprocessed_data_type + lpc_preprocessed_public_data = placeholder_public_preprocessor::process( + constraint_system, assignments.public_table(), desc, lpc_scheme + ); + auto printer = nil::blueprint::evm_verifier_printer( + constraint_system, + lpc_preprocessed_public_data.common_data, + "circuit2", + 26, // gates library size threshold + 60, // lookups library size threshold + 13, // gates inline size threshold + 15 // lookups inline size threshold + ); + printer.print(); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(placeholder_circuit3) + using Endianness = nil::marshalling::option::big_endian; + using TTypeBase = nil::marshalling::field_type; + using curve_type = algebra::curves::pallas; + using field_type = typename curve_type::base_field_type; + + struct placeholder_test_params { + using BlueprintFieldType = algebra::curves::pallas::base_field_type; + using merkle_hash_type = hashes::keccak_1600<256>; + using transcript_hash_type = hashes::keccak_1600<256>; + + constexpr static const std::size_t witness_columns = witness_columns_3; + constexpr static const std::size_t public_input_columns = public_columns_3; + constexpr static const std::size_t constant_columns = constant_columns_3; + constexpr static const std::size_t selector_columns = selector_columns_3; + + constexpr static const std::size_t lambda = 10; + constexpr static const std::size_t m = 2; + }; + + using circuit_params = placeholder_circuit_params; + using transcript_type = typename transcript::fiat_shamir_heuristic_sequential; + using lpc_params_type = commitments::list_polynomial_commitment_params< + typename placeholder_test_params::merkle_hash_type, + typename placeholder_test_params::transcript_hash_type, + placeholder_test_params::m + >; + + using lpc_type = commitments::list_polynomial_commitment; + using lpc_scheme_type = typename commitments::lpc_commitment_scheme; + using lpc_placeholder_params_type = nil::crypto3::zk::snark::placeholder_params; + using policy_type = zk::snark::detail::placeholder_policy; + +BOOST_FIXTURE_TEST_CASE(transpiler_test, test_initializer) { + auto circuit = circuit_test_3(test_global_alg_rnd_engine, test_global_rnd_engine); + + plonk_table_description desc( + placeholder_test_params::witness_columns, + placeholder_test_params::public_input_columns, + placeholder_test_params::constant_columns, + placeholder_test_params::selector_columns + ); + + desc.rows_amount = circuit.table_rows; + desc.usable_rows_amount = circuit.usable_rows; + std::size_t table_rows_log = std::ceil(std::log2(circuit.table_rows)); + + typename policy_type::constraint_system_type constraint_system( + circuit.gates, + circuit.copy_constraints, + circuit.lookup_gates, + circuit.lookup_tables + ); + typename policy_type::variable_assignment_type assignments = circuit.table; + + typename lpc_type::fri_type::params_type fri_params( + 1, table_rows_log, placeholder_test_params::lambda, 4 + ); + lpc_scheme_type lpc_scheme(fri_params); + + typename placeholder_public_preprocessor::preprocessed_data_type + preprocessed_public_data = placeholder_public_preprocessor::process( + constraint_system, assignments.public_table(), desc, lpc_scheme + ); + auto printer = nil::blueprint::evm_verifier_printer( + constraint_system, + preprocessed_public_data.common_data, + "circuit3", + 26, // gates library size threshold + 60, // lookups library size threshold + 13, // gates inline size threshold + 15 // lookups inline size threshold + ); + printer.print(); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(placeholder_circuit4) + using curve_type = algebra::curves::pallas; + using field_type = typename curve_type::base_field_type; + + struct placeholder_test_params { + using BlueprintFieldType = algebra::curves::pallas::base_field_type; + using merkle_hash_type = hashes::keccak_1600<256>; + using transcript_hash_type = hashes::keccak_1600<256>; + + constexpr static const std::size_t witness_columns = witness_columns_4; + constexpr static const std::size_t public_input_columns = public_columns_4; + constexpr static const std::size_t constant_columns = constant_columns_4; + constexpr static const std::size_t selector_columns = selector_columns_4; + + constexpr static const std::size_t lambda = 10; + constexpr static const std::size_t m = 2; + }; + + using circuit_params = placeholder_circuit_params; + using transcript_type = typename transcript::fiat_shamir_heuristic_sequential; + using lpc_params_type = commitments::list_polynomial_commitment_params< + typename placeholder_test_params::merkle_hash_type, + typename placeholder_test_params::transcript_hash_type, + placeholder_test_params::m + >; + + using lpc_type = commitments::list_polynomial_commitment; + using lpc_scheme_type = typename commitments::lpc_commitment_scheme; + using lpc_placeholder_params_type = nil::crypto3::zk::snark::placeholder_params; + using policy_type = zk::snark::detail::placeholder_policy; + +BOOST_FIXTURE_TEST_CASE(transpiler_test, test_initializer) { + auto circuit = circuit_test_4(test_global_alg_rnd_engine); + + plonk_table_description desc( + placeholder_test_params::witness_columns, + placeholder_test_params::public_input_columns, + placeholder_test_params::constant_columns, + placeholder_test_params::selector_columns + ); + + desc.rows_amount = circuit.table_rows; + desc.usable_rows_amount = circuit.usable_rows; + std::size_t table_rows_log = std::ceil(std::log2(circuit.table_rows)); + + typename policy_type::constraint_system_type constraint_system( + circuit.gates, + circuit.copy_constraints, + circuit.lookup_gates, + circuit.lookup_tables + ); + typename policy_type::variable_assignment_type assignments = circuit.table; + + typename lpc_type::fri_type::params_type fri_params( + 1, table_rows_log, placeholder_test_params::lambda, 4 + ); + lpc_scheme_type lpc_scheme(fri_params); + + typename placeholder_public_preprocessor::preprocessed_data_type + preprocessed_public_data = placeholder_public_preprocessor::process( + constraint_system, assignments.public_table(), desc, lpc_scheme + ); + auto printer = nil::blueprint::evm_verifier_printer( + constraint_system, + preprocessed_public_data.common_data, + "circuit4", + 26, // gates library size threshold + 60, // lookups library size threshold + 13, // gates inline size threshold + 15 // lookups inline size threshold + ); + printer.print(); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(placeholder_circuit5) + using curve_type = algebra::curves::pallas; + using field_type = typename curve_type::base_field_type; + + constexpr static const std::size_t table_rows_log = 3; + constexpr static const std::size_t table_rows = 1 << table_rows_log; + constexpr static const std::size_t usable_rows = 5; + + struct placeholder_test_params { + using BlueprintFieldType = algebra::curves::pallas::base_field_type; + using merkle_hash_type = hashes::keccak_1600<256>; + using transcript_hash_type = hashes::keccak_1600<256>; + + constexpr static const std::size_t witness_columns = witness_columns_5; + constexpr static const std::size_t public_input_columns = public_columns_5; + constexpr static const std::size_t constant_columns = constant_columns_5; + constexpr static const std::size_t selector_columns = selector_columns_5; + + constexpr static const std::size_t lambda = 10; + constexpr static const std::size_t m = 2; + }; + + using circuit_params = placeholder_circuit_params; + using transcript_type = typename transcript::fiat_shamir_heuristic_sequential; + using lpc_params_type = commitments::list_polynomial_commitment_params< + typename placeholder_test_params::merkle_hash_type, + typename placeholder_test_params::transcript_hash_type, + placeholder_test_params::m + >; + + using lpc_type = commitments::list_polynomial_commitment; + using lpc_scheme_type = typename commitments::lpc_commitment_scheme; + using lpc_placeholder_params_type = nil::crypto3::zk::snark::placeholder_params; + using policy_type = zk::snark::detail::placeholder_policy; + +BOOST_FIXTURE_TEST_CASE(transpiler_test, test_initializer) { + auto circuit = circuit_test_5(test_global_alg_rnd_engine); + + plonk_table_description desc( + placeholder_test_params::witness_columns, + placeholder_test_params::public_input_columns, + placeholder_test_params::constant_columns, + placeholder_test_params::selector_columns + ); + + desc.rows_amount = circuit.table_rows; + desc.usable_rows_amount = circuit.usable_rows; + std::size_t table_rows_log = std::ceil(std::log2(circuit.table_rows)); + + typename policy_type::constraint_system_type constraint_system( + circuit.gates, + circuit.copy_constraints, + circuit.lookup_gates, + circuit.lookup_tables + ); + typename policy_type::variable_assignment_type assignments = circuit.table; + + typename lpc_type::fri_type::params_type fri_params( + 1, table_rows_log, placeholder_test_params::lambda, 4 + ); + lpc_scheme_type lpc_scheme(fri_params); + + typename placeholder_public_preprocessor::preprocessed_data_type + preprocessed_public_data = placeholder_public_preprocessor::process( + constraint_system, assignments.public_table(), desc, lpc_scheme, 10 + ); + auto printer = nil::blueprint::evm_verifier_printer( + constraint_system, + preprocessed_public_data.common_data, + "circuit5_chunk10", + 26, // gates library size threshold + 60, // lookups library size threshold + 13, // gates inline size threshold + 15 // lookups inline size threshold + ); + printer.print(); +} + +BOOST_FIXTURE_TEST_CASE(transpiler_test100, test_initializer) { + auto circuit = circuit_test_5(test_global_alg_rnd_engine); + + plonk_table_description desc( + placeholder_test_params::witness_columns, + placeholder_test_params::public_input_columns, + placeholder_test_params::constant_columns, + placeholder_test_params::selector_columns + ); + + desc.rows_amount = circuit.table_rows; + desc.usable_rows_amount = circuit.usable_rows; + std::size_t table_rows_log = std::ceil(std::log2(circuit.table_rows)); + + typename policy_type::constraint_system_type constraint_system( + circuit.gates, + circuit.copy_constraints, + circuit.lookup_gates, + circuit.lookup_tables + ); + typename policy_type::variable_assignment_type assignments = circuit.table; + + typename lpc_type::fri_type::params_type fri_params( + 1, table_rows_log, placeholder_test_params::lambda, 4 + ); + lpc_scheme_type lpc_scheme(fri_params); + + typename placeholder_public_preprocessor::preprocessed_data_type + preprocessed_public_data = placeholder_public_preprocessor::process( + constraint_system, assignments.public_table(), desc, lpc_scheme, 100 + ); + auto printer = nil::blueprint::evm_verifier_printer( + constraint_system, + preprocessed_public_data.common_data, + "circuit5_chunk100", + 26, // gates library size threshold + 60, // lookups library size threshold + 13, // gates inline size threshold + 15 // lookups inline size threshold + ); + printer.print(); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(placeholder_circuit6) + using Endianness = nil::marshalling::option::big_endian; + using TTypeBase = nil::marshalling::field_type; + using curve_type = algebra::curves::pallas; + using field_type = typename curve_type::base_field_type; + + constexpr static const std::size_t table_rows_log = 3; + constexpr static const std::size_t table_rows = 1 << table_rows_log; + + struct placeholder_test_params { + using BlueprintFieldType = algebra::curves::pallas::base_field_type; + using merkle_hash_type = hashes::keccak_1600<256>; + using transcript_hash_type = hashes::keccak_1600<256>; + + constexpr static const std::size_t witness_columns = witness_columns_6; + constexpr static const std::size_t public_input_columns = public_columns_6; + constexpr static const std::size_t constant_columns = constant_columns_6; + constexpr static const std::size_t selector_columns = selector_columns_6; + + constexpr static const std::size_t lambda = 10; + constexpr static const std::size_t m = 2; + }; + + using circuit_params = placeholder_circuit_params; + using transcript_type = typename transcript::fiat_shamir_heuristic_sequential; + using lpc_params_type = commitments::list_polynomial_commitment_params< + typename placeholder_test_params::merkle_hash_type, + typename placeholder_test_params::transcript_hash_type, + placeholder_test_params::m + >; + + using lpc_type = commitments::list_polynomial_commitment; + using lpc_scheme_type = typename commitments::lpc_commitment_scheme; + using lpc_placeholder_params_type = nil::crypto3::zk::snark::placeholder_params; + using policy_type = zk::snark::detail::placeholder_policy; + +BOOST_FIXTURE_TEST_CASE(transpiler_test, test_initializer) { + auto circuit = circuit_test_6(test_global_alg_rnd_engine, test_global_rnd_engine); + + plonk_table_description desc( + placeholder_test_params::witness_columns, + placeholder_test_params::public_input_columns, + placeholder_test_params::constant_columns, + placeholder_test_params::selector_columns + ); + + desc.rows_amount = circuit.table_rows; + desc.usable_rows_amount = circuit.usable_rows; + std::size_t table_rows_log = std::ceil(std::log2(circuit.table_rows)); + + typename policy_type::constraint_system_type constraint_system( + circuit.gates, + circuit.copy_constraints, + circuit.lookup_gates, + circuit.lookup_tables + ); + typename policy_type::variable_assignment_type assignments = circuit.table; + + typename lpc_type::fri_type::params_type fri_params( + 1, table_rows_log, placeholder_test_params::lambda, 4 + ); + lpc_scheme_type lpc_scheme(fri_params); + + typename placeholder_public_preprocessor::preprocessed_data_type + preprocessed_public_data = placeholder_public_preprocessor::process( + constraint_system, assignments.public_table(), desc, lpc_scheme + ); + + auto printer = nil::blueprint::evm_verifier_printer( + constraint_system, + preprocessed_public_data.common_data, + "circuit6", + 26, // gates library size threshold + 60, // lookups library size threshold + 13, // gates inline size threshold + 15 // lookups inline size threshold + ); + printer.print(); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(placeholder_circuit7) + using Endianness = nil::marshalling::option::big_endian; + using TTypeBase = nil::marshalling::field_type; + using curve_type = algebra::curves::pallas; + using field_type = typename curve_type::base_field_type; + + struct placeholder_test_params { + using BlueprintFieldType = algebra::curves::pallas::base_field_type; + using merkle_hash_type = hashes::keccak_1600<256>; + using transcript_hash_type = hashes::keccak_1600<256>; + + constexpr static const std::size_t witness_columns = witness_columns_7; + constexpr static const std::size_t public_input_columns = public_columns_7; + constexpr static const std::size_t constant_columns = constant_columns_7; + constexpr static const std::size_t selector_columns = selector_columns_7; + + constexpr static const std::size_t lambda = 10; + constexpr static const std::size_t m = 2; + }; + + using circuit_params = placeholder_circuit_params; + using transcript_type = typename transcript::fiat_shamir_heuristic_sequential; + using lpc_params_type = commitments::list_polynomial_commitment_params< + typename placeholder_test_params::merkle_hash_type, + typename placeholder_test_params::transcript_hash_type, + placeholder_test_params::m + >; + + using lpc_type = commitments::list_polynomial_commitment; + using lpc_scheme_type = typename commitments::lpc_commitment_scheme; + using lpc_placeholder_params_type = nil::crypto3::zk::snark::placeholder_params; + using policy_type = zk::snark::detail::placeholder_policy; + +BOOST_FIXTURE_TEST_CASE(transpiler_test, test_initializer) { + auto circuit = circuit_test_7(test_global_alg_rnd_engine, test_global_rnd_engine); + + plonk_table_description desc( + placeholder_test_params::witness_columns, + placeholder_test_params::public_input_columns, + placeholder_test_params::constant_columns, + placeholder_test_params::selector_columns + ); + + desc.rows_amount = circuit.table_rows; + desc.usable_rows_amount = circuit.usable_rows; + std::size_t table_rows_log = std::ceil(std::log2(circuit.table_rows)); + + typename policy_type::constraint_system_type constraint_system( + circuit.gates, + circuit.copy_constraints, + circuit.lookup_gates, + circuit.lookup_tables + ); + typename policy_type::variable_assignment_type assignments = circuit.table; + + typename lpc_type::fri_type::params_type fri_params( + 1, table_rows_log, placeholder_test_params::lambda, 4 + ); + lpc_scheme_type lpc_scheme(fri_params); + + transcript_type transcript; + + typename placeholder_public_preprocessor::preprocessed_data_type + preprocessed_public_data = placeholder_public_preprocessor::process( + constraint_system, assignments.public_table(), desc, lpc_scheme + ); + + auto printer = nil::blueprint::evm_verifier_printer( + constraint_system, + preprocessed_public_data.common_data, + "circuit7", + 26, // gates library size threshold + 60, // lookups library size threshold + 13, // gates inline size threshold + 15 // lookups inline size threshold + ); + printer.print(); +} + +// TODO implement for EVM +/* +BOOST_FIXTURE_TEST_CASE(transpiler_test10, test_initializer) { + auto circuit = circuit_test_7(test_global_alg_rnd_engine, test_global_rnd_engine); + + plonk_table_description desc( + placeholder_test_params::witness_columns, + placeholder_test_params::public_input_columns, + placeholder_test_params::constant_columns, + placeholder_test_params::selector_columns + ); + + desc.rows_amount = circuit.table_rows; + desc.usable_rows_amount = circuit.usable_rows; + std::size_t table_rows_log = std::ceil(std::log2(circuit.table_rows)); + + typename policy_type::constraint_system_type constraint_system( + circuit.gates, + circuit.copy_constraints, + circuit.lookup_gates, + circuit.lookup_tables + ); + typename policy_type::variable_assignment_type assignments = circuit.table; + + typename lpc_type::fri_type::params_type fri_params( + 1, table_rows_log, placeholder_test_params::lambda, 4 + ); + lpc_scheme_type lpc_scheme(fri_params); + + transcript_type transcript; + + typename placeholder_public_preprocessor::preprocessed_data_type + preprocessed_public_data = placeholder_public_preprocessor::process( + constraint_system, assignments.public_table(), desc, lpc_scheme,10 + ); + + auto printer = nil::blueprint::evm_verifier_printer( + constraint_system, + preprocessed_public_data.common_data, + "circuit7_chunk10", + 26, // gates library size threshold + 60, // lookups library size threshold + 13, // gates inline size threshold + 15 // lookups inline size threshold + ); + printer.print(); +}*/ +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(recursive_circuit1) + using Endianness = nil::marshalling::option::big_endian; + using TTypeBase = nil::marshalling::field_type; + + using curve_type = algebra::curves::pallas; + using field_type = typename curve_type::base_field_type; + using policy = hashes::detail::mina_poseidon_policy; + using merkle_hash_type = hashes::poseidon; + using transcript_hash_type = hashes::poseidon; + + struct placeholder_test_params { + constexpr static const std::size_t witness_columns = witness_columns_1; + constexpr static const std::size_t public_input_columns = public_columns_1; + constexpr static const std::size_t constant_columns = constant_columns_1; + constexpr static const std::size_t selector_columns = selector_columns_1; + + constexpr static const std::size_t lambda = 4; + constexpr static const std::size_t m = 2; + }; + typedef placeholder_circuit_params circuit_params; + using transcript_type = typename transcript::fiat_shamir_heuristic_sequential; + + using lpc_params_type = commitments::list_polynomial_commitment_params< + merkle_hash_type, + transcript_hash_type, + placeholder_test_params::m + >; + + using lpc_type = commitments::list_polynomial_commitment; + using lpc_scheme_type = typename commitments::lpc_commitment_scheme; + using lpc_placeholder_params_type = nil::crypto3::zk::snark::placeholder_params; + using policy_type = zk::snark::detail::placeholder_policy; + using proof_type = nil::crypto3::zk::snark::placeholder_proof; + using common_data_type = nil::crypto3::zk::snark::placeholder_public_preprocessor::preprocessed_data_type::common_data_type; + +BOOST_FIXTURE_TEST_CASE(transpiler_test, test_initializer) { + std::cout << "Recursive_circuit 1" << std::endl; + auto circuit = circuit_test_1(test_global_alg_rnd_engine); + + plonk_table_description desc( + placeholder_test_params::witness_columns, + placeholder_test_params::public_input_columns, + placeholder_test_params::constant_columns, + placeholder_test_params::selector_columns + ); + + desc.rows_amount = circuit.table_rows; + desc.usable_rows_amount = circuit.usable_rows; + std::size_t table_rows_log = std::ceil(std::log2(circuit.table_rows)); + + typename policy_type::constraint_system_type constraint_system( + circuit.gates, + circuit.copy_constraints, + circuit.lookup_gates, + circuit.lookup_tables + ); + typename policy_type::variable_assignment_type assignments = circuit.table; + + typename lpc_type::fri_type::params_type fri_params( + 1, table_rows_log, placeholder_test_params::lambda, 4 + ); + lpc_scheme_type lpc_scheme(fri_params); + + typename placeholder_public_preprocessor::preprocessed_data_type + preprocessed_public_data = placeholder_public_preprocessor::process( + constraint_system, assignments.public_table(), desc, lpc_scheme + ); + { + std::string cpp_path = "./circuit1/placeholder_verifier.cpp"; + std::ofstream output_file; + output_file.open(cpp_path); + output_file << nil::blueprint::recursive_verifier_generator(desc).generate_recursive_verifier( + constraint_system, preprocessed_public_data.common_data, {desc.usable_rows_amount + 1} + ); + output_file.close(); + } + + typename placeholder_private_preprocessor::preprocessed_data_type + preprocessed_private_data = placeholder_private_preprocessor::process( + constraint_system, assignments.private_table(), desc); + + auto proof = placeholder_prover::process( + preprocessed_public_data, preprocessed_private_data, desc, constraint_system, lpc_scheme + ); + + bool verifier_res = placeholder_verifier::process( + preprocessed_public_data.common_data, + proof, + desc, + constraint_system, + lpc_scheme + ); + BOOST_CHECK(verifier_res); + + { + std::string inp_path = "./circuit1/placeholder_verifier.inp"; + std::ofstream output_file; + output_file.open(inp_path); + output_file << nil::blueprint::recursive_verifier_generator(desc).generate_input( + assignments.public_inputs(), proof, {desc.usable_rows_amount + 1} + ); + output_file.close(); + } +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(recursive_circuit2) + using Endianness = nil::marshalling::option::big_endian; + using TTypeBase = nil::marshalling::field_type; + + using curve_type = algebra::curves::pallas; + using field_type = typename curve_type::base_field_type; + + struct placeholder_test_params { + using BlueprintFieldType = algebra::curves::pallas::base_field_type; + using policy = hashes::detail::mina_poseidon_policy; + using merkle_hash_type = hashes::poseidon; + using transcript_hash_type = hashes::poseidon; + + constexpr static const std::size_t witness_columns = 3; + constexpr static const std::size_t public_input_columns = 1; + constexpr static const std::size_t constant_columns = 0; + constexpr static const std::size_t selector_columns = 2; + + constexpr static const std::size_t lambda = 10; + constexpr static const std::size_t m = 2; + }; + using circuit_t_params = placeholder_circuit_params< + field_type + >; + + using transcript_type = typename transcript::fiat_shamir_heuristic_sequential; + + using lpc_params_type = commitments::list_polynomial_commitment_params< + typename placeholder_test_params::merkle_hash_type, + typename placeholder_test_params::transcript_hash_type, + placeholder_test_params::m + >; + + using lpc_type = commitments::list_polynomial_commitment; + using lpc_scheme_type = typename commitments::lpc_commitment_scheme; + using lpc_placeholder_params_type = nil::crypto3::zk::snark::placeholder_params; + using policy_type = zk::snark::detail::placeholder_policy; + using proof_type = nil::crypto3::zk::snark::placeholder_proof; + using common_data_type = nil::crypto3::zk::snark::placeholder_public_preprocessor::preprocessed_data_type::common_data_type; + +BOOST_FIXTURE_TEST_CASE(transpiler_test, test_initializer) { + std::cout << "Recursive_circuit 2" << std::endl; + auto pi0 = test_global_alg_rnd_engine(); + auto circuit = circuit_test_t(pi0, test_global_alg_rnd_engine, test_global_rnd_engine); + + plonk_table_description desc( + placeholder_test_params::witness_columns, + placeholder_test_params::public_input_columns, + placeholder_test_params::constant_columns, + placeholder_test_params::selector_columns + ); + + desc.rows_amount = circuit.table_rows; + desc.usable_rows_amount = circuit.usable_rows; + std::size_t table_rows_log = std::ceil(std::log2(circuit.table_rows)); + + typename policy_type::constraint_system_type constraint_system( + circuit.gates, + circuit.copy_constraints, + circuit.lookup_gates, + circuit.lookup_tables + ); + typename policy_type::variable_assignment_type assignments = circuit.table; + + // LPC commitment scheme + typename lpc_type::fri_type::params_type fri_params( + 1, table_rows_log, placeholder_test_params::lambda, 4 + ); + lpc_scheme_type lpc_scheme(fri_params); + + typename placeholder_public_preprocessor::preprocessed_data_type + preprocessed_public_data = placeholder_public_preprocessor::process( + constraint_system, assignments.public_table(), desc, lpc_scheme + ); + { + std::string cpp_path = "./circuit2/placeholder_verifier.cpp"; + std::ofstream output_file; + output_file.open(cpp_path); + output_file << nil::blueprint::recursive_verifier_generator(desc).generate_recursive_verifier( + constraint_system, preprocessed_public_data.common_data, {3} + ); + output_file.close(); + } + + typename placeholder_private_preprocessor::preprocessed_data_type + preprocessed_private_data = placeholder_private_preprocessor::process( + constraint_system, assignments.private_table(), desc); + + auto proof = placeholder_prover::process( + preprocessed_public_data, preprocessed_private_data, desc, constraint_system, lpc_scheme); + + bool verifier_res = placeholder_verifier::process( + preprocessed_public_data.common_data, + proof, + desc, + constraint_system, + lpc_scheme + ); + BOOST_CHECK(verifier_res); + + std::string inp_path = "./circuit2/placeholder_verifier.inp"; + std::ofstream output_file; + output_file.open(inp_path); + output_file << nil::blueprint::recursive_verifier_generator(desc).generate_input( + assignments.public_inputs(), proof, {3} + ); + output_file.close(); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(recursive_circuit3) + using Endianness = nil::marshalling::option::big_endian; + using TTypeBase = nil::marshalling::field_type; + using curve_type = algebra::curves::pallas; + using field_type = typename curve_type::base_field_type; + + struct placeholder_test_params { + using BlueprintFieldType = algebra::curves::pallas::base_field_type; + using policy = hashes::detail::mina_poseidon_policy; + using merkle_hash_type = hashes::poseidon; + using transcript_hash_type = hashes::poseidon; + + constexpr static const std::size_t witness_columns = witness_columns_3; + constexpr static const std::size_t public_input_columns = public_columns_3; + constexpr static const std::size_t constant_columns = constant_columns_3; + constexpr static const std::size_t selector_columns = selector_columns_3; + + constexpr static const std::size_t lambda = 10; + constexpr static const std::size_t m = 2; + }; + + using circuit_params = placeholder_circuit_params; + using transcript_type = typename transcript::fiat_shamir_heuristic_sequential; + using lpc_params_type = commitments::list_polynomial_commitment_params< + typename placeholder_test_params::merkle_hash_type, + typename placeholder_test_params::transcript_hash_type, + placeholder_test_params::m + >; + + using lpc_type = commitments::list_polynomial_commitment; + using lpc_scheme_type = typename commitments::lpc_commitment_scheme; + using lpc_placeholder_params_type = nil::crypto3::zk::snark::placeholder_params; + using policy_type = zk::snark::detail::placeholder_policy; + using proof_type = nil::crypto3::zk::snark::placeholder_proof; + using common_data_type = nil::crypto3::zk::snark::placeholder_public_preprocessor::preprocessed_data_type::common_data_type; + +BOOST_FIXTURE_TEST_CASE(transpiler_test, test_initializer) { + std::cout << "Recursive_circuit 3" << std::endl; + auto circuit = circuit_test_3(); + + plonk_table_description desc( + placeholder_test_params::witness_columns, + placeholder_test_params::public_input_columns, + placeholder_test_params::constant_columns, + placeholder_test_params::selector_columns + ); + + desc.rows_amount = circuit.table_rows; + desc.usable_rows_amount = circuit.usable_rows; + std::size_t table_rows_log = std::ceil(std::log2(circuit.table_rows)); + + typename policy_type::constraint_system_type constraint_system( + circuit.gates, + circuit.copy_constraints, + circuit.lookup_gates, + circuit.lookup_tables + ); + typename policy_type::variable_assignment_type assignments = circuit.table; + + typename lpc_type::fri_type::params_type fri_params( + 1, table_rows_log, placeholder_test_params::lambda, 4 + ); + lpc_scheme_type lpc_scheme(fri_params); + + typename placeholder_public_preprocessor::preprocessed_data_type + preprocessed_public_data = placeholder_public_preprocessor::process( + constraint_system, assignments.public_table(), desc, lpc_scheme + ); + + std::string cpp_path = "./circuit3/placeholder_verifier.cpp"; + std::ofstream output_file; + output_file.open(cpp_path); + output_file << nil::blueprint::recursive_verifier_generator(desc).generate_recursive_verifier( + constraint_system, preprocessed_public_data.common_data, std::vector() + ); + output_file.close(); + + typename placeholder_private_preprocessor::preprocessed_data_type + preprocessed_private_data = placeholder_private_preprocessor::process( + constraint_system, assignments.private_table(), desc); + + auto proof = placeholder_prover::process( + preprocessed_public_data, preprocessed_private_data, desc, constraint_system, lpc_scheme); + + bool verifier_res = placeholder_verifier::process( + preprocessed_public_data.common_data, + proof, + desc, + constraint_system, + lpc_scheme + ); + BOOST_CHECK(verifier_res); + + { + std::string inp_path = "./circuit3/placeholder_verifier.inp"; + std::ofstream output_file; + output_file.open(inp_path); + output_file << nil::blueprint::recursive_verifier_generator(desc).generate_input( + assignments.public_inputs(), proof, std::vector() + ); + output_file.close(); + } +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(recursive_circuit4) + using curve_type = algebra::curves::pallas; + using field_type = typename curve_type::base_field_type; + + struct placeholder_test_params { + using BlueprintFieldType = algebra::curves::pallas::base_field_type; + using policy = hashes::detail::mina_poseidon_policy; + using merkle_hash_type = hashes::poseidon; + using transcript_hash_type = hashes::poseidon; + + constexpr static const std::size_t witness_columns = witness_columns_4; + constexpr static const std::size_t public_input_columns = public_columns_4; + constexpr static const std::size_t constant_columns = constant_columns_4; + constexpr static const std::size_t selector_columns = selector_columns_4; + + constexpr static const std::size_t lambda = 10; + constexpr static const std::size_t m = 2; + }; + + using circuit_params = placeholder_circuit_params; + using transcript_type = typename transcript::fiat_shamir_heuristic_sequential; + using lpc_params_type = commitments::list_polynomial_commitment_params< + typename placeholder_test_params::merkle_hash_type, + typename placeholder_test_params::transcript_hash_type, + placeholder_test_params::m + >; + + using lpc_type = commitments::list_polynomial_commitment; + using lpc_scheme_type = typename commitments::lpc_commitment_scheme; + using lpc_placeholder_params_type = nil::crypto3::zk::snark::placeholder_params; + using policy_type = zk::snark::detail::placeholder_policy; + using proof_type = nil::crypto3::zk::snark::placeholder_proof; + using common_data_type = nil::crypto3::zk::snark::placeholder_public_preprocessor::preprocessed_data_type::common_data_type; + +BOOST_FIXTURE_TEST_CASE(transpiler_test, test_initializer) { + std::cout << "Recursive_circuit 4" << std::endl; + auto circuit = circuit_test_4(test_global_alg_rnd_engine, test_global_rnd_engine); + + plonk_table_description desc( + placeholder_test_params::witness_columns, + placeholder_test_params::public_input_columns, + placeholder_test_params::constant_columns, + placeholder_test_params::selector_columns + ); + + desc.rows_amount = circuit.table_rows; + desc.usable_rows_amount = circuit.usable_rows; + std::size_t table_rows_log = std::ceil(std::log2(circuit.table_rows)); + + typename policy_type::constraint_system_type constraint_system( + circuit.gates, + circuit.copy_constraints, + circuit.lookup_gates, + circuit.lookup_tables + ); + typename policy_type::variable_assignment_type assignments = circuit.table; + + typename lpc_type::fri_type::params_type fri_params( + 1, table_rows_log, placeholder_test_params::lambda, 4 + ); + lpc_scheme_type lpc_scheme(fri_params); + + typename placeholder_public_preprocessor::preprocessed_data_type + preprocessed_public_data = placeholder_public_preprocessor::process( + constraint_system, assignments.public_table(), desc, lpc_scheme + ); + { + std::string cpp_path = "./circuit4/placeholder_verifier.cpp"; + std::ofstream output_file; + output_file.open(cpp_path); + output_file << nil::blueprint::recursive_verifier_generator(desc).generate_recursive_verifier( + constraint_system, preprocessed_public_data.common_data, std::vector() + ); + output_file.close(); + } + + typename placeholder_private_preprocessor::preprocessed_data_type + preprocessed_private_data = placeholder_private_preprocessor::process( + constraint_system, assignments.private_table(), desc); + + auto proof = placeholder_prover::process( + preprocessed_public_data, preprocessed_private_data, desc, constraint_system, lpc_scheme); + + bool verifier_res = placeholder_verifier::process( + preprocessed_public_data.common_data, + proof, + desc, + constraint_system, + lpc_scheme + ); + BOOST_CHECK(verifier_res); + + { + std::string inp_path = "./circuit4/placeholder_verifier.inp"; + std::ofstream output_file; + output_file.open(inp_path); + output_file << nil::blueprint::recursive_verifier_generator(desc).generate_input( + assignments.public_inputs(), proof, std::vector() + ); + output_file.close(); + } +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(recursive_circuit5_chunk10) + using curve_type = algebra::curves::pallas; + using field_type = typename curve_type::base_field_type; + + struct placeholder_test_params { + using BlueprintFieldType = algebra::curves::pallas::base_field_type; + using policy = hashes::detail::mina_poseidon_policy; + using merkle_hash_type = hashes::poseidon; + using transcript_hash_type = hashes::poseidon; + + constexpr static const std::size_t witness_columns = witness_columns_5; + constexpr static const std::size_t public_input_columns = public_columns_5; + constexpr static const std::size_t constant_columns = constant_columns_5; + constexpr static const std::size_t selector_columns = selector_columns_5; + + constexpr static const std::size_t lambda = 10; + constexpr static const std::size_t m = 2; + }; + + using circuit_params = placeholder_circuit_params; + using transcript_type = typename transcript::fiat_shamir_heuristic_sequential; + using lpc_params_type = commitments::list_polynomial_commitment_params< + typename placeholder_test_params::merkle_hash_type, + typename placeholder_test_params::transcript_hash_type, + placeholder_test_params::m + >; + + using lpc_type = commitments::list_polynomial_commitment; + using lpc_scheme_type = typename commitments::lpc_commitment_scheme; + using lpc_placeholder_params_type = nil::crypto3::zk::snark::placeholder_params; + using policy_type = zk::snark::detail::placeholder_policy; + using proof_type = nil::crypto3::zk::snark::placeholder_proof; + using common_data_type = nil::crypto3::zk::snark::placeholder_public_preprocessor::preprocessed_data_type::common_data_type; + +BOOST_FIXTURE_TEST_CASE(transpiler_test, test_initializer) { + std::cout << "Recursive_circuit 5" << std::endl; + auto circuit = circuit_test_5(test_global_alg_rnd_engine, test_global_rnd_engine); + + plonk_table_description desc( + placeholder_test_params::witness_columns, + placeholder_test_params::public_input_columns, + placeholder_test_params::constant_columns, + placeholder_test_params::selector_columns + ); + + desc.rows_amount = circuit.table_rows; + desc.usable_rows_amount = circuit.usable_rows; + std::size_t table_rows_log = std::ceil(std::log2(circuit.table_rows)); + + typename policy_type::constraint_system_type constraint_system( + circuit.gates, + circuit.copy_constraints, + circuit.lookup_gates, + circuit.lookup_tables + ); + typename policy_type::variable_assignment_type assignments = circuit.table; + + typename lpc_type::fri_type::params_type fri_params( + 1, table_rows_log, placeholder_test_params::lambda, 4 + ); + lpc_scheme_type lpc_scheme(fri_params); + + typename placeholder_public_preprocessor::preprocessed_data_type + preprocessed_public_data = placeholder_public_preprocessor::process( + constraint_system, assignments.public_table(), desc, lpc_scheme, 10 + ); + { + std::string cpp_path = "./circuit5_chunk10/placeholder_verifier.cpp"; + std::ofstream output_file; + output_file.open(cpp_path); + output_file << nil::blueprint::recursive_verifier_generator(desc).generate_recursive_verifier( + constraint_system, preprocessed_public_data.common_data, {135} + ); + output_file.close(); + } + + typename placeholder_private_preprocessor::preprocessed_data_type + preprocessed_private_data = placeholder_private_preprocessor::process( + constraint_system, assignments.private_table(), desc); + + auto proof = placeholder_prover::process( + preprocessed_public_data, preprocessed_private_data, desc, constraint_system, lpc_scheme); + + bool verifier_res = placeholder_verifier::process( + preprocessed_public_data.common_data, + proof, + desc, + constraint_system, + lpc_scheme + ); + BOOST_CHECK(verifier_res); + + { + std::string inp_path = "./circuit5_chunk10/placeholder_verifier.inp"; + std::ofstream output_file; + output_file.open(inp_path); + output_file << nil::blueprint::recursive_verifier_generator(desc).generate_input( + assignments.public_inputs(), proof, {135} + ); + output_file.close(); + } +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(recursive_circuit5_chunk100) + using curve_type = algebra::curves::pallas; + using field_type = typename curve_type::base_field_type; + + struct placeholder_test_params { + using BlueprintFieldType = algebra::curves::pallas::base_field_type; + using policy = hashes::detail::mina_poseidon_policy; + using merkle_hash_type = hashes::poseidon; + using transcript_hash_type = hashes::poseidon; + + constexpr static const std::size_t witness_columns = witness_columns_5; + constexpr static const std::size_t public_input_columns = public_columns_5; + constexpr static const std::size_t constant_columns = constant_columns_5; + constexpr static const std::size_t selector_columns = selector_columns_5; + + constexpr static const std::size_t lambda = 10; + constexpr static const std::size_t m = 2; + }; + + using circuit_params = placeholder_circuit_params; + using transcript_type = typename transcript::fiat_shamir_heuristic_sequential; + using lpc_params_type = commitments::list_polynomial_commitment_params< + typename placeholder_test_params::merkle_hash_type, + typename placeholder_test_params::transcript_hash_type, + placeholder_test_params::m + >; + + using lpc_type = commitments::list_polynomial_commitment; + using lpc_scheme_type = typename commitments::lpc_commitment_scheme; + using lpc_placeholder_params_type = nil::crypto3::zk::snark::placeholder_params; + using policy_type = zk::snark::detail::placeholder_policy; + using proof_type = nil::crypto3::zk::snark::placeholder_proof; + using common_data_type = nil::crypto3::zk::snark::placeholder_public_preprocessor::preprocessed_data_type::common_data_type; + +BOOST_FIXTURE_TEST_CASE(transpiler_test, test_initializer) { + std::cout << "Recursive_circuit 5" << std::endl; + auto circuit = circuit_test_5(test_global_alg_rnd_engine, test_global_rnd_engine); + + plonk_table_description desc( + placeholder_test_params::witness_columns, + placeholder_test_params::public_input_columns, + placeholder_test_params::constant_columns, + placeholder_test_params::selector_columns + ); + + desc.rows_amount = circuit.table_rows; + desc.usable_rows_amount = circuit.usable_rows; + std::size_t table_rows_log = std::ceil(std::log2(circuit.table_rows)); + + typename policy_type::constraint_system_type constraint_system( + circuit.gates, + circuit.copy_constraints, + circuit.lookup_gates, + circuit.lookup_tables + ); + typename policy_type::variable_assignment_type assignments = circuit.table; + + typename lpc_type::fri_type::params_type fri_params( + 1, table_rows_log, placeholder_test_params::lambda, 4 + ); + lpc_scheme_type lpc_scheme(fri_params); + + typename placeholder_public_preprocessor::preprocessed_data_type + preprocessed_public_data = placeholder_public_preprocessor::process( + constraint_system, assignments.public_table(), desc, lpc_scheme, 100 + ); + { + std::string cpp_path = "./circuit5_chunk100/placeholder_verifier.cpp"; + std::ofstream output_file; + output_file.open(cpp_path); + output_file << nil::blueprint::recursive_verifier_generator(desc).generate_recursive_verifier( + constraint_system, preprocessed_public_data.common_data, {135} + ); + output_file.close(); + } + + typename placeholder_private_preprocessor::preprocessed_data_type + preprocessed_private_data = placeholder_private_preprocessor::process( + constraint_system, assignments.private_table(), desc); + + auto proof = placeholder_prover::process( + preprocessed_public_data, preprocessed_private_data, desc, constraint_system, lpc_scheme); + + bool verifier_res = placeholder_verifier::process( + preprocessed_public_data.common_data, + proof, + desc, + constraint_system, + lpc_scheme + ); + BOOST_CHECK(verifier_res); + + { + std::string inp_path = "./circuit5_chunk100/placeholder_verifier.inp"; + std::ofstream output_file; + output_file.open(inp_path); + output_file << nil::blueprint::recursive_verifier_generator(desc).generate_input( + assignments.public_inputs(), proof, {135} + ); + output_file.close(); + } +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(recursive_circuit6) + using Endianness = nil::marshalling::option::big_endian; + using TTypeBase = nil::marshalling::field_type; + using curve_type = algebra::curves::pallas; + using field_type = typename curve_type::base_field_type; + + struct placeholder_test_params { + using BlueprintFieldType = algebra::curves::pallas::base_field_type; + using policy = hashes::detail::mina_poseidon_policy; + using merkle_hash_type = hashes::poseidon; + using transcript_hash_type = hashes::poseidon; + + constexpr static const std::size_t witness_columns = witness_columns_6; + constexpr static const std::size_t public_input_columns = public_columns_6; + constexpr static const std::size_t constant_columns = constant_columns_6; + constexpr static const std::size_t selector_columns = selector_columns_6; + + constexpr static const std::size_t lambda = 10; + constexpr static const std::size_t m = 2; + }; + + using circuit_params = placeholder_circuit_params; + using transcript_type = typename transcript::fiat_shamir_heuristic_sequential; + using lpc_params_type = commitments::list_polynomial_commitment_params< + typename placeholder_test_params::merkle_hash_type, + typename placeholder_test_params::transcript_hash_type, + placeholder_test_params::m + >; + + using lpc_type = commitments::list_polynomial_commitment; + using lpc_scheme_type = typename commitments::lpc_commitment_scheme; + using lpc_placeholder_params_type = nil::crypto3::zk::snark::placeholder_params; + using policy_type = zk::snark::detail::placeholder_policy; + using proof_type = nil::crypto3::zk::snark::placeholder_proof; + using common_data_type = nil::crypto3::zk::snark::placeholder_public_preprocessor::preprocessed_data_type::common_data_type; + +BOOST_FIXTURE_TEST_CASE(transpiler_test, test_initializer) { + std::cout << "Recursive_circuit 6" << std::endl; + auto circuit = circuit_test_6(test_global_alg_rnd_engine, test_global_rnd_engine); + + plonk_table_description desc( + placeholder_test_params::witness_columns, + placeholder_test_params::public_input_columns, + placeholder_test_params::constant_columns, + placeholder_test_params::selector_columns + ); + + desc.rows_amount = circuit.table_rows; + desc.usable_rows_amount = circuit.usable_rows; + std::size_t table_rows_log = std::ceil(std::log2(circuit.table_rows)); + + typename policy_type::constraint_system_type constraint_system( + circuit.gates, + circuit.copy_constraints, + circuit.lookup_gates, + circuit.lookup_tables + ); + typename policy_type::variable_assignment_type assignments = circuit.table; + + typename lpc_type::fri_type::params_type fri_params( + 1, table_rows_log, placeholder_test_params::lambda, 4 + ); + lpc_scheme_type lpc_scheme(fri_params); + + typename placeholder_public_preprocessor::preprocessed_data_type + preprocessed_public_data = placeholder_public_preprocessor::process( + constraint_system, assignments.public_table(), desc, lpc_scheme); + { + std::string cpp_path = "./circuit6/placeholder_verifier.cpp"; + std::ofstream output_file; + output_file.open(cpp_path); + output_file << nil::blueprint::recursive_verifier_generator(desc).generate_recursive_verifier( + constraint_system, preprocessed_public_data.common_data, std::vector() + ); + output_file.close(); + } + + typename placeholder_private_preprocessor::preprocessed_data_type + preprocessed_private_data = placeholder_private_preprocessor::process( + constraint_system, assignments.private_table(), desc); + + auto proof = placeholder_prover::process( + preprocessed_public_data, preprocessed_private_data, desc, constraint_system, lpc_scheme); + + bool verifier_res = placeholder_verifier::process( + preprocessed_public_data.common_data, + proof, + desc, + constraint_system, + lpc_scheme + ); + BOOST_CHECK(verifier_res); + + { + std::string inp_path = "./circuit6/placeholder_verifier.inp"; + std::ofstream output_file; + output_file.open(inp_path); + output_file << nil::blueprint::recursive_verifier_generator(desc).generate_input( + assignments.public_inputs(), proof, std::vector() + ); + output_file.close(); + } +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(recursive_circuit7) + using Endianness = nil::marshalling::option::big_endian; + using TTypeBase = nil::marshalling::field_type; + using curve_type = algebra::curves::pallas; + using field_type = typename curve_type::base_field_type; + + struct placeholder_test_params { + using BlueprintFieldType = algebra::curves::pallas::base_field_type; + using policy = hashes::detail::mina_poseidon_policy; + using merkle_hash_type = hashes::poseidon; + using transcript_hash_type = hashes::poseidon; + + constexpr static const std::size_t witness_columns = witness_columns_7; + constexpr static const std::size_t public_input_columns = public_columns_7; + constexpr static const std::size_t constant_columns = constant_columns_7; + constexpr static const std::size_t selector_columns = selector_columns_7; + + constexpr static const std::size_t lambda = 10; + constexpr static const std::size_t m = 2; + }; + + using circuit_params = placeholder_circuit_params; + using transcript_type = typename transcript::fiat_shamir_heuristic_sequential; + using lpc_params_type = commitments::list_polynomial_commitment_params< + typename placeholder_test_params::merkle_hash_type, + typename placeholder_test_params::transcript_hash_type, + placeholder_test_params::m + >; + + using lpc_type = commitments::list_polynomial_commitment; + using lpc_scheme_type = typename commitments::lpc_commitment_scheme; + using lpc_placeholder_params_type = nil::crypto3::zk::snark::placeholder_params; + using policy_type = zk::snark::detail::placeholder_policy; + using proof_type = nil::crypto3::zk::snark::placeholder_proof; + using common_data_type = nil::crypto3::zk::snark::placeholder_public_preprocessor::preprocessed_data_type::common_data_type; + +BOOST_FIXTURE_TEST_CASE(transpiler_test, test_initializer) { + std::cout << "Recursive_circuit 7" << std::endl; + auto circuit = circuit_test_7(test_global_alg_rnd_engine, test_global_rnd_engine); + plonk_table_description desc( + placeholder_test_params::witness_columns, + placeholder_test_params::public_input_columns, + placeholder_test_params::constant_columns, + placeholder_test_params::selector_columns + ); + + desc.rows_amount = circuit.table_rows; + desc.usable_rows_amount = circuit.usable_rows; + std::size_t table_rows_log = std::ceil(std::log2(circuit.table_rows)); + + typename policy_type::constraint_system_type constraint_system( + circuit.gates, + circuit.copy_constraints, + circuit.lookup_gates, + circuit.lookup_tables + ); + typename policy_type::variable_assignment_type assignments = circuit.table; + + typename lpc_type::fri_type::params_type fri_params( + 1, table_rows_log, placeholder_test_params::lambda, 4 + ); + lpc_scheme_type lpc_scheme(fri_params); + + transcript_type transcript; + + typename placeholder_public_preprocessor::preprocessed_data_type + preprocessed_public_data = placeholder_public_preprocessor::process( + constraint_system, assignments.public_table(), desc, lpc_scheme + ); + { + std::string cpp_path = "./circuit7/placeholder_verifier.cpp"; + std::ofstream output_file; + output_file.open(cpp_path); + output_file << nil::blueprint::recursive_verifier_generator(desc).generate_recursive_verifier( + constraint_system, preprocessed_public_data.common_data, std::vector() + ); + output_file.close(); + } + + typename placeholder_private_preprocessor::preprocessed_data_type + preprocessed_private_data = placeholder_private_preprocessor::process( + constraint_system, assignments.private_table(), desc); + + auto proof = placeholder_prover::process( + preprocessed_public_data, preprocessed_private_data, desc, constraint_system, lpc_scheme); + + bool verifier_res = placeholder_verifier::process( + preprocessed_public_data.common_data, + proof, + desc, + constraint_system, + lpc_scheme + ); + BOOST_CHECK(verifier_res); + + { + std::string inp_path = "./circuit7/placeholder_verifier.inp"; + std::ofstream output_file; + output_file.open(inp_path); + output_file << nil::blueprint::recursive_verifier_generator(desc).generate_input( + assignments.public_inputs(), proof, std::vector() + ); + output_file.close(); + } +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(recursive_circuit7_chunk10) + using Endianness = nil::marshalling::option::big_endian; + using TTypeBase = nil::marshalling::field_type; + using curve_type = algebra::curves::pallas; + using field_type = typename curve_type::base_field_type; + + struct placeholder_test_params { + using BlueprintFieldType = algebra::curves::pallas::base_field_type; + using policy = hashes::detail::mina_poseidon_policy; + using merkle_hash_type = hashes::poseidon; + using transcript_hash_type = hashes::poseidon; + + constexpr static const std::size_t witness_columns = witness_columns_7; + constexpr static const std::size_t public_input_columns = public_columns_7; + constexpr static const std::size_t constant_columns = constant_columns_7; + constexpr static const std::size_t selector_columns = selector_columns_7; + + constexpr static const std::size_t lambda = 10; + constexpr static const std::size_t m = 2; + }; + + using circuit_params = placeholder_circuit_params; + using transcript_type = typename transcript::fiat_shamir_heuristic_sequential; + using lpc_params_type = commitments::list_polynomial_commitment_params< + typename placeholder_test_params::merkle_hash_type, + typename placeholder_test_params::transcript_hash_type, + placeholder_test_params::m + >; + + using lpc_type = commitments::list_polynomial_commitment; + using lpc_scheme_type = typename commitments::lpc_commitment_scheme; + using lpc_placeholder_params_type = nil::crypto3::zk::snark::placeholder_params; + using policy_type = zk::snark::detail::placeholder_policy; + using proof_type = nil::crypto3::zk::snark::placeholder_proof; + using common_data_type = nil::crypto3::zk::snark::placeholder_public_preprocessor::preprocessed_data_type::common_data_type; + +BOOST_FIXTURE_TEST_CASE(transpiler_test, test_initializer) { + std::cout << "Recursive_circuit 7 chunk 10" << std::endl; + std::filesystem::create_directory("./circuit7_chunk10"); + auto circuit = circuit_test_7(test_global_alg_rnd_engine, test_global_rnd_engine); + plonk_table_description desc( + placeholder_test_params::witness_columns, + placeholder_test_params::public_input_columns, + placeholder_test_params::constant_columns, + placeholder_test_params::selector_columns + ); + + desc.rows_amount = circuit.table_rows; + desc.usable_rows_amount = circuit.usable_rows; + std::size_t table_rows_log = std::ceil(std::log2(circuit.table_rows)); + + typename policy_type::constraint_system_type constraint_system( + circuit.gates, + circuit.copy_constraints, + circuit.lookup_gates, + circuit.lookup_tables + ); + typename policy_type::variable_assignment_type assignments = circuit.table; + + typename lpc_type::fri_type::params_type fri_params( + 1, table_rows_log, placeholder_test_params::lambda, 4 + ); + lpc_scheme_type lpc_scheme(fri_params); + + transcript_type transcript; + + typename placeholder_public_preprocessor::preprocessed_data_type + preprocessed_public_data = placeholder_public_preprocessor::process( + constraint_system, assignments.public_table(), desc, lpc_scheme, 10 + ); + { + std::string cpp_path = "./circuit7_chunk10/placeholder_verifier.cpp"; + std::ofstream output_file; + output_file.open(cpp_path); + output_file << nil::blueprint::recursive_verifier_generator(desc).generate_recursive_verifier( + constraint_system, preprocessed_public_data.common_data, std::vector() + ); + output_file.close(); + } + + typename placeholder_private_preprocessor::preprocessed_data_type + preprocessed_private_data = placeholder_private_preprocessor::process( + constraint_system, assignments.private_table(), desc); + + auto proof = placeholder_prover::process( + preprocessed_public_data, preprocessed_private_data, desc, constraint_system, lpc_scheme); + + bool verifier_res = placeholder_verifier::process( + preprocessed_public_data.common_data, + proof, + desc, + constraint_system, + lpc_scheme + ); + BOOST_CHECK(verifier_res); + + { + std::string inp_path = "./circuit7_chunk10/placeholder_verifier.inp"; + std::ofstream output_file; + output_file.open(inp_path); + output_file << nil::blueprint::recursive_verifier_generator(desc).generate_input( + assignments.public_inputs(), proof, std::vector() + ); + output_file.close(); + } +} +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file