From c4ae6c24a6a29ea900cb359f4a418a7a94edd6bb Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Fri, 29 Nov 2024 16:46:18 +0000 Subject: [PATCH 01/13] simplify pub inputs handling --- .../honk_recursion_constraint.test.cpp | 5 +- .../acir_format/ivc_recursion_constraint.cpp | 13 +++-- .../acir_format/ivc_recursion_constraint.hpp | 5 +- .../ivc_recursion_constraint.test.cpp | 52 ++++++------------- .../dsl/acir_format/proof_surgeon.hpp | 4 +- 5 files changed, 29 insertions(+), 50 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.test.cpp index de6005c1942..e431959807e 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.test.cpp @@ -153,10 +153,11 @@ class AcirHonkRecursionConstraint : public ::testing::Test { std::vector key_witnesses = verification_key->to_field_elements(); std::vector proof_witnesses = inner_proof; - const size_t num_public_inputs = inner_circuit.get_public_inputs().size(); + const size_t num_public_inputs_to_extract = + inner_circuit.get_public_inputs().size() - bb::PAIRING_POINT_ACCUMULATOR_SIZE; auto [key_indices, proof_indices, inner_public_inputs] = ProofSurgeon::populate_recursion_witness_data( - witness, proof_witnesses, key_witnesses, num_public_inputs); + witness, proof_witnesses, key_witnesses, num_public_inputs_to_extract); RecursionConstraint honk_recursion_constraint{ .key = key_indices, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp index 4bd58eff722..4aa0c666016 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp @@ -21,7 +21,8 @@ ClientIVC create_mock_ivc_from_constraints(const std::vector(PROOF_TYPE::OINK) == constraint.proof_type) { - mock_ivc_oink_accumulation(ivc, constraint.public_inputs.size()); + ASSERT(constraint.public_inputs.size() == 0); // Apps are assumed to have no public inputs + mock_ivc_oink_accumulation(ivc); } else if (static_cast(PROOF_TYPE::PG) == constraint.proof_type) { // perform equivalent mocking for PG accumulation } @@ -38,10 +39,9 @@ ClientIVC create_mock_ivc_from_constraints(const std::vector mock_commitment_frs = field_conversion::convert_to_bn254_frs(mock_commitment); // Set proof preamble (metadata plus public inputs) - size_t total_num_public_inputs = num_public_inputs + bb::PAIRING_POINT_ACCUMULATOR_SIZE; + size_t total_num_public_inputs = bb::PAIRING_POINT_ACCUMULATOR_SIZE; verifier_inputs.proof.emplace_back(structured_dyadic_size); verifier_inputs.proof.emplace_back(total_num_public_inputs); verifier_inputs.proof.emplace_back(pub_inputs_offset); diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.hpp index 7709bee73c0..ffa28d59a55 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.hpp @@ -13,10 +13,9 @@ using namespace bb; ClientIVC create_mock_ivc_from_constraints(const std::vector& constraints); -void mock_ivc_oink_accumulation(ClientIVC& ivc, size_t num_public_inputs_app = 0); +void mock_ivc_oink_accumulation(ClientIVC& ivc); -ClientIVC::VerifierInputs create_dummy_vkey_and_proof_oink(const TraceSettings& trace_settings, - const size_t num_public_inputs); +ClientIVC::VerifierInputs create_dummy_vkey_and_proof_oink(const TraceSettings& trace_settings); ClientIVC::MergeProof create_dummy_merge_proof(); diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp index 4ea3df6a72e..5775b5473e2 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp @@ -28,17 +28,13 @@ class IvcRecursionConstraintTest : public ::testing::Test { /** * @brief Constuct a simple arbitrary circuit to represent a mock app circuit - * @details Includes a single unique public input for robustness and to distinguish the public inputs of one "app" - * from another in testing. * */ static Builder construct_mock_app_circuit(ClientIVC& ivc) { Builder circuit{ ivc.goblin.op_queue }; - GoblinMockCircuits::construct_simple_circuit(circuit); - - // add a random (unique) public input - circuit.add_public_variable(FF::random_element()); + GoblinMockCircuits::add_some_ecc_op_gates(circuit); + MockCircuits::add_arithmetic_gates(circuit); return circuit; } @@ -52,17 +48,15 @@ class IvcRecursionConstraintTest : public ::testing::Test { * @param num_public_inputs Number of public inputs to be extracted from the proof * @return RecursionConstraint */ - static RecursionConstraint create_recursion_constraint(const VerifierInputs& input, - SlabVector& witness, - const size_t num_public_inputs) + static RecursionConstraint create_recursion_constraint(const VerifierInputs& input, SlabVector& witness) { // Assemble simple vectors of witnesses for vkey and proof std::vector key_witnesses = input.honk_verification_key->to_field_elements(); std::vector proof_witnesses = input.proof; // proof contains the public inputs at this stage // Construct witness indices for each component in the constraint; populate the witness array - auto [key_indices, proof_indices, public_inputs_indices] = - ProofSurgeon::populate_recursion_witness_data(witness, proof_witnesses, key_witnesses, num_public_inputs); + auto [key_indices, proof_indices, public_inputs_indices] = ProofSurgeon::populate_recursion_witness_data( + witness, proof_witnesses, key_witnesses, /*num_public_inputs_to_extract=*/0); // The proof type can be either Oink or PG PROOF_TYPE proof_type = input.type == QUEUE_TYPE::OINK ? OINK : PG; @@ -88,19 +82,15 @@ class IvcRecursionConstraintTest : public ::testing::Test { * @param inner_circuit_num_pub_inputs Num pub inputs for each circuit whose accumulation is recursively verified * @return Builder */ - static AcirProgram construct_mock_kernel_program(const VerificationQueue& verification_queue, - const std::vector& inner_circuit_num_pub_inputs) + static AcirProgram construct_mock_kernel_program(const VerificationQueue& verification_queue) { - ASSERT(verification_queue.size() == inner_circuit_num_pub_inputs.size()); - AcirProgram program; // Construct recursion constraints based on the ivc verification queue; populate the witness along the way std::vector ivc_recursion_constraints; ivc_recursion_constraints.reserve(verification_queue.size()); - for (size_t idx = 0; idx < verification_queue.size(); ++idx) { - ivc_recursion_constraints.push_back(create_recursion_constraint( - verification_queue[idx], program.witness, inner_circuit_num_pub_inputs[idx])); + for (const auto& queue_entry : verification_queue) { + ivc_recursion_constraints.push_back(create_recursion_constraint(queue_entry, program.witness)); } // Construct a constraint system containing the business logic and ivc recursion constraints @@ -136,7 +126,7 @@ TEST_F(IvcRecursionConstraintTest, AccumulateTwo) ivc.accumulate(app_circuit); // Construct kernel_0 consisting only of the kernel completion logic - AcirProgram program_0 = construct_mock_kernel_program(ivc.verification_queue, { app_circuit.public_inputs.size() }); + AcirProgram program_0 = construct_mock_kernel_program(ivc.verification_queue); Builder kernel_0 = acir_format::create_kernel_circuit(program_0.constraints, ivc, program_0.witness); EXPECT_TRUE(CircuitChecker::check(kernel_0)); @@ -158,8 +148,7 @@ TEST_F(IvcRecursionConstraintTest, AccumulateFour) ivc.accumulate(app_circuit_0); // Construct kernel_0; consists of a single oink recursive verification for app (plus databus/merge logic) - size_t num_pub_inputs_app_0 = app_circuit_0.public_inputs.size(); - AcirProgram program_0 = construct_mock_kernel_program(ivc.verification_queue, { num_pub_inputs_app_0 }); + AcirProgram program_0 = construct_mock_kernel_program(ivc.verification_queue); Builder kernel_0 = acir_format::create_kernel_circuit(program_0.constraints, ivc, program_0.witness); ivc.accumulate(kernel_0); @@ -168,10 +157,7 @@ TEST_F(IvcRecursionConstraintTest, AccumulateFour) ivc.accumulate(app_circuit_1); // Construct kernel_1; consists of two PG recursive verifications for kernel_0 and app_1 (plus databus/merge logic) - size_t num_pub_inputs_kernel_0 = kernel_0.public_inputs.size(); - size_t num_pub_inputs_app_1 = app_circuit_0.public_inputs.size(); - AcirProgram program_1 = - construct_mock_kernel_program(ivc.verification_queue, { num_pub_inputs_kernel_0, num_pub_inputs_app_1 }); + AcirProgram program_1 = construct_mock_kernel_program(ivc.verification_queue); Builder kernel_1 = acir_format::create_kernel_circuit(program_1.constraints, ivc, program_1.witness); EXPECT_TRUE(CircuitChecker::check(kernel_1)); @@ -187,17 +173,15 @@ TEST_F(IvcRecursionConstraintTest, GenerateVK) // First, construct the kernel VK by running the full IVC (accumulate one app and one kernel) std::shared_ptr expected_kernel_vk; - size_t num_app_public_inputs = 0; { ClientIVC ivc{ trace_settings }; // Construct and accumulate mock app_circuit Builder app_circuit = construct_mock_app_circuit(ivc); ivc.accumulate(app_circuit); - num_app_public_inputs = app_circuit.public_inputs.size(); // Construct and accumulate kernel consisting only of the kernel completion logic - AcirProgram program = construct_mock_kernel_program(ivc.verification_queue, { num_app_public_inputs }); + AcirProgram program = construct_mock_kernel_program(ivc.verification_queue); Builder kernel = acir_format::create_kernel_circuit(program.constraints, ivc, program.witness); ivc.accumulate(kernel); expected_kernel_vk = ivc.verification_queue.back().honk_verification_key; @@ -208,10 +192,10 @@ TEST_F(IvcRecursionConstraintTest, GenerateVK) { ClientIVC ivc{ trace_settings }; - acir_format::mock_ivc_oink_accumulation(ivc, num_app_public_inputs - bb::PAIRING_POINT_ACCUMULATOR_SIZE); + acir_format::mock_ivc_oink_accumulation(ivc); // Construct kernel consisting only of the kernel completion logic - AcirProgram program = construct_mock_kernel_program(ivc.verification_queue, { num_app_public_inputs }); + AcirProgram program = construct_mock_kernel_program(ivc.verification_queue); Builder kernel = acir_format::create_kernel_circuit(program.constraints, ivc); // Note that this would normally happen in accumulate() kernel.add_pairing_point_accumulator(stdlib::recursion::init_default_agg_obj_indices(kernel)); @@ -235,17 +219,15 @@ TEST_F(IvcRecursionConstraintTest, GenerateVKFromConstraints) // First, construct the kernel VK by running the full IVC (accumulate one app and one kernel) std::shared_ptr expected_kernel_vk; - size_t num_app_public_inputs = 0; { ClientIVC ivc{ trace_settings }; // Construct and accumulate mock app_circuit Builder app_circuit = construct_mock_app_circuit(ivc); ivc.accumulate(app_circuit); - num_app_public_inputs = app_circuit.public_inputs.size(); // Construct and accumulate kernel consisting only of the kernel completion logic - AcirProgram program = construct_mock_kernel_program(ivc.verification_queue, { num_app_public_inputs }); + AcirProgram program = construct_mock_kernel_program(ivc.verification_queue); Builder kernel = acir_format::create_kernel_circuit(program.constraints, ivc, program.witness); ivc.accumulate(kernel); @@ -258,8 +240,8 @@ TEST_F(IvcRecursionConstraintTest, GenerateVKFromConstraints) ClientIVC ivc{ trace_settings }; // Construct kernel consisting only of the kernel completion logic - acir_format::mock_ivc_oink_accumulation(ivc, num_app_public_inputs - bb::PAIRING_POINT_ACCUMULATOR_SIZE); - AcirProgram program = construct_mock_kernel_program(ivc.verification_queue, { num_app_public_inputs }); + acir_format::mock_ivc_oink_accumulation(ivc); + AcirProgram program = construct_mock_kernel_program(ivc.verification_queue); program.witness = {}; // erase witness to mimic VK construction context // Create a mock IVC instance from the IVC recursion constraints in the kernel program diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/proof_surgeon.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/proof_surgeon.hpp index 0b2d1768bca..40bbedb02a3 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/proof_surgeon.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/proof_surgeon.hpp @@ -146,11 +146,9 @@ class ProofSurgeon { static RecursionWitnessData populate_recursion_witness_data(bb::SlabVector& witness, std::vector& proof_witnesses, const std::vector& key_witnesses, - const size_t num_public_inputs) + const size_t num_public_inputs_to_extract) { // Extract all public inputs except for those corresponding to the aggregation object - ASSERT(num_public_inputs >= bb::PAIRING_POINT_ACCUMULATOR_SIZE); - const size_t num_public_inputs_to_extract = num_public_inputs - bb::PAIRING_POINT_ACCUMULATOR_SIZE; std::vector public_input_witnesses = cut_public_inputs_from_proof(proof_witnesses, num_public_inputs_to_extract); From c5863680ac1d9d623c10e6dab8e2f77540b10dca Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Fri, 29 Nov 2024 17:56:49 +0000 Subject: [PATCH 02/13] atomize a bit --- .../acir_format/ivc_recursion_constraint.cpp | 91 ++++++++++++++----- .../acir_format/ivc_recursion_constraint.hpp | 9 ++ 2 files changed, 75 insertions(+), 25 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp index 4aa0c666016..ea68ba48f5e 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp @@ -24,7 +24,7 @@ ClientIVC create_mock_ivc_from_constraints(const std::vector(PROOF_TYPE::PG) == constraint.proof_type) { - // perform equivalent mocking for PG accumulation + mock_ivc_pg_accumulation(ivc); } } @@ -34,7 +34,7 @@ ClientIVC create_mock_ivc_from_constraints(const std::vector mock_commitment_frs = field_conversion::convert_to_bn254_frs(mock_commitment); +/** + * @brief Create a mock oink proof and VK that have the correct structure but are not necessarily valid + * + */ +std::vector create_mock_oink_proof(const size_t dyadic_size, + const size_t num_public_inputs, + const size_t pub_inputs_offset) +{ + using Flavor = ClientIVC::Flavor; + using FF = ClientIVC::FF; + + std::vector proof; // Set proof preamble (metadata plus public inputs) - size_t total_num_public_inputs = bb::PAIRING_POINT_ACCUMULATOR_SIZE; - verifier_inputs.proof.emplace_back(structured_dyadic_size); - verifier_inputs.proof.emplace_back(total_num_public_inputs); - verifier_inputs.proof.emplace_back(pub_inputs_offset); - for (size_t i = 0; i < total_num_public_inputs; ++i) { - verifier_inputs.proof.emplace_back(0); + // WORKTODO: num pub inputs depends on app vs kernel; kernel has +16 from DB + proof.emplace_back(dyadic_size); + proof.emplace_back(num_public_inputs); + proof.emplace_back(pub_inputs_offset); + for (size_t i = 0; i < num_public_inputs; ++i) { + proof.emplace_back(0); } // Witness polynomial commitments + auto mock_commitment = curve::BN254::AffineElement::one(); + std::vector mock_commitment_frs = field_conversion::convert_to_bn254_frs(mock_commitment); for (size_t i = 0; i < Flavor::NUM_WITNESS_ENTITIES; ++i) { for (const FF& val : mock_commitment_frs) { - verifier_inputs.proof.emplace_back(val); + proof.emplace_back(val); } } + return proof; +} + +/** + * @brief Create a mock oink proof and VK that have the correct structure but are not necessarily valid + * + */ +std::shared_ptr create_mock_honk_vk(const size_t dyadic_size, + const size_t num_public_inputs, + const size_t pub_inputs_offset) +{ // Set relevant VK metadata and commitments - verifier_inputs.honk_verification_key = std::make_shared(); - verifier_inputs.honk_verification_key->circuit_size = structured_dyadic_size; - verifier_inputs.honk_verification_key->num_public_inputs = total_num_public_inputs; - verifier_inputs.honk_verification_key->pub_inputs_offset = blocks.pub_inputs.trace_offset; // must be set correctly - verifier_inputs.honk_verification_key->contains_pairing_point_accumulator = true; - for (auto& commitment : verifier_inputs.honk_verification_key->get_all()) { - commitment = mock_commitment; + auto honk_verification_key = std::make_shared(); + honk_verification_key->circuit_size = dyadic_size; + honk_verification_key->num_public_inputs = num_public_inputs; + honk_verification_key->pub_inputs_offset = pub_inputs_offset; // must be set correctly + honk_verification_key->contains_pairing_point_accumulator = true; + + for (auto& commitment : honk_verification_key->get_all()) { + commitment = curve::BN254::AffineElement::one(); // arbitrary mock commitment } - return verifier_inputs; + return honk_verification_key; } /** diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.hpp index ffa28d59a55..6182b2af5b9 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.hpp @@ -14,6 +14,15 @@ using namespace bb; ClientIVC create_mock_ivc_from_constraints(const std::vector& constraints); void mock_ivc_oink_accumulation(ClientIVC& ivc); +void mock_ivc_pg_accumulation(ClientIVC& ivc); + +std::vector create_mock_oink_proof(const size_t dyadic_size, + const size_t num_public_inputs, + const size_t pub_inputs_offset); + +std::shared_ptr create_mock_honk_vk(const size_t dyadic_size, + const size_t num_public_inputs, + const size_t pub_inputs_offset); ClientIVC::VerifierInputs create_dummy_vkey_and_proof_oink(const TraceSettings& trace_settings); From 0f7b33ba68c71fc56d28bb685f4f12fd260708a7 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Fri, 29 Nov 2024 18:50:44 +0000 Subject: [PATCH 03/13] generalize a bit for queue type --- .../acir_format/ivc_recursion_constraint.cpp | 49 ++++++++++--------- .../acir_format/ivc_recursion_constraint.hpp | 10 ++-- .../ivc_recursion_constraint.test.cpp | 4 +- 3 files changed, 35 insertions(+), 28 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp index ea68ba48f5e..9f541bdc119 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp @@ -13,7 +13,6 @@ namespace acir_format { using namespace bb; -using field_ct = stdlib::field_t; ClientIVC create_mock_ivc_from_constraints(const std::vector& constraints) { @@ -22,31 +21,15 @@ ClientIVC create_mock_ivc_from_constraints(const std::vector(PROOF_TYPE::OINK) == constraint.proof_type) { ASSERT(constraint.public_inputs.size() == 0); // Apps are assumed to have no public inputs - mock_ivc_oink_accumulation(ivc); + mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::OINK); } else if (static_cast(PROOF_TYPE::PG) == constraint.proof_type) { - mock_ivc_pg_accumulation(ivc); + mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::PG); } } return ivc; } -/** - * @brief Populate an IVC instance with data that mimics the state after accumulating the first app (which runs the oink - * prover) - * @details Mock state consists a mock verification queue entry of type OINK (proof, VK) and a mocked merge proof - * - * @param ivc - * @param num_public_inputs_app num pub inputs in accumulated app, excluding fixed components, e.g. pairing points - */ -void mock_ivc_oink_accumulation(ClientIVC& ivc) -{ - ClientIVC::VerifierInputs oink_entry = acir_format::create_dummy_vkey_and_proof_oink(ivc.trace_settings); - ivc.verification_queue.emplace_back(oink_entry); - ivc.merge_verification_queue.emplace_back(acir_format::create_dummy_merge_proof()); - ivc.initialized = true; -} - /** * @brief Populate an IVC instance with data that mimics the state after PG accumulation * @details Mock state consists a mock verification queue entry of type OINK (proof, VK) and a mocked merge proof @@ -54,9 +37,9 @@ void mock_ivc_oink_accumulation(ClientIVC& ivc) * @param ivc * @param num_public_inputs_app num pub inputs in accumulated app, excluding fixed components, e.g. pairing points */ -void mock_ivc_pg_accumulation(ClientIVC& ivc) +void mock_ivc_accumulation(ClientIVC& ivc, ClientIVC::QUEUE_TYPE type) { - ClientIVC::VerifierInputs entry = acir_format::create_dummy_vkey_and_proof_oink(ivc.trace_settings); + ClientIVC::VerifierInputs entry = acir_format::create_mock_verification_queue_entry(type, ivc.trace_settings); ivc.verification_queue.emplace_back(entry); ivc.merge_verification_queue.emplace_back(acir_format::create_dummy_merge_proof()); ivc.initialized = true; @@ -66,7 +49,8 @@ void mock_ivc_pg_accumulation(ClientIVC& ivc) * @brief Create a mock oink proof and VK that have the correct structure but are not necessarily valid * */ -ClientIVC::VerifierInputs create_dummy_vkey_and_proof_oink(const TraceSettings& trace_settings) +ClientIVC::VerifierInputs create_mock_verification_queue_entry(ClientIVC::QUEUE_TYPE type, + const TraceSettings& trace_settings) { MegaExecutionTraceBlocks blocks; blocks.set_fixed_block_sizes(trace_settings); @@ -77,7 +61,7 @@ ClientIVC::VerifierInputs create_dummy_vkey_and_proof_oink(const TraceSettings& ClientIVC::VerifierInputs verifier_inputs{}; - verifier_inputs.type = ClientIVC::QUEUE_TYPE::OINK; + verifier_inputs.type = type; verifier_inputs.proof = create_mock_oink_proof(dyadic_size, num_public_inputs, pub_inputs_offset); verifier_inputs.honk_verification_key = create_mock_honk_vk(dyadic_size, num_public_inputs, pub_inputs_offset); @@ -118,6 +102,25 @@ std::vector create_mock_oink_proof(const size_t dyadic_size, return proof; } +/** + * @brief Create a mock oink proof and VK that have the correct structure but are not necessarily valid + * + */ +std::vector create_mock_pg_proof(const size_t dyadic_size, + const size_t num_public_inputs, + const size_t pub_inputs_offset) +{ + // using Flavor = ClientIVC::Flavor; + using FF = ClientIVC::FF; + + // WORKTODO: num pub inputs depends on app vs kernel; kernel has +16 from DB + std::vector proof = create_mock_oink_proof(dyadic_size, num_public_inputs, pub_inputs_offset); + + // WORKTODO: mock pg stuff here + + return proof; +} + /** * @brief Create a mock oink proof and VK that have the correct structure but are not necessarily valid * diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.hpp index 6182b2af5b9..7236e62e487 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.hpp @@ -13,18 +13,22 @@ using namespace bb; ClientIVC create_mock_ivc_from_constraints(const std::vector& constraints); -void mock_ivc_oink_accumulation(ClientIVC& ivc); -void mock_ivc_pg_accumulation(ClientIVC& ivc); +void mock_ivc_accumulation(ClientIVC& ivc, ClientIVC::QUEUE_TYPE type); std::vector create_mock_oink_proof(const size_t dyadic_size, const size_t num_public_inputs, const size_t pub_inputs_offset); +std::vector create_mock_pg_proof(const size_t dyadic_size, + const size_t num_public_inputs, + const size_t pub_inputs_offset); + std::shared_ptr create_mock_honk_vk(const size_t dyadic_size, const size_t num_public_inputs, const size_t pub_inputs_offset); -ClientIVC::VerifierInputs create_dummy_vkey_and_proof_oink(const TraceSettings& trace_settings); +ClientIVC::VerifierInputs create_mock_verification_queue_entry(ClientIVC::QUEUE_TYPE type, + const TraceSettings& trace_settings); ClientIVC::MergeProof create_dummy_merge_proof(); diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp index 5775b5473e2..c0c6e3d64e2 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp @@ -192,7 +192,7 @@ TEST_F(IvcRecursionConstraintTest, GenerateVK) { ClientIVC ivc{ trace_settings }; - acir_format::mock_ivc_oink_accumulation(ivc); + acir_format::mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::OINK); // Construct kernel consisting only of the kernel completion logic AcirProgram program = construct_mock_kernel_program(ivc.verification_queue); @@ -240,7 +240,7 @@ TEST_F(IvcRecursionConstraintTest, GenerateVKFromConstraints) ClientIVC ivc{ trace_settings }; // Construct kernel consisting only of the kernel completion logic - acir_format::mock_ivc_oink_accumulation(ivc); + acir_format::mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::OINK); AcirProgram program = construct_mock_kernel_program(ivc.verification_queue); program.witness = {}; // erase witness to mimic VK construction context From ea5fafe9eeb4553334b12b6f4edea20a1ad5357c Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Fri, 29 Nov 2024 21:42:48 +0000 Subject: [PATCH 04/13] reset kernel vk test runs but fails; debug with hash_circuit --- .../acir_format/ivc_recursion_constraint.cpp | 93 ++++++++++++++----- .../acir_format/ivc_recursion_constraint.hpp | 9 +- .../ivc_recursion_constraint.test.cpp | 75 +++++++++++++-- .../honk_verifier/oink_recursive_verifier.cpp | 6 ++ .../ultra_circuit_builder.cpp | 70 +++++++++++--- 5 files changed, 207 insertions(+), 46 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp index 9f541bdc119..59982d9742f 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp @@ -16,15 +16,28 @@ using namespace bb; ClientIVC create_mock_ivc_from_constraints(const std::vector& constraints) { + // WORKTODO: the settings here will just be set based on the one and only default trace structuring ClientIVC ivc{ { SMALL_TEST_STRUCTURE } }; - for (const auto& constraint : constraints) { - if (static_cast(PROOF_TYPE::OINK) == constraint.proof_type) { - ASSERT(constraint.public_inputs.size() == 0); // Apps are assumed to have no public inputs - mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::OINK); - } else if (static_cast(PROOF_TYPE::PG) == constraint.proof_type) { - mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::PG); - } + uint32_t oink_type = static_cast(PROOF_TYPE::OINK); + uint32_t pg_type = static_cast(PROOF_TYPE::PG); + + // There are only three valid combinations of IVC recursion constraints: (1) a single Oink recursive verification + // for an app circuit (init kernel), (2) a single PG recursive verification for a kernel circuit (reset kernel, tail + // kernel), or (3) two PG recursive verifications for a kernel and an app in that order (inner kernel). + if (constraints.size() == 1 && constraints[0].proof_type == oink_type) { + mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::OINK, /*is_kernel=*/false); + } else if (constraints.size() == 1 && constraints[0].proof_type == pg_type) { + ivc.verifier_accumulator = create_mock_decider_vk(); + mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::PG, /*is_kernel=*/true); + } else if (constraints.size() == 2) { + ASSERT(constraints[0].proof_type == pg_type && constraints[1].proof_type == pg_type); + ivc.verifier_accumulator = create_mock_decider_vk(); + mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::PG, /*is_kernel=*/true); + mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::PG, /*is_kernel=*/false); + } else { + info("WARNING: Invalid set of IVC recursion constraints!"); + ASSERT(false); } return ivc; @@ -37,9 +50,10 @@ ClientIVC create_mock_ivc_from_constraints(const std::vector(is_kernel) * bb::PROPAGATED_DATABUS_COMMITMENTS_SIZE; size_t pub_inputs_offset = blocks.pub_inputs.trace_offset; ClientIVC::VerifierInputs verifier_inputs{}; - verifier_inputs.type = type; - verifier_inputs.proof = create_mock_oink_proof(dyadic_size, num_public_inputs, pub_inputs_offset); + verifier_inputs.type = verification_type; + if (verification_type == ClientIVC::QUEUE_TYPE::OINK) { + verifier_inputs.proof = create_mock_oink_proof(dyadic_size, num_public_inputs, pub_inputs_offset); + } else { // ClientIVC::QUEUE_TYPE::PG) + verifier_inputs.proof = create_mock_pg_proof(dyadic_size, num_public_inputs, pub_inputs_offset); + } verifier_inputs.honk_verification_key = create_mock_honk_vk(dyadic_size, num_public_inputs, pub_inputs_offset); return verifier_inputs; @@ -81,16 +101,17 @@ std::vector create_mock_oink_proof(const size_t dyadic_size, std::vector proof; - // Set proof preamble (metadata plus public inputs) - // WORKTODO: num pub inputs depends on app vs kernel; kernel has +16 from DB + // Populate proof metadata proof.emplace_back(dyadic_size); proof.emplace_back(num_public_inputs); proof.emplace_back(pub_inputs_offset); + + // Populate mock public inputs for (size_t i = 0; i < num_public_inputs; ++i) { proof.emplace_back(0); } - // Witness polynomial commitments + // Populate mock witness polynomial commitments auto mock_commitment = curve::BN254::AffineElement::one(); std::vector mock_commitment_frs = field_conversion::convert_to_bn254_frs(mock_commitment); for (size_t i = 0; i < Flavor::NUM_WITNESS_ENTITIES; ++i) { @@ -103,7 +124,7 @@ std::vector create_mock_oink_proof(const size_t dyadic_size, } /** - * @brief Create a mock oink proof and VK that have the correct structure but are not necessarily valid + * @brief Create a mock PG proof and VK that have the correct structure but are not necessarily valid * */ std::vector create_mock_pg_proof(const size_t dyadic_size, @@ -112,11 +133,20 @@ std::vector create_mock_pg_proof(const size_t dyadic_size, { // using Flavor = ClientIVC::Flavor; using FF = ClientIVC::FF; + using DeciderProvingKeys = ClientIVC::DeciderProvingKeys; - // WORKTODO: num pub inputs depends on app vs kernel; kernel has +16 from DB + // The first part of a PG proof is an Oink proof std::vector proof = create_mock_oink_proof(dyadic_size, num_public_inputs, pub_inputs_offset); - // WORKTODO: mock pg stuff here + // Populate mock perturbator coefficients + for (size_t idx = 1; idx <= CONST_PG_LOG_N; idx++) { + proof.emplace_back(0); + } + + // Populate mock combiner quotient coefficients + for (size_t idx = DeciderProvingKeys::NUM; idx < DeciderProvingKeys::BATCHED_EXTENDED_LENGTH; idx++) { + proof.emplace_back(0); + } return proof; } @@ -143,6 +173,24 @@ std::shared_ptr create_mock_honk_vk(const size_t return honk_verification_key; } +/** + * @brief + * + */ +std::shared_ptr create_mock_decider_vk() +{ + // Set relevant VK metadata and commitments + auto decider_verification_key = std::make_shared(); + decider_verification_key->verification_key = create_mock_honk_vk(0, 0, 0); + decider_verification_key->is_accumulator = true; + + for (auto& commitment : decider_verification_key->witness_commitments.get_all()) { + commitment = curve::BN254::AffineElement::one(); // arbitrary mock commitment + } + + return decider_verification_key; +} + /** * @brief Create a mock merge proof which has the correct structure but is not necessarily valid * @@ -150,7 +198,7 @@ std::shared_ptr create_mock_honk_vk(const size_t */ ClientIVC::MergeProof create_dummy_merge_proof() { - using FF = bb::fr; + using FF = ClientIVC::FF; std::vector proof; @@ -191,8 +239,7 @@ void populate_dummy_vk_in_constraint(MegaCircuitBuilder& builder, const std::shared_ptr& mock_verification_key, std::vector& key_witness_indices) { - using Flavor = MegaFlavor; - using FF = Flavor::FF; + using FF = ClientIVC::FF; // Convert the VerificationKey to fields std::vector mock_vk_fields = mock_verification_key->to_field_elements(); diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.hpp index 7236e62e487..90e0657ab14 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.hpp @@ -13,7 +13,7 @@ using namespace bb; ClientIVC create_mock_ivc_from_constraints(const std::vector& constraints); -void mock_ivc_accumulation(ClientIVC& ivc, ClientIVC::QUEUE_TYPE type); +void mock_ivc_accumulation(ClientIVC& ivc, ClientIVC::QUEUE_TYPE type, const bool is_kernel); std::vector create_mock_oink_proof(const size_t dyadic_size, const size_t num_public_inputs, @@ -27,8 +27,11 @@ std::shared_ptr create_mock_honk_vk(const size_t const size_t num_public_inputs, const size_t pub_inputs_offset); -ClientIVC::VerifierInputs create_mock_verification_queue_entry(ClientIVC::QUEUE_TYPE type, - const TraceSettings& trace_settings); +std::shared_ptr create_mock_decider_vk(); + +ClientIVC::VerifierInputs create_mock_verification_queue_entry(const ClientIVC::QUEUE_TYPE type, + const TraceSettings& trace_settings, + const bool is_kernel); ClientIVC::MergeProof create_dummy_merge_proof(); diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp index c0c6e3d64e2..e4f2040a12e 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp @@ -192,7 +192,7 @@ TEST_F(IvcRecursionConstraintTest, GenerateVK) { ClientIVC ivc{ trace_settings }; - acir_format::mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::OINK); + acir_format::mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::OINK, /*is_kernel=*/false); // Construct kernel consisting only of the kernel completion logic AcirProgram program = construct_mock_kernel_program(ivc.verification_queue); @@ -213,7 +213,7 @@ TEST_F(IvcRecursionConstraintTest, GenerateVK) } // Test generation of "init" kernel VK via dummy IVC data -TEST_F(IvcRecursionConstraintTest, GenerateVKFromConstraints) +TEST_F(IvcRecursionConstraintTest, GenerateInitKernelVKFromConstraints) { const TraceSettings trace_settings{ SMALL_TEST_STRUCTURE }; @@ -240,15 +240,78 @@ TEST_F(IvcRecursionConstraintTest, GenerateVKFromConstraints) ClientIVC ivc{ trace_settings }; // Construct kernel consisting only of the kernel completion logic - acir_format::mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::OINK); + acir_format::mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::OINK, /*is_kernel=*/false); AcirProgram program = construct_mock_kernel_program(ivc.verification_queue); - program.witness = {}; // erase witness to mimic VK construction context // Create a mock IVC instance from the IVC recursion constraints in the kernel program ClientIVC mock_ivc = create_mock_ivc_from_constraints(program.constraints.ivc_recursion_constraints); - // Create a kernel circuit from the kernel program and the mocked IVC - Builder kernel = acir_format::create_kernel_circuit(program.constraints, mock_ivc); + // Create kernel circuit from kernel program and the mocked IVC (empty witness mimics VK construction context) + Builder kernel = acir_format::create_kernel_circuit(program.constraints, mock_ivc, /*witness=*/{}); + // Note: adding pairing point normally happens in accumulate() + kernel.add_pairing_point_accumulator(stdlib::recursion::init_default_agg_obj_indices(kernel)); + + // Manually construct the VK for the kernel circuit + auto proving_key = std::make_shared>(kernel, ivc.trace_settings); + MegaProver prover(proving_key); + kernel_vk = std::make_shared(prover.proving_key->proving_key); + } + + // PCS verification keys will not match so set to null before comparing + kernel_vk->pcs_verification_key = nullptr; + expected_kernel_vk->pcs_verification_key = nullptr; + + // Compare the VK constructed via running the IVc with the one constructed via mocking + EXPECT_EQ(*kernel_vk.get(), *expected_kernel_vk.get()); +} + +// Test generation of "init" kernel VK via dummy IVC data +TEST_F(IvcRecursionConstraintTest, GenerateResetKernelVKFromConstraints) +{ + const TraceSettings trace_settings{ SMALL_TEST_STRUCTURE }; + + ClientIVC genuine_ivc{ trace_settings }; + + // First, construct the kernel VK by running the full IVC (accumulate one app and one kernel) + std::shared_ptr expected_kernel_vk; + { + // ClientIVC ivc{ trace_settings }; + + // Construct and accumulate mock app_circuit + Builder app_circuit = construct_mock_app_circuit(genuine_ivc); + genuine_ivc.accumulate(app_circuit); + + { // Construct and accumulate a mock INIT kernel (oink recursion for app accumulation) + AcirProgram program = construct_mock_kernel_program(genuine_ivc.verification_queue); + Builder kernel = acir_format::create_kernel_circuit(program.constraints, genuine_ivc, program.witness); + genuine_ivc.accumulate(kernel); + } + + { // Construct and accumulate a mock RESET kernel (PG recursion for kernel accumulation) + EXPECT_TRUE(genuine_ivc.verification_queue.size() == 1); + EXPECT_TRUE(genuine_ivc.verification_queue[0].type == bb::ClientIVC::QUEUE_TYPE::PG); + AcirProgram program = construct_mock_kernel_program(genuine_ivc.verification_queue); + Builder kernel = acir_format::create_kernel_circuit(program.constraints, genuine_ivc, program.witness); + genuine_ivc.accumulate(kernel); + } + + expected_kernel_vk = genuine_ivc.verification_queue.back().honk_verification_key; + } + + // Now, construct the kernel VK by mocking the IVC state prior to kernel construction + std::shared_ptr kernel_vk; + { + ClientIVC ivc{ trace_settings }; + + // Construct kernel consisting only of the kernel completion logic + acir_format::mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::PG, /*is_kernel=*/true); + AcirProgram program = construct_mock_kernel_program(ivc.verification_queue); + + // Create a mock IVC instance from the IVC recursion constraints in the kernel program + ClientIVC mock_ivc = create_mock_ivc_from_constraints(program.constraints.ivc_recursion_constraints); + + // Create kernel circuit from kernel program and the mocked IVC (empty witness mimics VK construction context) + Builder kernel = acir_format::create_kernel_circuit(program.constraints, mock_ivc, /*witness=*/{}); // Note: adding pairing point normally happens in accumulate() kernel.add_pairing_point_accumulator(stdlib::recursion::init_default_agg_obj_indices(kernel)); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/oink_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/oink_recursive_verifier.cpp index d9974b8f056..c04859a5ad7 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/oink_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/oink_recursive_verifier.cpp @@ -48,6 +48,8 @@ template void OinkRecursiveVerifier_::verify() FF pub_inputs_offset = transcript->template receive_from_prover(domain_separator + "pub_inputs_offset"); if (static_cast(circuit_size.get_value()) != verification_key->verification_key->circuit_size) { + info("Proof circuit size = ", circuit_size.get_value()); + info("VK circuit size = ", verification_key->verification_key->circuit_size); throw_or_abort("OinkRecursiveVerifier::verify: proof circuit size does not match verification key"); } if (static_cast(public_input_size.get_value()) != verification_key->verification_key->num_public_inputs) { @@ -127,6 +129,10 @@ template void OinkRecursiveVerifier_::verify() verification_key->witness_commitments = std::move(commitments); verification_key->public_inputs = std::move(public_inputs); verification_key->alphas = std::move(alphas); + + if constexpr (!IsSimulator) { + info("Circuit hash = ", builder->hash_circuit()); + } } template class OinkRecursiveVerifier_>; diff --git a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_circuit_builder.cpp b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_circuit_builder.cpp index 29bf01cc42c..5cc92a88391 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_circuit_builder.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_circuit_builder.cpp @@ -2831,34 +2831,76 @@ void UltraCircuitBuilder_::create_poseidon2_internal_gate(const poseidon2_in template uint256_t UltraCircuitBuilder_::hash_circuit() { - finalize_circuit(/*ensure_nonzero=*/false); - size_t sum_of_block_sizes(0); - for (auto& block : blocks.get()) { - sum_of_block_sizes += block.size(); - } - - size_t num_bytes_in_selectors = sizeof(FF) * ExecutionTrace::NUM_SELECTORS * sum_of_block_sizes; - size_t num_bytes_in_wires_and_copy_constraints = - sizeof(uint32_t) * (ExecutionTrace::NUM_WIRES * sum_of_block_sizes + this->real_variable_index.size()); - size_t num_bytes_to_hash = num_bytes_in_selectors + num_bytes_in_wires_and_copy_constraints; - - std::vector to_hash(num_bytes_to_hash); + std::vector to_hash; const auto convert_and_insert = [&to_hash](auto& vector) { std::vector buffer = to_buffer(vector); to_hash.insert(to_hash.end(), buffer.begin(), buffer.end()); }; + // DEBUG: selectors! + // for (auto& block : blocks.get()) { + // convert_and_insert(block.q_m()); + // } + // for (auto& block : blocks.get()) { + // std::for_each(block.get_gate_selectors().begin(), block.get_gate_selectors().end(), convert_and_insert); + // } for (auto& block : blocks.get()) { std::for_each(block.selectors.begin(), block.selectors.end(), convert_and_insert); - std::for_each(block.wires.begin(), block.wires.end(), convert_and_insert); } - convert_and_insert(this->real_variable_index); + + // // DEBUG: wires! + // for (auto& block : blocks.get()) { + // std::for_each(block.wires.begin(), block.wires.end(), convert_and_insert); + // } + + // for (auto& block : blocks.get()) { + // std::for_each(block.selectors.begin(), block.selectors.end(), convert_and_insert); + // std::for_each(block.wires.begin(), block.wires.end(), convert_and_insert); + // } + // convert_and_insert(this->real_variable_index); return from_buffer(crypto::sha256(to_hash)); } +// template uint256_t UltraCircuitBuilder_::hash_circuit() +// { +// finalize_circuit(/*ensure_nonzero=*/false); + +// size_t sum_of_block_sizes(0); +// for (auto& block : blocks.get()) { +// sum_of_block_sizes += block.size(); +// } + +// size_t num_bytes_in_selectors = sizeof(FF) * ExecutionTrace::NUM_SELECTORS * sum_of_block_sizes; +// size_t num_bytes_in_wires_and_copy_constraints = +// sizeof(uint32_t) * (ExecutionTrace::NUM_WIRES * sum_of_block_sizes + this->real_variable_index.size()); +// size_t num_bytes_to_hash = num_bytes_in_selectors + num_bytes_in_wires_and_copy_constraints; + +// std::vector to_hash(num_bytes_to_hash); + +// const auto convert_and_insert = [&to_hash](auto& vector) { +// std::vector buffer = to_buffer(vector); +// to_hash.insert(to_hash.end(), buffer.begin(), buffer.end()); +// }; + +// for (auto& block : blocks.get()) { +// convert_and_insert(block.q_m()); +// } +// // for (auto& block : blocks.get()) { +// // std::for_each(block.get_gate_selectors().begin(), block.get_gate_selectors().end(), convert_and_insert); +// // } + +// // for (auto& block : blocks.get()) { +// // std::for_each(block.selectors.begin(), block.selectors.end(), convert_and_insert); +// // std::for_each(block.wires.begin(), block.wires.end(), convert_and_insert); +// // } +// // convert_and_insert(this->real_variable_index); + +// return from_buffer(crypto::sha256(to_hash)); +// } + /** * Export the existing circuit as msgpack compatible buffer. * Should be called after `finalize_circuit()` From 0f1b45dd77c447981535dd3d14626e0b2277d604 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Mon, 2 Dec 2024 17:49:01 +0000 Subject: [PATCH 05/13] vk test passes for a reset kernel --- .../barretenberg/client_ivc/client_ivc.cpp | 7 ++++++ .../acir_format/ivc_recursion_constraint.cpp | 13 ++++++++++- .../honk_verifier/oink_recursive_verifier.cpp | 4 ---- .../protogalaxy_recursive_verifier.cpp | 22 +++++++++++++++++++ 4 files changed, 41 insertions(+), 5 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp index 6412b711c94..7345c768d5b 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp @@ -93,6 +93,8 @@ void ClientIVC::perform_recursive_verification_and_databus_consistency_checks( } } + // info("PRE-DB HASH = ", circuit.hash_circuit()); + // Set the return data commitment to be propagated on the public inputs of the present kernel and peform consistency // checks between the calldata commitments and the return data commitments contained within the public inputs bus_depot.set_return_data_to_be_propagated_and_perform_consistency_checks( @@ -101,6 +103,8 @@ void ClientIVC::perform_recursive_verification_and_databus_consistency_checks( decider_vk->witness_commitments.secondary_calldata, decider_vk->public_inputs, decider_vk->verification_key->databus_propagation_data); + + // info("POST-DB HASH = ", circuit.hash_circuit()); } /** @@ -133,6 +137,7 @@ void ClientIVC::complete_kernel_circuit_logic(ClientCircuit& circuit) if (stdlib_verification_queue.empty()) { instantiate_stdlib_verification_queue(circuit); } + // info("HASH = ", circuit.hash_circuit()); // Peform recursive verification and databus consistency checks for each entry in the verification queue for (auto& [proof, vkey, type] : stdlib_verification_queue) { @@ -140,6 +145,8 @@ void ClientIVC::complete_kernel_circuit_logic(ClientCircuit& circuit) } stdlib_verification_queue.clear(); + // info("POST HASH = ", circuit.hash_circuit()); + // Propagate return data commitments via the public inputs for use in databus consistency checks bus_depot.propagate_return_data_commitments(circuit); diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp index 59982d9742f..29d97b868de 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp @@ -85,6 +85,14 @@ ClientIVC::VerifierInputs create_mock_verification_queue_entry(const ClientIVC:: } verifier_inputs.honk_verification_key = create_mock_honk_vk(dyadic_size, num_public_inputs, pub_inputs_offset); + // If the verification queue entry corresponds to a kernel circuit, set the databus data to indicate the presence of + // propagated return data commitments on the public inputs + if (is_kernel) { + verifier_inputs.honk_verification_key->databus_propagation_data.is_kernel = true; + verifier_inputs.honk_verification_key->databus_propagation_data.kernel_return_data_public_input_idx = 0; + verifier_inputs.honk_verification_key->databus_propagation_data.app_return_data_public_input_idx = 8; + } + return verifier_inputs; } @@ -179,10 +187,13 @@ std::shared_ptr create_mock_honk_vk(const size_t */ std::shared_ptr create_mock_decider_vk() { + using FF = ClientIVC::FF; + // Set relevant VK metadata and commitments auto decider_verification_key = std::make_shared(); - decider_verification_key->verification_key = create_mock_honk_vk(0, 0, 0); + decider_verification_key->verification_key = create_mock_honk_vk(0, 0, 0); // metadata does not need to be accurate decider_verification_key->is_accumulator = true; + decider_verification_key->gate_challenges = std::vector(static_cast(CONST_PG_LOG_N), 0); for (auto& commitment : decider_verification_key->witness_commitments.get_all()) { commitment = curve::BN254::AffineElement::one(); // arbitrary mock commitment diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/oink_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/oink_recursive_verifier.cpp index c04859a5ad7..65c3e007f9d 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/oink_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/oink_recursive_verifier.cpp @@ -129,10 +129,6 @@ template void OinkRecursiveVerifier_::verify() verification_key->witness_commitments = std::move(commitments); verification_key->public_inputs = std::move(public_inputs); verification_key->alphas = std::move(alphas); - - if constexpr (!IsSimulator) { - info("Circuit hash = ", builder->hash_circuit()); - } } template class OinkRecursiveVerifier_>; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/protogalaxy_verifier/protogalaxy_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/protogalaxy_verifier/protogalaxy_recursive_verifier.cpp index 10739d2aa45..a013e5d5c82 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/protogalaxy_verifier/protogalaxy_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/protogalaxy_verifier/protogalaxy_recursive_verifier.cpp @@ -167,8 +167,17 @@ std::shared_ptr ProtogalaxyRecursiv accumulator->is_accumulator = true; accumulator->target_sum = perturbator_evaluation * lagranges[0] + vanishing_polynomial_at_challenge * combiner_quotient_at_challenge; + + // if constexpr (!IsSimulator) { + // info("HASH = ", builder->hash_circuit()); + // } + accumulator->gate_challenges = update_gate_challenges(perturbator_challenge, accumulator->gate_challenges, deltas); + // if constexpr (!IsSimulator) { + // info("HASH = ", builder->hash_circuit()); + // } + // Set the accumulator circuit size data based on the max of the keys being accumulated const size_t accumulator_log_circuit_size = keys_to_fold.get_max_log_circuit_size(); accumulator->verification_key->log_circuit_size = accumulator_log_circuit_size; @@ -178,11 +187,20 @@ std::shared_ptr ProtogalaxyRecursiv for (auto [combination, to_combine] : zip_view(accumulator->alphas, keys_to_fold.get_alphas())) { combination = linear_combination(to_combine, lagranges); } + + // if constexpr (!IsSimulator) { + // info("HASH = ", builder->hash_circuit()); + // } + for (auto [combination, to_combine] : zip_view(accumulator->relation_parameters.get_to_fold(), keys_to_fold.get_relation_parameters())) { combination = linear_combination(to_combine, lagranges); } + // if constexpr (!IsSimulator) { + // info("HASH = ", builder->hash_circuit()); + // } + auto accumulator_vkey = accumulator->verification_key->get_all(); for (size_t i = 0; i < Flavor::NUM_PRECOMPUTED_ENTITIES; ++i) { accumulator_vkey[i] = output_commitments[i]; @@ -193,6 +211,10 @@ std::shared_ptr ProtogalaxyRecursiv accumulator_witnesses[i] = output_commitments[i + accumulator_vkey.size()]; } + // if constexpr (!IsSimulator) { + // info("HASH = ", builder->hash_circuit()); + // } + return accumulator; } From ec11069d02f191e67c61b67f49abafc38ec0827f Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Mon, 2 Dec 2024 18:52:51 +0000 Subject: [PATCH 06/13] inner kernel vk consistency passes --- .../ivc_recursion_constraint.test.cpp | 76 ++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp index e4f2040a12e..010a787e24f 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp @@ -265,7 +265,7 @@ TEST_F(IvcRecursionConstraintTest, GenerateInitKernelVKFromConstraints) EXPECT_EQ(*kernel_vk.get(), *expected_kernel_vk.get()); } -// Test generation of "init" kernel VK via dummy IVC data +// Test generation of "reset" or "tail" kernel VK via dummy IVC data TEST_F(IvcRecursionConstraintTest, GenerateResetKernelVKFromConstraints) { const TraceSettings trace_settings{ SMALL_TEST_STRUCTURE }; @@ -325,6 +325,80 @@ TEST_F(IvcRecursionConstraintTest, GenerateResetKernelVKFromConstraints) kernel_vk->pcs_verification_key = nullptr; expected_kernel_vk->pcs_verification_key = nullptr; + // Compare the VK constructed via running the IVc with the one constructed via mocking + EXPECT_EQ(*kernel_vk.get(), *expected_kernel_vk.get()); +} + +// Test generation of "inner" kernel VK via dummy IVC data +TEST_F(IvcRecursionConstraintTest, GenerateInnerKernelVKFromConstraints) +{ + const TraceSettings trace_settings{ SMALL_TEST_STRUCTURE }; + + ClientIVC genuine_ivc{ trace_settings }; + + // First, construct the kernel VK by running the full IVC (accumulate one app and one kernel) + std::shared_ptr expected_kernel_vk; + { + // ClientIVC ivc{ trace_settings }; + + // Construct and accumulate mock app_circuit + { + Builder app_circuit = construct_mock_app_circuit(genuine_ivc); + genuine_ivc.accumulate(app_circuit); + } + + { // Construct and accumulate a mock INIT kernel (oink recursion for app accumulation) + AcirProgram program = construct_mock_kernel_program(genuine_ivc.verification_queue); + Builder kernel = acir_format::create_kernel_circuit(program.constraints, genuine_ivc, program.witness); + genuine_ivc.accumulate(kernel); + } + + // Construct and accumulate a second mock app_circuit + { + Builder app_circuit = construct_mock_app_circuit(genuine_ivc); + genuine_ivc.accumulate(app_circuit); + } + + { // Construct and accumulate a mock RESET kernel (PG recursion for kernel accumulation) + EXPECT_TRUE(genuine_ivc.verification_queue.size() == 2); + EXPECT_TRUE(genuine_ivc.verification_queue[0].type == bb::ClientIVC::QUEUE_TYPE::PG); + EXPECT_TRUE(genuine_ivc.verification_queue[1].type == bb::ClientIVC::QUEUE_TYPE::PG); + AcirProgram program = construct_mock_kernel_program(genuine_ivc.verification_queue); + Builder kernel = acir_format::create_kernel_circuit(program.constraints, genuine_ivc, program.witness); + genuine_ivc.accumulate(kernel); + } + + expected_kernel_vk = genuine_ivc.verification_queue.back().honk_verification_key; + } + + // Now, construct the kernel VK by mocking the IVC state prior to kernel construction + std::shared_ptr kernel_vk; + { + ClientIVC ivc{ trace_settings }; + + // Construct kernel consisting only of the kernel completion logic + acir_format::mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::PG, /*is_kernel=*/true); + acir_format::mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::PG, /*is_kernel=*/false); + AcirProgram program = construct_mock_kernel_program(ivc.verification_queue); + + // Create a mock IVC instance from the IVC recursion constraints in the kernel program + ClientIVC mock_ivc = create_mock_ivc_from_constraints(program.constraints.ivc_recursion_constraints); + + // Create kernel circuit from kernel program and the mocked IVC (empty witness mimics VK construction context) + Builder kernel = acir_format::create_kernel_circuit(program.constraints, mock_ivc, /*witness=*/{}); + // Note: adding pairing point normally happens in accumulate() + kernel.add_pairing_point_accumulator(stdlib::recursion::init_default_agg_obj_indices(kernel)); + + // Manually construct the VK for the kernel circuit + auto proving_key = std::make_shared>(kernel, ivc.trace_settings); + MegaProver prover(proving_key); + kernel_vk = std::make_shared(prover.proving_key->proving_key); + } + + // PCS verification keys will not match so set to null before comparing + kernel_vk->pcs_verification_key = nullptr; + expected_kernel_vk->pcs_verification_key = nullptr; + // Compare the VK constructed via running the IVc with the one constructed via mocking EXPECT_EQ(*kernel_vk.get(), *expected_kernel_vk.get()); } \ No newline at end of file From 325d2efdc786e47d65fd1d3cb8f33391b5bde1fa Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Mon, 2 Dec 2024 20:13:02 +0000 Subject: [PATCH 07/13] simplify test suit a bit --- .../acir_format/ivc_recursion_constraint.cpp | 33 +++-- .../ivc_recursion_constraint.test.cpp | 121 ++++++++---------- 2 files changed, 71 insertions(+), 83 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp index 29d97b868de..0d837e2cdb9 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp @@ -67,33 +67,42 @@ ClientIVC::VerifierInputs create_mock_verification_queue_entry(const ClientIVC:: const TraceSettings& trace_settings, const bool is_kernel) { + using FF = ClientIVC::FF; + using MegaVerificationKey = ClientIVC::MegaVerificationKey; + + // WORKTODO: is there a way to use some internal IVC data for this instead of constructing blocks? MegaExecutionTraceBlocks blocks; blocks.set_fixed_block_sizes(trace_settings); blocks.compute_offsets(/*is_structured=*/true); size_t dyadic_size = blocks.get_structured_dyadic_size(); - size_t num_public_inputs = - bb::PAIRING_POINT_ACCUMULATOR_SIZE + static_cast(is_kernel) * bb::PROPAGATED_DATABUS_COMMITMENTS_SIZE; + size_t num_public_inputs = bb::PAIRING_POINT_ACCUMULATOR_SIZE; + if (is_kernel) { + num_public_inputs += bb::PROPAGATED_DATABUS_COMMITMENTS_SIZE; + } size_t pub_inputs_offset = blocks.pub_inputs.trace_offset; - ClientIVC::VerifierInputs verifier_inputs{}; - - verifier_inputs.type = verification_type; + // Construct a mock Oink or PG proof + std::vector proof; if (verification_type == ClientIVC::QUEUE_TYPE::OINK) { - verifier_inputs.proof = create_mock_oink_proof(dyadic_size, num_public_inputs, pub_inputs_offset); + proof = create_mock_oink_proof(dyadic_size, num_public_inputs, pub_inputs_offset); } else { // ClientIVC::QUEUE_TYPE::PG) - verifier_inputs.proof = create_mock_pg_proof(dyadic_size, num_public_inputs, pub_inputs_offset); + proof = create_mock_pg_proof(dyadic_size, num_public_inputs, pub_inputs_offset); } - verifier_inputs.honk_verification_key = create_mock_honk_vk(dyadic_size, num_public_inputs, pub_inputs_offset); + + // Construct a mock MegaHonk verification key + std::shared_ptr verification_key = + create_mock_honk_vk(dyadic_size, num_public_inputs, pub_inputs_offset); // If the verification queue entry corresponds to a kernel circuit, set the databus data to indicate the presence of // propagated return data commitments on the public inputs if (is_kernel) { - verifier_inputs.honk_verification_key->databus_propagation_data.is_kernel = true; - verifier_inputs.honk_verification_key->databus_propagation_data.kernel_return_data_public_input_idx = 0; - verifier_inputs.honk_verification_key->databus_propagation_data.app_return_data_public_input_idx = 8; + // WORKTODO: how can we make this a little less magical? + verification_key->databus_propagation_data.is_kernel = true; + verification_key->databus_propagation_data.kernel_return_data_public_input_idx = 0; + verification_key->databus_propagation_data.app_return_data_public_input_idx = 8; } - return verifier_inputs; + return ClientIVC::VerifierInputs{ proof, verification_key, verification_type }; } /** diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp index 010a787e24f..413893cc862 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp @@ -103,6 +103,24 @@ class IvcRecursionConstraintTest : public ::testing::Test { return program; } + static std::shared_ptr construct_kernel_vk_from_acir_program( + AcirProgram& program, const TraceSettings& trace_settings) + { + // Create a mock IVC instance from the IVC recursion constraints in the kernel program + ClientIVC mock_ivc = create_mock_ivc_from_constraints(program.constraints.ivc_recursion_constraints); + + // Create kernel circuit from kernel program and the mocked IVC (empty witness mimics VK construction context) + Builder kernel = acir_format::create_kernel_circuit(program.constraints, mock_ivc, /*witness=*/{}); + // Note: adding pairing point normally happens in accumulate() + kernel.add_pairing_point_accumulator(stdlib::recursion::init_default_agg_obj_indices(kernel)); + + // Manually construct the VK for the kernel circuit + auto proving_key = std::make_shared(kernel, trace_settings); + MegaProver prover(proving_key); + + return std::make_shared(prover.proving_key->proving_key); + } + protected: void SetUp() override { @@ -243,18 +261,7 @@ TEST_F(IvcRecursionConstraintTest, GenerateInitKernelVKFromConstraints) acir_format::mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::OINK, /*is_kernel=*/false); AcirProgram program = construct_mock_kernel_program(ivc.verification_queue); - // Create a mock IVC instance from the IVC recursion constraints in the kernel program - ClientIVC mock_ivc = create_mock_ivc_from_constraints(program.constraints.ivc_recursion_constraints); - - // Create kernel circuit from kernel program and the mocked IVC (empty witness mimics VK construction context) - Builder kernel = acir_format::create_kernel_circuit(program.constraints, mock_ivc, /*witness=*/{}); - // Note: adding pairing point normally happens in accumulate() - kernel.add_pairing_point_accumulator(stdlib::recursion::init_default_agg_obj_indices(kernel)); - - // Manually construct the VK for the kernel circuit - auto proving_key = std::make_shared>(kernel, ivc.trace_settings); - MegaProver prover(proving_key); - kernel_vk = std::make_shared(prover.proving_key->proving_key); + kernel_vk = construct_kernel_vk_from_acir_program(program, trace_settings); } // PCS verification keys will not match so set to null before comparing @@ -270,32 +277,30 @@ TEST_F(IvcRecursionConstraintTest, GenerateResetKernelVKFromConstraints) { const TraceSettings trace_settings{ SMALL_TEST_STRUCTURE }; - ClientIVC genuine_ivc{ trace_settings }; - // First, construct the kernel VK by running the full IVC (accumulate one app and one kernel) std::shared_ptr expected_kernel_vk; { - // ClientIVC ivc{ trace_settings }; + ClientIVC ivc{ trace_settings }; // Construct and accumulate mock app_circuit - Builder app_circuit = construct_mock_app_circuit(genuine_ivc); - genuine_ivc.accumulate(app_circuit); + Builder app_circuit = construct_mock_app_circuit(ivc); + ivc.accumulate(app_circuit); { // Construct and accumulate a mock INIT kernel (oink recursion for app accumulation) - AcirProgram program = construct_mock_kernel_program(genuine_ivc.verification_queue); - Builder kernel = acir_format::create_kernel_circuit(program.constraints, genuine_ivc, program.witness); - genuine_ivc.accumulate(kernel); + AcirProgram program = construct_mock_kernel_program(ivc.verification_queue); + Builder kernel = acir_format::create_kernel_circuit(program.constraints, ivc, program.witness); + ivc.accumulate(kernel); } { // Construct and accumulate a mock RESET kernel (PG recursion for kernel accumulation) - EXPECT_TRUE(genuine_ivc.verification_queue.size() == 1); - EXPECT_TRUE(genuine_ivc.verification_queue[0].type == bb::ClientIVC::QUEUE_TYPE::PG); - AcirProgram program = construct_mock_kernel_program(genuine_ivc.verification_queue); - Builder kernel = acir_format::create_kernel_circuit(program.constraints, genuine_ivc, program.witness); - genuine_ivc.accumulate(kernel); + EXPECT_TRUE(ivc.verification_queue.size() == 1); + EXPECT_TRUE(ivc.verification_queue[0].type == bb::ClientIVC::QUEUE_TYPE::PG); + AcirProgram program = construct_mock_kernel_program(ivc.verification_queue); + Builder kernel = acir_format::create_kernel_circuit(program.constraints, ivc, program.witness); + ivc.accumulate(kernel); } - expected_kernel_vk = genuine_ivc.verification_queue.back().honk_verification_key; + expected_kernel_vk = ivc.verification_queue.back().honk_verification_key; } // Now, construct the kernel VK by mocking the IVC state prior to kernel construction @@ -307,18 +312,7 @@ TEST_F(IvcRecursionConstraintTest, GenerateResetKernelVKFromConstraints) acir_format::mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::PG, /*is_kernel=*/true); AcirProgram program = construct_mock_kernel_program(ivc.verification_queue); - // Create a mock IVC instance from the IVC recursion constraints in the kernel program - ClientIVC mock_ivc = create_mock_ivc_from_constraints(program.constraints.ivc_recursion_constraints); - - // Create kernel circuit from kernel program and the mocked IVC (empty witness mimics VK construction context) - Builder kernel = acir_format::create_kernel_circuit(program.constraints, mock_ivc, /*witness=*/{}); - // Note: adding pairing point normally happens in accumulate() - kernel.add_pairing_point_accumulator(stdlib::recursion::init_default_agg_obj_indices(kernel)); - - // Manually construct the VK for the kernel circuit - auto proving_key = std::make_shared>(kernel, ivc.trace_settings); - MegaProver prover(proving_key); - kernel_vk = std::make_shared(prover.proving_key->proving_key); + kernel_vk = construct_kernel_vk_from_acir_program(program, trace_settings); } // PCS verification keys will not match so set to null before comparing @@ -334,41 +328,37 @@ TEST_F(IvcRecursionConstraintTest, GenerateInnerKernelVKFromConstraints) { const TraceSettings trace_settings{ SMALL_TEST_STRUCTURE }; - ClientIVC genuine_ivc{ trace_settings }; - // First, construct the kernel VK by running the full IVC (accumulate one app and one kernel) std::shared_ptr expected_kernel_vk; { - // ClientIVC ivc{ trace_settings }; + ClientIVC ivc{ trace_settings }; - // Construct and accumulate mock app_circuit - { - Builder app_circuit = construct_mock_app_circuit(genuine_ivc); - genuine_ivc.accumulate(app_circuit); + { // Construct and accumulate mock app_circuit + Builder app_circuit = construct_mock_app_circuit(ivc); + ivc.accumulate(app_circuit); } { // Construct and accumulate a mock INIT kernel (oink recursion for app accumulation) - AcirProgram program = construct_mock_kernel_program(genuine_ivc.verification_queue); - Builder kernel = acir_format::create_kernel_circuit(program.constraints, genuine_ivc, program.witness); - genuine_ivc.accumulate(kernel); + AcirProgram program = construct_mock_kernel_program(ivc.verification_queue); + Builder kernel = acir_format::create_kernel_circuit(program.constraints, ivc, program.witness); + ivc.accumulate(kernel); } - // Construct and accumulate a second mock app_circuit - { - Builder app_circuit = construct_mock_app_circuit(genuine_ivc); - genuine_ivc.accumulate(app_circuit); + { // Construct and accumulate a second mock app_circuit + Builder app_circuit = construct_mock_app_circuit(ivc); + ivc.accumulate(app_circuit); } { // Construct and accumulate a mock RESET kernel (PG recursion for kernel accumulation) - EXPECT_TRUE(genuine_ivc.verification_queue.size() == 2); - EXPECT_TRUE(genuine_ivc.verification_queue[0].type == bb::ClientIVC::QUEUE_TYPE::PG); - EXPECT_TRUE(genuine_ivc.verification_queue[1].type == bb::ClientIVC::QUEUE_TYPE::PG); - AcirProgram program = construct_mock_kernel_program(genuine_ivc.verification_queue); - Builder kernel = acir_format::create_kernel_circuit(program.constraints, genuine_ivc, program.witness); - genuine_ivc.accumulate(kernel); + EXPECT_TRUE(ivc.verification_queue.size() == 2); + EXPECT_TRUE(ivc.verification_queue[0].type == bb::ClientIVC::QUEUE_TYPE::PG); + EXPECT_TRUE(ivc.verification_queue[1].type == bb::ClientIVC::QUEUE_TYPE::PG); + AcirProgram program = construct_mock_kernel_program(ivc.verification_queue); + Builder kernel = acir_format::create_kernel_circuit(program.constraints, ivc, program.witness); + ivc.accumulate(kernel); } - expected_kernel_vk = genuine_ivc.verification_queue.back().honk_verification_key; + expected_kernel_vk = ivc.verification_queue.back().honk_verification_key; } // Now, construct the kernel VK by mocking the IVC state prior to kernel construction @@ -381,18 +371,7 @@ TEST_F(IvcRecursionConstraintTest, GenerateInnerKernelVKFromConstraints) acir_format::mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::PG, /*is_kernel=*/false); AcirProgram program = construct_mock_kernel_program(ivc.verification_queue); - // Create a mock IVC instance from the IVC recursion constraints in the kernel program - ClientIVC mock_ivc = create_mock_ivc_from_constraints(program.constraints.ivc_recursion_constraints); - - // Create kernel circuit from kernel program and the mocked IVC (empty witness mimics VK construction context) - Builder kernel = acir_format::create_kernel_circuit(program.constraints, mock_ivc, /*witness=*/{}); - // Note: adding pairing point normally happens in accumulate() - kernel.add_pairing_point_accumulator(stdlib::recursion::init_default_agg_obj_indices(kernel)); - - // Manually construct the VK for the kernel circuit - auto proving_key = std::make_shared>(kernel, ivc.trace_settings); - MegaProver prover(proving_key); - kernel_vk = std::make_shared(prover.proving_key->proving_key); + kernel_vk = construct_kernel_vk_from_acir_program(program, trace_settings); } // PCS verification keys will not match so set to null before comparing From cd448955743b48353171011dbf7d1adb125b4f11 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Mon, 2 Dec 2024 20:20:20 +0000 Subject: [PATCH 08/13] remove hash circuit debug method --- .../barretenberg/client_ivc/client_ivc.cpp | 8 +- .../protogalaxy_recursive_verifier.cpp | 10 +-- .../ultra_circuit_builder.cpp | 74 +++++-------------- .../ultra_circuit_builder.hpp | 35 +++++++++ 4 files changed, 62 insertions(+), 65 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp index 7345c768d5b..7a65da75cea 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp @@ -93,7 +93,7 @@ void ClientIVC::perform_recursive_verification_and_databus_consistency_checks( } } - // info("PRE-DB HASH = ", circuit.hash_circuit()); + // info("PRE-DB HASH = ", circuit.hash_circuit_for_debug()); // Set the return data commitment to be propagated on the public inputs of the present kernel and peform consistency // checks between the calldata commitments and the return data commitments contained within the public inputs @@ -104,7 +104,7 @@ void ClientIVC::perform_recursive_verification_and_databus_consistency_checks( decider_vk->public_inputs, decider_vk->verification_key->databus_propagation_data); - // info("POST-DB HASH = ", circuit.hash_circuit()); + // info("POST-DB HASH = ", circuit.hash_circuit_for_debug()); } /** @@ -137,7 +137,7 @@ void ClientIVC::complete_kernel_circuit_logic(ClientCircuit& circuit) if (stdlib_verification_queue.empty()) { instantiate_stdlib_verification_queue(circuit); } - // info("HASH = ", circuit.hash_circuit()); + // info("HASH = ", circuit.hash_circuit_for_debug()); // Peform recursive verification and databus consistency checks for each entry in the verification queue for (auto& [proof, vkey, type] : stdlib_verification_queue) { @@ -145,7 +145,7 @@ void ClientIVC::complete_kernel_circuit_logic(ClientCircuit& circuit) } stdlib_verification_queue.clear(); - // info("POST HASH = ", circuit.hash_circuit()); + // info("POST HASH = ", circuit.hash_circuit_for_debug()); // Propagate return data commitments via the public inputs for use in databus consistency checks bus_depot.propagate_return_data_commitments(circuit); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/protogalaxy_verifier/protogalaxy_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/protogalaxy_verifier/protogalaxy_recursive_verifier.cpp index a013e5d5c82..ee59309fc0d 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/protogalaxy_verifier/protogalaxy_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/protogalaxy_verifier/protogalaxy_recursive_verifier.cpp @@ -169,13 +169,13 @@ std::shared_ptr ProtogalaxyRecursiv perturbator_evaluation * lagranges[0] + vanishing_polynomial_at_challenge * combiner_quotient_at_challenge; // if constexpr (!IsSimulator) { - // info("HASH = ", builder->hash_circuit()); + // info("HASH = ", builder->hash_circuit_for_debug()); // } accumulator->gate_challenges = update_gate_challenges(perturbator_challenge, accumulator->gate_challenges, deltas); // if constexpr (!IsSimulator) { - // info("HASH = ", builder->hash_circuit()); + // info("HASH = ", builder->hash_circuit_for_debug()); // } // Set the accumulator circuit size data based on the max of the keys being accumulated @@ -189,7 +189,7 @@ std::shared_ptr ProtogalaxyRecursiv } // if constexpr (!IsSimulator) { - // info("HASH = ", builder->hash_circuit()); + // info("HASH = ", builder->hash_circuit_for_debug()); // } for (auto [combination, to_combine] : @@ -198,7 +198,7 @@ std::shared_ptr ProtogalaxyRecursiv } // if constexpr (!IsSimulator) { - // info("HASH = ", builder->hash_circuit()); + // info("HASH = ", builder->hash_circuit_for_debug()); // } auto accumulator_vkey = accumulator->verification_key->get_all(); @@ -212,7 +212,7 @@ std::shared_ptr ProtogalaxyRecursiv } // if constexpr (!IsSimulator) { - // info("HASH = ", builder->hash_circuit()); + // info("HASH = ", builder->hash_circuit_for_debug()); // } return accumulator; diff --git a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_circuit_builder.cpp b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_circuit_builder.cpp index 5cc92a88391..f99670fb330 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_circuit_builder.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_circuit_builder.cpp @@ -2831,76 +2831,38 @@ void UltraCircuitBuilder_::create_poseidon2_internal_gate(const poseidon2_in template uint256_t UltraCircuitBuilder_::hash_circuit() { + finalize_circuit(/*ensure_nonzero=*/false); - std::vector to_hash; + size_t sum_of_block_sizes(0); + for (auto& block : blocks.get()) { + sum_of_block_sizes += block.size(); + } + + size_t num_bytes_in_selectors = sizeof(FF) * ExecutionTrace::NUM_SELECTORS * sum_of_block_sizes; + size_t num_bytes_in_wires_and_copy_constraints = + sizeof(uint32_t) * (ExecutionTrace::NUM_WIRES * sum_of_block_sizes + this->real_variable_index.size()); + size_t num_bytes_to_hash = num_bytes_in_selectors + num_bytes_in_wires_and_copy_constraints; + + std::vector to_hash(num_bytes_to_hash); const auto convert_and_insert = [&to_hash](auto& vector) { std::vector buffer = to_buffer(vector); to_hash.insert(to_hash.end(), buffer.begin(), buffer.end()); }; - // DEBUG: selectors! - // for (auto& block : blocks.get()) { - // convert_and_insert(block.q_m()); - // } - // for (auto& block : blocks.get()) { - // std::for_each(block.get_gate_selectors().begin(), block.get_gate_selectors().end(), convert_and_insert); - // } for (auto& block : blocks.get()) { - std::for_each(block.selectors.begin(), block.selectors.end(), convert_and_insert); + std::for_each(block.get_gate_selectors().begin(), block.get_gate_selectors().end(), convert_and_insert); } - // // DEBUG: wires! - // for (auto& block : blocks.get()) { - // std::for_each(block.wires.begin(), block.wires.end(), convert_and_insert); - // } - - // for (auto& block : blocks.get()) { - // std::for_each(block.selectors.begin(), block.selectors.end(), convert_and_insert); - // std::for_each(block.wires.begin(), block.wires.end(), convert_and_insert); - // } - // convert_and_insert(this->real_variable_index); + for (auto& block : blocks.get()) { + std::for_each(block.selectors.begin(), block.selectors.end(), convert_and_insert); + std::for_each(block.wires.begin(), block.wires.end(), convert_and_insert); + } + convert_and_insert(this->real_variable_index); return from_buffer(crypto::sha256(to_hash)); } -// template uint256_t UltraCircuitBuilder_::hash_circuit() -// { -// finalize_circuit(/*ensure_nonzero=*/false); - -// size_t sum_of_block_sizes(0); -// for (auto& block : blocks.get()) { -// sum_of_block_sizes += block.size(); -// } - -// size_t num_bytes_in_selectors = sizeof(FF) * ExecutionTrace::NUM_SELECTORS * sum_of_block_sizes; -// size_t num_bytes_in_wires_and_copy_constraints = -// sizeof(uint32_t) * (ExecutionTrace::NUM_WIRES * sum_of_block_sizes + this->real_variable_index.size()); -// size_t num_bytes_to_hash = num_bytes_in_selectors + num_bytes_in_wires_and_copy_constraints; - -// std::vector to_hash(num_bytes_to_hash); - -// const auto convert_and_insert = [&to_hash](auto& vector) { -// std::vector buffer = to_buffer(vector); -// to_hash.insert(to_hash.end(), buffer.begin(), buffer.end()); -// }; - -// for (auto& block : blocks.get()) { -// convert_and_insert(block.q_m()); -// } -// // for (auto& block : blocks.get()) { -// // std::for_each(block.get_gate_selectors().begin(), block.get_gate_selectors().end(), convert_and_insert); -// // } - -// // for (auto& block : blocks.get()) { -// // std::for_each(block.selectors.begin(), block.selectors.end(), convert_and_insert); -// // std::for_each(block.wires.begin(), block.wires.end(), convert_and_insert); -// // } -// // convert_and_insert(this->real_variable_index); - -// return from_buffer(crypto::sha256(to_hash)); -// } - /** * Export the existing circuit as msgpack compatible buffer. * Should be called after `finalize_circuit()` diff --git a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_circuit_builder.hpp b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_circuit_builder.hpp index 499dc9df159..0d50eb6ee57 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_circuit_builder.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_circuit_builder.hpp @@ -865,6 +865,41 @@ class UltraCircuitBuilder_ : public CircuitBuilderBase uint256_t hash_circuit_for_debug() + { + + std::vector to_hash; + + const auto convert_and_insert = [&to_hash](auto& vector) { + std::vector buffer = to_buffer(vector); + to_hash.insert(to_hash.end(), buffer.begin(), buffer.end()); + }; + + // DEBUG: selectors! + // for (auto& block : blocks.get()) { + // convert_and_insert(block.q_m()); + // } + // for (auto& block : blocks.get()) { + // std::for_each(block.get_gate_selectors().begin(), block.get_gate_selectors().end(), convert_and_insert); + // } + for (auto& block : blocks.get()) { + std::for_each(block.selectors.begin(), block.selectors.end(), convert_and_insert); + } + + // // DEBUG: wires! + // for (auto& block : blocks.get()) { + // std::for_each(block.wires.begin(), block.wires.end(), convert_and_insert); + // } + + // for (auto& block : blocks.get()) { + // std::for_each(block.selectors.begin(), block.selectors.end(), convert_and_insert); + // std::for_each(block.wires.begin(), block.wires.end(), convert_and_insert); + // } + // convert_and_insert(this->real_variable_index); + + return from_buffer(crypto::sha256(to_hash)); + } + msgpack::sbuffer export_circuit() override; }; using UltraCircuitBuilder = UltraCircuitBuilder_; From cd3811592f9cc90830605f6c6d8bae379b9da6c5 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Mon, 2 Dec 2024 21:33:58 +0000 Subject: [PATCH 09/13] fix hash circuit --- .../stdlib_circuit_builders/ultra_circuit_builder.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_circuit_builder.cpp b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_circuit_builder.cpp index f99670fb330..29bf01cc42c 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_circuit_builder.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_circuit_builder.cpp @@ -2850,10 +2850,6 @@ template uint256_t UltraCircuitBuilder_ Date: Mon, 2 Dec 2024 22:24:47 +0000 Subject: [PATCH 10/13] comments and cleanup --- .../acir_format/ivc_recursion_constraint.cpp | 72 ++++++++++++------- .../acir_format/ivc_recursion_constraint.hpp | 3 +- .../ivc_recursion_constraint.test.cpp | 3 +- .../stdlib_circuit_builders/databus.hpp | 10 +++ 4 files changed, 60 insertions(+), 28 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp index 0d837e2cdb9..12070d1dacb 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp @@ -14,38 +14,60 @@ namespace acir_format { using namespace bb; -ClientIVC create_mock_ivc_from_constraints(const std::vector& constraints) +/** + * @brief Create an IVC object with mocked state corresponding to a set of IVC recursion constraints + * @details Construction of a kernel circuit requires two inputs: kernel prgram acir constraints and an IVC instance + * containing state needed to complete the kernel logic, e.g. proofs for input to recursive verifiers. To construct + * verification keys for kernel circuits without running a full IVC, we mock the IVC state corresponding to a provided + * set of IVC recurson constraints. For example, if the constraints contain a single PG recursive verification, we + * initialize an IVC with mocked data for the verifier accumulator, the folding proof, the circuit verification key, + * and a merge proof. + * @note There are only three valid combinations of IVC recursion constraints for a kernel program. See below for + * details. + * + * @param constraints IVC recursion constraints from a kernel circuit + * @param trace_settings + * @return ClientIVC + */ +ClientIVC create_mock_ivc_from_constraints(const std::vector& constraints, + const TraceSettings& trace_settings) { - // WORKTODO: the settings here will just be set based on the one and only default trace structuring - ClientIVC ivc{ { SMALL_TEST_STRUCTURE } }; + ClientIVC ivc{ trace_settings }; uint32_t oink_type = static_cast(PROOF_TYPE::OINK); uint32_t pg_type = static_cast(PROOF_TYPE::PG); - // There are only three valid combinations of IVC recursion constraints: (1) a single Oink recursive verification - // for an app circuit (init kernel), (2) a single PG recursive verification for a kernel circuit (reset kernel, tail - // kernel), or (3) two PG recursive verifications for a kernel and an app in that order (inner kernel). + // There are only three valid combinations of IVC recursion constraints: + + // Case: INIT kernel; single Oink recursive verification of an app if (constraints.size() == 1 && constraints[0].proof_type == oink_type) { mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::OINK, /*is_kernel=*/false); - } else if (constraints.size() == 1 && constraints[0].proof_type == pg_type) { + return ivc; + } + + // Case: RESET or TAIL kernel; single PG recursive verification of a kernel + if (constraints.size() == 1 && constraints[0].proof_type == pg_type) { ivc.verifier_accumulator = create_mock_decider_vk(); mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::PG, /*is_kernel=*/true); - } else if (constraints.size() == 2) { + return ivc; + } + + // Case: INNER kernel; two PG recursive verifications, kernel and app in that order + if (constraints.size() == 2) { ASSERT(constraints[0].proof_type == pg_type && constraints[1].proof_type == pg_type); ivc.verifier_accumulator = create_mock_decider_vk(); mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::PG, /*is_kernel=*/true); mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::PG, /*is_kernel=*/false); - } else { - info("WARNING: Invalid set of IVC recursion constraints!"); - ASSERT(false); + return ivc; } - return ivc; + ASSERT(false && "WARNING: Invalid set of IVC recursion constraints!"); + return ClientIVC{}; } /** - * @brief Populate an IVC instance with data that mimics the state after PG accumulation - * @details Mock state consists a mock verification queue entry of type OINK (proof, VK) and a mocked merge proof + * @brief Populate an IVC instance with data that mimics the state after a single IVC accumulation (Oink or PG) + * @details Mock state consists of a mock verification queue entry of type OINK (proof, VK) and a mocked merge proof * * @param ivc * @param num_public_inputs_app num pub inputs in accumulated app, excluding fixed components, e.g. pairing points @@ -60,7 +82,8 @@ void mock_ivc_accumulation(ClientIVC& ivc, ClientIVC::QUEUE_TYPE type, const boo } /** - * @brief Create a mock oink proof and VK that have the correct structure but are not necessarily valid + * @brief Create a mock verification queue entry with proof and VK that have the correct structure but are not + * necessarily valid * */ ClientIVC::VerifierInputs create_mock_verification_queue_entry(const ClientIVC::QUEUE_TYPE verification_type, @@ -70,16 +93,17 @@ ClientIVC::VerifierInputs create_mock_verification_queue_entry(const ClientIVC:: using FF = ClientIVC::FF; using MegaVerificationKey = ClientIVC::MegaVerificationKey; - // WORKTODO: is there a way to use some internal IVC data for this instead of constructing blocks? + // Use the trace settings to determine the correct dyadic size and the public inputs offset MegaExecutionTraceBlocks blocks; blocks.set_fixed_block_sizes(trace_settings); blocks.compute_offsets(/*is_structured=*/true); size_t dyadic_size = blocks.get_structured_dyadic_size(); + size_t pub_inputs_offset = blocks.pub_inputs.trace_offset; + // All circuits have pairing point public inputs; kernels have additional public inputs for two databus commitments size_t num_public_inputs = bb::PAIRING_POINT_ACCUMULATOR_SIZE; if (is_kernel) { num_public_inputs += bb::PROPAGATED_DATABUS_COMMITMENTS_SIZE; } - size_t pub_inputs_offset = blocks.pub_inputs.trace_offset; // Construct a mock Oink or PG proof std::vector proof; @@ -96,17 +120,14 @@ ClientIVC::VerifierInputs create_mock_verification_queue_entry(const ClientIVC:: // If the verification queue entry corresponds to a kernel circuit, set the databus data to indicate the presence of // propagated return data commitments on the public inputs if (is_kernel) { - // WORKTODO: how can we make this a little less magical? - verification_key->databus_propagation_data.is_kernel = true; - verification_key->databus_propagation_data.kernel_return_data_public_input_idx = 0; - verification_key->databus_propagation_data.app_return_data_public_input_idx = 8; + verification_key->databus_propagation_data = bb::DatabusPropagationData::kernel_default(); } return ClientIVC::VerifierInputs{ proof, verification_key, verification_type }; } /** - * @brief Create a mock oink proof and VK that have the correct structure but are not necessarily valid + * @brief Create a mock oink proof that has the correct structure but is not in general valid * */ std::vector create_mock_oink_proof(const size_t dyadic_size, @@ -141,14 +162,13 @@ std::vector create_mock_oink_proof(const size_t dyadic_size, } /** - * @brief Create a mock PG proof and VK that have the correct structure but are not necessarily valid + * @brief Create a mock PG proof that has the correct structure but is not in general valid * */ std::vector create_mock_pg_proof(const size_t dyadic_size, const size_t num_public_inputs, const size_t pub_inputs_offset) { - // using Flavor = ClientIVC::Flavor; using FF = ClientIVC::FF; using DeciderProvingKeys = ClientIVC::DeciderProvingKeys; @@ -169,7 +189,7 @@ std::vector create_mock_pg_proof(const size_t dyadic_size, } /** - * @brief Create a mock oink proof and VK that have the correct structure but are not necessarily valid + * @brief Create a mock MegaHonk VK that has the correct structure * */ std::shared_ptr create_mock_honk_vk(const size_t dyadic_size, @@ -223,7 +243,7 @@ ClientIVC::MergeProof create_dummy_merge_proof() std::vector proof; FF mock_val(5); - auto mock_commitment = curve::BN254::AffineElement::one() * mock_val; + auto mock_commitment = curve::BN254::AffineElement::one(); std::vector mock_commitment_frs = field_conversion::convert_to_bn254_frs(mock_commitment); // There are 12 entities in the merge protocol (4 columns x 3 components; aggregate transcript, previous aggregate diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.hpp index 90e0657ab14..8d89c6ecfc5 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.hpp @@ -11,7 +11,8 @@ using namespace bb; // TODO(https://github.com/AztecProtocol/barretenberg/issues/1148): logic in this file is incomplete. See issue for // details. -ClientIVC create_mock_ivc_from_constraints(const std::vector& constraints); +ClientIVC create_mock_ivc_from_constraints(const std::vector& constraints, + const TraceSettings& trace_settings); void mock_ivc_accumulation(ClientIVC& ivc, ClientIVC::QUEUE_TYPE type, const bool is_kernel); diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp index 413893cc862..3e0d299e2d6 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp @@ -107,7 +107,8 @@ class IvcRecursionConstraintTest : public ::testing::Test { AcirProgram& program, const TraceSettings& trace_settings) { // Create a mock IVC instance from the IVC recursion constraints in the kernel program - ClientIVC mock_ivc = create_mock_ivc_from_constraints(program.constraints.ivc_recursion_constraints); + ClientIVC mock_ivc = + create_mock_ivc_from_constraints(program.constraints.ivc_recursion_constraints, trace_settings); // Create kernel circuit from kernel program and the mocked IVC (empty witness mimics VK construction context) Builder kernel = acir_format::create_kernel_circuit(program.constraints, mock_ivc, /*witness=*/{}); diff --git a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/databus.hpp b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/databus.hpp index 92fda074a99..54f26c4d4c2 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/databus.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/databus.hpp @@ -95,6 +95,16 @@ struct DatabusPropagationData { return os; }; + // Construct a class instance with the default settings for a kernel circuit + static DatabusPropagationData kernel_default() + { + DatabusPropagationData data; + data.kernel_return_data_public_input_idx = 0; // kernel return data commitment is first public input + data.app_return_data_public_input_idx = 8; // followed by app return data commitment + data.is_kernel = true; + return data; + } + MSGPACK_FIELDS(app_return_data_public_input_idx, kernel_return_data_public_input_idx, is_kernel); }; From e41eb74383e9157bacd4854c2fcf03e5e015d591 Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Mon, 2 Dec 2024 23:34:50 +0000 Subject: [PATCH 11/13] comments --- .../dsl/acir_format/ivc_recursion_constraint.cpp | 2 +- .../dsl/acir_format/ivc_recursion_constraint.test.cpp | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp index 12070d1dacb..70fa6c65a83 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp @@ -211,7 +211,7 @@ std::shared_ptr create_mock_honk_vk(const size_t } /** - * @brief + * @brief Create a mock Decider verification key for initilization of a mock verifier accumulator * */ std::shared_ptr create_mock_decider_vk() diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp index 3e0d299e2d6..cba986527f0 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp @@ -103,6 +103,13 @@ class IvcRecursionConstraintTest : public ::testing::Test { return program; } + /** + * @brief Construct a kernel circuit VK from an acir program with IVC recursion constraints + * + * @param program Acir program representing a kernel circuit + * @param trace_settings needed for construction of the VK + * @return std::shared_ptr + */ static std::shared_ptr construct_kernel_vk_from_acir_program( AcirProgram& program, const TraceSettings& trace_settings) { From 553cf549b6ff57963d4c6c5811dacd8562d115eb Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Tue, 3 Dec 2024 17:01:19 +0000 Subject: [PATCH 12/13] clean --- .../barretenberg/client_ivc/client_ivc.cpp | 7 ---- .../acir_format/ivc_recursion_constraint.cpp | 2 +- .../honk_verifier/oink_recursive_verifier.cpp | 2 -- .../protogalaxy_recursive_verifier.cpp | 20 ----------- .../stdlib_circuit_builders/databus.hpp | 2 +- .../ultra_circuit_builder.hpp | 35 ------------------- 6 files changed, 2 insertions(+), 66 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp index 96003708a5e..4ba9ae098c7 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp @@ -93,8 +93,6 @@ void ClientIVC::perform_recursive_verification_and_databus_consistency_checks( } } - // info("PRE-DB HASH = ", circuit.hash_circuit_for_debug()); - // Set the return data commitment to be propagated on the public inputs of the present kernel and peform consistency // checks between the calldata commitments and the return data commitments contained within the public inputs bus_depot.set_return_data_to_be_propagated_and_perform_consistency_checks( @@ -103,8 +101,6 @@ void ClientIVC::perform_recursive_verification_and_databus_consistency_checks( decider_vk->witness_commitments.secondary_calldata, decider_vk->public_inputs, decider_vk->verification_key->databus_propagation_data); - - // info("POST-DB HASH = ", circuit.hash_circuit_for_debug()); } /** @@ -137,7 +133,6 @@ void ClientIVC::complete_kernel_circuit_logic(ClientCircuit& circuit) if (stdlib_verification_queue.empty()) { instantiate_stdlib_verification_queue(circuit); } - // info("HASH = ", circuit.hash_circuit_for_debug()); // Peform recursive verification and databus consistency checks for each entry in the verification queue for (auto& [proof, vkey, type] : stdlib_verification_queue) { @@ -145,8 +140,6 @@ void ClientIVC::complete_kernel_circuit_logic(ClientCircuit& circuit) } stdlib_verification_queue.clear(); - // info("POST HASH = ", circuit.hash_circuit_for_debug()); - // Propagate return data commitments via the public inputs for use in databus consistency checks bus_depot.propagate_return_data_commitments(circuit); diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp index 70fa6c65a83..f815610631e 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp @@ -37,7 +37,7 @@ ClientIVC create_mock_ivc_from_constraints(const std::vector(PROOF_TYPE::OINK); uint32_t pg_type = static_cast(PROOF_TYPE::PG); - // There are only three valid combinations of IVC recursion constraints: + // There are only three valid combinations of IVC recursion constraints for Aztec kernel circuits: // Case: INIT kernel; single Oink recursive verification of an app if (constraints.size() == 1 && constraints[0].proof_type == oink_type) { diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/oink_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/oink_recursive_verifier.cpp index 65c3e007f9d..d9974b8f056 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/oink_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/oink_recursive_verifier.cpp @@ -48,8 +48,6 @@ template void OinkRecursiveVerifier_::verify() FF pub_inputs_offset = transcript->template receive_from_prover(domain_separator + "pub_inputs_offset"); if (static_cast(circuit_size.get_value()) != verification_key->verification_key->circuit_size) { - info("Proof circuit size = ", circuit_size.get_value()); - info("VK circuit size = ", verification_key->verification_key->circuit_size); throw_or_abort("OinkRecursiveVerifier::verify: proof circuit size does not match verification key"); } if (static_cast(public_input_size.get_value()) != verification_key->verification_key->num_public_inputs) { diff --git a/barretenberg/cpp/src/barretenberg/stdlib/protogalaxy_verifier/protogalaxy_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/protogalaxy_verifier/protogalaxy_recursive_verifier.cpp index ee59309fc0d..607f7b17f17 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/protogalaxy_verifier/protogalaxy_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/protogalaxy_verifier/protogalaxy_recursive_verifier.cpp @@ -168,16 +168,8 @@ std::shared_ptr ProtogalaxyRecursiv accumulator->target_sum = perturbator_evaluation * lagranges[0] + vanishing_polynomial_at_challenge * combiner_quotient_at_challenge; - // if constexpr (!IsSimulator) { - // info("HASH = ", builder->hash_circuit_for_debug()); - // } - accumulator->gate_challenges = update_gate_challenges(perturbator_challenge, accumulator->gate_challenges, deltas); - // if constexpr (!IsSimulator) { - // info("HASH = ", builder->hash_circuit_for_debug()); - // } - // Set the accumulator circuit size data based on the max of the keys being accumulated const size_t accumulator_log_circuit_size = keys_to_fold.get_max_log_circuit_size(); accumulator->verification_key->log_circuit_size = accumulator_log_circuit_size; @@ -188,19 +180,11 @@ std::shared_ptr ProtogalaxyRecursiv combination = linear_combination(to_combine, lagranges); } - // if constexpr (!IsSimulator) { - // info("HASH = ", builder->hash_circuit_for_debug()); - // } - for (auto [combination, to_combine] : zip_view(accumulator->relation_parameters.get_to_fold(), keys_to_fold.get_relation_parameters())) { combination = linear_combination(to_combine, lagranges); } - // if constexpr (!IsSimulator) { - // info("HASH = ", builder->hash_circuit_for_debug()); - // } - auto accumulator_vkey = accumulator->verification_key->get_all(); for (size_t i = 0; i < Flavor::NUM_PRECOMPUTED_ENTITIES; ++i) { accumulator_vkey[i] = output_commitments[i]; @@ -211,10 +195,6 @@ std::shared_ptr ProtogalaxyRecursiv accumulator_witnesses[i] = output_commitments[i + accumulator_vkey.size()]; } - // if constexpr (!IsSimulator) { - // info("HASH = ", builder->hash_circuit_for_debug()); - // } - return accumulator; } diff --git a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/databus.hpp b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/databus.hpp index 54f26c4d4c2..44e5797f51e 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/databus.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/databus.hpp @@ -95,7 +95,7 @@ struct DatabusPropagationData { return os; }; - // Construct a class instance with the default settings for a kernel circuit + // Construct an instance of this class with the default settings for a kernel circuit static DatabusPropagationData kernel_default() { DatabusPropagationData data; diff --git a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_circuit_builder.hpp b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_circuit_builder.hpp index 0d50eb6ee57..499dc9df159 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_circuit_builder.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_circuit_builder.hpp @@ -865,41 +865,6 @@ class UltraCircuitBuilder_ : public CircuitBuilderBase uint256_t hash_circuit_for_debug() - { - - std::vector to_hash; - - const auto convert_and_insert = [&to_hash](auto& vector) { - std::vector buffer = to_buffer(vector); - to_hash.insert(to_hash.end(), buffer.begin(), buffer.end()); - }; - - // DEBUG: selectors! - // for (auto& block : blocks.get()) { - // convert_and_insert(block.q_m()); - // } - // for (auto& block : blocks.get()) { - // std::for_each(block.get_gate_selectors().begin(), block.get_gate_selectors().end(), convert_and_insert); - // } - for (auto& block : blocks.get()) { - std::for_each(block.selectors.begin(), block.selectors.end(), convert_and_insert); - } - - // // DEBUG: wires! - // for (auto& block : blocks.get()) { - // std::for_each(block.wires.begin(), block.wires.end(), convert_and_insert); - // } - - // for (auto& block : blocks.get()) { - // std::for_each(block.selectors.begin(), block.selectors.end(), convert_and_insert); - // std::for_each(block.wires.begin(), block.wires.end(), convert_and_insert); - // } - // convert_and_insert(this->real_variable_index); - - return from_buffer(crypto::sha256(to_hash)); - } - msgpack::sbuffer export_circuit() override; }; using UltraCircuitBuilder = UltraCircuitBuilder_; From 887ce343c545c5d1db0db7e26acb43c1d43dd25e Mon Sep 17 00:00:00 2001 From: ledwards2225 Date: Tue, 3 Dec 2024 18:12:02 +0000 Subject: [PATCH 13/13] comment fix --- .../dsl/acir_format/ivc_recursion_constraint.test.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp index cba986527f0..1cd9d5b5595 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp @@ -45,7 +45,6 @@ class IvcRecursionConstraintTest : public ::testing::Test { * * @param input bberg style proof and verification key * @param witness Array of witnesses into which the above data is placed - * @param num_public_inputs Number of public inputs to be extracted from the proof * @return RecursionConstraint */ static RecursionConstraint create_recursion_constraint(const VerifierInputs& input, SlabVector& witness)