Skip to content

Commit 7a8942c

Browse files
iakovenkosThunkar
authored andcommitted
fix: CIVC components share a transcript (#14144)
Closes AztecProtocol/barretenberg#1262
1 parent 513717b commit 7a8942c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+499
-1140
lines changed

barretenberg/cpp/src/barretenberg/benchmark/goblin_bench/eccvm.bench.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ using namespace bb;
99

1010
using Flavor = ECCVMFlavor;
1111
using Builder = ECCVMCircuitBuilder;
12+
using Transcript = ECCVMFlavor::Transcript;
1213

1314
namespace {
1415

@@ -48,7 +49,8 @@ void eccvm_generate_prover(State& state) noexcept
4849
size_t target_num_gates = 1 << static_cast<size_t>(state.range(0));
4950
for (auto _ : state) {
5051
Builder builder = generate_trace(target_num_gates);
51-
ECCVMProver prover(builder);
52+
std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
53+
ECCVMProver prover(builder, prover_transcript);
5254
};
5355
}
5456

@@ -57,7 +59,8 @@ void eccvm_prove(State& state) noexcept
5759

5860
size_t target_num_gates = 1 << static_cast<size_t>(state.range(0));
5961
Builder builder = generate_trace(target_num_gates);
60-
ECCVMProver prover(builder);
62+
std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
63+
ECCVMProver prover(builder, prover_transcript);
6164
for (auto _ : state) {
6265
ECCVMProof proof = prover.construct_proof();
6366
};

barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -264,8 +264,7 @@ void ClientIVC::hide_op_queue_accumulation_result(ClientCircuit& circuit)
264264
* @brief Construct the proving key of the hiding circuit, which recursively verifies the last folding proof and the
265265
* decider proof.
266266
*/
267-
std::pair<std::shared_ptr<ClientIVC::DeciderZKProvingKey>, ClientIVC::MergeProof> ClientIVC::
268-
construct_hiding_circuit_key()
267+
std::shared_ptr<ClientIVC::DeciderZKProvingKey> ClientIVC::construct_hiding_circuit_key()
269268
{
270269
trace_usage_tracker.print(); // print minimum structured sizes for each block
271270
BB_ASSERT_EQ(verification_queue.size(), static_cast<size_t>(1));
@@ -330,25 +329,26 @@ std::pair<std::shared_ptr<ClientIVC::DeciderZKProvingKey>, ClientIVC::MergeProof
330329

331330
auto decider_pk = std::make_shared<DeciderZKProvingKey>(builder, TraceSettings(), bn254_commitment_key);
332331
honk_vk = std::make_shared<MegaZKVerificationKey>(decider_pk->proving_key);
333-
// Construct the last merge proof for the present circuit
334-
MergeProof merge_proof = goblin.prove_merge();
335332

336-
return { decider_pk, merge_proof };
333+
return decider_pk;
337334
}
338335

339336
/**
340337
* @brief Construct the hiding circuit then produce a proof of the circuit's correctness with MegaHonk.
341338
*
342339
* @return HonkProof - a Mega proof
343340
*/
344-
std::pair<HonkProof, ClientIVC::MergeProof> ClientIVC::construct_and_prove_hiding_circuit()
341+
HonkProof ClientIVC::construct_and_prove_hiding_circuit()
345342
{
346-
auto [decider_pk, merge_proof] = construct_hiding_circuit_key();
347-
// FoldingRecursiveVerifier circuit is proven by a MegaZKProver
348-
MegaZKProver prover(decider_pk);
343+
// Create a transcript to be shared by final merge prover, ECCVM, Translator, and Hiding Circuit provers.
344+
goblin.transcript = std::make_shared<Goblin::Transcript>();
345+
goblin.transcript->enable_manifest();
346+
auto decider_pk = construct_hiding_circuit_key();
347+
// Hiding circuit is proven by a MegaZKProver
348+
MegaZKProver prover(decider_pk, goblin.transcript);
349349
HonkProof proof = prover.construct_proof();
350350

351-
return { proof, merge_proof };
351+
return proof;
352352
}
353353

354354
/**
@@ -358,19 +358,27 @@ std::pair<HonkProof, ClientIVC::MergeProof> ClientIVC::construct_and_prove_hidin
358358
*/
359359
ClientIVC::Proof ClientIVC::prove()
360360
{
361-
auto [mega_proof, merge_proof] = construct_and_prove_hiding_circuit();
361+
auto mega_proof = construct_and_prove_hiding_circuit();
362+
363+
// Construct the last merge proof for the present circuit
364+
MergeProof merge_proof = goblin.prove_final_merge();
365+
366+
// Prove ECCVM and Translator
362367
return { mega_proof, goblin.prove(merge_proof) };
363368
};
364369

365370
bool ClientIVC::verify(const Proof& proof, const VerificationKey& vk)
366371
{
372+
// Create a transcript to be shared by MegaZK-, Merge-, ECCVM-, and Translator- Verifiers.
373+
std::shared_ptr<Goblin::Transcript> civc_verifier_transcript = std::make_shared<Goblin::Transcript>();
367374
// Verify the hiding circuit proof
368-
MegaZKVerifier verifer{ vk.mega };
375+
MegaZKVerifier verifer{ vk.mega, /*ipa_verification_key=*/{}, civc_verifier_transcript };
369376
bool mega_verified = verifer.verify_proof(proof.mega_proof);
370377
vinfo("Mega verified: ", mega_verified);
371378
// Goblin verification (final merge, eccvm, translator)
372-
bool goblin_verified = Goblin::verify(proof.goblin_proof);
379+
bool goblin_verified = Goblin::verify(proof.goblin_proof, civc_verifier_transcript);
373380
vinfo("Goblin verified: ", goblin_verified);
381+
// TODO(https://github.com/AztecProtocol/barretenberg/issues/1396): State tracking in CIVC verifiers.
374382
return goblin_verified && mega_verified;
375383
}
376384

barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,9 +199,9 @@ class ClientIVC {
199199

200200
Proof prove();
201201

202-
std::pair<std::shared_ptr<ClientIVC::DeciderZKProvingKey>, MergeProof> construct_hiding_circuit_key();
202+
std::shared_ptr<ClientIVC::DeciderZKProvingKey> construct_hiding_circuit_key();
203203
static void hide_op_queue_accumulation_result(ClientCircuit& circuit);
204-
std::pair<HonkProof, MergeProof> construct_and_prove_hiding_circuit();
204+
HonkProof construct_and_prove_hiding_circuit();
205205

206206
static bool verify(const Proof& proof, const VerificationKey& vk);
207207

barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,17 @@ class ClientIVCTests : public ::testing::Test {
4545
}
4646
}
4747
}
48+
49+
static std::pair<ClientIVC::Proof, ClientIVC::VerificationKey> generate_ivc_proof(size_t num_circuits)
50+
{
51+
ClientIVC ivc{ { SMALL_TEST_STRUCTURE } };
52+
ClientIVCMockCircuitProducer circuit_producer;
53+
for (size_t j = 0; j < num_circuits; ++j) {
54+
auto circuit = circuit_producer.create_next_circuit(ivc, /*log2_num_gates=*/5);
55+
ivc.accumulate(circuit);
56+
}
57+
return { ivc.prove(), ivc.get_vk() };
58+
};
4859
};
4960

