-
Notifications
You must be signed in to change notification settings - Fork 598
chore: civc tidy 3 #16671
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
chore: civc tidy 3 #16671
Changes from all commits
1e1aa97
007db1e
c016a25
ae13c4a
674d53a
07cac06
3e562a5
65ba35d
f9c8770
acc73bc
be7457c
063b712
cb3f22b
cb6e829
045a909
8d9097b
9dca508
6b792ed
0308e4f
824cf8c
2989802
c0f85e4
17da7bb
7e1d814
c7bcd9f
5c1ed1a
8f089ef
0351a10
be46a3f
ec09536
4ebd6f1
0543364
578e8fe
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -172,8 +172,6 @@ ClientIVC::perform_recursive_verification_and_databus_consistency_checks( | |
| } | ||
| case QUEUE_TYPE::PG: | ||
| case QUEUE_TYPE::PG_TAIL: { | ||
| BB_ASSERT_NEQ(input_verifier_accumulator, nullptr); | ||
|
|
||
| output_verifier_accumulator = perform_pg_recursive_verification(circuit, | ||
| input_verifier_accumulator, | ||
| verifier_instance, | ||
|
|
@@ -184,18 +182,10 @@ ClientIVC::perform_recursive_verification_and_databus_consistency_checks( | |
| break; | ||
| } | ||
| case QUEUE_TYPE::PG_FINAL: { | ||
| BB_ASSERT_NEQ(input_verifier_accumulator, nullptr); | ||
| BB_ASSERT_EQ(stdlib_verification_queue.size(), size_t(1)); | ||
|
|
||
| hide_op_queue_accumulation_result(circuit); | ||
|
|
||
| // Propagate the public inputs of the tail kernel by converting them to public inputs of the hiding circuit. | ||
| auto num_public_inputs = static_cast<size_t>(honk_vk->num_public_inputs); | ||
| num_public_inputs -= KernelIO::PUBLIC_INPUTS_SIZE; // exclude fixed kernel_io public inputs | ||
| for (size_t i = 0; i < num_public_inputs; i++) { | ||
| verifier_inputs.proof[i].set_public(); | ||
| } | ||
|
|
||
| auto final_verifier_accumulator = perform_pg_recursive_verification(circuit, | ||
| input_verifier_accumulator, | ||
| verifier_instance, | ||
|
|
@@ -245,7 +235,7 @@ ClientIVC::perform_recursive_verification_and_databus_consistency_checks( | |
| kernel_input.output_pg_accum_hash.assert_equal(*prev_accum_hash); | ||
|
|
||
| if (!is_hiding_kernel) { | ||
| // The hiding kernel has no return data but uses the traditional public-inputs mechanism | ||
| // The hiding kernel has no return data; it uses the traditional public-inputs mechanism | ||
| bus_depot.set_kernel_return_data_commitment(witness_commitments.return_data); | ||
| } | ||
| } else { | ||
|
|
@@ -384,7 +374,7 @@ HonkProof ClientIVC::construct_oink_proof(const std::shared_ptr<DeciderProvingKe | |
| proving_key->gate_challenges = | ||
| prover_accumulation_transcript->template get_powers_of_challenge<FF>("gate_challenge", CONST_PG_LOG_N); | ||
|
|
||
| fold_output.accumulator = proving_key; // initialize the prover accum with the completed key | ||
| prover_accumulator = proving_key; // initialize the prover accum with the completed key | ||
|
|
||
| HonkProof oink_proof = oink_prover.export_proof(); | ||
| vinfo("oink proof constructed"); | ||
|
|
@@ -406,13 +396,14 @@ HonkProof ClientIVC::construct_pg_proof(const std::shared_ptr<DeciderProvingKey> | |
| info("Accumulator hash in PG prover: ", accum_hash); | ||
| } | ||
| auto verifier_instance = std::make_shared<DeciderVerificationKey_<Flavor>>(honk_vk); | ||
| FoldingProver folding_prover({ fold_output.accumulator, proving_key }, | ||
| FoldingProver folding_prover({ prover_accumulator, proving_key }, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. quite funny. I think we were only using the accumulator of the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the other member was the |
||
| { native_verifier_accum, verifier_instance }, | ||
| transcript, | ||
| trace_usage_tracker); | ||
| fold_output = folding_prover.prove(); | ||
| auto output = folding_prover.prove(); | ||
| prover_accumulator = output.accumulator; // update the prover accumulator | ||
| vinfo("pg proof constructed"); | ||
| return fold_output.proof; | ||
| return output.proof; | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -472,8 +463,6 @@ void ClientIVC::accumulate(ClientCircuit& circuit, const std::shared_ptr<MegaVer | |
| proving_key->commitment_key = bn254_commitment_key; | ||
| trace_usage_tracker.update(circuit); | ||
|
|
||
| honk_vk = precomputed_vk; | ||
|
|
||
| // We're accumulating a kernel if the verification queue is empty (because the kernel circuit contains recursive | ||
| // verifiers for all the entries previously present in the verification queue) and if it's not the first accumulate | ||
| // call (which will always be for an app circuit). | ||
|
|
@@ -495,22 +484,22 @@ void ClientIVC::accumulate(ClientCircuit& circuit, const std::shared_ptr<MegaVer | |
| case QUEUE_TYPE::OINK: | ||
| vinfo("Accumulating first app circuit with OINK"); | ||
| BB_ASSERT_EQ(is_kernel, false, "First circuit accumulated must always be an app"); | ||
| proof = construct_oink_proof(proving_key, honk_vk, prover_accumulation_transcript); | ||
| proof = construct_oink_proof(proving_key, precomputed_vk, prover_accumulation_transcript); | ||
| break; | ||
| case QUEUE_TYPE::PG: | ||
| case QUEUE_TYPE::PG_TAIL: | ||
| proof = construct_pg_proof(proving_key, honk_vk, prover_accumulation_transcript, is_kernel); | ||
| proof = construct_pg_proof(proving_key, precomputed_vk, prover_accumulation_transcript, is_kernel); | ||
| break; | ||
| case QUEUE_TYPE::PG_FINAL: | ||
| proof = construct_pg_proof(proving_key, honk_vk, prover_accumulation_transcript, is_kernel); | ||
| proof = construct_pg_proof(proving_key, precomputed_vk, prover_accumulation_transcript, is_kernel); | ||
| decider_proof = construct_decider_proof(prover_accumulation_transcript); | ||
| break; | ||
| case QUEUE_TYPE::MEGA: | ||
| proof = construct_mega_proof_for_hiding_kernel(circuit); | ||
| proof = construct_honk_proof_for_hiding_kernel(circuit, precomputed_vk); | ||
| break; | ||
| } | ||
|
|
||
| VerifierInputs queue_entry{ std::move(proof), honk_vk, queue_type, is_kernel }; | ||
| VerifierInputs queue_entry{ std::move(proof), precomputed_vk, queue_type, is_kernel }; | ||
| verification_queue.push_back(queue_entry); | ||
|
|
||
| // Update native verifier accumulator and construct merge proof (excluded for hiding kernel since PG terminates with | ||
|
|
@@ -612,14 +601,14 @@ void ClientIVC::hide_op_queue_content_in_hiding(ClientCircuit& circuit) | |
| * @brief Construct a zero-knowledge proof for the hiding circuit, which recursively verifies the last folding, | ||
| * merge and decider proof. | ||
| */ | ||
| HonkProof ClientIVC::construct_mega_proof_for_hiding_kernel(ClientCircuit& circuit) | ||
| HonkProof ClientIVC::construct_honk_proof_for_hiding_kernel( | ||
| ClientCircuit& circuit, const std::shared_ptr<MegaVerificationKey>& verification_key) | ||
| { | ||
| // Note: a structured trace is not used for the hiding kernel | ||
| auto hiding_decider_pk = std::make_shared<DeciderZKProvingKey>(circuit, TraceSettings(), bn254_commitment_key); | ||
| honk_vk = std::make_shared<MegaZKVerificationKey>(hiding_decider_pk->get_precomputed()); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. prior to this PR we were recomputing the hiding VK on the fly rather than using the precomputed one. This is why we weren't getting errors even though the precomputed VK was incorrectly using a structured trace |
||
| auto& hiding_circuit_vk = honk_vk; | ||
|
|
||
| // Hiding circuit is proven by a MegaZKProver | ||
| MegaZKProver prover(hiding_decider_pk, hiding_circuit_vk, transcript); | ||
| MegaZKProver prover(hiding_decider_pk, verification_key, transcript); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. just to make sure I understand correctly. We do not keep the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah ever since the updates from you/leila that final VK (hiding VK) is a precomputed input just like for all of the other circuits - until now we just weren't using it and instead recomputed it on the fly |
||
| HonkProof proof = prover.construct_proof(); | ||
|
|
||
| return proof; | ||
|
|
@@ -633,7 +622,7 @@ HonkProof ClientIVC::construct_mega_proof_for_hiding_kernel(ClientCircuit& circu | |
| ClientIVC::Proof ClientIVC::prove() | ||
| { | ||
| // deallocate the protogalaxy accumulator | ||
| fold_output.accumulator = nullptr; | ||
| prover_accumulator = nullptr; | ||
| auto mega_proof = verification_queue.front().proof; | ||
|
|
||
| // A transcript is shared between the Hiding circuit prover and the Goblin prover | ||
|
|
@@ -669,17 +658,6 @@ bool ClientIVC::verify(const Proof& proof, const VerificationKey& vk) | |
| return goblin_verified && mega_verified; | ||
| } | ||
|
|
||
| /** | ||
| * @brief Verify a full proof of the IVC | ||
| * | ||
| * @param proof | ||
| * @return bool | ||
| */ | ||
| bool ClientIVC::verify(const Proof& proof) const | ||
| { | ||
| return verify(proof, get_vk()); | ||
| } | ||
|
|
||
| /** | ||
| * @brief Internal method for constructing a decider proof | ||
| * | ||
|
|
@@ -688,36 +666,12 @@ bool ClientIVC::verify(const Proof& proof) const | |
| HonkProof ClientIVC::construct_decider_proof(const std::shared_ptr<Transcript>& transcript) | ||
| { | ||
| vinfo("prove decider..."); | ||
| fold_output.accumulator->commitment_key = bn254_commitment_key; | ||
| MegaDeciderProver decider_prover(fold_output.accumulator, transcript); | ||
| prover_accumulator->commitment_key = bn254_commitment_key; | ||
| MegaDeciderProver decider_prover(prover_accumulator, transcript); | ||
| decider_prover.construct_proof(); | ||
| return decider_prover.export_proof(); | ||
| } | ||
|
|
||
| /** | ||
| * @brief Construct and verify a proof for the IVC | ||
| * @note Use of this method only makes sense when the prover and verifier are the same entity, e.g. in | ||
| * development/testing. | ||
| * | ||
| */ | ||
| bool ClientIVC::prove_and_verify() | ||
| { | ||
| auto start = std::chrono::steady_clock::now(); | ||
| const auto proof = prove(); | ||
| auto end = std::chrono::steady_clock::now(); | ||
| auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - start); | ||
| vinfo("time to call ClientIVC::prove: ", diff.count(), " ms."); | ||
|
|
||
| start = end; | ||
| const bool verified = verify(proof); | ||
| end = std::chrono::steady_clock::now(); | ||
|
|
||
| diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - start); | ||
| vinfo("time to verify ClientIVC proof: ", diff.count(), " ms."); | ||
|
|
||
| return verified; | ||
| } | ||
|
|
||
| // Proof methods | ||
| size_t ClientIVC::Proof::size() const | ||
| { | ||
|
|
@@ -842,7 +796,12 @@ ClientIVC::Proof ClientIVC::Proof::from_file_msgpack(const std::string& filename | |
| // VerificationKey construction | ||
| ClientIVC::VerificationKey ClientIVC::get_vk() const | ||
| { | ||
| return { honk_vk, std::make_shared<ECCVMVerificationKey>(), std::make_shared<TranslatorVerificationKey>() }; | ||
| BB_ASSERT_EQ(verification_queue.size(), 1UL); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we now just extract the hiding kernel VK from the queue |
||
| BB_ASSERT_EQ(verification_queue.front().type == QUEUE_TYPE::MEGA, true); | ||
| auto verification_key = verification_queue.front().honk_vk; | ||
| return { verification_key, | ||
| std::make_shared<ECCVMVerificationKey>(), | ||
| std::make_shared<TranslatorVerificationKey>() }; | ||
| } | ||
|
|
||
| void ClientIVC::update_native_verifier_accumulator(const VerifierInputs& queue_entry, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -257,8 +257,6 @@ class ClientIVC { | |
| ExecutionTraceUsageTracker trace_usage_tracker; | ||
|
|
||
| private: | ||
| using ProverFoldOutput = FoldingResult<Flavor>; | ||
|
|
||
| // Transcript for CIVC prover (shared between Hiding circuit, Merge, ECCVM, and Translator) | ||
| std::shared_ptr<Transcript> transcript = std::make_shared<Transcript>(); | ||
|
|
||
|
|
@@ -269,14 +267,13 @@ class ClientIVC { | |
| public: | ||
| size_t num_circuits_accumulated = 0; // number of circuits accumulated so far | ||
|
|
||
| ProverFoldOutput fold_output; // prover accumulator and fold proof | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we only track the |
||
| HonkProof decider_proof; // decider proof to be verified in the hiding circuit | ||
| std::shared_ptr<DeciderProvingKey> prover_accumulator; // current PG prover accumulator instance | ||
| HonkProof decider_proof; // decider proof to be verified in the hiding circuit | ||
|
|
||
| std::shared_ptr<DeciderVerificationKey> | ||
| recursive_verifier_native_accum; // native verifier accumulator used in recursive folding | ||
| std::shared_ptr<DeciderVerificationKey> | ||
| native_verifier_accum; // native verifier accumulator used in prover folding | ||
| std::shared_ptr<MegaVerificationKey> honk_vk; // honk vk to be completed and folded into the accumulator | ||
| native_verifier_accum; // native verifier accumulator used in prover folding | ||
|
|
||
| // Set of tuples {proof, verification_key, type (Oink/PG)} to be recursively verified | ||
| VerificationQueue verification_queue; | ||
|
|
@@ -327,14 +324,9 @@ class ClientIVC { | |
| static void hide_op_queue_accumulation_result(ClientCircuit& circuit); | ||
| static void hide_op_queue_content_in_tail(ClientCircuit& circuit); | ||
| static void hide_op_queue_content_in_hiding(ClientCircuit& circuit); | ||
| HonkProof construct_mega_proof_for_hiding_kernel(ClientCircuit& circuit); | ||
|
|
||
| static bool verify(const Proof& proof, const VerificationKey& vk); | ||
|
|
||
| bool verify(const Proof& proof) const; | ||
|
|
||
| bool prove_and_verify(); | ||
|
|
||
| HonkProof construct_decider_proof(const std::shared_ptr<Transcript>& transcript); | ||
|
|
||
| VerificationKey get_vk() const; | ||
|
|
@@ -358,6 +350,9 @@ class ClientIVC { | |
| const std::shared_ptr<Transcript>& transcript, | ||
| bool is_kernel); | ||
|
|
||
| HonkProof construct_honk_proof_for_hiding_kernel(ClientCircuit& circuit, | ||
| const std::shared_ptr<MegaVerificationKey>& verification_key); | ||
|
|
||
| QUEUE_TYPE get_queue_type() const; | ||
|
|
||
| static std::shared_ptr<RecursiveDeciderVerificationKey> perform_oink_recursive_verification( | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -67,10 +67,6 @@ class ClientIVCTests : public ::testing::Test { | |
| ClientIVC ivc{ num_circuits, trace_settings }; | ||
|
|
||
| for (size_t j = 0; j < num_circuits; ++j) { | ||
| // Use default test settings for the mock hiding kernel since it's size must always be consistent | ||
| if (j == num_circuits - 1) { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is now handled internal to the mock circuit produced |
||
| settings = TestSettings{}; | ||
| } | ||
| circuit_producer.construct_and_accumulate_next_circuit(ivc, settings); | ||
| } | ||
| return { ivc.prove(), ivc.get_vk() }; | ||
|
|
@@ -112,7 +108,8 @@ TEST_F(ClientIVCTests, BadProofFailure) | |
| for (size_t idx = 0; idx < NUM_CIRCUITS; ++idx) { | ||
| circuit_producer.construct_and_accumulate_next_circuit(ivc, settings); | ||
| } | ||
| EXPECT_TRUE(ivc.prove_and_verify()); | ||
| auto proof = ivc.prove(); | ||
| EXPECT_TRUE(ClientIVC::verify(proof, ivc.get_vk())); | ||
| } | ||
|
|
||
| // The IVC throws an exception if the FIRST fold proof is tampered with | ||
|
|
@@ -139,7 +136,8 @@ TEST_F(ClientIVCTests, BadProofFailure) | |
| num_public_inputs); // tamper with first proof | ||
| } | ||
| } | ||
| EXPECT_FALSE(ivc.prove_and_verify()); | ||
| auto proof = ivc.prove(); | ||
| EXPECT_FALSE(ClientIVC::verify(proof, ivc.get_vk())); | ||
| } | ||
|
|
||
| // The IVC fails if the SECOND fold proof is tampered with | ||
|
|
@@ -160,7 +158,8 @@ TEST_F(ClientIVCTests, BadProofFailure) | |
| circuit.num_public_inputs()); // tamper with second proof | ||
| } | ||
| } | ||
| EXPECT_FALSE(ivc.prove_and_verify()); | ||
| auto proof = ivc.prove(); | ||
| EXPECT_FALSE(ClientIVC::verify(proof, ivc.get_vk())); | ||
| } | ||
|
|
||
| EXPECT_TRUE(true); | ||
|
|
@@ -313,7 +312,8 @@ TEST_F(ClientIVCTests, StructuredTraceOverflow) | |
| log2_num_gates += 1; | ||
| } | ||
|
|
||
| EXPECT_TRUE(ivc.prove_and_verify()); | ||
| auto proof = ivc.prove(); | ||
| EXPECT_TRUE(ClientIVC::verify(proof, ivc.get_vk())); | ||
| }; | ||
|
|
||
| /** | ||
|
|
@@ -348,8 +348,9 @@ TEST_F(ClientIVCTests, DynamicTraceOverflow) | |
| ivc, { .log2_num_gates = test.log2_num_arith_gates[idx] }); | ||
| } | ||
|
|
||
| EXPECT_EQ(check_accumulator_target_sum_manual(ivc.fold_output.accumulator), true); | ||
| EXPECT_TRUE(ivc.prove_and_verify()); | ||
| EXPECT_EQ(check_accumulator_target_sum_manual(ivc.prover_accumulator), true); | ||
| auto proof = ivc.prove(); | ||
| EXPECT_TRUE(ClientIVC::verify(proof, ivc.get_vk())); | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -421,5 +422,6 @@ TEST_F(ClientIVCTests, DatabusFailure) | |
| ivc.accumulate(circuit, vk); | ||
| } | ||
|
|
||
| EXPECT_FALSE(ivc.prove_and_verify()); | ||
| auto proof = ivc.prove(); | ||
| EXPECT_FALSE(ClientIVC::verify(proof, ivc.get_vk())); | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -202,6 +202,11 @@ class PrivateFunctionExecutionMockCircuitProducer { | |
| std::pair<ClientCircuit, std::shared_ptr<VerificationKey>> create_next_circuit_and_vk(ClientIVC& ivc, | ||
| TestSettings settings = {}) | ||
| { | ||
| // If this is a mock hiding kernel, remove the settings and use a default (non-structured) trace | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oops seems like I forgot about this when refactoring the tests. thanks! |
||
| if (ivc.num_circuits_accumulated == ivc.get_num_circuits() - 1) { | ||
| settings = TestSettings{}; | ||
| ivc.trace_settings = TraceSettings{}; | ||
| } | ||
| auto circuit = create_next_circuit(ivc, settings.log2_num_gates, settings.num_public_inputs); | ||
| return { circuit, get_verification_key(circuit, ivc.trace_settings) }; | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,23 +13,6 @@ | |
|
|
||
| namespace bb { | ||
|
|
||
| /** | ||
| * @brief Verify an IVC proof | ||
| * | ||
| */ | ||
| bool verify_ivc(ClientIVC::Proof& proof, ClientIVC& ivc) | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. unused |
||
| { | ||
| bool verified = ivc.verify(proof); | ||
|
|
||
| // This is a benchmark, not a test, so just print success or failure to the log | ||
| if (verified) { | ||
| info("IVC successfully verified!"); | ||
| } else { | ||
| info("IVC failed to verify."); | ||
| } | ||
| return verified; | ||
| } | ||
|
|
||
| /** | ||
| * @brief Perform a specified number of circuit accumulation rounds | ||
| * | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the tail now uses the databus - it has no public inputs to propagate
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah great! I think I removed it and had some tests failing in my previous clean up.