From e70206d365f985e62fb3da0f490c2b85fab2a762 Mon Sep 17 00:00:00 2001 From: Iluvmagick Date: Sun, 22 Sep 2024 16:29:08 +0400 Subject: [PATCH] Added aggregated proof json export. --- .../zk/detail/random_test_data_generation.hpp | 4 +- .../marshalling/zk/types/commitments/lpc.hpp | 6 +- .../crypto3/zk/commitments/polynomial/lpc.hpp | 8 +- .../crypto3/zk/commitments/polynomial/lpc.hpp | 8 +- .../aggregated_verifier_generator.hpp | 130 +++++++++++------- .../recursive_verifier_generator.hpp | 10 +- transpiler/test/transpiler.cpp | 76 ++++++++++ 7 files changed, 176 insertions(+), 66 deletions(-) diff --git a/crypto3/libs/marshalling/zk/include/nil/crypto3/marshalling/zk/detail/random_test_data_generation.hpp b/crypto3/libs/marshalling/zk/include/nil/crypto3/marshalling/zk/detail/random_test_data_generation.hpp index 029fc77e1b..101bc7bd62 100644 --- a/crypto3/libs/marshalling/zk/include/nil/crypto3/marshalling/zk/detail/random_test_data_generation.hpp +++ b/crypto3/libs/marshalling/zk/include/nil/crypto3/marshalling/zk/detail/random_test_data_generation.hpp @@ -415,9 +415,9 @@ typename LPC::aggregated_proof_type generate_random_lpc_aggregated_proof( res.fri_proof = generate_random_lpc_intial_fri_proof( d, max_batch_size, step_list, lambda, use_grinding, alg_rnd, rnd); - res.intial_proofs_per_prover.resize(lambda); + res.initial_proofs_per_prover.resize(lambda); for (std::size_t i = 0; i < lambda; i++) { - res.intial_proofs_per_prover[i] = generate_random_lpc_inital_proof( + res.initial_proofs_per_prover[i] = generate_random_lpc_inital_proof( d, max_batch_size, step_list, lambda, use_grinding, alg_rnd, rnd); } diff --git a/crypto3/libs/marshalling/zk/include/nil/crypto3/marshalling/zk/types/commitments/lpc.hpp b/crypto3/libs/marshalling/zk/include/nil/crypto3/marshalling/zk/types/commitments/lpc.hpp index 1cb4bb5915..d408da5c17 100644 --- a/crypto3/libs/marshalling/zk/include/nil/crypto3/marshalling/zk/types/commitments/lpc.hpp +++ b/crypto3/libs/marshalling/zk/include/nil/crypto3/marshalling/zk/types/commitments/lpc.hpp @@ -524,7 +524,7 @@ namespace nil { std::tuple< // fri_proof_type fri_proof; initial_fri_proof_type, - // std::vector intial_proofs_per_prover; + // std::vector initial_proofs_per_prover; nil::marshalling::types::standard_array_list< TTypeBase, inital_eval_proof @@ -552,7 +552,7 @@ namespace nil { TTypeBase, inital_eval_proof > filled_initial_proofs; - for (const auto &initial_proof : proof.intial_proofs_per_prover) { + for (const auto &initial_proof : proof.initial_proofs_per_prover) { filled_initial_proofs.value().push_back( fill_initial_eval_proof( initial_proof @@ -582,7 +582,7 @@ namespace nil { std::get<0>(filled_proof.value())); for (const auto &filled_initial_proof : std::get<1>(filled_proof.value()).value()) { - proof.intial_proofs_per_prover.push_back( + proof.initial_proofs_per_prover.push_back( make_initial_eval_proof( filled_initial_proof ) diff --git a/crypto3/libs/zk/include/nil/crypto3/zk/commitments/polynomial/lpc.hpp b/crypto3/libs/zk/include/nil/crypto3/zk/commitments/polynomial/lpc.hpp index d22db35917..c88964f43a 100644 --- a/crypto3/libs/zk/include/nil/crypto3/zk/commitments/polynomial/lpc.hpp +++ b/crypto3/libs/zk/include/nil/crypto3/zk/commitments/polynomial/lpc.hpp @@ -172,9 +172,9 @@ namespace nil { } } - /** This function must be called for the cases where we want to skip the + /** This function must be called for the cases where we want to skip the * round proof for FRI. Must be called once per instance of prover for the aggregated FRI. - * \param[in] combined_Q - Polynomial combined_Q was already computed by the current + * \param[in] combined_Q - Polynomial combined_Q was already computed by the current prover in the previous step of the aggregated FRI protocol. * \param[in] challenges - These challenges were sent from the "Main" prover, on which the round proof was created for the polynomial F(x) = Sum(combined_Q). @@ -601,7 +601,7 @@ namespace nil { struct aggregated_proof_type { bool operator==(const aggregated_proof_type &rhs) const { return fri_proof == rhs.fri_proof && - intial_proofs_per_prover == rhs.intial_proofs_per_prover && + initial_proofs_per_prover == rhs.initial_proofs_per_prover && proof_of_work == rhs.proof_of_work; } @@ -613,7 +613,7 @@ namespace nil { fri_proof_type fri_proof; // For each prover we have an initial proof. - std::vector intial_proofs_per_prover; + std::vector initial_proofs_per_prover; typename LPCParams::grinding_type::output_type proof_of_work; }; diff --git a/parallel-crypto3/libs/parallel-zk/include/nil/crypto3/zk/commitments/polynomial/lpc.hpp b/parallel-crypto3/libs/parallel-zk/include/nil/crypto3/zk/commitments/polynomial/lpc.hpp index e30c8337e4..02c6a2f6c5 100644 --- a/parallel-crypto3/libs/parallel-zk/include/nil/crypto3/zk/commitments/polynomial/lpc.hpp +++ b/parallel-crypto3/libs/parallel-zk/include/nil/crypto3/zk/commitments/polynomial/lpc.hpp @@ -173,9 +173,9 @@ namespace nil { } } - /** This function must be called for the cases where we want to skip the + /** This function must be called for the cases where we want to skip the * round proof for FRI. Must be called once per instance of prover for the aggregated FRI. - * \param[in] combined_Q - Polynomial combined_Q was already computed by the current + * \param[in] combined_Q - Polynomial combined_Q was already computed by the current prover in the previous step of the aggregated FRI protocol. * \param[in] challenges - These challenges were sent from the "Main" prover, on which the round proof was created for the polynomial F(x) = Sum(combined_Q). @@ -679,7 +679,7 @@ namespace nil { struct aggregated_proof_type { bool operator==(const aggregated_proof_type &rhs) const { return fri_proof == rhs.fri_proof && - intial_proofs_per_prover == rhs.intial_proofs_per_prover && + initial_proofs_per_prover == rhs.initial_proofs_per_prover && proof_of_work == rhs.proof_of_work; } @@ -691,7 +691,7 @@ namespace nil { fri_proof_type fri_proof; // For each prover we have an initial proof. - std::vector intial_proofs_per_prover; + std::vector initial_proofs_per_prover; typename LPCParams::grinding_type::output_type proof_of_work; }; diff --git a/transpiler/include/nil/blueprint/transpiler/aggregated_verifier_generator.hpp b/transpiler/include/nil/blueprint/transpiler/aggregated_verifier_generator.hpp index ddaa4e6ac1..b8812d0afa 100644 --- a/transpiler/include/nil/blueprint/transpiler/aggregated_verifier_generator.hpp +++ b/transpiler/include/nil/blueprint/transpiler/aggregated_verifier_generator.hpp @@ -49,12 +49,10 @@ namespace nil { namespace blueprint { - template + template struct aggregated_verifier_generator { using field_type = typename PlaceholderParams::field_type; using proof_type = AggregatedProofType; - using common_data_type = CommonDataType; - using verification_key_type = typename common_data_type::verification_key_type; using commitment_scheme_type = typename PlaceholderParams::commitment_scheme_type; using constraint_system_type = typename PlaceholderParams::constraint_system_type; using columns_rotations_type = std::vector>; @@ -67,6 +65,32 @@ namespace nil { using pow_operation_type = typename constraint_system_type::pow_operation_type; using assignment_table_type = typename PlaceholderParams::assignment_table_type; + static std::string generate_field_array2_from_64_hex_string(std::string str){ + BOOST_ASSERT_MSG(str.size() == 64, "input string must be 64 hex characters long"); + std::string first_half = str.substr(0, 32); + std::string second_half = str.substr(32, 32); + return "{\"vector\": [{\"field\": \"0x" + first_half + "\"},{\"field\": \"0x" + second_half + "\"}]}"; + } + + template + static inline std::string generate_hash(typename HashType::digest_type hashed_data){ + if constexpr(std::is_same>::value){ + std::stringstream out; + out << hashed_data; + return generate_field_array2_from_64_hex_string(out.str()); + } else if constexpr(std::is_same>::value){ + std::stringstream out; + out << hashed_data; + return generate_field_array2_from_64_hex_string(out.str()); + } else { + std::stringstream out; + out << "{\"field\": \"" << hashed_data << "\"}"; + return out.str(); + } + BOOST_ASSERT_MSG(false, "unsupported merkle hash type"); + return "unsupported merkle hash type"; + } + template static inline std::string generate_commitment(typename CommitmentSchemeType::commitment_type commitment) { return generate_hash(commitment); @@ -122,7 +146,7 @@ namespace nil { << generate_commitment(commitment); after_first = true; } - out << "\t\t]}," << std::endl; + out << "\t\t]}]}," << std::endl; } // aggregated proof type const auto &aggregated_proof = proof.aggregated_proof; @@ -130,29 +154,30 @@ namespace nil { // single fri proof checking that F(x) is low degree // basic_fri::round_proofs_batch_type fri_round_proof - const auto &fri_round_proof = aggregated_proof.fri_round_proof; + const auto &fri_round_proof = aggregated_proof.fri_proof; // which is in essence std::vector> round_proofs; out << "\t\t{\"array\":[" << std::endl; bool after_first = false; - for (const auto &outer_proof_vector : fri_round_proof.round_proofs) { + for (const auto &outer_proof_vector : fri_round_proof.fri_round_proof.round_proofs) { if (after_first) [[likely]] out << "," << std::endl; out << "\t\t\t{\"array\":[" << std::endl; bool after_first_inner = false; for (const auto &round_proof : outer_proof_vector) { if (after_first_inner) [[likely]] out << "," << std::endl; BOOST_ASSERT_MSG(round_proof.y.size() == 1, "Unsupported step_list value"); - out << "\t\t\t\t{\"field\":\"" << round_proof.y[0][0] << "\"}," << std::endl; - out << "\t\t\t\t{\"field\":\"" << round_proof.y[0][1] << "\"}"; - out << std::endl << "\t\t\t]}"; + out << "\t\t\t\t{\"array\":[" << std::endl; + out << "\t\t\t\t\t{\"field\":\"" << round_proof.y[0][0] << "\"}," << std::endl; + out << "\t\t\t\t\t{\"field\":\"" << round_proof.y[0][1] << "\"}"; + out << std::endl << "\t\t\t\t]}"; after_first_inner = true; } out << "\t\t\t]}" << std::endl; after_first = true; } - out << "\t\t]}," << std::endl; + out << "\t]}]}," << std::endl; // typename basic_fri::commitments_part_of_proof fri_commitments_proof_part; // consisting of std::vector fri_roots; - auto &fri_commitments_proof_part = aggregated_proof.fri_commitments_proof_part; + auto &fri_commitments_proof_part = fri_round_proof.fri_commitments_proof_part; out << "\t\t{\"array\":[" << std::endl; after_first = false; for (const auto &fri_root : fri_commitments_proof_part.fri_roots) { @@ -173,9 +198,11 @@ namespace nil { } out << std::endl << "\t\t]}," << std::endl; - // std::vector intial_proofs_per_prover; + // std::vector initial_proofs_per_prover; out << "\t\t{\"array\":[" << std::endl; - for (const auto &lpc_proof : proof.initial_proofs_per_prover) { + after_first = false; + for (const auto &lpc_proof : aggregated_proof.initial_proofs_per_prover) { + if (after_first) [[likely]] out << "," << std::endl; // eval_storage_type z; out << "\t\t\t{\"array\":[" << std::endl; const auto &eval_storage = lpc_proof.z; @@ -194,47 +221,55 @@ namespace nil { out << std::endl << "\t\t]}," << std::endl; // and basic_fri::initial_proofs_batch_type initial_fri_proofs; // which is std::vector> initial_proofs; - const auto &initial_proofs = lpc_proof.initial_fri_proofs; + const auto &initial_proofs = lpc_proof.initial_fri_proofs.initial_proofs; out << "\t\t{\"array\":[" << std::endl; - after_first = false; - for (const auto &[key, value] : initial_proofs) { - if (after_first) [[likely]] out << "," << std::endl; + bool map_after_first = false; + for (const auto &initial_proofs_map : initial_proofs) { + if (map_after_first) [[likely]] out << "," << std::endl; out << "\t\t\t{\"struct\":[" << std::endl; - // each initial proof is polynomials_values_type values; - // which is std::vector>> - // and merkle_proof_type p; - after_first = true; - // first the values - // I have no idea if we have to store keys, I hope we do not - const auto &values = value.values; - bool outer_vec_after_first = false; - for (const auto &outer_vector : values) { - if (outer_vec_after_first) [[likely]] out << "," << std::endl; - out << "\t\t\t\t{\"array\":[" << std::endl; - bool inner_after_first = false; - for (const auto &inner_vector : outer_vector) { - if (inner_after_first) [[likely]] out << "," << std::endl; - out << "\t\t\t\t\t{\"array\":[" << std::endl; - bool array_after_first = false; - for (const auto &elem : inner_vector) { - if (array_after_first) [[likely]] out << "," << std::endl; - out << "\t\t\t\t\t\t{\"field\":\"" << elem << "\"}"; - array_after_first = true; + bool inner_after_first = false; + for (const auto &[index, value] : initial_proofs_map) { + if (inner_after_first) [[likely]] out << "," << std::endl; + // each initial proof is polynomials_values_type values; + // which is std::vector>> + // and merkle_proof_type p; + // first the values + // I have no idea if we have to store keys, I hope we do not + const auto &values = value.values; + bool outer_vec_after_first = false; + for (const auto &outer_vector : values) { + if (outer_vec_after_first) [[likely]] out << "," << std::endl; + out << "\t\t\t\t{\"array\":[" << std::endl; + bool core_after_first = false; + for (const auto &inner_vector : outer_vector) { + if (core_after_first) [[likely]] out << "," << std::endl; + out << "\t\t\t\t\t{\"array\":[" << std::endl; + bool array_after_first = false; + for (const auto &elem : inner_vector) { + if (array_after_first) [[likely]] out << "," << std::endl; + out << "\t\t\t\t\t\t{\"field\":\"" << elem << "\"}"; + array_after_first = true; + } + out << std::endl << "\t\t\t\t\t]}"; + core_after_first = true; } - out << std::endl << "\t\t\t\t\t]}"; - inner_after_first = true; + out << std::endl << "\t\t\t\t]}"; + outer_vec_after_first = true; } - out << std::endl << "\t\t\t\t]"; - outer_vec_after_first = true; + // we skip the merkle proof, as those are the same for all initial proofs + // we serialize it right after this loop + inner_after_first = true; } - out << std::endl << "\t\t]}," << std::endl; - // we skip the merkle proof, as those are the same for all initial proofs - // we serialize it right after this loop + out << "\t\t\t]}" << std::endl; + map_after_first = true; } + out << "\t\t]}" << std::endl; + after_first = true; } out << "\t\t]}," << std::endl; // and now serialize one of the merkle proofs - const auto &merkle_proof_path = proof.initial_proofs_per_prover.initial_proofs.begin()->second.p.path(); + const auto &merkle_proof_path = + aggregated_proof.initial_proofs_per_prover.begin()->initial_fri_proofs.initial_proofs.begin()->begin()->second.p.path(); out << "\t\t{\"array\":[" << std::endl; after_first = false; for (const auto &path_elem : merkle_proof_path) { @@ -246,8 +281,9 @@ namespace nil { } out << std::endl << "\t\t]}," << std::endl; // typename LPCParams::grinding_type::output_type proof_of_work; - out << "\t\t{\"field\":\"" << aggregated_proof.proof_of_work << "\"}" << std::endl; - out << "\t]}" << std::endl; + out << "\t{\"field\":\"" << aggregated_proof.proof_of_work << "\"}" << std::endl; + out << "]" << std::endl; + return out.str(); } aggregated_verifier_generator( diff --git a/transpiler/include/nil/blueprint/transpiler/recursive_verifier_generator.hpp b/transpiler/include/nil/blueprint/transpiler/recursive_verifier_generator.hpp index 67eacae36f..ff3b8d0489 100644 --- a/transpiler/include/nil/blueprint/transpiler/recursive_verifier_generator.hpp +++ b/transpiler/include/nil/blueprint/transpiler/recursive_verifier_generator.hpp @@ -207,10 +207,8 @@ namespace nil { 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; @@ -486,10 +484,10 @@ namespace nil { }; static inline std::string rot_string (int j){ - if(j == 0) return "xi"; else - if(j == 1 ) return "xi*omega"; else - if(j == -1) return "xi/omega"; else - if(j > 0) return "xi*pow<" + to_string(j) + ">(omega)"; else + if(j == 0) return "xi"; + if(j == 1 ) return "xi*omega"; + if(j == -1) return "xi/omega"; + if(j > 0) return "xi*pow<" + to_string(j) + ">(omega)"; if(j < 0) return "xi/pow<" + to_string(-j) + ">(omega)"; return ""; } diff --git a/transpiler/test/transpiler.cpp b/transpiler/test/transpiler.cpp index d0683f921f..5d43063f89 100644 --- a/transpiler/test/transpiler.cpp +++ b/transpiler/test/transpiler.cpp @@ -71,6 +71,8 @@ #include #include +#include +#include #include "./detail/circuits.hpp" @@ -900,6 +902,80 @@ BOOST_FIXTURE_TEST_CASE(transpiler_test, test_initializer) { output_file.close(); } } + +BOOST_FIXTURE_TEST_CASE(aggregated_proof_sanity_test, test_initializer) { + auto circuit = circuit_test_1( + test_global_alg_rnd_engine, test_global_rnd_engine + ); + plonk_table_description desc( + placeholder_test_params::witness_columns, + placeholder_test_params::public_input_columns, + placeholder_test_params::constant_columns, + placeholder_test_params::selector_columns + ); + using batch_lpc_type = commitments::list_polynomial_commitment; + using batch_lpc_scheme_type = typename commitments::lpc_commitment_scheme; + using batch_lpc_placeholder_params_type = + nil::crypto3::zk::snark::placeholder_params; + + 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; + + typename batch_lpc_type::fri_type::params_type fri_params( + 1, table_rows_log, placeholder_test_params::lambda, 4 + ); + batch_lpc_scheme_type lpc_scheme(fri_params); + + typename placeholder_public_preprocessor::preprocessed_data_type + preprocessed_public_data = placeholder_public_preprocessor::process( + constraint_system, assignments.public_table(), desc, lpc_scheme, 10 + ); + + 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 + ); + // now we get a vector of partial proofs + std::vector> partial_proofs; + for (std::size_t i = 0; i < 5; i++) { + partial_proofs.push_back(proof); + } + // and lpc aggregated proof + auto lpc_proof = generate_random_lpc_aggregated_proof( + 7, 5, + fri_params.step_list, + 2, + false, + test_global_alg_rnd_engine, test_global_rnd_engine + ); + + using aggregated_proof_type = nil::crypto3::zk::snark::placeholder_aggregated_proof< + field_type, batch_lpc_placeholder_params_type>; + aggregated_proof_type aggregated_proof; + aggregated_proof.partial_proofs = partial_proofs; + aggregated_proof.aggregated_proof = lpc_proof; + nil::blueprint::aggregated_verifier_generator + verifier_generator(desc); + auto json = verifier_generator.generate_input( + assignments.public_inputs(), aggregated_proof, {desc.usable_rows_amount + 1} + ); + boost::property_tree::ptree ptree; + auto json_stream = std::istringstream(json); + boost::property_tree::read_json(json_stream, ptree); +} + BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE(recursive_circuit2)