diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml new file mode 100644 index 0000000..9f28dd9 --- /dev/null +++ b/.github/workflows/pull_request.yml @@ -0,0 +1,18 @@ +name: Handle pull request event + +on: + pull_request: + +concurrency: + group: ${{ + ( github.ref == 'refs/heads/master' && 'master' ) || + format('{0}/{1}', github.workflow, github.ref) }} + cancel-in-progress: true + +jobs: + handle-syncwith: + name: Call Reusable SyncWith Handler + uses: NilFoundation/ci-cd/.github/workflows/reusable-handle-syncwith.yml@v1.1.2 + with: + ci-cd-ref: 'v1.1.2' + secrets: inherit diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml deleted file mode 100644 index 8d48997..0000000 --- a/.github/workflows/run_tests.yml +++ /dev/null @@ -1,146 +0,0 @@ -name: Run tests - -on: - # Triggers the workflow on pull request events but only for the master branch - pull_request: - branches: [ master ] - - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -env: - SUITE_REPO: "NilFoundation/crypto3" - LIB_NAME: "blueprint" - CACHE_NAME: "checkout-job-cache" - -jobs: - checkout: - runs-on: [self-hosted, tests-runner] - steps: - - name: Cleanup # TODO - move to scripts on runner - run: | - rm -rf ./* || true - rm -rf ./.??* || true - - - name: Checkout suite - uses: actions/checkout@v3 - with: - repository: ${{ env.SUITE_REPO }} - submodules: recursive - - - name: Checkout source code - uses: actions/checkout@v3 - with: - path: ./libs/${{ env.LIB_NAME }} - submodules: recursive - - - name: Cmake and build - env: - CMAKE_ARGS: " - -DCMAKE_BUILD_TYPE=Debug - -DBUILD_SHARED_LIBS=FALSE - -DBUILD_TESTS=TRUE - " - run: | - mkdir build - cd build - cmake ${{ env.CMAKE_ARGS }} .. - - - name: Archive build results - run: | - touch ${{ env.CACHE_NAME }}.tar.gz - tar -czf ${{ env.CACHE_NAME }}.tar.gz --exclude=${{ env.CACHE_NAME }}.tar.gz . - - - name: Cache archived job output - uses: actions/upload-artifact@v3 - with: - name: ${{ env.CACHE_NAME }} - path: ${{ env.CACHE_NAME }}.tar.gz - retention-days: 1 - - - run_tests: - runs-on: [self-hosted] - needs: [checkout] - strategy: - fail-fast: false - matrix: - target: [ - blueprint_hashes_plonk_sha256_test, - blueprint_hashes_plonk_decomposition_test, - blueprint_hashes_plonk_sha256_process_test, - blueprint_hashes_plonk_sha512_process_test, - blueprint_hashes_plonk_poseidon_test, - blueprint_non_native_plonk_range_test, - blueprint_non_native_plonk_field_add_test, - blueprint_non_native_plonk_field_sub_test, - blueprint_non_native_plonk_field_mul_test, - blueprint_non_native_plonk_fixed_base_mul_test, - blueprint_non_native_plonk_complete_addition_test, - blueprint_non_native_plonk_var_base_mul_per_bit_test, - blueprint_non_native_plonk_variable_base_multiplication_test, - blueprint_algebra_fields_plonk_field_operations_test, - blueprint_algebra_fields_plonk_sqrt_test, - blueprint_algebra_fields_plonk_exponentiation_test, - blueprint_algebra_fields_plonk_range_check_test, - blueprint_algebra_curves_plonk_variable_base_scalar_mul_test, - blueprint_algebra_curves_plonk_unified_addition_test, - blueprint_algebra_curves_plonk_endo_scalar_test, - blueprint_algebra_curves_plonk_multi_scalar_multiplication_test, - blueprint_verifiers_kimchi_base_field_test, - blueprint_verifiers_kimchi_prepare_batch_scalar_test, - blueprint_verifiers_kimchi_verify_scalar_test, - blueprint_verifiers_kimchi_oracles_scalar_test, - blueprint_verifiers_kimchi_batch_verify_base_field_test, - blueprint_verifiers_kimchi_batch_verify_scalar_field_test, - blueprint_verifiers_kimchi_detail_lagrange_denominators_test, - blueprint_verifiers_kimchi_detail_b_poly_test, - blueprint_verifiers_kimchi_detail_b_poly_coefficients_test, - blueprint_verifiers_kimchi_detail_to_group_test, - blueprint_verifiers_kimchi_detail_public_evaluations_test, - blueprint_verifiers_kimchi_detail_prev_chal_evals_test, - blueprint_verifiers_kimchi_detail_ft_eval_test, - blueprint_verifiers_kimchi_detail_combine_proof_evals_test, - blueprint_verifiers_kimchi_detail__constraints_index_terms_scalars_test, - blueprint_verifiers_kimchi_detail_constraints_rpn_expression_test, - blueprint_verifiers_kimchi_detail_constraints_vanishes_on_last_4_rows_test, - blueprint_verifiers_kimchi_detail_constraints_unnormalized_lagrange_basis_test, - blueprint_verifiers_kimchi_detail_constraints_perm_scalars_test, - blueprint_verifiers_kimchi_detail_constraints_generic_scalars_test, - blueprint_verifiers_kimchi_detail_oracles_cip_test, - blueprint_verifiers_kimchi_detail_zk_w3_test, - blueprint_verifiers_kimchi_detail_zkpm_evaluate_test, - blueprint_verifiers_kimchi_detail_prepare_scalars_test, - blueprint_verifiers_kimchi_sponge_compare_test, - blueprint_verifiers_kimchi_sponge_transcript_fr_test, - blueprint_verifiers_kimchi_sponge_transcript_fq_test, - blueprint_verifiers_kimchi_sponge_sponge_test, - blueprint_verifiers_kimchi_sponge_oracles_test - ] # Tests to execute - steps: - - name: Cleanup # TODO - move to scripts on runner - run: | - rm -rf ./* || true - rm -rf ./.??* || true - - - name: Upload checkout job cache - uses: actions/download-artifact@v3 - with: - name: ${{ env.CACHE_NAME }} - - - name: Extract artifacts - run: | - tar -xf ${{ env.CACHE_NAME }}.tar.gz - rm ${{ env.CACHE_NAME }}.tar.gz - - - name: Build - working-directory: ./build - run: cmake --build . -t ${{ matrix.target }} - - - name: Run test - working-directory: ./build - run: | - cd libs/${{ env.LIB_NAME }}/test - COLOR='\033[0;33m' - echo -e "${COLOR}${{ matrix.target }}" - ./${{ matrix.target }} diff --git a/include/nil/blueprint/transpiler/contracts_templates.hpp b/include/nil/blueprint/transpiler/contracts_templates.hpp deleted file mode 100644 index a722b74..0000000 --- a/include/nil/blueprint/transpiler/contracts_templates.hpp +++ /dev/null @@ -1,185 +0,0 @@ -//---------------------------------------------------------------------------// -// 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 __CONTRACTS_TEMPLATE_HPP__ -#define __CONTRACTS_TEMPLATE_HPP__ - -#include - -namespace nil { - namespace blueprint { - std::string main_contract_template = R"( -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 "../../interfaces/modular_commitment.sol"; -import "../../interfaces/modular_gate_argument.sol"; -import "../../interfaces/modular_lookup_argument.sol"; -import "../../interfaces/modular_permutation_argument.sol"; -import "hardhat/console.sol"; - -contract modular_verifier_circuit3 is IModularVerifier{ - uint256 constant modulus = $MODULUS$; - bool constant use_lookups = false; - bytes32 constant vk1 = bytes32($VERIFICATION_KEY_1$); - bytes32 constant vk2 = bytes32($VERIFICATION_KEY_2$); - bytes32 transcript_state; - address _gate_argument_address; - address _permutation_argument_address; - address _lookup_argument_address; - address _commitment_contract_address; - uint8 constant f_parts = 8; // Individually on parts - uint32 constant z_offset = 212; - uint32 constant table_offset = z_offset + 0x20 * 10; - uint32 constant z_end = 0x35 * 0x20; - - bytes constant batched_points = hex"020202020202020202020303030203"; - bytes constant variable_points = hex"010101"; - bytes constant permutation_points = hex"0202"; - bytes constant quotient_points = hex"010101010101"; - bytes constant lookup_points = hex"0303"; - - uint16 constant fixed_points_num = 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 3 + 3 + 3 + 2 + 3; - uint16 constant variable_points_num = 3; - uint16 constant permutation_points_num = 4; - uint16 constant quotient_points_num = 6; - uint16 constant lookup_points_num = 6; - uint16 constant table_points_num = fixed_points_num - 10 + variable_points_num; - - constructor(){ - } - - function initialize( - address permutation_argument_address, - address lookup_argument_address, - address gate_argument_address, - address commitment_contract_address - ) public{ - console.log("Initialize"); - 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); - - _gate_argument_address = gate_argument_address; - _permutation_argument_address = permutation_argument_address; - _lookup_argument_address = lookup_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); - transcript_state = tr_state.current_challenge; - } - - function verify( - bytes calldata blob - ) public view{ - uint256 gas = gasleft(); - //0. Check proof size - // No direct public input - - //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 - $CALL_PERMUTATION_ARGUMENT$ - uint256 a = transcript.get_field_challenge(tr_state, modulus);//beta - console.log("beta: ", a); - uint256 b = transcript.get_field_challenge(tr_state, modulus);//beta - console.log("gamma:", b); - IModularPermutationArgument permutation_argument = IModularPermutationArgument(_permutation_argument_address); - permutation_argument.verify( - blob[z_offset:z_end], - a, - b - ); - } - - { - $CALL_LOOKUP_ARGUMENT$ - //4. Lookup argument - IModularLookupArgument lookup_argument = IModularLookupArgument(_lookup_argument_address); - ( , tr_state.current_challenge) = lookup_argument.verify( - blob[table_offset: table_offset + table_points_num*0x20], blob[table_offset:z_end], basic_marshalling.get_uint256_be(blob, 0x81), tr_state.current_challenge - ); - } - - //5. Push permutation batch to transcript - transcript.update_transcript_b32_by_offset_calldata(tr_state, blob, 0x31); - - { - $CALL_GATE_ARGUMENT$ - //6. Gate argument - IModularGateArgument gate_argument = IModularGateArgument(_gate_argument_address); - gate_argument.verify(blob[table_offset:table_offset + table_points_num*0x20], transcript.get_field_challenge(tr_state, modulus)); - } - - // No public input gate - - { - //7. Push quotient to transcript - uint256[f_parts] memory alphas; - for( uint8 i = 0; i < f_parts;){ - alphas[i] = transcript.get_field_challenge(tr_state, modulus); - console.log("alpha ", i, ":", alphas[i]); - unchecked{i++;} - } - transcript.update_transcript_b32_by_offset_calldata(tr_state, blob, 0x59); - } - - //8. Commitment scheme proof_eval - {. - $CALL_COMMITMENT_SCHEME$ - ICommitmentScheme commitment_scheme = ICommitmentScheme(_commitment_contract_address); - - uint256[] memory commitments = new uint256[](5); - commitments[0] = uint256(vk2); - commitments[1] = basic_marshalling.get_uint256_be(blob, 0x9); - commitments[2] = basic_marshalling.get_uint256_be(blob, 0x31); - commitments[3] = basic_marshalling.get_uint256_be(blob, 0x59); - commitments[4] = basic_marshalling.get_uint256_be(blob, 0x81); - if(!commitment_scheme.verify_eval( - blob[z_offset:], commitments, basic_marshalling.get_uint256_be(blob, 0xa1), tr_state.current_challenge - )) console.log("Error from commitment scheme!"); - } - - //9. Final check - console.log("Gas for verification:", gas-gasleft()); - } -} - )"; - } -} - -#endif //__GATE_ARGUMENT_TEMPLATE_HPP__ \ No newline at end of file diff --git a/include/nil/blueprint/transpiler/evm_verifier_gen.hpp b/include/nil/blueprint/transpiler/evm_verifier_gen.hpp index e5f596a..228bed0 100644 --- a/include/nil/blueprint/transpiler/evm_verifier_gen.hpp +++ b/include/nil/blueprint/transpiler/evm_verifier_gen.hpp @@ -1,3 +1,28 @@ +//---------------------------------------------------------------------------// +// 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__ @@ -5,293 +30,940 @@ #include #include #include +#include -#include +#include #include #include #include #include #include +#include +#include +#include #include #include +#include +#include +#include + namespace nil { namespace blueprint { - 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); - } - std::ofstream out; - out.open(output_file_name); - out << code; - out.close(); - } - template - using common_data_type = typename nil::crypto3::zk::snark::placeholder_public_preprocessor< - typename PlaceholderParams::field_type, - PlaceholderParams - >::preprocessed_data_type::common_data_type; + 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; - template - std::string zero_indices(std::array, PlaceholderParams::total_columns> col_rotations){ - std::vector zero_indices; - std::uint16_t fixed_values_points; - std::stringstream result; - - for(std::size_t i= 0; i < PlaceholderParams::constant_columns + PlaceholderParams::selector_columns; i++){ - fixed_values_points += col_rotations[i + PlaceholderParams::witness_columns + PlaceholderParams::public_input_columns].size() + 1; - } + 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::array, PlaceholderParams::total_columns>; - for(std::size_t i= 0; i < PlaceholderParams::total_columns; i++){ + variable_indices_type get_plonk_variable_indices(const columns_rotations_type &col_rotations){ + using variable_type = nil::crypto3::zk::snark::plonk_variable; + std::map result; std::size_t j = 0; - for(auto& rot: col_rotations[i]){ - if(rot == 0){ - zero_indices.push_back(j); - break; + for(std::size_t i = 0; i < PlaceholderParams::constant_columns; i++){ + for(auto& rot: col_rotations[i + PlaceholderParams::witness_columns + PlaceholderParams::public_input_columns]){ + variable_type v(i, rot, true, variable_type::column_type::constant); + result[v] = j; + j++; } j++; } - } - std::uint16_t sum = fixed_values_points; - std::size_t i = 0; - for(; i < PlaceholderParams::witness_columns + PlaceholderParams::public_input_columns; i++){ - zero_indices[i] = (sum + zero_indices[i]) * 0x20; - sum += col_rotations[i].size(); - result << std::hex << std::setfill('0') << std::setw(4) << zero_indices[i]; + for(std::size_t i = 0; i < PlaceholderParams::selector_columns; i++){ + for(auto& rot: col_rotations[i + PlaceholderParams::witness_columns + PlaceholderParams::public_input_columns + PlaceholderParams::constant_columns]){ + variable_type v(i, rot, true, variable_type::column_type::selector); + result[v] = j; + j++; + } + j++; + } + for(std::size_t i = 0; i < PlaceholderParams::witness_columns; i++){ + for(auto& rot: col_rotations[i]){ + variable_type v(i, rot, true, variable_type::column_type::witness); + result[v] = j; + j++; + } + } + for(std::size_t i = 0; i < PlaceholderParams::public_input_columns; i++){ + for(auto& rot: col_rotations[i + PlaceholderParams::witness_columns]){ + variable_type v(i, rot, true, variable_type::column_type::public_input); + result[v] = j; + j++; + } + } + return result; } - sum = 0; - for(; i < PlaceholderParams::total_columns; i++){ - zero_indices[i] = (sum + zero_indices[i]) * 0x20; - sum += col_rotations[i].size(); - result << std::hex << std::setfill('0') << std::setw(4) << zero_indices[i]; - } - return result.str(); - } + std::string zero_indices(columns_rotations_type col_rotations){ + std::vector zero_indices; + std::uint16_t fixed_values_points = 0; + std::stringstream result; - template - std::map, std::size_t> - get_plonk_variable_indices(std::array, PlaceholderParams::total_columns> col_rotations){ - using variable_type = nil::crypto3::zk::snark::plonk_variable; - std::map result; - std::size_t j = 0; - for(std::size_t i = 0; i < PlaceholderParams::constant_columns; i++){ - for(auto& rot: col_rotations[i + PlaceholderParams::witness_columns + PlaceholderParams::public_input_columns]){ - variable_type v(i, rot, true, variable_type::column_type::constant); - result[v] = j; - j++; + for(std::size_t i= 0; i < PlaceholderParams::constant_columns + PlaceholderParams::selector_columns; i++){ + fixed_values_points += col_rotations[i + PlaceholderParams::witness_columns + PlaceholderParams::public_input_columns].size() + 1; } - j++; - } - for(std::size_t i = 0; i < PlaceholderParams::selector_columns; i++){ - for(auto& rot: col_rotations[i + PlaceholderParams::witness_columns + PlaceholderParams::public_input_columns + PlaceholderParams::constant_columns]){ - variable_type v(i, rot, true, variable_type::column_type::selector); - result[v] = j; - j++; + + for(std::size_t i= 0; i < PlaceholderParams::total_columns; i++){ + std::size_t j = 0; + for(auto& rot: col_rotations[i]){ + if(rot == 0){ + zero_indices.push_back(j); + break; + } + j++; + } } - j++; + + std::uint16_t sum = fixed_values_points; + std::size_t i = 0; + for(; i < PlaceholderParams::witness_columns + PlaceholderParams::public_input_columns; i++){ + zero_indices[i] = (sum + zero_indices[i]) * 0x20; + sum += col_rotations[i].size(); + result << std::hex << std::setfill('0') << std::setw(4) << zero_indices[i]; + } + + sum = 0; + for(; i < PlaceholderParams::total_columns; i++){ + zero_indices[i] = (sum + zero_indices[i]) * 0x20; + sum += col_rotations[i].size() + 1; + result << std::hex << std::setfill('0') << std::setw(4) << zero_indices[i]; + } + return result.str(); } - for(std::size_t i = 0; i < PlaceholderParams::witness_columns; i++){ - for(auto& rot: col_rotations[i]){ - variable_type v(i, rot, true, variable_type::column_type::witness); - result[v] = j; - j++; + + /* 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; } - for(std::size_t i = 0; i < PlaceholderParams::public_input_columns; i++){ - for(auto& rot: col_rotations[i + PlaceholderParams::witness_columns]){ - variable_type v(i, rot, true, variable_type::column_type::public_input); - result[v] = j; - j++; + + /* 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; } - return result; - } - template - std::string constraint_computation_code( - const std::map, std::size_t> &var_indices, - const typename nil::crypto3::zk::snark::plonk_constraint &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; + 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; + } } } - result << "\t\tsum = addmod(sum, prod, modulus);" << std::endl; + return result.str(); } - return result.str(); - } - - template - void print_evm_verifier( - const typename PlaceholderParams::constraint_system_type &constraint_system, - const common_data_type &common_data, - const typename PlaceholderParams::commitment_scheme_type &lpc_scheme, - std::size_t permutation_size, - std::string folder_name - ){ - std::string test_name; - std::size_t found = folder_name.rfind("/"); - if( found == std::string::npos ){ - test_name = folder_name; - } else{ - test_name = folder_name.substr(found + 1); + + 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(); } - std::cout << "Generating verifier " << test_name << std::endl; + public: + evm_verifier_printer( + const typename PlaceholderParams::constraint_system_type &constraint_system, + const common_data_type &common_data, + const typename PlaceholderParams::commitment_scheme_type &lpc_scheme, + std::size_t permutation_size, + 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), + _lpc_scheme(lpc_scheme), + _permutation_size(permutation_size), + _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) + { + 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; - bool use_lookups = constraint_system.lookup_gates().size() > 0; + _z_offset = _use_lookups ? 0xc9 : 0xa1; + _special_selectors_offset = _z_offset + _permutation_size * 0x80; + _table_z_offset = _special_selectors_offset + 0xc0; + _variable_values_offset = 0; - std::size_t z_offset = use_lookups ? 0xc9 : 0xa1; - std::size_t special_selectors_offset = z_offset + permutation_size * 0x80; - std::size_t table_z_offset = special_selectors_offset + 0xc0; - std::size_t variable_values_offset = 0; + for( std::size_t i = 0; i < PlaceholderParams::arithmetization_params::constant_columns + PlaceholderParams::arithmetization_params::selector_columns; i++){ + _variable_values_offset += 0x20 * (_common_data.columns_rotations[i + PlaceholderParams::arithmetization_params::witness_columns + PlaceholderParams::arithmetization_params::public_input_columns].size()+1); + } - for( std::size_t i = 0; i < PlaceholderParams::arithmetization_params::constant_columns + PlaceholderParams::arithmetization_params::selector_columns; i++){ - variable_values_offset += 0x20 * (common_data.columns_rotations[i + PlaceholderParams::arithmetization_params::witness_columns + PlaceholderParams::arithmetization_params::public_input_columns].size()+1); + _permutation_offset = _variable_values_offset; + _public_input_offset = _variable_values_offset; + for( std::size_t i = 0; i < PlaceholderParams::arithmetization_params::witness_columns + PlaceholderParams::arithmetization_params::public_input_columns; i++){ + if(i == PlaceholderParams::arithmetization_params::witness_columns){ + _public_input_offset = _permutation_offset; + } + _permutation_offset += 0x20 * (_common_data.columns_rotations[i].size()); + } + + _quotient_offset = _use_lookups? _permutation_offset + 0x80: _permutation_offset + 0x40; + + _var_indices = get_plonk_variable_indices(_common_data.columns_rotations); } - std::size_t permutation_offset = variable_values_offset; - for( std::size_t i = 0; i < PlaceholderParams::arithmetization_params::witness_columns + PlaceholderParams::arithmetization_params::public_input_columns; i++){ - permutation_offset += 0x20 * (common_data.columns_rotations[i].size()); + 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(); } - std::size_t quotient_offset = use_lookups? permutation_offset + 0x80: permutation_offset + 0x40; + void print_lookups_library_file(std::size_t library_id, + std::vector const& lookups_list, + std::unordered_map const& lookup_codes) { - auto var_indices = get_plonk_variable_indices(common_data.columns_rotations); + std::string library_lookups; - using variable_type = nil::crypto3::zk::snark::plonk_variable; - std::stringstream gate_argument_code; - gate_argument_code << "\t\tuint256 sum;" << std::endl; - gate_argument_code << "\t\tuint256 gate;" << std::endl; - gate_argument_code << "\t\tuint256 prod;" << std::endl; - gate_argument_code << "\t\tuint256 theta_acc=1;" << std::endl; - for(const auto &gate: constraint_system.gates()){ - gate_argument_code << "\t\tgate = 0;" << std::endl; + 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){ - gate_argument_code << constraint_computation_code(var_indices, constraint); - gate_argument_code << "\t\tgate = addmod(gate, mulmod(theta_acc, sum, modulus), modulus);" << std::endl; - gate_argument_code << "\t\ttheta_acc = mulmod(theta_acc, theta, modulus);" << std::endl; + 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); - gate_argument_code << "\t\t\tgate = mulmod(gate, basic_marshalling.get_uint256_be(blob, " << var_indices.at(sel_var) * 0x20 << "), modulus);" << std::endl; - gate_argument_code << "\t\t\tF = addmod(F, gate, modulus);" <(var_indices, expression) << std::endl << std::endl; - lookup_argument_code << - "\t\t\tl = addmod( l, mulmod( mulmod(state.theta_acc, state.selector_value, modulus), sum, modulus), modulus);" << std::endl; - lookup_argument_code << "\t\t\tstate.theta_acc = mulmod(state.theta_acc, state.theta, modulus);" << std::endl; + out << constraint_computation_code(_var_indices, expression) << std::endl << std::endl; + out << "\t\tl = addmod( l, mulmod( mulmod($STATE$theta_acc, $STATE$selector_value, modulus), sum, modulus), modulus);" << std::endl; + out << "\t\t$STATE$theta_acc = mulmod($STATE$theta_acc, $STATE$theta, modulus);" << std::endl; } - lookup_argument_code << "state.g = mulmod(state.g, mulmod(addmod(1, state.beta, modulus), addmod(l,state.gamma, modulus), modulus), modulus);" << std::endl; - j++; + out << "\t\t$STATE$g = mulmod($STATE$g, mulmod(addmod(1, $STATE$beta, modulus), addmod(l, $STATE$gamma, modulus), modulus), modulus);" << std::endl; } + + return out.str(); } - lookup_argument_code << std::endl; - 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_argument_code << "\t\tstate.selector_value=basic_marshalling.get_uint256_be(blob, " << var_indices.at(sel_var) * 0x20 << ");" << std::endl; - lookup_argument_code << "\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_argument_code << - "\t\t\tl= mulmod( " << table_index << ", state.selector_value, modulus);" << std::endl; - lookup_argument_code << - "\t\t\tstate.l_shifted = mulmod( " << table_index << ", state.shifted_selector_value, modulus);" << std::endl; - lookup_argument_code << "\t\t\tstate.theta_acc=state.theta;" << std::endl; - for( const auto &var: option ){ - lookup_argument_code << - "\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_argument_code << - "\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_argument_code << "\t\t\tstate.theta_acc = mulmod(state.theta_acc, state.theta, modulus);" << std::endl; + std::size_t estimate_constraint_cost(std::string const& code) { + /* proof-of-concept: cost = number of lines */ + std::size_t lines = 0; + for(auto &ch: code) { + lines += ch == '\n'; + } + return lines; + } + + std::size_t estimate_gate_cost(std::string const& code) { + /* proof-of-concept: cost = number of lines */ + std::size_t lines = 0; + for(auto &ch: code) { + lines += ch == '\n'; + } + return lines; + } + + std::size_t estimate_lookup_cost(std::string const& code) { + /* proof-of-concept: cost = number of lines */ + std::size_t lines = 0; + for(auto &ch: code) { + lines += ch == '\n'; + } + return lines; + } + + /** @brief Split items into buckets, each bucket is limited + * to max_bucket_size, minimizes number of buckets. + * items must be sorted + * @param[in] items (item_id, item_size) + * @param[in] max_bucket_size + * @returns buckets (bucket_id -> [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; + } } - lookup_argument_code << - "\t\t\tl= mulmod( l, state.mask, modulus);" << std::endl; - lookup_argument_code << - "\t\t\tstate.l_shifted = mulmod( state.l_shifted, state.shifted_mask, modulus);" << std::endl; - lookup_argument_code << "\t\t\t state.g = mulmod(state.g, addmod( state.factor, addmod(l, mulmod(state.beta, state.l_shifted, modulus), modulus), modulus), modulus);" << std::endl; - j++; + + 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::cout << "Gates modules count" << gate_modules_count << std::endl; + 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); } - table_index++; + + 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(); } - lookup_argument_code << std::endl; - - std::string commitment_code = generate_commitment_scheme_code(common_data, lpc_scheme); - - // Prepare all necessary replacements - transpiler_replacements reps; - reps["$LOOKUP_LIBRARY_CALL$"] = use_lookups ? lookup_library_call :" //No lookups"; - reps["$TEST_NAME$"] = test_name; - reps["$MODULUS$"] = to_string(PlaceholderParams::field_type::modulus); - reps["$VERIFICATION_KEY1$"] = "0x" + to_string(common_data.vk.constraint_system_hash); - reps["$VERIFICATION_KEY2$"] = "0x" + to_string(common_data.vk.fixed_values_commitment); - reps["$BATCHES_NUM$"] = use_lookups ? "5" :"4"; - reps["$EVAL_PROOF_OFFSET$"] = use_lookups ? "0xa1" :"0x79"; - 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$"] = use_lookups ? "0xc9" :"0xa1"; - reps["$PERMUTATION_SIZE$"] = to_string(permutation_size); - reps["$SPECIAL_SELECTORS_OFFSET$"] = to_string(special_selectors_offset); - reps["$TABLE_Z_OFFSET$"] = to_string(table_z_offset); - reps["$PERMUTATION_TABLE_OFFSET$"] = to_string(permutation_offset); - reps["$QUOTIENT_OFFSET$"] = to_string(quotient_offset); - reps["$ROWS_AMOUNT$"] = to_string(common_data.rows_amount); - reps["$OMEGA$"] = to_string(common_data.basic_domain->get_domain_element(1)); - reps["$ZERO_INDICES$"] = zero_indices(common_data.columns_rotations); - reps["$GATE_ARGUMENT_COMPUTATION$"] = gate_argument_code.str(); - reps["$LOOKUP_ARGUMENT_COMPUTATION$"] = lookup_argument_code.str(); - reps["$COMMITMENT_CODE$"] = commitment_code; - - commitment_scheme_replaces(reps, common_data, lpc_scheme, permutation_size, use_lookups); - - replace_and_print(modular_verifier_template, reps, folder_name + "/modular_verifier.sol"); - replace_and_print(modular_permutation_argument_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) - replace_and_print(modular_lookup_argument_library_template, reps, folder_name + "/lookup_argument.sol"); - else - replace_and_print(modular_dummy_lookup_argument_library_template, reps, folder_name + "/lookup_argument.sol"); - } + + 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 += PlaceholderParams::arithmetization_params::constant_columns; + poly_points += PlaceholderParams::arithmetization_params::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 = PlaceholderParams::witness_columns + PlaceholderParams::public_input_columns; + j = 0; + while (j < PlaceholderParams::arithmetization_params::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 += PlaceholderParams::constant_columns; + j = 0; + while (j < PlaceholderParams::arithmetization_params::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(); + } + + void print(){ + 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, _lpc_scheme); + + // Prepare all necessary replacements + transpiler_replacements reps; + reps["$LOOKUP_LIBRARY_CALL$"] = _use_lookups ? lookup_library_call :" //No lookups"; + 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$"] = _use_lookups ? "5" :"4"; + reps["$EVAL_PROOF_OFFSET$"] = _use_lookups ? "0xa1" :"0x79"; + 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$"] = _use_lookups ? "0xc9" :"0xa1"; + reps["$PERMUTATION_SIZE$"] = to_string(_permutation_size); + reps["$SPECIAL_SELECTORS_OFFSET$"] = to_string(_special_selectors_offset); + reps["$TABLE_Z_OFFSET$"] = to_string(_table_z_offset); + reps["$PUBLIC_INPUT_OFFSET$"] = to_string(_public_input_offset); + reps["$PERMUTATION_TABLE_OFFSET$"] = to_string(_permutation_offset); + reps["$QUOTIENT_OFFSET$"] = to_string(_quotient_offset); + reps["$ROWS_AMOUNT$"] = to_string(_common_data.rows_amount); + reps["$OMEGA$"] = to_string(_common_data.basic_domain->get_domain_element(1)); + reps["$ZERO_INDICES$"] = zero_indices(_common_data.columns_rotations); + 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(); + + std::size_t _lookup_degree = _constraint_system.lookup_poly_degree_bound(); + std::size_t _rows_amount = _common_data.rows_amount; + std::size_t _quotient_degree = std::max( + (_permutation_size + 2) * (_common_data.rows_amount -1 ), + (_lookup_degree + 1) * (_common_data.rows_amount -1 ) + ); + + std::size_t _quotient_polys = (_quotient_degree % _rows_amount != 0)? (_quotient_degree / _rows_amount + 1): (_quotient_degree / _rows_amount); + + commitment_scheme_replaces( + reps, _common_data, _lpc_scheme, _permutation_size, _quotient_polys, + _use_lookups?_constraint_system.sorted_lookup_columns_number():0, _use_lookups); + + replace_and_print(modular_verifier_template, reps, _folder_name + "/modular_verifier.sol"); + replace_and_print(modular_permutation_argument_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) + replace_and_print(modular_lookup_argument_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 typename PlaceholderParams::constraint_system_type &_constraint_system; + const common_data_type &_common_data; + const typename PlaceholderParams::commitment_scheme_type &_lpc_scheme; + std::size_t _permutation_size; + std::string _folder_name; + std::string _test_name; + bool _use_lookups; + std::size_t _z_offset; + std::size_t _special_selectors_offset; + std::size_t _table_z_offset; + std::size_t _variable_values_offset; + std::size_t _permutation_offset; + std::size_t _quotient_offset; + std::size_t _public_input_offset; + variable_indices_type _var_indices; + + 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; + }; } } diff --git a/include/nil/blueprint/transpiler/lpc_scheme_gen.hpp b/include/nil/blueprint/transpiler/lpc_scheme_gen.hpp index d13a0e7..241724f 100644 --- a/include/nil/blueprint/transpiler/lpc_scheme_gen.hpp +++ b/include/nil/blueprint/transpiler/lpc_scheme_gen.hpp @@ -1,3 +1,28 @@ +//---------------------------------------------------------------------------// +// 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__ @@ -6,153 +31,88 @@ #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, + typename PlaceholderParams::field_type, PlaceholderParams >::preprocessed_data_type::common_data_type; - - std::string rot_string (int j){ - 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 ""; - } - - template + template void commitment_scheme_replaces( 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; - for(std::size_t i = 0; i < permutation_size*2; i++){ - points.push_back(rot_string(0) + "& _etha& "); - } - unique_points.insert(rot_string(0) + "& _etha& "); - points.push_back(rot_string(0) + "& "+ rot_string(1) + "& _etha& "); - points.push_back(rot_string(0) + "& "+ rot_string(1) + "& _etha& "); - unique_points.insert(rot_string(0) + "& "+ rot_string(1) + "& _etha& "); - - for(std::size_t i = 0; i < PlaceholderParams::constant_columns; i++){ - std::stringstream str; - for(auto j:common_data.columns_rotations[i + PlaceholderParams::witness_columns + PlaceholderParams::public_input_columns]){ - str << rot_string(j) << "& "; - } - str << "_etha& "; - unique_points.insert(str.str()); - points.push_back(str.str()); - } - - for(std::size_t i = 0; i < PlaceholderParams::selector_columns; i++){ - std::stringstream str; - for(auto j:common_data.columns_rotations[i + PlaceholderParams::witness_columns + PlaceholderParams::public_input_columns + PlaceholderParams::constant_columns]){ - str << rot_string(j) << "& "; - } - str << "_etha& "; - unique_points.insert(str.str()); - points.push_back(str.str()); - } - - for(std::size_t i = 0; i < PlaceholderParams::witness_columns; i++){ - std::stringstream str; - for(auto j:common_data.columns_rotations[i]){ - str << rot_string(j) << "& "; - } - unique_points.insert(str.str()); - points.push_back(str.str()); - } + auto [z_points_indices, singles_strs, singles_map, poly_ids] = calculate_unique_points>( + common_data, permutation_size, use_lookups, quotient_polys, lookup_polys, + "evm" // Generator mode + ); - for(std::size_t i = 0; i < PlaceholderParams::public_input_columns; i++){ - std::stringstream str; - for(auto j:common_data.columns_rotations[i + PlaceholderParams::witness_columns]){ - str << rot_string(j) << "& "; - } - unique_points.insert(str.str()); - points.push_back(str.str()); - } - - unique_points.insert(rot_string(0) + "& " + rot_string(1) + "& ");//Permutation - unique_points.insert(rot_string(0) + "& ");// Quotient - if(use_lookups) - unique_points.insert(rot_string(0) + "& " + rot_string(1) + "& " + rot_string(common_data.usable_rows_amount) + "& "); // Lookups + std::stringstream points_initializer; + std::size_t i = 0; - std::size_t permutation_point_id; - std::size_t quotient_point_id; - std::size_t lookup_point_id; - std::size_t j = 0; - for( const auto &unique_point:unique_points){ - if( unique_point == rot_string(0) + "& ") quotient_point_id = j; - if( unique_point == rot_string(0) + "& " + rot_string(1) + "& " + rot_string(common_data.usable_rows_amount) + "& " ) lookup_point_id = j; - if( unique_point == rot_string(0) + "& " + rot_string(1) + "& " ) permutation_point_id = j; - j++; + for(const auto& point: singles_strs){ + points_initializer << "\t\tresult[" << i << "] = " << point << ";" << std::endl; + i++; } std::stringstream points_ids; - for(std::size_t i = 0; i < points.size(); i++){ - std::size_t j = 0; - for(const auto &unique_point:unique_points){ - if(points[i] == unique_point){ - points_ids << std::hex << std::setw(2) << std::setfill('0') << j; - break; - } - j++; - } + for( const auto& point_id: z_points_indices){ + points_ids << std::hex << std::setw(2) << std::setfill('0') << point_id; } - std::stringstream points_initializer; - std::size_t i = 0; - for(const auto& point: unique_points){ - points_initializer << "\t\t result[" << i << "] = new uint256[](" << std::count(point.begin(), point.end(), '&') << ");" << std::endl; - std::size_t prev = 0; - std::size_t found = point.find("& "); - std::size_t j = 0; - while (found!=std::string::npos){ - points_initializer << "\t\t result[" << i << "][" << j << "] = " << point.substr(prev, found-prev) << ";" << std::endl; - prev = found + 2; - found = point.find("& ",prev); - j++; + 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; } - i++; } std::vector init_blob = {}; nil::crypto3::zk::transcript::fiat_shamir_heuristic_sequential transcript(init_blob); - transcript(common_data.vk.constraint_system_hash); + 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_fri_params(); + + auto fri_params = lpc_scheme.get_commitment_params(); replacements["$R$"] = to_string(fri_params.r); replacements["$LAMBDA$"] = to_string(PlaceholderParams::commitment_scheme_type::fri_type::lambda); replacements["$D0_SIZE$"] = to_string(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(unique_points.size()); - replacements["$DIFFERENT_POINTS$"] = to_string(unique_points.size()); - replacements["$PERMUTATION_POINTS_ID$"] = to_string(permutation_point_id); - replacements["$QUOTIENT_POINTS_ID$"] = to_string(quotient_point_id); - replacements["$LOOKUP_POINTS_ID$"] = to_string(lookup_point_id); + 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["$ETHA$"] = to_string(etha); + replacements["$ETA$"] = to_string(etha); if( PlaceholderParams::commitment_scheme_type::fri_type::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 @@ -160,7 +120,7 @@ namespace nil { const common_data_type &common_data, const typename PlaceholderParams::commitment_scheme_type& lpc_scheme ){ - auto fri_params = lpc_scheme.get_fri_params(); + auto fri_params = lpc_scheme.get_commitment_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); diff --git a/include/nil/blueprint/transpiler/minimized_profiling_plonk_circuit.hpp b/include/nil/blueprint/transpiler/minimized_profiling_plonk_circuit.hpp index 195fc83..4946bcb 100644 --- a/include/nil/blueprint/transpiler/minimized_profiling_plonk_circuit.hpp +++ b/include/nil/blueprint/transpiler/minimized_profiling_plonk_circuit.hpp @@ -105,14 +105,14 @@ namespace nil { 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( + crypto3::math::expression_for_each_variable_visitor visitor( [this](const variable_type& var){ if (var.type == variable_type::witness) { this->need_witness = true; @@ -130,7 +130,7 @@ namespace nil { if( var.rotation != 0) { this->rotated_selector = true; } } }); - visitor.visit(constraint); + visitor.visit(constraint); } } @@ -138,8 +138,8 @@ namespace nil { 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; + // 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++) { @@ -274,14 +274,14 @@ namespace nil { 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( + 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); + visitor.visit(constraint); } } /* @@ -430,8 +430,8 @@ namespace nil { 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; + // 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(); diff --git a/include/nil/blueprint/transpiler/print_contracts.hpp b/include/nil/blueprint/transpiler/print_contracts.hpp deleted file mode 100644 index 4eeb1e9..0000000 --- a/include/nil/blueprint/transpiler/print_contracts.hpp +++ /dev/null @@ -1,707 +0,0 @@ -//---------------------------------------------------------------------------// -// 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_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; - - using columns_rotations_type = std::array, ArithmetizationParams::total_columns>; - 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(); - } - }; - - static inline 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 < ArithmetizationParams::total_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); - } - - static 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 + ArithmetizationParams::witness_columns; - } - if (var.type == variable_type::constant) { - global_index = var.index + ArithmetizationParams::witness_columns + - ArithmetizationParams::public_input_columns; - } - if (var.type == variable_type::selector) { - global_index = var.index + ArithmetizationParams::witness_columns + - ArithmetizationParams::public_input_columns + - ArithmetizationParams::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 - static 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 - static 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(); - } - - - static 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"; - } - - static 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(); - } - - static 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; - } - - static 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; - } - - static 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; - } - - - static 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(); - } - } - }; - } // namespace blueprint -} // namespace nil - -#endif // CRYPTO3_MINIMIZED_PROFILING_PLONK_CIRCUIT_HPP diff --git a/include/nil/blueprint/transpiler/recursive_verifier_generator.hpp b/include/nil/blueprint/transpiler/recursive_verifier_generator.hpp new file mode 100644 index 0000000..1511aa6 --- /dev/null +++ b/include/nil/blueprint/transpiler/recursive_verifier_generator.hpp @@ -0,0 +1,911 @@ +//---------------------------------------------------------------------------// +// 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 + +namespace nil { + namespace blueprint { + template + struct recursive_verifier_generator{ + using field_type = typename PlaceholderParams::field_type; + using arithmetization_params = typename PlaceholderParams::arithmetization_params; + 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::array, PlaceholderParams::total_columns>; + 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; + + // TODO: Move logic to utils.hpp. It's similar to EVM verifier generator + static std::string zero_indices(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 < PlaceholderParams::constant_columns + PlaceholderParams::selector_columns; i++){ + fixed_values_points += col_rotations[i + PlaceholderParams::witness_columns + PlaceholderParams::public_input_columns].size() + 1; + } + + for(std::size_t i= 0; i < PlaceholderParams::total_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 < PlaceholderParams::witness_columns + PlaceholderParams::public_input_columns; i++){ + zero_indices[i] = sum + zero_indices[i]; + sum += col_rotations[i].size(); + } + + sum = 0; + for(; i < PlaceholderParams::total_columns; i++){ + zero_indices[i] = sum + zero_indices[i]; + sum += col_rotations[i].size() + 1; + } + + for( i = 0; i < PlaceholderParams::total_columns; i++){ + if( i != 0 ) result << ", "; + result << zero_indices[i] + 4 * permutation_size + 6; + } + return result.str(); + } + + 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){ + return "{\"field\": \"" << hashed_data << "\"}"; + } 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) { + if( CommitmentSchemeType::lpc::use_grinding ){ + BOOST_ASSERT_MSG(false, "grinding is not supported"); + std::cout << "Grinding is not supported" << std::endl; + return "Grinding is not supported"; + } + + 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++){ + 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{\"field\":\"" << round_proof.y[0][0] << "\"}," << std::endl; + out << "\t\t\t{\"field\":\"" << round_proof.y[0][1] << "\"}"; + cur++; + cur++; + } + } + out << std::endl << "\t\t]}," << std::endl; + + out << "\t\t{\"array\": [" << std::endl; + cur = 0; + for( std::size_t i = 0; i < eval_proof.fri_proof.query_proofs.size(); i++){ + 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{\"int\":" << initial_proof.p.path()[k][0].position() << "}"; + cur ++; + } + break; + } + } + out << std::endl << "\t\t]}," << std::endl; + + out << "\t\t{\"array\": [" << std::endl; + cur = 0; + for( std::size_t i = 0; i < eval_proof.fri_proof.query_proofs.size(); i++){ + 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" << generate_hash( + initial_proof.p.path()[k][0].hash() + ); + cur ++; + } + } + } + out << std::endl << "\t\t]}," << std::endl; + + out << "\t\t{\"array\": [" << std::endl; + cur = 0; + for( std::size_t i = 0; i < eval_proof.fri_proof.query_proofs.size(); i++){ + 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{\"int\": " << p.path()[k][0].position() << "}"; + cur++; + } + } + } + out << std::endl << "\t\t]}," << std::endl; + + out << "\t\t{\"array\": [" << std::endl; + cur = 0; + for( std::size_t i = 0; i < eval_proof.fri_proof.query_proofs.size(); i++){ + 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" << generate_hash( + p.path()[k][0].hash() + ); + cur++; + } + } + } + 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"; + } + + static inline std::string generate_input( + const verification_key_type &vk, + const typename assignment_table_type::public_input_container_type &public_inputs, + const proof_type &proof, + const std::array public_input_sizes + ){ + std::stringstream out; + out << "[" << std::endl; + + if(arithmetization_params::public_input_columns != 0){ + out << "\t{\"array\":[" << std::endl; + std::size_t cur = 0; + for(std::size_t i = 0; i < arithmetization_params::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{\"array\":[" << std::endl; + out << "\t\t" << generate_hash( + vk.constraint_system_with_params_hash + ) << "," << std::endl; + out << "\t\t" << generate_hash( + vk.fixed_values_commitment + ) << std::endl; + out << "\t]}," << std::endl; + + out << "\t{\"struct\":[" << std::endl; + out << "\t\t{\"array\":[" << std::endl; + out << "\t\t\t" << generate_commitment(proof.commitments.at(1))//(nil::crypto3::zk::snark::VARIABLE_VALUES_BATCH) + << "," << std::endl; + out << "\t\t\t" << generate_commitment( + proof.commitments.at(2))//(nil::crypto3::zk::snark::PERMUTATION_BATCH) + << "," << std::endl; + out << "\t\t\t" << generate_commitment( + proof.commitments.at(3)) // (nil::crypto3::zk::snark::QUOTIENT_BATCH) + ; + + if( proof.commitments.find(4) != proof.commitments.end() ){ /*nil::crypto3::zk::snark::LOOKUP_BATCH*/ + out << "," << std::endl << "\t\t\t" << generate_commitment( + proof.commitments.at(4) //nil::crypto3::zk::snark::LOOKUP_BATCH) + ); + } + out << std::endl; + + 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 + static 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 < PlaceholderParams::constant_columns; i++){ + for(auto& rot: col_rotations[i + PlaceholderParams::witness_columns + PlaceholderParams::public_input_columns]){ + variable_type v(i, rot, true, variable_type::column_type::constant); + result[v] = j + start_index; + j++; + } + j++; + } + for(std::size_t i = 0; i < PlaceholderParams::selector_columns; i++){ + for(auto& rot: col_rotations[i + PlaceholderParams::witness_columns + PlaceholderParams::public_input_columns + PlaceholderParams::constant_columns]){ + variable_type v(i, rot, true, variable_type::column_type::selector); + result[v] = j + start_index; + j++; + } + j++; + } + for(std::size_t i = 0; i < PlaceholderParams::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 < PlaceholderParams::public_input_columns; i++){ + for(auto& rot: col_rotations[i + PlaceholderParams::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()) + "_cppui255)"); + 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 + ")"; + } + } + }; + + 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(omega, " + to_string(j) + ")"; else + if(j < 0) return "xi/pow(omega, " + to_string(-j) + ")"; + 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; + } + + static inline std::tuple< + std::vector>, std::vector, std::map + > calculate_unique_point_sets( + const common_data_type &common_data, + std::size_t permutation_size, + bool use_lookups, + std::size_t quotient_size, + std::size_t sorted_size + ){ + std::set unique_points; + std::vector points; + std::map singles; + std::vector> result; + std::vector points_ids; + + singles["eta"] = singles.size(); + singles[rot_string(0)] = singles.size(); + singles[rot_string(1)] = singles.size(); + + for(std::size_t i = 0; i < permutation_size*2; i++){ + points.push_back(rot_string(0) + "& eta& "); + } + unique_points.insert(rot_string(0) + "& eta& "); + points.push_back(rot_string(0) + "& "+ rot_string(1) + "& eta& "); + points.push_back(rot_string(0) + "& "+ rot_string(1) + "& eta& "); + unique_points.insert(rot_string(0) + "& "+ rot_string(1) + "& eta& "); + + for(std::size_t i = 0; i < PlaceholderParams::constant_columns; i++){ + std::stringstream str; + for(auto j:common_data.columns_rotations[i + PlaceholderParams::witness_columns + PlaceholderParams::public_input_columns]){ + if(singles.find(rot_string(j)) == singles.end()) + singles[rot_string(j)] = singles.size(); + str << rot_string(j) << "& "; + } + str << "eta& "; + unique_points.insert(str.str()); + points.push_back(str.str()); + } + + for(std::size_t i = 0; i < PlaceholderParams::selector_columns; i++){ + std::stringstream str; + for(auto j:common_data.columns_rotations[i + PlaceholderParams::witness_columns + PlaceholderParams::public_input_columns + PlaceholderParams::constant_columns]){ + if(singles.find(rot_string(j)) == singles.end()) + singles[rot_string(j)] = singles.size(); + str << rot_string(j) << "& "; + } + str << "eta& "; + unique_points.insert(str.str()); + points.push_back(str.str()); + } + + for(std::size_t i = 0; i < PlaceholderParams::witness_columns; i++){ + std::stringstream str; + for(auto j:common_data.columns_rotations[i]){ + if(singles.find(rot_string(j)) == singles.end()) + singles[rot_string(j)] = singles.size(); + str << rot_string(j) << "& "; + } + unique_points.insert(str.str()); + points.push_back(str.str()); + } + + for(std::size_t i = 0; i < PlaceholderParams::public_input_columns; i++){ + std::stringstream str; + for(auto j:common_data.columns_rotations[i + PlaceholderParams::witness_columns]){ + if(singles.find(rot_string(j)) == singles.end()) + singles[rot_string(j)] = singles.size(); + str << rot_string(j) << "& "; + } + unique_points.insert(str.str()); + points.push_back(str.str()); + } + + unique_points.insert(rot_string(0) + "& " + rot_string(1) + "& ");//Permutation + points.push_back(rot_string(0) + "& " + rot_string(1) + "& "); + if(use_lookups){ + points.push_back(rot_string(0) + "& " + rot_string(1) + "& "); + } + unique_points.insert(rot_string(0) + "& ");// Quotient + for(std::size_t i = 0; i < quotient_size; i++){ + points.push_back(rot_string(0) + "& "); + } + if(use_lookups){ + unique_points.insert(rot_string(0) + "& " + rot_string(1) + "& " + rot_string(common_data.usable_rows_amount) + "& "); // Lookups + for( std::size_t i = 0; i < sorted_size; i++ ){ + points.push_back(rot_string(0) + "& " + rot_string(1) + "& " + rot_string(common_data.usable_rows_amount) + "& "); + } + singles[rot_string(common_data.usable_rows_amount)] = singles.size(); + } + + for(std::size_t i = 0; i < points.size(); i++){ + std::size_t j = 0; + bool found = false; + for(const auto &unique_point:unique_points){ + if(points[i] == unique_point){ + found = true; + points_ids.push_back(j); + break; + } + j++; + } + BOOST_ASSERT(found); + } + + for( const auto &p: unique_points){ + result.push_back(split_point_string(p)); + } + + return std::make_tuple(result, points_ids, singles); + } + + static inline std::string generate_recursive_verifier( + const constraint_system_type &constraint_system, + const common_data_type &common_data, + const commitment_scheme_type &commitment_scheme, + std::size_t permutation_size, + const std::array public_input_sizes + ){ + 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 = commitment_scheme.get_commitment_params(); + std::size_t batches_num = use_lookups?5:4; + auto lambda = PlaceholderParams::commitment_scheme_type::fri_type::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 = common_data.rows_amount; + std::size_t quotient_degree = std::max( + (permutation_size + 2) * (common_data.rows_amount -1 ), + (lookup_degree + 1) * (common_data.rows_amount -1 ) + ); + + std::size_t quotient_polys = (quotient_degree % rows_amount != 0)? (quotient_degree / rows_amount + 1): (quotient_degree / rows_amount); + + std::size_t poly_num = 2 * permutation_size + 2 + (use_lookups?2:1) + + arithmetization_params::total_columns + + constraint_system.sorted_lookup_columns_number() + quotient_polys; + + std::size_t points_num = 4 * permutation_size + 6; + std::size_t table_values_num = 0; + for(std::size_t i = 0; i < arithmetization_params::constant_columns + arithmetization_params::selector_columns; i++){ + points_num += common_data.columns_rotations[i + arithmetization_params::witness_columns + arithmetization_params::public_input_columns].size() + 1; + table_values_num += common_data.columns_rotations[i + arithmetization_params::witness_columns + arithmetization_params::public_input_columns].size() + 1; + } + for(std::size_t i = 0; i < arithmetization_params::witness_columns + arithmetization_params::public_input_columns; i++){ + points_num += common_data.columns_rotations[i].size(); + table_values_num += common_data.columns_rotations[i].size(); + } + points_num += use_lookups? 4 : 2; + points_num += quotient_polys; + + if( use_lookups ) { + points_num += constraint_system.sorted_lookup_columns_number() * 3; + } + + + 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, 4*permutation_size + 6); + + 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( + common_data, permutation_size, use_lookups, 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++){ + for(std::size_t j = 0; j m) - 1)); + reps["$INITIAL_MERKLE_PROOFS_HASH_NUM$"] = to_string(lambda * (log2(fri_params.D[0]->m) - 1) * batches_num); + reps["$ROUND_MERKLE_PROOFS_POSITION_NUM$"] = to_string(lambda * round_proof_layers_num); + reps["$ROUND_MERKLE_PROOFS_HASH_NUM$"] = to_string(lambda * round_proof_layers_num); + 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["$ZERO_INDICES$"] = zero_indices(common_data.columns_rotations, permutation_size); + reps["$TOTAL_COLUMNS$"] = to_string(arithmetization_params::total_columns); + 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(arithmetization_params::witness_columns); + reps["$PUBLIC_INPUT_COLUMNS_AMOUNT$"] = to_string(arithmetization_params::public_input_columns); + reps["$CONSTANT_COLUMNS_AMOUNT$"] = to_string(arithmetization_params::constant_columns); + reps["$SELECTOR_COLUMNS_AMOUNT$"] = to_string(arithmetization_params::selector_columns); + reps["$QUOTIENT_POLYS_START$"] = to_string(4*permutation_size + 6 + table_values_num + (use_lookups?4:2)); + 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)) + "_cppui255)"; + reps["$OMEGA$"] = "pallas::base_field_type::value_type(0x" + to_hex_string(common_data.basic_domain->get_domain_element(1)) + "_cppui255)"; + 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: 1); + 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(4*permutation_size + 6 + table_values_num + (use_lookups?4:2) + quotient_polys); + reps["$BATCHES_AMOUNT_LIST$"] = batches_size_list; + reps["$PUBLIC_INPUT_SIZES$"] = public_input_sizes_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$"] = arithmetization_params::public_input_columns == 0 ? "" :public_input_check_str; + reps["$PUBLIC_INPUT_INPUT$"] = arithmetization_params::public_input_columns == 0 ? "" : public_input_input_str; + + result = replace_all(result, reps); + return result; + } + }; + } +} + +#endif // CRYPTO3_RECURSIVE_VERIFIER_GENERATOR_HPP \ No newline at end of file diff --git a/include/nil/blueprint/transpiler/templates/commitment_scheme.hpp b/include/nil/blueprint/transpiler/templates/commitment_scheme.hpp index ac29ce4..d438915 100644 --- a/include/nil/blueprint/transpiler/templates/commitment_scheme.hpp +++ b/include/nil/blueprint/transpiler/templates/commitment_scheme.hpp @@ -8,8 +8,9 @@ namespace nil { 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); - transcript.get_integral_challenge_be(tr_state, 4); - )"; + 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. @@ -48,16 +49,16 @@ library modular_commitment_scheme_$TEST_NAME$ { uint256 constant max_degree = $MAX_DEGREE$; uint256 constant D0_omega = $D0_OMEGA$; uint256 constant unique_points = $UNIQUE_POINTS$; - uint256 constant permutation_point = $PERMUTATION_POINTS_ID$; - uint256 constant quotient_point = $QUOTIENT_POINTS_ID$; - uint256 constant lookup_point = $LOOKUP_POINTS_ID$; - bytes constant points_ids = hex"$POINTS_IDS$"; uint256 constant omega = $OMEGA$; - uint256 constant _etha = $ETHA$; + uint256 constant _eta = $ETA$; + 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; @@ -73,215 +74,49 @@ library modular_commitment_scheme_$TEST_NAME$ { uint256 domain_size; uint256[] final_polynomial; uint256 leaf_length; - uint256[][unique_points] denominators; - uint256[unique_points] factors; - uint256[][unique_points] combined_U; - uint256[][unique_points] unique_eval_points; + uint256[2][unique_points] denominators; + uint256[unique_points] U; + uint256[unique_points] unique_eval_points; + uint256[unique_points] theta_factors; uint256[2] y; + uint256[2] Q; uint256 j; uint256 offset; + uint16[][unique_points] poly_inds; } - function calculate_2points_interpolation(uint256[] memory xi, uint256[2] memory z, uint256 modulus) - internal pure returns(uint256[2] memory U){ -// require( xi.length == 2 ); - U[0] = addmod(mulmod(z[0], xi[1], modulus),modulus - mulmod(z[1], xi[0], modulus), modulus); - U[1] = addmod(z[1], modulus - z[0], modulus); - } - -// coeffs for zs on each degree can be precomputed if necessary - function calculate_3points_interpolation(uint256[] memory xi, uint256[3] memory z, uint256 modulus) - internal pure returns(uint256[3] memory U){ -// require( xi.length == 3 ); - z[0] = mulmod(z[0], addmod(xi[1], modulus - xi[2], modulus), modulus); - z[1] = mulmod(z[1], addmod(xi[2], modulus - xi[0], modulus), modulus); - z[2] = mulmod(z[2], addmod(xi[0], modulus - xi[1], modulus), modulus); - - U[0] = mulmod(z[0], mulmod(xi[1], xi[2], modulus), modulus); - U[0] = addmod(U[0], mulmod(z[1], mulmod(xi[0], xi[2], modulus), modulus), modulus); - U[0] = addmod(U[0], mulmod(z[2], mulmod(xi[0], xi[1], modulus), modulus), modulus); - - U[1] = modulus - mulmod(z[0], addmod(xi[1], xi[2], modulus), modulus); - U[1] = addmod(U[1], modulus - mulmod(z[1], addmod(xi[0], xi[2], modulus), modulus), modulus); - U[1] = addmod(U[1], modulus - mulmod(z[2], addmod(xi[0], xi[1], modulus), modulus), modulus); - - U[2] = addmod(z[0], addmod(z[1], z[2], modulus), modulus); - } - function prepare_eval_points(uint256[][unique_points] memory result, uint256 xi) internal view { + function prepare_eval_points(uint256[unique_points] memory result, uint256 xi, uint256 eta) internal view { uint256 inversed_omega = field.inverse_static(omega, modulus); $POINTS_INITIALIZATION$ } - function prepare_U_V(bytes calldata blob, commitment_state memory state, uint256 xi) internal view returns(bool result){ - result = true; - uint64 ind = 0; - prepare_eval_points(state.unique_eval_points, xi); - // Prepare denominators - for( ind = 0; ind < state.unique_eval_points.length;){ - state.denominators[ind] = new uint256[](state.unique_eval_points[ind].length + 1); - if( state.unique_eval_points[ind].length == 1 ){ - state.factors[ind] = 1; - state.denominators[ind][0] = modulus - state.unique_eval_points[ind][0]; - state.denominators[ind][1] = 1; - } else - if( state.unique_eval_points[ind].length == 2 ){ - // xi1 - xi0 - state.factors[ind] = - addmod(state.unique_eval_points[ind][1], modulus - state.unique_eval_points[ind][0], modulus); - state.denominators[ind][2] = 1; - - state.denominators[ind][1] = - modulus - addmod(state.unique_eval_points[ind][0], state.unique_eval_points[ind][1], modulus); - - state.denominators[ind][0] = - mulmod(state.unique_eval_points[ind][0], state.unique_eval_points[ind][1], modulus); - state.denominators[ind][0] = mulmod(state.denominators[ind][0], state.factors[ind], modulus); - state.denominators[ind][1] = mulmod(state.denominators[ind][1], state.factors[ind], modulus); - state.denominators[ind][2] = mulmod(state.denominators[ind][2], state.factors[ind], modulus); - } else - if( state.unique_eval_points[ind].length == 3 ){ - state.factors[ind] = modulus - - mulmod( - mulmod( - addmod(state.unique_eval_points[ind][0], modulus - state.unique_eval_points[ind][1], modulus), - addmod(state.unique_eval_points[ind][1], modulus - state.unique_eval_points[ind][2], modulus), - modulus - ), - addmod(state.unique_eval_points[ind][2], modulus - state.unique_eval_points[ind][0], modulus), - modulus - ); - state.denominators[ind][3] = 1; - state.denominators[ind][2] = - modulus - addmod( - state.unique_eval_points[ind][0], - addmod(state.unique_eval_points[ind][1],state.unique_eval_points[ind][2], modulus), - modulus - ); - state.denominators[ind][1] = - addmod( - mulmod(state.unique_eval_points[ind][0], state.unique_eval_points[ind][1], modulus), - addmod( - mulmod(state.unique_eval_points[ind][0], state.unique_eval_points[ind][2], modulus), - mulmod(state.unique_eval_points[ind][1], state.unique_eval_points[ind][2], modulus), - modulus - ), - modulus - ); - state.denominators[ind][0] = - modulus - mulmod( - state.unique_eval_points[ind][0], - mulmod(state.unique_eval_points[ind][1],state.unique_eval_points[ind][2], modulus), - modulus - ); - state.denominators[ind][0] = mulmod(state.denominators[ind][0], state.factors[ind], modulus); - state.denominators[ind][1] = mulmod(state.denominators[ind][1], state.factors[ind], modulus); - state.denominators[ind][2] = mulmod(state.denominators[ind][2], state.factors[ind], modulus); - state.denominators[ind][3] = mulmod(state.denominators[ind][3], state.factors[ind], modulus); - } else { - console.log("UNPROCESSED number of evaluation points"); - return false; - } - unchecked{ind++;} - } - - // Prepare combined U - for( uint256 ind = 0; ind < unique_points;){ - uint256[] memory point = state.unique_eval_points[ind]; - state.combined_U[ind] = new uint256[](state.unique_eval_points[ind].length); - uint64 cur = 0; - uint256 offset = 0x8; - for( uint256 k = 0; k < batches_num;){ - for( uint256 i = 0; i < state.batch_sizes[k];){ - uint256 cur_point = 0; - if(cur < points_ids.length ) cur_point = uint8(points_ids[cur]); - else if(k == 2) cur_point = permutation_point; - else if(k == 3) cur_point = quotient_point; - else if(k == 4) cur_point = lookup_point; - else console.log("Wrong index"); - - polynomial.multiply_poly_on_coeff( - state.combined_U[ind], - state.theta, - modulus - ); - if( cur_point == ind ){ - if( point.length == 1 ){ - state.combined_U[ind][0] = addmod( - state.combined_U[ind][0], - basic_marshalling.get_uint256_be(blob, offset), - modulus - ); - } else - if( point.length == 2 ){ - uint256[2] memory tmp; - tmp[0] = basic_marshalling.get_uint256_be(blob, offset); - tmp[1] = basic_marshalling.get_uint256_be(blob, offset + 0x20); - tmp = calculate_2points_interpolation( - point, tmp, modulus - ); - state.combined_U[ind][0] = addmod(state.combined_U[ind][0], tmp[0], modulus); - state.combined_U[ind][1] = addmod(state.combined_U[ind][1], tmp[1], modulus); - } else - if( point.length == 3){ - uint256[3] memory tmp; - tmp[0] = basic_marshalling.get_uint256_be(blob, offset); - tmp[1] = basic_marshalling.get_uint256_be(blob, offset + 0x20); - tmp[2] = basic_marshalling.get_uint256_be(blob, offset + 0x40); - tmp = calculate_3points_interpolation( - point, tmp, modulus - ); - state.combined_U[ind][0] = addmod(state.combined_U[ind][0], tmp[0], modulus); - state.combined_U[ind][1] = addmod(state.combined_U[ind][1], tmp[1], modulus); - state.combined_U[ind][2] = addmod(state.combined_U[ind][2], tmp[2], modulus); - } else { - return false; - } - } - offset += state.unique_eval_points[cur_point].length * 0x20; - unchecked{i++;cur++;} - } - unchecked{k++;} - } - unchecked{ind++;} - } - } - - function compute_combined_Q(bytes calldata blob,commitment_state memory state) internal view returns(uint256[2] memory y){ - for(uint256 p = 0; p < unique_points; ){ - uint256[2] memory tmp; - uint256 offset = state.initial_data_offset - state.poly_num * 0x40; // Save initial data offset for future use; - uint256 cur = 0; - for(uint256 b = 0; b < batches_num;){ - for(uint256 j = 0; j < state.batch_sizes[b];){ - uint256 cur_point = 0; - if(cur < points_ids.length ) cur_point = uint8(points_ids[cur]); - else if(b == 2) cur_point = permutation_point; - else if(b == 3) cur_point = quotient_point; - else if(b == 4) cur_point = lookup_point; - else console.log("Wrong index"); - - tmp[0] = mulmod(tmp[0], state.theta, modulus); - tmp[1] = mulmod(tmp[1], state.theta, modulus); - - if(cur_point == p){ - tmp[0] = addmod(tmp[0], basic_marshalling.get_uint256_be(blob, offset), modulus); - tmp[1] = addmod(tmp[1], basic_marshalling.get_uint256_be(blob, offset + 0x20), modulus); - } - unchecked{offset += 0x40;j++; cur++;} + 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); } - unchecked{b++;} + 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; } - tmp[0] = mulmod(tmp[0], state.factors[p], modulus); - tmp[1] = mulmod(tmp[1], state.factors[p], modulus); - uint256 s = state.x; - tmp[0] = addmod(tmp[0], modulus - polynomial.evaluate(state.combined_U[p], s , modulus), modulus); - tmp[1] = addmod(tmp[1], modulus - polynomial.evaluate(state.combined_U[p], modulus - s, modulus), modulus); - tmp[0] = mulmod(tmp[0], field.inverse_static(polynomial.evaluate(state.denominators[p], s, modulus), modulus), modulus); - tmp[1] = mulmod(tmp[1], field.inverse_static(polynomial.evaluate(state.denominators[p], modulus - s, modulus), modulus), modulus); - y[0] = addmod(y[0], tmp[0], modulus); - y[1] = addmod(y[1], tmp[1], modulus); - unchecked{p++;} } } @@ -290,22 +125,22 @@ library modular_commitment_scheme_$TEST_NAME$ { ) internal returns(bytes32 tr_state_after){ types.transcript_data memory tr_state; tr_state.current_challenge = tr_state_before; - uint256 etha = transcript.get_field_challenge(tr_state, modulus); - require(etha == _etha, "Wrong etha"); + 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) + 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), + add(leaf, 0x20), c ) mstore( - add(leaf, 0x40), + add(leaf, 0x40), d ) } @@ -316,17 +151,17 @@ library modular_commitment_scheme_$TEST_NAME$ { } } - function copy_reverted_memory_pair_and_check(bytes calldata blob, uint256 proof_offset, bytes memory leaf, uint256[2] memory pair) + 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), + add(leaf, 0x20), d ) mstore( - add(leaf, 0x40), + add(leaf, 0x40), c ) } @@ -337,159 +172,161 @@ library modular_commitment_scheme_$TEST_NAME$ { } } - function copy_pairs_and_check(bytes calldata blob, uint256 offset, bytes memory leaf, uint256 size, uint256 proof_offset) + function copy_pairs_and_check(bytes calldata blob, uint256 offset, bytes memory leaf, uint256 size, uint256 proof_offset) internal pure returns(bool b){ - 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))) - ) - } - unchecked{ + 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; + 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) + function copy_reverted_pairs_and_check(bytes calldata blob, uint256 offset, bytes memory leaf, uint256 size, uint256 proof_offset) internal pure returns(bool){ - 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)) - ) - } - unchecked{ + 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; + 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){ - 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), + 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 - ), - modulus - ); - uint256 tmp1 = mulmod(colinear_value , 2, modulus); - tmp1 = mulmod(tmp1 , x, modulus); - if( tmp != tmp1 ){ - console.log("Colinear check failed"); - return false; - } + ); + uint256 tmp1 = mulmod(colinear_value , 2, modulus); + tmp1 = mulmod(tmp1 , x, modulus); + if( tmp != tmp1 ){ + return false; + } return true; + } } function verify_eval( bytes calldata blob, - uint256[5] memory commitments, + 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; - if (challenge!= transcript.get_field_challenge(tr_state, modulus)) return false; + if (challenge!= transcript.get_field_challenge(tr_state, modulus)) { + console.log("Wrong challenge"); + return false; + } for(uint8 i = 0; i < batches_num;){ transcript.update_transcript_b32(tr_state, bytes32(commitments[i])); - unchecked{i++;} + i++; } state.theta = transcript.get_field_challenge(tr_state, modulus); state.points_num = basic_marshalling.get_length(blob, 0x0); - unchecked{ - offset = 0x8 + state.points_num*0x20 + 0x8; - } + 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]; - unchecked { i++; offset +=2;} - } - unchecked{ - offset += 0x8; - offset += state.poly_num; - state.roots_offset = offset + 0x8; - offset += 0x8; + 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); - unchecked{i++; offset +=40; } + i++; offset +=40; } $GRINDING_CHECK$ - - unchecked{ - offset += 0x8 + r; - state.initial_data_offset = offset + 0x8; - offset += 0x8 + 0x20*basic_marshalling.get_length(blob, offset); - } - unchecked{ - state.round_data_offset = offset + 0x8; - offset += 0x8 + 0x20*basic_marshalling.get_length(blob, offset); - offset += 0x8; - } - state.initial_proof_offset = offset; - for(uint8 i = 0; i < lambda;){ - for(uint j = 0; j < batches_num;){ + 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); - unchecked{j++;} + j++; } - unchecked{i++;} + 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; + 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); - unchecked{j++;} + j++; } - unchecked{i++;} + i++; } state.final_polynomial = new uint256[](basic_marshalling.get_length(blob, offset)); - unchecked{offset += 0x8;} + offset += 0x8; for (uint256 i = 0; i < state.final_polynomial.length;) { state.final_polynomial[i] = basic_marshalling.get_uint256_be(blob, offset); - unchecked{ i++; offset+=0x20;} + i++; offset+=0x20; } } if( state.final_polynomial.length > (( 1 << (field.log2(max_degree + 1) - r + 1) ) ) ){ @@ -497,15 +334,46 @@ library modular_commitment_scheme_$TEST_NAME$ { return false; } - if( !prepare_U_V(blob, state, challenge) ) return false; + prepare_eval_points(state.unique_eval_points, challenge, _eta); + { + 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++; + } + 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++; + } + for(uint256 i = 0; i < state.unique_eval_points.length;){ + i++; + } + } +$ETA_VALUES_VERIFICATION$ + + 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(uint256 i = 0; i < lambda;){ + for(uint64 i = 0; i < lambda;){ // Initial proofs + state.query_proof_offset = state.initial_data_offset; state.x_index = uint256(transcript.get_integral_challenge_be(tr_state, 8)) % D0_size; state.x = field.pow_small(D0_omega, state.x_index, modulus); state.domain_size = D0_size >> 1; - for(uint256 j = 0; j < batches_num;){ + for(uint64 j = 0; j < batches_num;){ if( state.x_index < state.domain_size ){ 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"); @@ -520,20 +388,25 @@ library modular_commitment_scheme_$TEST_NAME$ { 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); - unchecked{j++;} + j++; } - { - state.y = compute_combined_Q(blob, state); - if( state.x_index < state.domain_size ){ - if( !copy_memory_pair_and_check(blob, state.round_proof_offset, state.leaf_data, state.y) ){ - console.log("Not validated!"); - return false; - } - }else{ - if( !copy_reverted_memory_pair_and_check(blob, state.round_proof_offset, state.leaf_data, state.y) ){ - console.log("Not validated!"); - return false; - } + + 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); + } + prepare_Y(blob, state.query_proof_offset, state); + if( state.x_index < state.domain_size ){ + if( !copy_memory_pair_and_check(blob, state.round_proof_offset, state.leaf_data, state.y) ){ + console.log("Not validated!"); + return false; + } + }else{ + if( !copy_reverted_memory_pair_and_check(blob, state.round_proof_offset, state.leaf_data, state.y) ){ + console.log("Not validated!"); + return false; } } if( !colinear_check(state.x, state.y, state.alphas[0], basic_marshalling.get_uint256_be(blob,state.round_data_offset)) ){ @@ -543,9 +416,9 @@ library modular_commitment_scheme_$TEST_NAME$ { 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_index %= state.domain_size; state.x = mulmod(state.x, state.x, modulus); - state.domain_size >>= 1; + state.domain_size >>= 1; if( state.x_index < state.domain_size ){ 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"); @@ -563,7 +436,7 @@ library modular_commitment_scheme_$TEST_NAME$ { console.log("Round colinear check failed"); return false; } - unchecked{state.j++; state.round_data_offset += 0x40;} + state.j++; state.round_data_offset += 0x40; state.round_proof_offset = merkle_verifier.skip_merkle_proof_be(blob, state.round_proof_offset); } @@ -577,15 +450,14 @@ library modular_commitment_scheme_$TEST_NAME$ { return false; } state.round_data_offset += 0x40; - - unchecked{i++;} + i++; } - console.log("EVALUATION PROOF verified"); return true; +} } -} +} )"; } } -#endif //__MODULAR_CONTRACT_TEMPLATE_HPP__ \ No newline at end of file +#endif //__MODULAR_CONTRACT_TEMPLATE_HPP__ diff --git a/include/nil/blueprint/transpiler/templates/external_gate.hpp b/include/nil/blueprint/transpiler/templates/external_gate.hpp new file mode 100644 index 0000000..356dca8 --- /dev/null +++ b/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/include/nil/blueprint/transpiler/templates/external_lookup.hpp b/include/nil/blueprint/transpiler/templates/external_lookup.hpp new file mode 100644 index 0000000..0f1238d --- /dev/null +++ b/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/include/nil/blueprint/transpiler/templates/gate_argument.hpp b/include/nil/blueprint/transpiler/templates/gate_argument.hpp index 3beb1e4..44747c9 100644 --- a/include/nil/blueprint/transpiler/templates/gate_argument.hpp +++ b/include/nil/blueprint/transpiler/templates/gate_argument.hpp @@ -5,6 +5,10 @@ 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. //---------------------------------------------------------------------------// @@ -28,6 +32,7 @@ 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$; @@ -37,10 +42,14 @@ contract modular_gate_argument_$TEST_NAME$ is IGateArgument{ 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__ \ No newline at end of file +#endif //__MODULAR_CONTRACT_TEMPLATE_HPP__ diff --git a/include/nil/blueprint/transpiler/templates/lookup_argument.hpp b/include/nil/blueprint/transpiler/templates/lookup_argument.hpp index e89ef97..3fb0e23 100644 --- a/include/nil/blueprint/transpiler/templates/lookup_argument.hpp +++ b/include/nil/blueprint/transpiler/templates/lookup_argument.hpp @@ -5,12 +5,16 @@ 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 Apache License, Version 2.0 (the "License"); +// 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 // @@ -24,17 +28,9 @@ namespace nil { //---------------------------------------------------------------------------// 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"; -import "hardhat/console.sol"; - library modular_lookup_argument_$TEST_NAME${ -} - )"; +} +)"; std::string modular_lookup_argument_library_template = R"( // SPDX-License-Identifier: Apache-2.0. @@ -61,6 +57,7 @@ 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{ @@ -125,7 +122,6 @@ contract modular_lookup_argument_$TEST_NAME$ is ILookupArgument{ 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$ } { @@ -196,9 +192,9 @@ contract modular_lookup_argument_$TEST_NAME$ is ILookupArgument{ } tr_state_after = tr_state.current_challenge; } -} - )"; +} +)"; } } -#endif //__MODULAR_CONTRACT_TEMPLATE_HPP__ \ No newline at end of file +#endif //__MODULAR_CONTRACT_TEMPLATE_HPP__ diff --git a/include/nil/blueprint/transpiler/templates/modular_verifier.hpp b/include/nil/blueprint/transpiler/templates/modular_verifier.hpp index db946a5..10972b6 100644 --- a/include/nil/blueprint/transpiler/templates/modular_verifier.hpp +++ b/include/nil/blueprint/transpiler/templates/modular_verifier.hpp @@ -9,12 +9,12 @@ namespace nil { { uint256 lookup_offset = table_offset + quotient_offset + uint256(uint8(blob[z_offset + basic_marshalling.get_length(blob, z_offset - 0x8) *0x20 + 0xf])) * 0x20; uint256[4] memory lookup_argument; + uint256 lookup_commitment = basic_marshalling.get_uint256_be(blob, 0x81); ILookupArgument lookup_contract = ILookupArgument(_lookup_argument_address); (lookup_argument, tr_state.current_challenge) = lookup_contract.verify( -// (lookup_argument, tr_state.current_challenge) = modular_lookup_argument_$TEST_NAME$.verify( - blob[special_selectors_offset: table_offset + quotient_offset], - blob[lookup_offset:lookup_offset + sorted_columns * 0x60], - basic_marshalling.get_uint256_be(blob, 0x81), + blob[special_selectors_offset: table_offset + quotient_offset], + blob[lookup_offset:lookup_offset + sorted_columns * 0x60], + lookup_commitment, state.l0, tr_state.current_challenge ); @@ -78,11 +78,10 @@ contract modular_verifier_$TEST_NAME$ is IModularVerifier{ function initialize( // address permutation_argument_address, - address lookup_argument_address, + address lookup_argument_address, address gate_argument_address, address commitment_contract_address ) public{ - console.log("Initialize"); types.transcript_data memory tr_state; transcript.init_transcript(tr_state, hex""); transcript.update_transcript_b32(tr_state, vk1); @@ -104,28 +103,75 @@ contract modular_verifier_$TEST_NAME$ is IModularVerifier{ 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 - ) public view{ + bytes calldata blob, + uint256[] calldata public_input + ) public returns (bool result) { verifier_state memory state; - uint256 gas = gasleft(); - uint256 xi = basic_marshalling.get_uint256_be(blob, $EVAL_PROOF_OFFSET$); - state.Z_at_xi = addmod(field.pow_small(xi, rows_amount, modulus), modulus-1, modulus); + 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(xi, modulus - 1, modulus), rows_amount, modulus), modulus), + state.Z_at_xi, + field.inverse_static(mulmod(addmod(state.xi, modulus - 1, modulus), rows_amount, modulus), modulus), modulus ); - //0. Check proof size - // No direct public input + //0. Direct public input check + if(public_input.length > 0) { + if (!public_input_direct(blob[$TABLE_Z_OFFSET$:$TABLE_Z_OFFSET$+$QUOTIENT_OFFSET$], public_input, state)) { + emit WrongPublicInput(); + state.b = false; + } + } - //1. Init transcript + //1. Init transcript types.transcript_data memory tr_state; tr_state.current_challenge = transcript_state; - // TODO: Just do something with it { //2. Push variable_values commitment to transcript @@ -133,8 +179,8 @@ contract modular_verifier_$TEST_NAME$ is IModularVerifier{ //3. Permutation argument uint256[3] memory permutation_argument = modular_permutation_argument_$TEST_NAME$.verify( - blob[$Z_OFFSET$:$TABLE_Z_OFFSET$+$QUOTIENT_OFFSET$], - transcript.get_field_challenge(tr_state, modulus), + blob[$Z_OFFSET$:$TABLE_Z_OFFSET$+$QUOTIENT_OFFSET$], + transcript.get_field_challenge(tr_state, modulus), transcript.get_field_challenge(tr_state, modulus), state.l0 ); @@ -143,6 +189,7 @@ contract modular_verifier_$TEST_NAME$ is IModularVerifier{ state.F[2] = permutation_argument[2]; } + //4. Lookup library call $LOOKUP_LIBRARY_CALL$ //5. Push permutation batch to transcript @@ -152,6 +199,19 @@ contract modular_verifier_$TEST_NAME$ is IModularVerifier{ //6. Gate argument IGateArgument modular_gate_argument = IGateArgument(_gate_argument_address); state.F[7] = modular_gate_argument.verify(blob[table_offset:table_end_offset], transcript.get_field_challenge(tr_state, modulus)); + 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 + 0x60), + modulus + ), + modulus + ), + modulus + ); } // No public input gate @@ -163,11 +223,9 @@ contract modular_verifier_$TEST_NAME$ is IModularVerifier{ F_consolidated = addmod(F_consolidated, mulmod(state.F[i],transcript.get_field_challenge(tr_state, modulus), modulus), modulus); unchecked{i++;} } - uint256 points_num = basic_marshalling.get_length(blob, $EVAL_PROOF_OFFSET$ + 0x20); transcript.update_transcript_b32_by_offset_calldata(tr_state, blob, 0x59); } - bool b = true; //8. Commitment scheme verify_eval { // ICommitmentScheme commitment_scheme = ICommitmentScheme(_commitment_contract_address); @@ -178,10 +236,10 @@ contract modular_verifier_$TEST_NAME$ is IModularVerifier{ unchecked{i++;} } if(!modular_commitment_scheme_$TEST_NAME$.verify_eval( - blob[z_offset - 0x8:], commitments, xi, tr_state.current_challenge + blob[z_offset - 0x8:], commitments, state.xi, tr_state.current_challenge )) { - console.log("Error from commitment scheme!"); - b = false; + emit WrongCommitment(); + state.b = false; } } @@ -191,25 +249,26 @@ contract modular_verifier_$TEST_NAME$ is IModularVerifier{ uint256 factor = 1; for(uint64 i = 0; i < uint64(uint8(blob[z_offset + basic_marshalling.get_length(blob, z_offset - 0x8) *0x20 + 0xf]));){ T_consolidated = addmod( - T_consolidated, - mulmod(basic_marshalling.get_uint256_be(blob, table_offset + quotient_offset + i *0x20), factor, modulus), + 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) ) { - console.log("Error. Table does't satisfy constraint system"); - b = false; + emit ConstraintSystemNotSatisfied(); + state.b = false; } - if(b) console.log("SUCCESS!"); else console.log("FAILURE!"); } - console.log("Gas for verification:", gas-gasleft()); + emit VerificationResult(state.b); + + result = state.b; } -} +} )"; } } -#endif //__MODULAR_CONTRACT_TEMPLATE_HPP__ \ No newline at end of file +#endif //__MODULAR_CONTRACT_TEMPLATE_HPP__ diff --git a/include/nil/blueprint/transpiler/templates/recursive_verifier.hpp b/include/nil/blueprint/transpiler/templates/recursive_verifier.hpp new file mode 100644 index 0000000..28c2be3 --- /dev/null +++ b/include/nil/blueprint/transpiler/templates/recursive_verifier.hpp @@ -0,0 +1,796 @@ +#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 alphas = challenges.lookup_alphas; + 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; + pair_type V_L_values = { + proof.z[4*permutation_size + 6 + table_values_num + 2], // V + proof.z[4*permutation_size + 6 + table_values_num + 3], // V_shifted + }; + pair_type q_last = {proof.z[4*permutation_size], proof.z[4*permutation_size + 1]}; + pair_type q_blind = {proof.z[4*permutation_size + 3], proof.z[4*permutation_size + 4]}; + + lookup_output_type lookup_argument; + + std::array lookup_input; + std::size_t cur = 0; + std::size_t cur_e = 0; + for(std::size_t g = 0; g < lookup_gate_amount; g++){ + for( std::size_t i = 0; i < lookup_constraints_amount_list[g]; i++ ){ + lookup_input[cur] = lookup_gate_selectors[g] * lookup_gate_constraints_table_ids[cur]; + pallas::base_field_type::value_type theta_acc = theta; + for(std::size_t e = 0; e < lookup_expressions_amount_list[cur]; e++){ + lookup_input[cur] = lookup_input[cur] + lookup_gate_selectors[g] * lookup_gate_constraints_lookup_inputs[cur_e] * theta_acc; + theta_acc = theta_acc * theta; + cur_e++; + } + cur++; + } + } + + std::array lookup_value; + std::array lookup_shifted_value; + cur = 0; + std::size_t cur_o = 0; + pallas::base_field_type::value_type tab_id = 1; + for( std::size_t t = 0; t < lookup_table_amount; t++ ){ + for( std::size_t o = 0; o < lookup_options_amount_list[t]; o++ ){ + pallas::base_field_type::value_type theta_acc = theta; + lookup_value[cur] = lookup_table_selectors[t] * tab_id; + lookup_shifted_value[cur] = shifted_lookup_table_selectors[t] * tab_id; + for( std::size_t c = 0; c < lookup_tables_columns_amount_list[t]; c++){ + lookup_value[cur] = lookup_value[cur] + lookup_table_selectors[t] * lookup_table_lookup_options[cur_o] * theta_acc; + lookup_shifted_value[cur] = lookup_shifted_value[cur] + shifted_lookup_table_selectors[t] * shifted_lookup_table_lookup_options[cur_o] * theta_acc; + theta_acc = theta_acc * theta; + cur_o++; + } + lookup_value[cur] = lookup_value[cur] * (pallas::base_field_type::value_type(1) - q_last[0] - q_blind[0]); + lookup_shifted_value[cur] = lookup_shifted_value[cur] * (pallas::base_field_type::value_type(1) - q_last[1] - q_blind[1]); + cur++; + } + tab_id = tab_id + 1; + } + + 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); + + for( std::size_t i = 0; i < lookup_constraints_amount; i++ ){ + g = g *(pallas::base_field_type::value_type(1)+beta)*(gamma + lookup_input[i]); + } + for( std::size_t i = 0; i < lookup_options_amount; i++ ){ + g = g * ((pallas::base_field_type::value_type(1)+beta) * gamma + lookup_value[i] + beta * lookup_shifted_value[i]); + } + for( std::size_t i = 0; i < m_parameter; i++ ){ + h = h * ((pallas::base_field_type::value_type(1)+beta) * gamma + sorted[3*i] + beta * sorted[3*i+1]); + } + + lookup_argument[0] = (pallas::base_field_type::value_type(1) - V_L_values[0]) * L0; + lookup_argument[1] = q_last[0]*(V_L_values[0] * V_L_values[0] - V_L_values[0]); + lookup_argument[2] = (pallas::base_field_type::value_type(1) - q_last[0] - q_blind[0]) * (V_L_values[1] * h - V_L_values[0] * g); + 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] + 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 + std::size_t cur = 0; + for( std::size_t i = 0; i < public_input_amount; i++){ + 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[zero_indices[witness_amount + i]] == precomputed_values.Z_at_xi * result); + } +)"; + std::string public_input_input_str = "\tstd::array public_input,\n"; + + std::string recursive_verifier_template = R"( +#include +#include +#include + +using namespace nil::crypto3; +using namespace nil::crypto3::algebra::curves; + +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$; + +namespace placeholder_verifier{ + +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 zero_indices = {$ZERO_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$}; + +$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; // lambda times + std::array round_proof_values; // lambda times + std::array initial_proof_positions; // lambda times + std::array initial_proof_hashes; // lambda times + std::array round_merkle_proof_positions; // lambda times + std::array 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; + 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_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 pow2_p(pallas::base_field_type::value_type x, size_t plog){ + if(plog == 0) return pallas::base_field_type::value_type(1); + pallas::base_field_type::value_type result = x; + for(std::size_t i = 0; i < plog; 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; +} + +pallas::base_field_type::value_type pow(pallas::base_field_type::value_type x, size_t p){ + if( p == 0 ) return pallas::base_field_type::value_type(1); + if( p == 1 ) return x; + pallas::base_field_type::value_type result = pow(x, p/2); + result = result * result; + if( 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 std::array &vk, + const placeholder_proof_type &proof +){ + placeholder_challenges_type challenges; + + transcript_state_type tr_state; + tr_state.state[0] = pallas::base_field_type::value_type(0); + 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; + + transcript(tr_state, vk[0]); + transcript(tr_state, vk[1]); + + // LPC additional point + challenges.eta = transcript_challenge(tr_state); + transcript(tr_state, proof.commitments[0]); + + challenges.perm_beta = transcript_challenge(tr_state); + challenges.perm_gamma = transcript_challenge(tr_state); + + // Call lookup argument + if( use_lookups ){ + challenges.lookup_theta = transcript_challenge(tr_state); + transcript(tr_state, proof.commitments[3]); + challenges.lookup_beta = transcript_challenge(tr_state); + challenges.lookup_gamma = transcript_challenge(tr_state); + + for(std::size_t i = 0; i < sorted_columns-1; i++){ + challenges.lookup_alphas[i] = transcript_challenge(tr_state); + } + } + + // Call gate argument + transcript(tr_state, proof.commitments[1]); + challenges.gate_theta = transcript_challenge(tr_state); + + for(std::size_t i = 0; i < 8; i++){ + challenges.alphas[i] = transcript_challenge(tr_state); + } + transcript(tr_state, proof.commitments[2]); + + challenges.xi = transcript_challenge(tr_state); + + transcript(tr_state, vk[1]); + for(std::size_t i = 0; i < proof.commitments.size(); i++){ + transcript(tr_state, proof.commitments[i]); + } + + challenges.lpc_theta = transcript_challenge(tr_state); + + for(std::size_t i = 0; i < fri_roots_num; i++){ + transcript(tr_state, proof.fri_roots[i]); + challenges.fri_alphas[i] = transcript_challenge(tr_state); + } + + for(std::size_t i = 0; i < lambda; i++){ + challenges.fri_x_indices[i] = transcript_challenge(tr_state); + } + + return challenges; +} + +std::pair xi_polys( + pallas::base_field_type::value_type xi +){ + pallas::base_field_type::value_type xi_n = pow2_p(xi, rows_log) - 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$ + +typename pallas::base_field_type::value_type + gate_argument_verifier( + std::array selectors, + std::array constraints, + typename pallas::base_field_type::value_type theta + ) { + + return __builtin_assigner_gate_arg_verifier( + selectors.data(), + (int*)&gates_sizes, + gates_amount, + constraints.data(), + constraints_amount, + theta + ); +} + +std::array getV3( + pallas::base_field_type::value_type xi0,pallas::base_field_type::value_type xi1,pallas::base_field_type::value_type xi2 +){ + std::array result; + result[0] = - xi0 * xi1 * xi2; + result[1] = xi0 * xi1 + xi1 * xi2 + xi0 * xi2; + result[2] = - xi0 - xi1 - xi2; + result[3] = pallas::base_field_type::value_type(1); +// __builtin_assigner_exit_check(result[0] + xi0 * result[1] + xi0 * xi0 * result[2] + xi0*xi0*xi0*result[3] == pallas::base_field_type::value_type(0)); + return result; +} + +std::array getV2( + pallas::base_field_type::value_type xi0,pallas::base_field_type::value_type xi1 +){ + std::array result; + result[0] = xi0 * xi1; + result[1] = - xi0 - xi1; + result[2] = pallas::base_field_type::value_type(1); + result[3] = pallas::base_field_type::value_type(0); +// __builtin_assigner_exit_check(result[0] + xi0 * result[1] + xi0 * xi0 * result[2] + xi0*xi0*xi0*result[3] == pallas::base_field_type::value_type(0)); + return result; +} + +std::array getV1( + pallas::base_field_type::value_type xi0 +){ + std::array result; + result[0] = - xi0; + result[1] = pallas::base_field_type::value_type(1); + result[2] = pallas::base_field_type::value_type(0); + result[3] = pallas::base_field_type::value_type(0); +// __builtin_assigner_exit_check(result[0] + xi0 * result[1] + xi0 * xi0 * result[2] + xi0*xi0*xi0*result[3] == pallas::base_field_type::value_type(0)); + return result; +} + +std::array getU3( + pallas::base_field_type::value_type x0,pallas::base_field_type::value_type x1,pallas::base_field_type::value_type x2, + pallas::base_field_type::value_type z0,pallas::base_field_type::value_type z1,pallas::base_field_type::value_type z2 +){ + std::array result; + pallas::base_field_type::value_type denom = (x0-x1)*(x1-x2)*(x2-x0); + + z0 = z0 * (x2-x1); + z1 = z1 * (x0-x2); + z2 = z2 * (x1-x0); + + result[0] = (z0*x1*x2 + z1*x0*x2 + z2*x0*x1)/denom; + result[1] = (-z0*(x1 + x2) - z1*(x0 + x2) - z2 * (x0 + x1))/denom; + result[2] = (z0 + z1 + z2)/denom; + +// __builtin_assigner_exit_check(result[0] + x0 * result[1] + x0 * x0 * result[2] == z0/(x2-x1)); +// __builtin_assigner_exit_check(result[0] + x1 * result[1] + x1 * x1 * result[2] == z1/(x0-x2)); +// __builtin_assigner_exit_check(result[0] + x2 * result[1] + x2 * x2 * result[2] == z2/(x1-x0)); + + return result; +} + +std::array getU2( + pallas::base_field_type::value_type x0,pallas::base_field_type::value_type x1, + pallas::base_field_type::value_type z0,pallas::base_field_type::value_type z1 +){ + std::array result; + pallas::base_field_type::value_type denom = (x0-x1); + result[0] = (-z0*x1 + z1*x0)/denom; + result[1] = (z0 - z1)/denom; + result[2] = pallas::base_field_type::value_type(0); + +// __builtin_assigner_exit_check(result[0] + x0 * result[1] + x0 * x0 * result[2] == z0); +// __builtin_assigner_exit_check(result[0] + x1 * result[1] + x1 * x1 * result[2] == z1); + + return result; +} + +std::array getU1( + pallas::base_field_type::value_type x0, + pallas::base_field_type::value_type z0 +){ + std::array result; + result[0] = z0; + result[1] = pallas::base_field_type::value_type(0); + result[2] = pallas::base_field_type::value_type(0); + +// __builtin_assigner_exit_check(result[0] + x0 * result[1] + x0 * x0 * result[2] == z0); + + return result; +} + +pallas::base_field_type::value_type eval4(std::array poly, pallas::base_field_type::value_type x){ + pallas::base_field_type::value_type result; + result = poly[3]; + result = result *x + poly[2]; + result = result *x + poly[1]; + result = result *x + poly[0]; +// __builtin_assigner_exit_check(poly[0] + x * poly[1] + x * x * poly[2] + x*x*x*poly[3] == result); + return result; +} + +pallas::base_field_type::value_type eval3(std::array poly, pallas::base_field_type::value_type x){ + pallas::base_field_type::value_type result; + result = poly[2]; + result = result *x + poly[1]; + result = result *x + poly[0]; +// __builtin_assigner_exit_check(poly[0] + x * poly[1] + x * x * poly[2] == result); + return result; +} + +pallas::base_field_type::value_type calculate_leaf_hash( + std::array val, + std::size_t start_index, + std::size_t leaf_size +){ + pallas::base_field_type::value_type hash_state = pallas::base_field_type::value_type(0); + for(std::size_t pos = 0; pos < leaf_size; pos+=2){ + hash_state = __builtin_assigner_poseidon_pallas_base( + {hash_state, val[start_index + pos], val[start_index + pos+1]} + )[2]; + } + return hash_state; +} + +pallas::base_field_type::value_type calculate_reversed_leaf_hash( + std::array &val, + std::size_t start_index, + std::size_t leaf_size +){ + pallas::base_field_type::value_type hash_state = pallas::base_field_type::value_type(0); + for(std::size_t pos = 0; pos < leaf_size; pos+=2){ + hash_state = __builtin_assigner_poseidon_pallas_base( + {hash_state, val[start_index + pos + 1], val[start_index + pos]} + )[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; +}; + +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$ + std::array vk, + placeholder_proof_type proof +) { + placeholder_challenges_type challenges = generate_challenges(vk, proof); + __builtin_assigner_exit_check(challenges.xi == proof.challenge); + + precomputed_values_type precomputed_values; + std::tie(precomputed_values.l0, precomputed_values.Z_at_xi) = xi_polys(challenges.xi); + + $PUBLIC_INPUT_CHECK$ + + std::array F;// = {0,0,0,0,0,0,0,0}; + + // Call permutation argument + placeholder_permutation_argument_input_type perm_arg_input; + perm_arg_input.thetas[0] = challenges.perm_beta; + perm_arg_input.thetas[1] = challenges.perm_gamma; + + for( std::size_t i = 0; i < permutation_size; i++ ){ + perm_arg_input.xi_values[i] = proof.z[zero_indices[i]]; + perm_arg_input.id_perm[i] = proof.z[2*i]; + perm_arg_input.sigma_perm[i] = proof.z[2*permutation_size + 2*i]; + } + + permutation_argument_output_type permutation_argument = __builtin_assigner_permutation_arg_verifier( + perm_arg_input.xi_values.data(), + perm_arg_input.id_perm.data(), + perm_arg_input.sigma_perm.data(), + permutation_size, + precomputed_values.l0, + proof.z[4*permutation_size + 6 + table_values_num], // V + proof.z[4*permutation_size + 6 + table_values_num + 1], // V_shifted + proof.z[4*permutation_size], // q_last + proof.z[4*permutation_size + 3], // q_blind + perm_arg_input.thetas + ); + + F[0] = permutation_argument[0]; + F[1] = permutation_argument[1]; + F[2] = permutation_argument[2]; + + $LOOKUP_CODE$ + + if constexpr( gates_amount > 0) { + std::array constraints; + std::array selectors; + constraints = calculate_constraints(proof.z); + + for( std::size_t i = 0; i < gates_amount; i++ ){ + selectors[i] = proof.z[zero_indices[witness_amount + public_input_amount + constant_amount + gates_selector_indices[i]]]; + } + + F[7] = gate_argument_verifier( + selectors, + constraints, + challenges.gate_theta + ); + F[7] *= (pallas::base_field_type::value_type(1) - proof.z[4*permutation_size] - proof.z[4*permutation_size + 3]); + } + + 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; + +$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++){ + __builtin_assigner_fri_cosets(res.data(), D0_log, D0_omega, challenges.fri_x_indices[i]); + cur_val = 0; + + pallas::base_field_type::value_type hash_state; + for(std::size_t b = 0; b < batches_num; b++){ + pallas::base_field_type::value_type hash_state(0); + if(res[0][2] == pallas::base_field_type::value_type(0)){ + hash_state = calculate_leaf_hash(proof.initial_proof_values[i], cur_val, batches_amount_list[b] *2); + } else if(res[0][2] == pallas::base_field_type::value_type(1)){ + hash_state = calculate_reversed_leaf_hash(proof.initial_proof_values[i], cur_val, batches_amount_list[b] *2); + } + cur_val += batches_amount_list[b] *2; + for(std::size_t r = i * initial_merkle_proofs_position_num/lambda; r < (i + 1)* initial_merkle_proofs_position_num/lambda ; r++){ + if(proof.initial_proof_positions[r] == 1){ + hash_state = __builtin_assigner_poseidon_pallas_base({0, hash_state, proof.initial_proof_hashes[initial_proof_hash_ind]})[2]; + } else{ + hash_state = __builtin_assigner_poseidon_pallas_base({0, proof.initial_proof_hashes[initial_proof_hash_ind], hash_state})[2]; + } + initial_proof_hash_ind ++; + } + if(b == 0) + __builtin_assigner_exit_check(hash_state == vk[1]); + else + __builtin_assigner_exit_check(hash_state == proof.commitments[b-1]); + } + + std::array y = {0,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; + for(std::size_t j = 0; j < fri_rounds; j++){ + if(res[j][2] == pallas::base_field_type::value_type(0)){ + rhash = __builtin_assigner_poseidon_pallas_base({0, y[0], y[1]})[2]; + } else { + rhash = __builtin_assigner_poseidon_pallas_base({0, y[1], y[0]})[2]; + } + for( std::size_t d = 0; d < D; d++){ + if(proof.round_merkle_proof_positions[round_proof_hash_ind] == 1){ + rhash = __builtin_assigner_poseidon_pallas_base({0, rhash, proof.round_proof_hashes[round_proof_hash_ind]})[2]; + } else { + rhash = __builtin_assigner_poseidon_pallas_base({0, proof.round_proof_hashes[round_proof_hash_ind], rhash})[2]; + } + round_proof_hash_ind++; + } + __builtin_assigner_exit_check(rhash == proof.fri_roots[j]); + D--; + + interpolant = __builtin_assigner_fri_lin_inter( + res[j][0], + y[0], + y[1], + challenges.fri_alphas[j] + ); + __builtin_assigner_exit_check(interpolant == proof.round_proof_values[round_proof_ind]); + y[0] = proof.round_proof_values[round_proof_ind]; + y[1] = proof.round_proof_values[round_proof_ind + 1]; + + pallas::base_field_type::value_type rhash; + round_proof_ind += 2; + } + + interpolant = pallas::base_field_type::value_type(0); + pallas::base_field_type::value_type x = res[fri_rounds][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 == y[0]); + + interpolant = pallas::base_field_type::value_type(0); + x = res[fri_rounds][1]; + 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 == y[1]); + } + return true; +} + +} + )"; + } +} + +#endif //__RECURSIVE_VERIFIER_TEMPLATE_HPP__ \ No newline at end of file diff --git a/include/nil/blueprint/transpiler/templates/utils_template.hpp b/include/nil/blueprint/transpiler/templates/utils_template.hpp new file mode 100644 index 0000000..9612d89 --- /dev/null +++ b/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/include/nil/blueprint/transpiler/util.hpp b/include/nil/blueprint/transpiler/util.hpp index 0f34e1e..504d819 100644 --- a/include/nil/blueprint/transpiler/util.hpp +++ b/include/nil/blueprint/transpiler/util.hpp @@ -1,3 +1,28 @@ +//---------------------------------------------------------------------------// +// 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__ @@ -5,8 +30,8 @@ #include #include #include - -#include +#include +//#include namespace nil { namespace blueprint { @@ -17,6 +42,218 @@ namespace nil { 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(omega, " + to_string(j) + ")"; else + if(j < 0) return "xi/pow(omega, " + to_string(-j) + ")"; + } 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); + } + 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 CommonDataType &common_data, + std::size_t permutation_size, + bool use_lookups, + 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.rows_amount; + + singles.push_back(rot_string(0, rows_amount, mode)); + singles_map[rot_string(0, rows_amount, mode)] = singles_map.size(); + + singles.push_back("eta"); + singles_map["eta"] = singles_map.size(); + poly_ids.resize(singles.size()); + + // Sigma and permutation polys + std::size_t count = 0; + for( std::size_t i = 0; i < permutation_size; i++){ + poly_ids[singles_map[rot_string(0, rows_amount, mode)]].push_back(count); + poly_ids[singles_map["eta"]].push_back(count); + z_points_indices.push_back(singles_map[rot_string(0, rows_amount, mode)]); + z_points_indices.push_back(singles_map["eta"]); + poly_ids[singles_map["eta"]].push_back(count+1); + 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)]); + z_points_indices.push_back(singles_map["eta"]); + 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["eta"]].push_back(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)]); + z_points_indices.push_back(singles_map["eta"]); + count++; + poly_ids[singles_map["eta"]].push_back(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)]); + z_points_indices.push_back(singles_map["eta"]); + count++; + + for(std::size_t i = 0; i < PlaceholderParams::constant_columns; i++){ + std::stringstream str; + for(auto j:common_data.columns_rotations[i + PlaceholderParams::witness_columns + PlaceholderParams::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)]); + } + poly_ids[singles_map["eta"]].push_back(count); + z_points_indices.push_back(singles_map["eta"]); + count++; + } + + for(std::size_t i = 0; i < PlaceholderParams::selector_columns; i++){ + std::stringstream str; + for(auto j:common_data.columns_rotations[i + PlaceholderParams::witness_columns + PlaceholderParams::public_input_columns + PlaceholderParams::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)]); + } + poly_ids[singles_map["eta"]].push_back(count); + z_points_indices.push_back(singles_map["eta"]); + count++; + } + + for(std::size_t i = 0; i < PlaceholderParams::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 < PlaceholderParams::public_input_columns; i++){ + std::stringstream str; + for(auto j:common_data.columns_rotations[i + PlaceholderParams::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 + 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++; + + // Lookup permutation + if(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++; + } + // Quotient + for(std::size_t i = 0; i < 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(use_lookups){ + if(singles_map.find(rot_string(common_data.usable_rows_amount, rows_amount, mode)) == singles_map.end()){ + singles_map[rot_string(common_data.usable_rows_amount, rows_amount, mode)] = singles.size(); + singles.push_back(rot_string(common_data.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.usable_rows_amount, rows_amount, mode)]].push_back(count); + z_points_indices.push_back(singles_map[rot_string(common_data.usable_rows_amount, rows_amount, mode)]); + count++; + } + } + + return std::make_tuple(z_points_indices, singles, singles_map, poly_ids); + } } } diff --git a/test/detail/circuits.hpp b/test/detail/circuits.hpp index a40a426..f19ae0f 100644 --- a/test/detail/circuits.hpp +++ b/test/detail/circuits.hpp @@ -26,8 +26,8 @@ // SOFTWARE. //---------------------------------------------------------------------------// -#ifndef CRYPTO3_ZK_MARSHALLING_TEST_PLONK_CIRCUITS_HPP -#define CRYPTO3_ZK_MARSHALLING_TEST_PLONK_CIRCUITS_HPP +#ifndef CRYPTO3_ZK_TEST_PLONK_CIRCUITS_HPP +#define CRYPTO3_ZK_TEST_PLONK_CIRCUITS_HPP #define _RND_ algebra::random_element(); @@ -53,7 +53,7 @@ namespace nil { namespace crypto3 { namespace zk { namespace snark { - template + template class circuit_description { typedef zk::snark::detail::placeholder_policy policy_type; @@ -61,12 +61,8 @@ namespace nil { constexpr static const std::size_t public_columns = ParamsType::public_input_columns; public: - const std::size_t table_rows = 1 << rows_log; - - std::shared_ptr> domain; - - typename FieldType::value_type omega; - typename FieldType::value_type delta; + std::size_t table_rows; + std::size_t usable_rows = usable_rows_amount; typename policy_type::variable_assignment_type table; @@ -76,10 +72,7 @@ namespace nil { std::vector> lookup_tables; - circuit_description() - : domain(math::make_evaluation_domain(table_rows)) - , omega(domain->get_domain_element(1)) - , delta(algebra::fields::arithmetic_params::multiplicative_generator) { + circuit_description() : table_rows(0){ } }; @@ -95,40 +88,40 @@ namespace nil { // ADD: x + y = z // MUL: x * y = z //---------------------------------------------------------------------------// - constexpr static const std::size_t witness_columns_1 = 3; - constexpr static const std::size_t public_columns_1 = 1; - constexpr static const std::size_t constant_columns_1 = 0; - constexpr static const std::size_t selector_columns_1 = 2; + 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; using arithmetization_params_1 = plonk_arithmetization_params; template - circuit_description, 4, 4> circuit_test_1( - typename nil::crypto3::random::algebraic_engine alg_rnd = nil::crypto3::random::algebraic_engine() + circuit_description, rows_amount_1, 4> 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 rows_log = 4; + constexpr static const std::size_t usable_rows = 13; constexpr static const std::size_t permutation = 4; 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 = + constexpr static const std::size_t table_columns = witness_columns + public_columns + constant_columns; typedef placeholder_circuit_params circuit_params; - - circuit_description test_circuit; - + circuit_description test_circuit; std::array, table_columns> table; - std::vector q_add(test_circuit.table_rows); - std::vector q_mul(test_circuit.table_rows); + 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.table_rows); + table[j].resize(test_circuit.usable_rows); } // init values @@ -136,40 +129,45 @@ namespace nil { table[0][0] = alg_rnd(); table[1][0] = alg_rnd(); table[2][0] = alg_rnd(); -// table[3][0] = algebra::random_element(); + table[3][0] = table[2][0]; + plonk_variable x(2, 0, 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)); + 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.table_rows - 5; i++) { + 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(); + table[3][i] = table[3][0]; 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)); + plonk_variable x(0, i, false, + plonk_variable::column_type::public_input); + plonk_variable y(0, 0, false, + plonk_variable::column_type::public_input); + 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 - 3; i++) { + 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(); + table[3][i] = table[2][i]; q_add[i] = FieldType::value_type::zero(); q_mul[i] = one; - plonk_variable x(1, i, false, + plonk_variable x(2, i, false, plonk_variable::column_type::witness); - plonk_variable y(0, 0, false, + plonk_variable y(0, i, false, plonk_variable::column_type::public_input); - //test_circuit.copy_constraints.push_back(plonk_copy_constraint(x, y)); + test_circuit.copy_constraints.push_back(plonk_copy_constraint(x, y)); } std::array, witness_columns> private_assignment; @@ -184,15 +182,13 @@ namespace nil { 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]; - } + public_input_assignment[0] = table[3]; 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.init(); + 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); @@ -209,7 +205,7 @@ namespace nil { plonk_constraint mul_constraint; typename plonk_constraint::term_type w0_term(w0); - typename plonk_constraint::term_type w1_term(w1); + typename plonk_constraint::term_type w1_term(w1); mul_constraint += w0_term * w1_term; mul_constraint -= w2; @@ -236,74 +232,77 @@ namespace nil { 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; using arithmetization_params_t = plonk_arithmetization_params; template - circuit_description, 4, 4> - circuit_test_t(typename FieldType::value_type pi0 = FieldType::value_type::zero()) { + circuit_description, 5, 4> + 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 rows_log = 4; constexpr static const std::size_t permutation = 4; - 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 = + constexpr static const std::size_t table_columns = witness_columns + public_columns + constant_columns; typedef placeholder_circuit_params circuit_params; - circuit_description test_circuit; + circuit_description test_circuit; std::array, table_columns> table; - std::vector q_add(test_circuit.table_rows); - std::vector q_mul(test_circuit.table_rows); + 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.table_rows); + table[j].resize(test_circuit.usable_rows); } // init values typename FieldType::value_type one = FieldType::value_type::one(); - table[0][0] = algebra::random_element(); - table[1][0] = algebra::random_element(); - table[2][0] = algebra::random_element(); + 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 < test_circuit.table_rows - 5; i++) { - table[0][i] = algebra::random_element(); + 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 x(1, i, false, plonk_variable::column_type::witness); - plonk_variable y(2, i - 1, false, + 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 - 3; i++) { - table[0][i] = algebra::random_element(); + 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 x(1, i, false, plonk_variable::column_type::witness); - plonk_variable y(0, 0, false, + plonk_variable y(0, 0, false, plonk_variable::column_type::public_input); test_circuit.copy_constraints.push_back(plonk_copy_constraint(x, y)); } @@ -329,6 +328,7 @@ namespace nil { 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); @@ -350,7 +350,7 @@ namespace nil { plonk_constraint mul_constraint; typename plonk_constraint::term_type w0_term(w0); - typename plonk_constraint::term_type w1_term(w1); + typename plonk_constraint::term_type w1_term(w1); mul_constraint += w0_term * w1_term; mul_constraint -= w2; mul_constraint += w0_prev; @@ -367,44 +367,55 @@ namespace nil { 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; + constexpr static const std::size_t permutation_size_3 = 3; using arithmetization_params_3 = plonk_arithmetization_params; template - circuit_description, 3, 3> circuit_test_3() { + circuit_description, usable_rows_3, permutation_size_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; using field_type = typename FieldType::value_type; - constexpr static const std::size_t rows_log = 3; - constexpr static const std::size_t permutation = 3; - + constexpr static const std::size_t permutation = permutation_size_3; 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 = + 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; + circuit_description test_circuit; std::array, table_columns> table; for (std::size_t j = 0; j < table_columns; j++) { - table[j].resize(test_circuit.table_rows); + table[j].resize(test_circuit.usable_rows); } // lookup inputs typename FieldType::value_type one = FieldType::value_type::one(); typename FieldType::value_type zero = FieldType::value_type::zero(); - table[0] = {1, 0, 0, 0, 0, 0, 0, 0}; // Witness 1 - table[1] = {0, 0, 0, 0, 0, 0, 0, 0}; - table[2] = {0, 0, 0, 0, 0, 0, 0, 0}; + table[0] = {1, 3, 0, 0}; // Witness 1 + table[1] = {0, 0, 0, 0}; + table[2] = {0, 0, 0, 3}; + + plonk_variable x(0, 1, false, + plonk_variable::column_type::witness); + plonk_variable y(2, 3, false, + plonk_variable::column_type::witness); + test_circuit.copy_constraints.push_back(plonk_copy_constraint(x, y)); + - table[3] = {0, 1, 0, 1, 0, 0, 0, 0}; //Lookup values - table[4] = {0, 0, 1, 0, 0, 0, 0, 0}; //Lookup values - table[5] = {0, 1, 0, 0, 0, 0, 0, 0}; //Lookup values + 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::array, witness_columns> private_assignment; for (std::size_t i = 0; i < witness_columns; i++) { @@ -417,17 +428,11 @@ namespace nil { std::array, constant_columns> constant_assignment; std::vector sel_lookup(test_circuit.table_rows); - sel_lookup[0] = one; - sel_lookup[1] = zero; - sel_lookup[2] = zero; - sel_lookup[3] = zero; + sel_lookup = {1, 0, 0, 0}; selectors_assignment[0] = sel_lookup; std::vector sel_lookup_table(test_circuit.table_rows); - sel_lookup_table[0] = zero; - sel_lookup_table[1] = one; - sel_lookup_table[2] = one; - sel_lookup_table[3] = one; + sel_lookup_table = {0, 1, 1, 1}; selectors_assignment[1] = sel_lookup_table; for (std::size_t i = 0; i < constant_columns; i++) { @@ -437,6 +442,7 @@ namespace nil { 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); @@ -465,8 +471,8 @@ namespace nil { return test_circuit; } - // Binary multiplication. - // b_i -- random binaries, + // Binary multiplication. + // b_i -- random binaries, // r_i ordinary random numbers. // One gate: w1*w2 - w3 = 0 // ---------------------------------------------------------------------------------- @@ -489,7 +495,10 @@ namespace nil { template circuit_description, 3, 3> circuit_test_4() { + arithmetization_params_4>, 3, 3> 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; @@ -499,7 +508,7 @@ namespace nil { 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 = + constexpr static const std::size_t table_columns = witness_columns + public_columns + constant_columns; typedef placeholder_circuit_params circuit_params; @@ -511,17 +520,16 @@ namespace nil { table[j].resize(test_circuit.table_rows); } - srand(time(NULL)); // lookup inputs typename FieldType::value_type one = FieldType::value_type::one(); typename FieldType::value_type zero = FieldType::value_type::zero(); - table[0] = {rand() % 2, rand() % 2, rand(), rand() % 2, rand() % 2, 0, 0, 0}; - table[1] = {rand() % 2, rand() % 2, rand(), rand() % 2, rand() % 2, 0, 0, 0};; + 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 + // 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}; @@ -566,7 +574,7 @@ namespace nil { plonk_constraint mul_constraint; typename plonk_constraint::term_type w0_term(w0); - typename plonk_constraint::term_type w1_term(w1); + typename plonk_constraint::term_type w1_term(w1); mul_constraint += w0_term * w1_term; mul_constraint -= w2; @@ -592,161 +600,14 @@ namespace nil { return test_circuit; } - - // Lookup complex test - // 1. Lookup gate with 4 constraints - // 1.1 w1 \in table 1 - // 1.2 w3 \in table1 - // 1.3 w1 \in table 2 - // 1.4 w1, w2, w3 \in table 3 - // 2. Lookup gate with 2 constraints - // 2.1 w2 \in table 1 - // 2.2 w2 \in table 2 - // --------------------------------------------------------------------------- - // | Table tag 0 | Table tag 1 | W1 | W2 | W3 | Lookup tag | L1 | L2 | L3 | - // --------------------------------------------------------------------------- - // | 1 | 1 | 1 | 2 | 123 | 0 | 0 | 0 | 0 | - // | 2 | 1 | 124| 2 | 3 | 1 | 1 | 0 | 0 | - // | 1 | 1 | 3 | 4 | 125 | 1 | 2 | 0 | 0 | - // | 2 | 1 | 127| 4 | 5 | 1 | 3 | 0 | 0 | - // | 1 | 2 | 5 | 6 | 128 | 1 | 4 | 0 | 0 | - // | 3 | 2 | 6 | 7 | 129 | 1 | 5 | 0 | 0 | - // | 3 | 2 | 7 | 8 | 130 | 2 | 6 | 0 | 0 | - // | 3 | 2 | 8 | 9 | 131 | 2 | 7 | 0 | 0 | - // | 3 | 2 | 9 | 10 | 132 | 2 | 8 | 0 | 0 | - // | 4 | 0 | 0 | 0 | 1 | 2 | 9 | 0 | 0 | - // | 4 | 0 | 0 | 1 | 0 | 2 | 10| 0 | 0 | - // | 4 | 0 | 1 | 0 | 0 | 3 | 0 | 0 | 1 | - // | 4 | 0 | 1 | 1 | 1 | 3 | 1 | 0 | 0 | - // | 0 | 0 | 0 | 0 | 128| 3 | 0 | 1 | 0 | - // | 0 | 0 | 0 | 0 | 129| 3 | 1 | 1 | 1 | - // | 0 | 0 | 0 | 0 | 130| 0 | 0 | 0 | 0 | - ///--------------------------------------------------------------------------- - constexpr static const std::size_t witness_columns_5= 3; - constexpr static const std::size_t public_columns_5 = 0; - constexpr static const std::size_t constant_columns_5 = 3; - constexpr static const std::size_t selector_columns_5 = 3; - - using arithmetization_params_5 = plonk_arithmetization_params; - - template - circuit_description, 4, 3> circuit_test_5() { - using assignment_type = typename FieldType::value_type; - - constexpr static const std::size_t rows_log = 4; - constexpr static const std::size_t permutation = 3; - - constexpr static const std::size_t witness_columns = witness_columns_5; - constexpr static const std::size_t public_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_columns + constant_columns + selector_columns; - - typedef placeholder_circuit_params circuit_params; - - circuit_description test_circuit; - - std::array, table_columns> table; - for (std::size_t j = 0; j < table_columns; j++) { - table[j].resize(test_circuit.table_rows); - } - - // lookup inputs - typename FieldType::value_type one = FieldType::value_type::one(); - typename FieldType::value_type zero = FieldType::value_type::zero(); - - // Witness - table[0] = { 1, 124, 3, 127, 5, 6, 7, 8, 9, 0, 0, 1, 1, 131, 133, 135}; // W0 - table[1] = { 2, 2, 4, 4, 6, 7, 8, 9, 10, 0, 1, 0, 1, 132, 134, 136}; // W1 - table[2] = {123, 3, 125, 5, 129, 130, 131, 132, 10, 1, 0, 0, 0, 128, 129, 130}; // W2 - - // Tags - table[3] = { 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 0}; // Lookup table tag - table[4] = { 1, 2, 1, 2, 1, 3, 3, 3, 3, 4, 4, 4, 4, 0, 0, 136}; // Lookup tag1 - table[5] = { 1, 1, 1, 1, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 130}; // Lookup tag2 - - // Lookups - table[6] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0, 1, 1, 0}; // L1 - table[7] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 136}; // L2 - table[8] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 130}; // L3 - - std::array, witness_columns> private_assignment; - for (std::size_t i = 0; i < witness_columns; i++) { - private_assignment[i] = table[i]; - } - - - std::array, selector_columns> selectors_assignment; - std::array, public_columns> public_input_assignment = {}; - std::array, constant_columns> constant_assignment; - - for (std::size_t i = 0; i < selector_columns; i++) { - selectors_assignment[i] = table[witness_columns + i]; - } - - 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)); - - 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 l0(0, 0, true, - plonk_variable::column_type::constant); - plonk_variable l1(1, 0, true, - plonk_variable::column_type::constant); - plonk_variable l2(2, 0, true, - plonk_variable::column_type::constant); - - std::vector> lookup_constraints0(4); - lookup_constraints0[0].lookup_input.push_back(typename plonk_constraint::term_type(w0)); - lookup_constraints0[0].table_id = 1; - lookup_constraints0[1].lookup_input.push_back(typename plonk_constraint::term_type(w2)); - lookup_constraints0[1].table_id = 1; - lookup_constraints0[2].lookup_input.push_back(typename plonk_constraint::term_type(w1)); - lookup_constraints0[2].table_id = 2; - lookup_constraints0[3].lookup_input.push_back(typename plonk_constraint::term_type(w0)); - lookup_constraints0[3].lookup_input.push_back(typename plonk_constraint::term_type(w1)); - lookup_constraints0[3].lookup_input.push_back(typename plonk_constraint::term_type(w2)); - lookup_constraints0[3].table_id = 3; - plonk_lookup_gate> lookup_gate0(1, lookup_constraints0); - - std::vector> lookup_constraints1(2); - lookup_constraints1[0].lookup_input.push_back(typename plonk_constraint::term_type(w1)); - lookup_constraints1[0].table_id = 1; - lookup_constraints1[1].lookup_input.push_back(typename plonk_constraint::term_type(w1)); - lookup_constraints1[1].table_id = 2; - plonk_lookup_gate> lookup_gate1(2, lookup_constraints1); - - test_circuit.lookup_gates.push_back(lookup_gate0); - test_circuit.lookup_gates.push_back(lookup_gate1); - - plonk_lookup_table lookup_table({l0, l1, l2}, 0); - test_circuit.lookup_table = lookup_table; - - 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 | + // 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) @@ -759,9 +620,11 @@ namespace nil { using arithmetization_params_fib = plonk_arithmetization_params; - template - circuit_description, rows_log, 2> - circuit_test_fib() { + template + circuit_description, usable_rows, 2> + 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 permutation = 2; @@ -770,20 +633,19 @@ namespace nil { 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 = + constexpr static const std::size_t table_columns = witness_columns + public_columns + selector_columns; typedef placeholder_circuit_params circuit_params; - circuit_description test_circuit; + circuit_description test_circuit; std::array, table_columns> table; - std::vector q_add(test_circuit.table_rows); - std::vector q_mul(test_circuit.table_rows); + 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.table_rows); + 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(); @@ -797,7 +659,7 @@ namespace nil { // selector table[2][0] = zero; - table[2][0] = one; + 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); @@ -807,15 +669,11 @@ namespace nil { // 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.table_rows - 1; i++) { + 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] = one; + table[2][i-1] = one; } - table[2][test_circuit.table_rows - 4] = zero; - table[2][test_circuit.table_rows - 3] = zero; - table[2][test_circuit.table_rows - 2] = zero; - table[2][test_circuit.table_rows - 1] = zero; std::array, witness_columns> private_assignment; private_assignment[0] = table[0]; @@ -829,18 +687,20 @@ namespace nil { 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); + typename plonk_constraint::term_type w1_term(w1); + typename plonk_constraint::term_type w2_term(w2); plonk_constraint fib_constraint; fib_constraint += w0_term; @@ -850,7 +710,7 @@ namespace nil { std::vector> fib_costraints {fib_constraint}; plonk_gate> fib_gate(0, fib_costraints); test_circuit.gates.push_back(fib_gate); - + return test_circuit; } @@ -863,7 +723,7 @@ namespace nil { // Lookup gate2: // w1{-1} + w1 \in Table 2 // --------------------------------------------------------------------------------- - // | s1 | s2 | W1 | W2 | LT1 | L1 | L2 | L3 | + // | 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 @@ -877,52 +737,55 @@ namespace nil { 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; using arithmetization_params_6 = plonk_arithmetization_params; template circuit_description, 3, 3> circuit_test_6() { + arithmetization_params_6>, usable_rows_6, 3> 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 rows_log = 3; constexpr static const std::size_t permutation = 3; 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 = + constexpr static const std::size_t table_columns = witness_columns + public_columns + constant_columns + selector_columns; + constexpr static const std::size_t usable_rows = usable_rows_6; typedef placeholder_circuit_params circuit_params; - circuit_description test_circuit; + circuit_description test_circuit; std::array, table_columns> table; for (std::size_t j = 0; j < table_columns; j++) { - table[j].resize(test_circuit.table_rows); + table[j].resize(test_circuit.usable_rows); } - srand(time(NULL)); // lookup inputs typename FieldType::value_type one = FieldType::value_type::one(); typename FieldType::value_type zero = FieldType::value_type::zero(); - table[0] = {rand() % 5 + 2, rand() % 5 + 2, rand() % 5 + 2, rand() % 5 + 2, rand() % 5 + 2, rand() % 5 + 2, 0, 0}; - 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], 0, 0};; + 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, 0, 0}; // LT1 - table[3] = {1, 1, 1, 1, 1, 1, 0, 0}; // For the first lookup gate - table[4] = {0, 1, 1, 1, 1, 1, 0, 0}; // For the second lookup gate + // 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, 0, 0}; // L1 - table[6] = {0, 7, 8, 9, 10, 11, 0, 0}; // L2 - table[7] = {0, 12, 12, 12, 12, 12, 0, 0}; // L3 + 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::array, witness_columns> private_assignment; for (std::size_t i = 0; i < witness_columns; i++) { @@ -944,6 +807,7 @@ namespace nil { 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); @@ -1005,60 +869,61 @@ namespace nil { // | 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 | 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 + // | 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; using arithmetization_params_7 = plonk_arithmetization_params; template circuit_description, 4, 3> circuit_test_7() { + arithmetization_params_7>, usable_rows_7, 4> 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 rows_log = 4; - constexpr static const std::size_t permutation = 3; + constexpr static const std::size_t permutation = 4; 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 = + constexpr static const std::size_t table_columns = witness_columns + public_columns + constant_columns + selector_columns; + constexpr static const std::size_t usable_rows = usable_rows_7; typedef placeholder_circuit_params circuit_params; - circuit_description test_circuit; + circuit_description test_circuit; std::array, table_columns> table; for (std::size_t j = 0; j < table_columns; j++) { - table[j].resize(test_circuit.table_rows); + table[j].resize(test_circuit.usable_rows); } - srand(time(NULL)); // lookup inputs typename FieldType::value_type one = FieldType::value_type::one(); typename FieldType::value_type zero = FieldType::value_type::zero(); - auto r = rand() % 8; - table[0] = std::vector(16); + auto r = rnd() % 7; std::size_t j = 0; for( std::size_t i = 0; i < 7; i++){ if( j == r ) j++; @@ -1072,24 +937,24 @@ namespace nil { } // selectors - // Reserved zero row for unselected lookup input rows + // Reserved zero row for unselected lookup input rows std::array, selector_columns> selectors_assignment; - selectors_assignment[0] = {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0 }; // Selector for single gate - selectors_assignment[1] = {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 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, 0, 0 }; // Selector for gate w1 = 2^w0 - selectors_assignment[3] = {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 }; // 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, 0, 0 }; // Selector for lookup tables 2, 3 - selectors_assignment[5] = {0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }; // Selector for lookup table with 7 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::array, constant_columns> constant_assignment; - constant_assignment[0] = {0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 0, 0 }; // Lookup tables - constant_assignment[1] = {0, 2, 2, 1, 1, 1, 1, 1, 1, 2, 4, 8, 16, 32, 0, 0 }; // Lookup tables - constant_assignment[2] = {0, 3, 3, 3, 2, 2, 2, 2, 6, 7, 7, 7, 7, 7, 0, 0 }; // Lookup tables - constant_assignment[3] = {0, 4, 4, 4, 4, 3, 3, 3, 64, 128, 128, 128, 128, 128, 0, 0 }; // Lookup tables - constant_assignment[4] = {0, 5, 5, 5, 5, 5, 4, 4, 1, 2, 4, 8, 16, 32, 0, 0 }; // Lookup tables - constant_assignment[5] = {0, 6, 6, 6, 6, 6, 5, 5, 64, 128, 256, 512, 1024, 2048, 0, 0 }; // Lookup tables - constant_assignment[6] = {0, 7, 7, 7, 7, 7, 7, 6,4096,8192,16384,16384,16384,16384, 0, 0 }; // Lookup tables + 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::array, witness_columns> private_assignment; for (std::size_t i = 0; i < witness_columns; i++) { @@ -1098,11 +963,11 @@ namespace nil { std::array, public_columns> public_input_assignment = {}; - 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); @@ -1151,7 +1016,7 @@ namespace nil { 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); + typename plonk_constraint::term_type w1_term(w1); lookup_constraint3.lookup_input = {w1__1_term* w1_term}; lookup_constraint3.table_id = 3; @@ -1182,4 +1047,4 @@ namespace nil { } // namespace nil -#endif // CRYPTO3_MARSHALLING_ZK_TEST_PLONK_CIRCUITS_HPP +#endif // CRYPTO3_ZK_TEST_PLONK_CIRCUITS_HPP diff --git a/test/transpiler.cpp b/test/transpiler.cpp index 50121e6..450c519 100644 --- a/test/transpiler.cpp +++ b/test/transpiler.cpp @@ -49,6 +49,7 @@ #include #include #include +#include #include #include @@ -63,12 +64,14 @@ #include #include #include +#include #include #include #include #include +#include #include "./detail/circuits.hpp" @@ -100,23 +103,18 @@ inline std::vector generate_random_step_list(const std::size_t r, c } template -typename fri_type::params_type create_fri_params(std::size_t degree_log, const int max_step = 1) { - typename fri_type::params_type params; - math::polynomial q = {0, 0, 1}; - - std::size_t expand_factor = 4; +typename fri_type::params_type create_fri_params( + std::size_t degree_log, const int max_step = 1, std::size_t expand_factor = 4) { std::size_t r = degree_log - 1; - std::vector>> domain_set = - math::calculate_domain_set(degree_log + expand_factor, r); - - params.r = r; - params.D = domain_set; - params.max_degree = (1 << degree_log) - 1; - params.step_list = generate_random_step_list(r, max_step); - - return params; + return typename fri_type::params_type( + (1 << degree_log) - 1, // max_degree + math::calculate_domain_set(degree_log + expand_factor, r), + generate_random_step_list(r, max_step), + expand_factor + ); } + // ******************************************************************************* // * Randomness setup // *******************************************************************************/ @@ -129,7 +127,7 @@ 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; @@ -152,6 +150,7 @@ struct test_initializer { 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() { @@ -173,7 +172,6 @@ BOOST_AUTO_TEST_SUITE(placeholder_circuit1) using merkle_hash_type = hashes::keccak_1600<256>; using transcript_hash_type = hashes::keccak_1600<256>; constexpr static const std::size_t table_rows_log = 4; - constexpr static const std::size_t table_rows = 1 << table_rows_log; struct placeholder_test_params { constexpr static const std::size_t table_rows = 1 << table_rows_log; @@ -195,34 +193,36 @@ BOOST_AUTO_TEST_SUITE(placeholder_circuit1) typedef placeholder_circuit_params circuit_params; using transcript_type = typename transcript::fiat_shamir_heuristic_sequential; - using lpc_params_type = commitments::list_polynomial_commitment_params< + using lpc_params_type = commitments::list_polynomial_commitment_params< merkle_hash_type, - transcript_hash_type, - placeholder_test_params::lambda, + transcript_hash_type, + placeholder_test_params::lambda, placeholder_test_params::m, - true + true, + crypto3::zk::commitments::proof_of_work >; 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; - desc.rows_amount = table_rows; + desc.rows_amount = placeholder_test_params::table_rows; desc.usable_rows_amount = placeholder_test_params::usable_rows; typename policy_type::constraint_system_type constraint_system( - circuit.gates, - circuit.copy_constraints, + circuit.gates, + circuit.copy_constraints, circuit.lookup_gates, circuit.lookup_tables ); typename policy_type::variable_assignment_type assignments = circuit.table; - std::vector columns_with_copy_constraints = {0, 1, 2, 3}; @@ -234,12 +234,18 @@ BOOST_FIXTURE_TEST_CASE(transpiler_test, test_initializer) { constraint_system, assignments.public_table(), desc, lpc_scheme, columns_with_copy_constraints.size() ); - nil::blueprint::print_evm_verifier( - constraint_system, - lpc_preprocessed_public_data.common_data, + auto printer = nil::blueprint::evm_verifier_printer( + constraint_system, + lpc_preprocessed_public_data.common_data, lpc_scheme, - columns_with_copy_constraints.size(),"circuit1" + columns_with_copy_constraints.size(), + "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() @@ -250,7 +256,7 @@ BOOST_AUTO_TEST_SUITE(placeholder_circuit2) using curve_type = algebra::curves::bls12<381>; using field_type = typename curve_type::scalar_field_type; - constexpr static const std::size_t table_rows_log = 4; + 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 permutation_size = 4; constexpr static const std::size_t usable_rows = (1 << table_rows_log) - 3; @@ -271,16 +277,16 @@ BOOST_AUTO_TEST_SUITE(placeholder_circuit2) constexpr static const std::size_t m = 2; }; using circuit_t_params = placeholder_circuit_params< - field_type, + field_type, typename placeholder_test_params::arithmetization_params >; using transcript_type = typename transcript::fiat_shamir_heuristic_sequential; - using lpc_params_type = commitments::list_polynomial_commitment_params< + 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::lambda, + typename placeholder_test_params::transcript_hash_type, + placeholder_test_params::lambda, placeholder_test_params::m >; @@ -289,23 +295,24 @@ BOOST_AUTO_TEST_SUITE(placeholder_circuit2) 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 = nil::crypto3::algebra::random_element(); - auto circuit = circuit_test_t(pi0); + 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; desc.rows_amount = table_rows; desc.usable_rows_amount = usable_rows; typename policy_type::constraint_system_type constraint_system( - circuit.gates, - circuit.copy_constraints, + circuit.gates, + circuit.copy_constraints, circuit.lookup_gates, circuit.lookup_tables ); typename policy_type::variable_assignment_type assignments = circuit.table; - std::vector columns_with_copy_constraints = {0, 1, 2, 3}; + std::vector columns_with_copy_constraints = {0, 1, 2, 3}; bool verifier_res; @@ -317,13 +324,18 @@ BOOST_FIXTURE_TEST_CASE(transpiler_test, test_initializer) { lpc_preprocessed_public_data = placeholder_public_preprocessor::process( constraint_system, assignments.public_table(), desc, lpc_scheme, columns_with_copy_constraints.size() ); - nil::blueprint::print_evm_verifier( - constraint_system, - lpc_preprocessed_public_data.common_data, + auto printer = nil::blueprint::evm_verifier_printer( + constraint_system, + lpc_preprocessed_public_data.common_data, lpc_scheme, columns_with_copy_constraints.size(), - "circuit2" + "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() @@ -356,10 +368,10 @@ BOOST_AUTO_TEST_SUITE(placeholder_circuit3) using circuit_params = placeholder_circuit_params; using transcript_type = typename transcript::fiat_shamir_heuristic_sequential; - using lpc_params_type = commitments::list_polynomial_commitment_params< + 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::lambda, + typename placeholder_test_params::transcript_hash_type, + placeholder_test_params::lambda, placeholder_test_params::m, true >; @@ -368,16 +380,18 @@ BOOST_AUTO_TEST_SUITE(placeholder_circuit3) 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(); + auto circuit = circuit_test_3(test_global_alg_rnd_engine, test_global_rnd_engine); + plonk_table_description desc; desc.rows_amount = table_rows; desc.usable_rows_amount = usable_rows; typename policy_type::constraint_system_type constraint_system( - circuit.gates, - circuit.copy_constraints, + circuit.gates, + circuit.copy_constraints, circuit.lookup_gates, circuit.lookup_tables ); @@ -391,13 +405,18 @@ BOOST_FIXTURE_TEST_CASE(transpiler_test, test_initializer) { typename placeholder_public_preprocessor::preprocessed_data_type preprocessed_public_data = placeholder_public_preprocessor::process( constraint_system, assignments.public_table(), desc, lpc_scheme, columns_with_copy_constraints.size()); - nil::blueprint::print_evm_verifier( - constraint_system, - preprocessed_public_data.common_data, + auto printer = nil::blueprint::evm_verifier_printer( + constraint_system, + preprocessed_public_data.common_data, lpc_scheme, columns_with_copy_constraints.size(), - "circuit3" + "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() @@ -428,10 +447,10 @@ BOOST_AUTO_TEST_SUITE(placeholder_circuit4) using circuit_params = placeholder_circuit_params; using transcript_type = typename transcript::fiat_shamir_heuristic_sequential; - using lpc_params_type = commitments::list_polynomial_commitment_params< + 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::lambda, + typename placeholder_test_params::transcript_hash_type, + placeholder_test_params::lambda, placeholder_test_params::m, true >; @@ -440,16 +459,18 @@ BOOST_AUTO_TEST_SUITE(placeholder_circuit4) 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(); + auto circuit = circuit_test_4(test_global_alg_rnd_engine); plonk_table_description desc; + desc.rows_amount = table_rows; desc.usable_rows_amount = usable_rows; typename policy_type::constraint_system_type constraint_system( - circuit.gates, - circuit.copy_constraints, + circuit.gates, + circuit.copy_constraints, circuit.lookup_gates, circuit.lookup_tables ); @@ -463,13 +484,18 @@ BOOST_FIXTURE_TEST_CASE(transpiler_test, test_initializer) { typename placeholder_public_preprocessor::preprocessed_data_type preprocessed_public_data = placeholder_public_preprocessor::process( constraint_system, assignments.public_table(), desc, lpc_scheme, columns_with_copy_constraints.size()); - nil::blueprint::print_evm_verifier( - constraint_system, + auto printer = nil::blueprint::evm_verifier_printer( + constraint_system, preprocessed_public_data.common_data, - lpc_scheme, + lpc_scheme, columns_with_copy_constraints.size(), - "circuit4" + "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() @@ -481,7 +507,7 @@ BOOST_AUTO_TEST_SUITE(placeholder_circuit6) 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 permutation_size = 3; + constexpr static const std::size_t permutation_size = 4; constexpr static const std::size_t usable_rows = 6; struct placeholder_test_params { @@ -502,10 +528,10 @@ BOOST_AUTO_TEST_SUITE(placeholder_circuit6) using circuit_params = placeholder_circuit_params; using transcript_type = typename transcript::fiat_shamir_heuristic_sequential; - using lpc_params_type = commitments::list_polynomial_commitment_params< + 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::lambda, + typename placeholder_test_params::transcript_hash_type, + placeholder_test_params::lambda, placeholder_test_params::m, true >; @@ -514,16 +540,18 @@ BOOST_AUTO_TEST_SUITE(placeholder_circuit6) 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(); + auto circuit = circuit_test_6(test_global_alg_rnd_engine, test_global_rnd_engine); plonk_table_description desc; + desc.rows_amount = table_rows; desc.usable_rows_amount = usable_rows; typename policy_type::constraint_system_type constraint_system( - circuit.gates, - circuit.copy_constraints, + circuit.gates, + circuit.copy_constraints, circuit.lookup_gates, circuit.lookup_tables ); @@ -537,13 +565,19 @@ BOOST_FIXTURE_TEST_CASE(transpiler_test, test_initializer) { typename placeholder_public_preprocessor::preprocessed_data_type preprocessed_public_data = placeholder_public_preprocessor::process( constraint_system, assignments.public_table(), desc, lpc_scheme, columns_with_copy_constraints.size()); - nil::blueprint::print_evm_verifier( - constraint_system, - preprocessed_public_data.common_data, + + auto printer = nil::blueprint::evm_verifier_printer( + constraint_system, + preprocessed_public_data.common_data, lpc_scheme, columns_with_copy_constraints.size(), - "circuit6" + "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() @@ -576,10 +610,10 @@ BOOST_AUTO_TEST_SUITE(placeholder_circuit7) using circuit_params = placeholder_circuit_params; using transcript_type = typename transcript::fiat_shamir_heuristic_sequential; - using lpc_params_type = commitments::list_polynomial_commitment_params< + 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::lambda, + typename placeholder_test_params::transcript_hash_type, + placeholder_test_params::lambda, placeholder_test_params::m, true >; @@ -588,16 +622,410 @@ BOOST_AUTO_TEST_SUITE(placeholder_circuit7) 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; + + desc.rows_amount = circuit.table_rows; + desc.usable_rows_amount = circuit.usable_rows; + std::size_t table_rows_log = 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; + + auto fri_params = create_fri_params(table_rows_log); + lpc_scheme_type lpc_scheme(fri_params); + + std::vector columns_with_copy_constraints = {0, 1, 2, 3}; + + 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, columns_with_copy_constraints.size()); + + + auto printer = nil::blueprint::evm_verifier_printer( + constraint_system, + preprocessed_public_data.common_data, + lpc_scheme, + columns_with_copy_constraints.size(), + "circuit7", + 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; + + constexpr static const std::size_t table_rows_log = 4; + constexpr static const std::size_t table_rows = 1 << table_rows_log; + + struct placeholder_test_params { + constexpr static const std::size_t table_rows = 1 << table_rows_log; + constexpr static const std::size_t permutation_size = 4; + constexpr static const std::size_t usable_rows = (1 << table_rows_log) - 3; + + 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; + + using arithmetization_params = + plonk_arithmetization_params; + + constexpr static const std::size_t lambda = 2; + 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::lambda, + 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) { + auto circuit = circuit_test_1(test_global_alg_rnd_engine); + plonk_table_description desc; + + desc.rows_amount = table_rows; + desc.usable_rows_amount = placeholder_test_params::usable_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; + + + std::vector columns_with_copy_constraints = {0, 1, 2, 3}; + + + typename lpc_type::fri_type::params_type fri_params = create_fri_params(table_rows_log); + 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, columns_with_copy_constraints.size() + ); + { + std::string cpp_path = "./circuit1/placeholder_verifier.cpp"; + std::ofstream output_file; + output_file.open(cpp_path); + output_file << nil::blueprint::recursive_verifier_generator::generate_recursive_verifier( + constraint_system, preprocessed_public_data.common_data, lpc_scheme, columns_with_copy_constraints.size(), {preprocessed_public_data.common_data.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, proof, 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::generate_input( + preprocessed_public_data.common_data.vk, assignments.public_inputs(), proof, {preprocessed_public_data.common_data.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 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; + + using arithmetization_params = + plonk_arithmetization_params; + + 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, + typename placeholder_test_params::arithmetization_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::lambda, + 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) { + 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; + desc.rows_amount = circuit.table_rows; + desc.usable_rows_amount = circuit.usable_rows; + auto table_rows_log = 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; + + std::vector columns_with_copy_constraints = {0, 1, 2, 3}; + + // LPC commitment scheme + typename lpc_type::fri_type::params_type fri_params = create_fri_params(table_rows_log); + 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, columns_with_copy_constraints.size() + ); + { + std::string cpp_path = "./circuit2/placeholder_verifier.cpp"; + std::ofstream output_file; + output_file.open(cpp_path); + output_file << nil::blueprint::recursive_verifier_generator::generate_recursive_verifier( + constraint_system, preprocessed_public_data.common_data, lpc_scheme, columns_with_copy_constraints.size(), {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, proof, 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::generate_input( + preprocessed_public_data.common_data.vk, 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; + + 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 permutation_size = 4; + constexpr static const std::size_t usable_rows = 4; + + struct placeholder_test_params { + 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; + + using arithmetization_params = + plonk_arithmetization_params; + + 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::lambda, + 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) { + auto circuit = circuit_test_3(); + plonk_table_description desc; + + desc.rows_amount = table_rows; + desc.usable_rows_amount = usable_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; + + auto fri_params = create_fri_params(table_rows_log); + lpc_scheme_type lpc_scheme(fri_params); + + std::vector columns_with_copy_constraints = {0, 1, 2, 3}; + + typename placeholder_public_preprocessor::preprocessed_data_type + preprocessed_public_data = placeholder_public_preprocessor::process( + constraint_system, assignments.public_table(), desc, lpc_scheme, columns_with_copy_constraints.size() + ); + { + std::string cpp_path = "./circuit3/placeholder_verifier.cpp"; + std::ofstream output_file; + output_file.open(cpp_path); + output_file << nil::blueprint::recursive_verifier_generator::generate_recursive_verifier( + constraint_system, preprocessed_public_data.common_data, lpc_scheme, columns_with_copy_constraints.size(), std::array() + ); + 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, proof, 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::generate_input( + preprocessed_public_data.common_data.vk, assignments.public_inputs(), proof, std::array() + ); + 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; + + 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 permutation_size = 4; + constexpr static const std::size_t usable_rows = 5; + + struct placeholder_test_params { + 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; + + using arithmetization_params = + plonk_arithmetization_params; + + constexpr static const std::size_t lambda = 40; + 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::lambda, + 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) { - auto circuit = circuit_test_7(); + auto circuit = circuit_test_4(test_global_alg_rnd_engine, test_global_rnd_engine); plonk_table_description desc; desc.rows_amount = table_rows; desc.usable_rows_amount = usable_rows; typename policy_type::constraint_system_type constraint_system( - circuit.gates, - circuit.copy_constraints, + circuit.gates, + circuit.copy_constraints, circuit.lookup_gates, circuit.lookup_tables ); @@ -611,12 +1039,237 @@ BOOST_FIXTURE_TEST_CASE(transpiler_test, test_initializer) { typename placeholder_public_preprocessor::preprocessed_data_type preprocessed_public_data = placeholder_public_preprocessor::process( constraint_system, assignments.public_table(), desc, lpc_scheme, columns_with_copy_constraints.size()); - nil::blueprint::print_evm_verifier( - constraint_system, - preprocessed_public_data.common_data, - lpc_scheme, - columns_with_copy_constraints.size(), - "circuit7" + { + std::string cpp_path = "./circuit4/placeholder_verifier.cpp"; + std::ofstream output_file; + output_file.open(cpp_path); + output_file << nil::blueprint::recursive_verifier_generator::generate_recursive_verifier( + constraint_system, preprocessed_public_data.common_data, lpc_scheme, columns_with_copy_constraints.size(), std::array() + ); + 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, proof, 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::generate_input( + preprocessed_public_data.common_data.vk, assignments.public_inputs(), proof, std::array() + ); + 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; + + 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 permutation_size = 3; + constexpr static const std::size_t usable_rows = 6; + + struct placeholder_test_params { + 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; + + using arithmetization_params = + plonk_arithmetization_params; + + 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::lambda, + 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) { + auto circuit = circuit_test_6(test_global_alg_rnd_engine, test_global_rnd_engine); + + plonk_table_description desc; + desc.rows_amount = table_rows; + desc.usable_rows_amount = usable_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; + + auto fri_params = create_fri_params(table_rows_log); + lpc_scheme_type lpc_scheme(fri_params); + + std::vector columns_with_copy_constraints = {0, 1, 2}; + + typename placeholder_public_preprocessor::preprocessed_data_type + preprocessed_public_data = placeholder_public_preprocessor::process( + constraint_system, assignments.public_table(), desc, lpc_scheme, columns_with_copy_constraints.size()); + { + std::string cpp_path = "./circuit6/placeholder_verifier.cpp"; + std::ofstream output_file; + output_file.open(cpp_path); + output_file << nil::blueprint::recursive_verifier_generator::generate_recursive_verifier( + constraint_system, preprocessed_public_data.common_data, lpc_scheme, columns_with_copy_constraints.size(), std::array() + ); + 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, proof, 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::generate_input( + preprocessed_public_data.common_data.vk, assignments.public_inputs(), proof, std::array() + ); + 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; + + constexpr static const std::size_t table_rows_log = 4; + constexpr static const std::size_t table_rows = 1 << table_rows_log; + constexpr static const std::size_t permutation_size = 4; + constexpr static const std::size_t usable_rows = 14; + + struct placeholder_test_params { + 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; + + using arithmetization_params = + plonk_arithmetization_params; + + 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::lambda, + 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) { + auto circuit = circuit_test_7(test_global_alg_rnd_engine, test_global_rnd_engine); + plonk_table_description desc; + + desc.rows_amount = circuit.table_rows; + desc.usable_rows_amount = circuit.usable_rows; + std::size_t table_rows_log = 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; + + auto fri_params = create_fri_params(table_rows_log); + lpc_scheme_type lpc_scheme(fri_params); + + std::vector columns_with_copy_constraints = {0, 1, 2, 3}; + 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, columns_with_copy_constraints.size()); + { + std::string cpp_path = "./circuit7/placeholder_verifier.cpp"; + std::ofstream output_file; + output_file.open(cpp_path); + output_file << nil::blueprint::recursive_verifier_generator::generate_recursive_verifier( + constraint_system, preprocessed_public_data.common_data, lpc_scheme, columns_with_copy_constraints.size(), std::array() + ); + 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, proof, 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::generate_input( + preprocessed_public_data.common_data.vk, assignments.public_inputs(), proof, std::array() + ); + output_file.close(); + } } BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file