5061
/**
@@ -290,6 +301,61 @@ TEST_F(ClientIVCTests, StructuredPrecomputedVKs)
290301
EXPECT_TRUE(ivc.prove_and_verify());
291302
};
292303

304+
/**
305+
* @brief Produce 2 valid CIVC proofs. Ensure that replacing a proof component with a component from a different proof
306+
* leads to a verification failure.
307+
*
308+
*/
309+
TEST_F(ClientIVCTests, WrongProofComponentFailure)
310+
{
311+
// Produce two valid proofs
312+
auto [civc_proof_1, civc_vk_1] = generate_ivc_proof(/*num_circuits=*/2);
313+
{
314+
EXPECT_TRUE(ClientIVC::verify(civc_proof_1, civc_vk_1));
315+
}
316+
317+
auto [civc_proof_2, civc_vk_2] = generate_ivc_proof(/*num_circuits=*/2);
318+
{
319+
EXPECT_TRUE(ClientIVC::verify(civc_proof_2, civc_vk_2));
320+
}
321+
322+
{
323+
// Replace Merge proof
324+
ClientIVC::Proof tampered_proof = civc_proof_1;
325+
326+
tampered_proof.goblin_proof.merge_proof = civc_proof_2.goblin_proof.merge_proof;
327+
328+
EXPECT_FALSE(ClientIVC::verify(tampered_proof, civc_vk_1));
329+
}
330+
331+
{
332+
// Replace hiding circuit proof
333+
ClientIVC::Proof tampered_proof = civc_proof_1;
334+
335+
tampered_proof.mega_proof = civc_proof_2.mega_proof;
336+
337+
EXPECT_FALSE(ClientIVC::verify(tampered_proof, civc_vk_1));
338+
}
339+
340+
{
341+
// Replace ECCVM proof
342+
ClientIVC::Proof tampered_proof = civc_proof_1;
343+
344+
tampered_proof.goblin_proof.eccvm_proof = civc_proof_2.goblin_proof.eccvm_proof;
345+
346+
EXPECT_FALSE(ClientIVC::verify(tampered_proof, civc_vk_1));
347+
}
348+
349+
{
350+
// Replace Translator proof
351+
ClientIVC::Proof tampered_proof = civc_proof_1;
352+
353+
tampered_proof.goblin_proof.translator_proof = civc_proof_2.goblin_proof.translator_proof;
354+
355+
EXPECT_FALSE(ClientIVC::verify(tampered_proof, civc_vk_1));
356+
}
357+
};
358+
293359
/**
294360
* @brief Ensure that the CIVC VK is independent of the number of circuits accumulated
295361
*

barretenberg/cpp/src/barretenberg/eccvm/eccvm.test.cpp

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
using namespace bb;
1818
using FF = ECCVMFlavor::FF;
1919
using PK = ECCVMFlavor::ProvingKey;
20+
using Transcript = ECCVMFlavor::Transcript;
2021
class ECCVMTests : public ::testing::Test {
2122
protected:
2223
void SetUp() override { srs::init_file_crs_factory(bb::srs::bb_crs_path()); };
@@ -93,9 +94,13 @@ void complete_proving_key_for_test(bb::RelationParameters<FF>& relation_paramete
9394
TEST_F(ECCVMTests, BaseCaseFixedSize)
9495
{
9596
ECCVMCircuitBuilder builder = generate_circuit(&engine);
96-
ECCVMProver prover(builder);
97+
98+
std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
99+
ECCVMProver prover(builder, prover_transcript);
97100
ECCVMProof proof = prover.construct_proof();
98-
ECCVMVerifier verifier(prover.key);
101+
102+
std::shared_ptr<Transcript> verifier_transcript = std::make_shared<Transcript>();
103+
ECCVMVerifier verifier(verifier_transcript);
99104
bool verified = verifier.verify_proof(proof);
100105

101106
ASSERT_TRUE(verified);
@@ -107,10 +112,13 @@ TEST_F(ECCVMTests, EqFailsFixedSize)
107112
// Tamper with the eq op such that the expected value is incorect
108113
builder.op_queue->add_erroneous_equality_op_for_testing();
109114

110-
ECCVMProver prover(builder);
115+
std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
116+
ECCVMProver prover(builder, prover_transcript);
111117

112118
ECCVMProof proof = prover.construct_proof();
113-
ECCVMVerifier verifier(prover.key);
119+
120+
std::shared_ptr<Transcript> verifier_transcript = std::make_shared<Transcript>();
121+
ECCVMVerifier verifier(verifier_transcript);
114122
bool verified = verifier.verify_proof(proof);
115123
ASSERT_FALSE(verified);
116124
}
@@ -127,17 +135,19 @@ TEST_F(ECCVMTests, CommittedSumcheck)
127135
std::vector<FF> gate_challenges(CONST_ECCVM_LOG_N);
128136

129137
ECCVMCircuitBuilder builder = generate_circuit(&engine);
130-
131-
ECCVMProver prover(builder);
132-
auto pk = std::make_shared<ProvingKey>(builder);
133-
134138
std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
139+
ECCVMProver prover(builder, prover_transcript);
140+
auto pk = std::make_shared<ProvingKey>(builder);
135141

136142
// Prepare the inputs for the sumcheck prover:
137143
// Compute and add beta to relation parameters
138144
const FF alpha = FF::random_element();
139145
complete_proving_key_for_test(relation_parameters, pk, gate_challenges);
140146

147+
// Clear the transcript
148+
prover_transcript = std::make_shared<Transcript>();
149+
150+
// Run Sumcheck on the ECCVM Prover polynomials
141151
using SumcheckProver = SumcheckProver<ECCVMFlavor, CONST_ECCVM_LOG_N>;
142152
SumcheckProver sumcheck_prover(pk->circuit_size, prover_transcript);
143153

@@ -146,7 +156,6 @@ TEST_F(ECCVMTests, CommittedSumcheck)
146156
auto prover_output =
147157
sumcheck_prover.prove(pk->polynomials, relation_parameters, alpha, gate_challenges, zk_sumcheck_data);
148158

149-
ECCVMVerifier verifier(prover.key);
150159
std::shared_ptr<Transcript> verifier_transcript = std::make_shared<Transcript>(prover_transcript->proof_data);
151160

152161
// Execute Sumcheck Verifier
@@ -180,24 +189,29 @@ TEST_F(ECCVMTests, FixedVK)
180189
{
181190
// Generate a circuit and its verification key (computed at runtime from the proving key)
182191
ECCVMCircuitBuilder builder = generate_circuit(&engine);
183-
ECCVMProver prover(builder);
184-
ECCVMVerifier verifier(prover.key);
192+
std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
193+
ECCVMProver prover(builder, prover_transcript);
194+
195+
std::shared_ptr<Transcript> verifier_transcript = std::make_shared<Transcript>();
196+
ECCVMVerifier verifier(verifier_transcript);
185197

186198
// Generate the default fixed VK
187199
ECCVMFlavor::VerificationKey fixed_vk{};
200+
// Generate a VK from PK
201+
ECCVMFlavor::VerificationKey vk_computed_by_prover(prover.key);
188202

189203
// Set verifier PCS key to null in both the fixed VK and the generated VK
190204
fixed_vk.pcs_verification_key = nullptr;
191-
verifier.key->pcs_verification_key = nullptr;
205+
vk_computed_by_prover.pcs_verification_key = nullptr;
192206

193207
auto labels = verifier.key->get_labels();
194208
size_t index = 0;
195-
for (auto [vk_commitment, fixed_commitment] : zip_view(verifier.key->get_all(), fixed_vk.get_all())) {
209+
for (auto [vk_commitment, fixed_commitment] : zip_view(vk_computed_by_prover.get_all(), fixed_vk.get_all())) {
196210
EXPECT_EQ(vk_commitment, fixed_commitment)
197211
<< "Mismatch between vk_commitment and fixed_commitment at label: " << labels[index];
198212
++index;
199213
}
200214

201215
// Check that the fixed VK is equal to the generated VK
202-
EXPECT_EQ(fixed_vk, *verifier.key.get());
216+
EXPECT_EQ(fixed_vk, vk_computed_by_prover);
203217
}

0 commit comments

Comments
 (0)