Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
eccvm_transcript.test.cpp
Go to the documentation of this file.
11#include <gtest/gtest.h>
12
13using namespace bb;
14
15namespace {
19void add_hiding_op_for_test(const std::shared_ptr<ECCOpQueue>& op_queue)
20{
22 op_queue->append_hiding_op(Fq::random_element(), Fq::random_element());
23}
24} // namespace
25
26class ECCVMTranscriptTests : public ::testing::Test {
27 public:
32
45 {
46 TranscriptManifest manifest_expected;
47 // Size of types is number of bb::frs needed to represent the type
48 size_t frs_per_Fq = FrCodec::calc_num_fields<FF>();
49 size_t frs_per_Fr = FrCodec::calc_num_fields<Flavor::BF>();
50 size_t frs_per_G = FrCodec::calc_num_fields<typename Flavor::Commitment>();
51 size_t frs_per_evals = (Flavor::NUM_ALL_ENTITIES)*frs_per_Fq;
52
53 size_t round = 0;
54 manifest_expected.add_entry(round, "vk_hash", frs_per_Fr);
55 manifest_expected.add_entry(round, "Gemini:masking_poly_comm", frs_per_G);
56 manifest_expected.add_entry(round, "TRANSCRIPT_ADD", frs_per_G);
57 manifest_expected.add_entry(round, "TRANSCRIPT_EQ", frs_per_G);
58 manifest_expected.add_entry(round, "TRANSCRIPT_MSM_TRANSITION", frs_per_G);
59 manifest_expected.add_entry(round, "TRANSCRIPT_PX", frs_per_G);
60 manifest_expected.add_entry(round, "TRANSCRIPT_PY", frs_per_G);
61 manifest_expected.add_entry(round, "TRANSCRIPT_Z1", frs_per_G);
62 manifest_expected.add_entry(round, "TRANSCRIPT_Z2", frs_per_G);
63 manifest_expected.add_entry(round, "TRANSCRIPT_Z1ZERO", frs_per_G);
64 manifest_expected.add_entry(round, "TRANSCRIPT_Z2ZERO", frs_per_G);
65 manifest_expected.add_entry(round, "TRANSCRIPT_OP", frs_per_G);
66 manifest_expected.add_entry(round, "TRANSCRIPT_MSM_X", frs_per_G);
67 manifest_expected.add_entry(round, "TRANSCRIPT_MSM_Y", frs_per_G);
68 manifest_expected.add_entry(round, "PRECOMPUTE_POINT_TRANSITION", frs_per_G);
69 manifest_expected.add_entry(round, "PRECOMPUTE_S1LO", frs_per_G);
70 manifest_expected.add_entry(round, "PRECOMPUTE_S2HI", frs_per_G);
71 manifest_expected.add_entry(round, "PRECOMPUTE_S2LO", frs_per_G);
72 manifest_expected.add_entry(round, "PRECOMPUTE_S3HI", frs_per_G);
73 manifest_expected.add_entry(round, "PRECOMPUTE_S3LO", frs_per_G);
74 manifest_expected.add_entry(round, "PRECOMPUTE_S4HI", frs_per_G);
75 manifest_expected.add_entry(round, "PRECOMPUTE_S4LO", frs_per_G);
76 manifest_expected.add_entry(round, "PRECOMPUTE_SKEW", frs_per_G);
77 manifest_expected.add_entry(round, "MSM_SIZE_OF_MSM", frs_per_G);
78 manifest_expected.add_entry(round, "MSM_ADD2", frs_per_G);
79 manifest_expected.add_entry(round, "MSM_ADD3", frs_per_G);
80 manifest_expected.add_entry(round, "MSM_ADD4", frs_per_G);
81 manifest_expected.add_entry(round, "MSM_X1", frs_per_G);
82 manifest_expected.add_entry(round, "MSM_Y1", frs_per_G);
83 manifest_expected.add_entry(round, "MSM_X2", frs_per_G);
84 manifest_expected.add_entry(round, "MSM_Y2", frs_per_G);
85 manifest_expected.add_entry(round, "MSM_X3", frs_per_G);
86 manifest_expected.add_entry(round, "MSM_Y3", frs_per_G);
87 manifest_expected.add_entry(round, "MSM_X4", frs_per_G);
88 manifest_expected.add_entry(round, "MSM_Y4", frs_per_G);
89 manifest_expected.add_entry(round, "MSM_COLLISION_X1", frs_per_G);
90 manifest_expected.add_entry(round, "MSM_COLLISION_X2", frs_per_G);
91 manifest_expected.add_entry(round, "MSM_COLLISION_X3", frs_per_G);
92 manifest_expected.add_entry(round, "MSM_COLLISION_X4", frs_per_G);
93 manifest_expected.add_entry(round, "MSM_LAMBDA1", frs_per_G);
94 manifest_expected.add_entry(round, "MSM_LAMBDA2", frs_per_G);
95 manifest_expected.add_entry(round, "MSM_LAMBDA3", frs_per_G);
96 manifest_expected.add_entry(round, "MSM_LAMBDA4", frs_per_G);
97 manifest_expected.add_entry(round, "MSM_SLICE1", frs_per_G);
98 manifest_expected.add_entry(round, "MSM_SLICE2", frs_per_G);
99 manifest_expected.add_entry(round, "MSM_SLICE3", frs_per_G);
100 manifest_expected.add_entry(round, "MSM_SLICE4", frs_per_G);
101 manifest_expected.add_entry(round, "TRANSCRIPT_RESET_ACCUMULATOR", frs_per_G);
102 manifest_expected.add_entry(round, "LOOKUP_READ_COUNTS_0", frs_per_G);
103 manifest_expected.add_entry(round, "LOOKUP_READ_COUNTS_1", frs_per_G);
104 manifest_expected.add_entry(round, "TRANSCRIPT_BASE_INFINITY", frs_per_G);
105 manifest_expected.add_entry(round, "TRANSCRIPT_BASE_X_INVERSE", frs_per_G);
106 manifest_expected.add_entry(round, "TRANSCRIPT_BASE_Y_INVERSE", frs_per_G);
107 manifest_expected.add_entry(round, "TRANSCRIPT_ADD_X_EQUAL", frs_per_G);
108 manifest_expected.add_entry(round, "TRANSCRIPT_ADD_Y_EQUAL", frs_per_G);
109 manifest_expected.add_entry(round, "TRANSCRIPT_ADD_LAMBDA", frs_per_G);
110 manifest_expected.add_entry(round, "TRANSCRIPT_MSM_INTERMEDIATE_X", frs_per_G);
111 manifest_expected.add_entry(round, "TRANSCRIPT_MSM_INTERMEDIATE_Y", frs_per_G);
112 manifest_expected.add_entry(round, "TRANSCRIPT_MSM_INFINITY", frs_per_G);
113 manifest_expected.add_entry(round, "TRANSCRIPT_MSM_X_INVERSE", frs_per_G);
114 manifest_expected.add_entry(round, "TRANSCRIPT_MSM_COUNT_ZERO_AT_TRANSITION", frs_per_G);
115 manifest_expected.add_entry(round, "TRANSCRIPT_MSM_COUNT_AT_TRANSITION_INVERSE", frs_per_G);
116 manifest_expected.add_entry(round, "TRANSCRIPT_MUL", frs_per_G);
117 manifest_expected.add_entry(round, "TRANSCRIPT_MSM_COUNT", frs_per_G);
118 manifest_expected.add_entry(round, "PRECOMPUTE_SCALAR_SUM", frs_per_G);
119 manifest_expected.add_entry(round, "PRECOMPUTE_S1HI", frs_per_G);
120 manifest_expected.add_entry(round, "PRECOMPUTE_DX", frs_per_G);
121 manifest_expected.add_entry(round, "PRECOMPUTE_DY", frs_per_G);
122 manifest_expected.add_entry(round, "PRECOMPUTE_TX", frs_per_G);
123 manifest_expected.add_entry(round, "PRECOMPUTE_TY", frs_per_G);
124 manifest_expected.add_entry(round, "MSM_TRANSITION", frs_per_G);
125 manifest_expected.add_entry(round, "MSM_ADD", frs_per_G);
126 manifest_expected.add_entry(round, "MSM_DOUBLE", frs_per_G);
127 manifest_expected.add_entry(round, "MSM_SKEW", frs_per_G);
128 manifest_expected.add_entry(round, "MSM_ACCUMULATOR_X", frs_per_G);
129 manifest_expected.add_entry(round, "MSM_ACCUMULATOR_Y", frs_per_G);
130 manifest_expected.add_entry(round, "MSM_COUNT", frs_per_G);
131 manifest_expected.add_entry(round, "MSM_ROUND", frs_per_G);
132 manifest_expected.add_entry(round, "MSM_ADD1", frs_per_G);
133 manifest_expected.add_entry(round, "MSM_PC", frs_per_G);
134 manifest_expected.add_entry(round, "PRECOMPUTE_PC", frs_per_G);
135 manifest_expected.add_entry(round, "TRANSCRIPT_PC", frs_per_G);
136 manifest_expected.add_entry(round, "PRECOMPUTE_ROUND", frs_per_G);
137 manifest_expected.add_entry(round, "PRECOMPUTE_SELECT", frs_per_G);
138 manifest_expected.add_entry(round, "TRANSCRIPT_ACCUMULATOR_NOT_EMPTY", frs_per_G);
139 manifest_expected.add_entry(round, "TRANSCRIPT_ACCUMULATOR_X", frs_per_G);
140 manifest_expected.add_entry(round, "TRANSCRIPT_ACCUMULATOR_Y", frs_per_G);
141 manifest_expected.add_challenge(round, std::array{ "beta", "gamma" });
142
143 round++;
144 manifest_expected.add_entry(round, "LOOKUP_INVERSES", frs_per_G);
145 manifest_expected.add_entry(round, "Z_PERM", frs_per_G);
146 manifest_expected.add_challenge(round, "Sumcheck:alpha");
147
148 for (size_t i = 0; i < CONST_ECCVM_LOG_N; i++) {
149 round++;
150 std::string label = "Sumcheck:gate_challenge_" + std::to_string(i);
151 manifest_expected.add_challenge(round, label);
152 }
153 round++;
154
155 manifest_expected.add_entry(round, "Libra:concatenation_commitment", frs_per_G);
156 manifest_expected.add_entry(round, "Libra:Sum", frs_per_Fq);
157 // get the challenge for the ZK Sumcheck claim
158 manifest_expected.add_challenge(round, "Libra:Challenge");
159
160 for (size_t i = 0; i < CONST_ECCVM_LOG_N; ++i) {
161 round++;
162 std::string idx = std::to_string(i);
163 manifest_expected.add_entry(round, "Sumcheck:univariate_comm_" + idx, frs_per_G);
164 manifest_expected.add_entry(round, "Sumcheck:univariate_" + idx + "_eval_0", frs_per_Fq);
165 manifest_expected.add_entry(round, "Sumcheck:univariate_" + idx + "_eval_1", frs_per_Fq);
166 std::string label = "Sumcheck:u_" + idx;
167 manifest_expected.add_challenge(round, label);
168 }
169
170 round++;
171
172 manifest_expected.add_entry(round, "Sumcheck:evaluations", frs_per_evals);
173 manifest_expected.add_entry(round, "Libra:claimed_evaluation", frs_per_Fq);
174 manifest_expected.add_entry(round, "Libra:grand_sum_commitment", frs_per_G);
175 manifest_expected.add_entry(round, "Libra:quotient_commitment", frs_per_G);
176
177 manifest_expected.add_challenge(round, "rho");
178
179 round++;
180 for (size_t i = 1; i < CONST_ECCVM_LOG_N; ++i) {
181 std::string idx = std::to_string(i);
182 manifest_expected.add_entry(round, "Gemini:FOLD_" + idx, frs_per_G);
183 }
184 manifest_expected.add_challenge(round, "Gemini:r");
185 round++;
186 for (size_t i = 1; i <= CONST_ECCVM_LOG_N; ++i) {
187 std::string idx = std::to_string(i);
188 manifest_expected.add_entry(round, "Gemini:a_" + idx, frs_per_Fq);
189 }
190 manifest_expected.add_entry(round, "Libra:concatenation_eval", frs_per_Fq);
191 manifest_expected.add_entry(round, "Libra:shifted_grand_sum_eval", frs_per_Fq);
192 manifest_expected.add_entry(round, "Libra:grand_sum_eval", frs_per_Fq);
193 manifest_expected.add_entry(round, "Libra:quotient_eval", frs_per_Fq);
194 manifest_expected.add_challenge(round, "Shplonk:nu");
195 round++;
196 manifest_expected.add_entry(round, "Shplonk:Q", frs_per_G);
197 manifest_expected.add_challenge(round, "Shplonk:z");
198
199 round++;
200 manifest_expected.add_entry(round, "Translation:concatenated_masking_term_commitment", frs_per_G);
201 manifest_expected.add_challenge(round, "Translation:evaluation_challenge_x");
202
203 round++;
204 manifest_expected.add_entry(round, "Translation:op", frs_per_Fq);
205 manifest_expected.add_entry(round, "Translation:Px", frs_per_Fq);
206 manifest_expected.add_entry(round, "Translation:Py", frs_per_Fq);
207 manifest_expected.add_entry(round, "Translation:z1", frs_per_Fq);
208 manifest_expected.add_entry(round, "Translation:z2", frs_per_Fq);
209 manifest_expected.add_challenge(round, "Translation:batching_challenge_v");
210
211 round++;
212 manifest_expected.add_entry(round, "Translation:masking_term_eval", frs_per_Fq);
213 manifest_expected.add_entry(round, "Translation:grand_sum_commitment", frs_per_G);
214 manifest_expected.add_entry(round, "Translation:quotient_commitment", frs_per_G);
215 manifest_expected.add_challenge(round, "Translation:small_ipa_evaluation_challenge");
216
217 round++;
218 manifest_expected.add_entry(round, "Translation:concatenation_eval", frs_per_Fq);
219 manifest_expected.add_entry(round, "Translation:grand_sum_shift_eval", frs_per_Fq);
220 manifest_expected.add_entry(round, "Translation:grand_sum_eval", frs_per_Fq);
221 manifest_expected.add_entry(round, "Translation:quotient_eval", frs_per_Fq);
222 manifest_expected.add_challenge(round, "Shplonk:nu");
223
224 round++;
225 manifest_expected.add_entry(round, "Shplonk:Q", frs_per_G);
226 manifest_expected.add_challenge(round, "Shplonk:z");
227
228 return manifest_expected;
229 }
230
232 {
233 TranscriptManifest manifest_expected;
234 // Size of types is number of bb::frs needed to represent the type
235 size_t frs_per_Fq = FrCodec::calc_num_fields<FF>();
236 size_t frs_per_G = FrCodec::calc_num_fields<Flavor::Commitment>();
237 size_t round = 0;
238
239 manifest_expected.add_entry(round, "IPA:commitment", frs_per_G);
240 manifest_expected.add_entry(round, "IPA:challenge", frs_per_Fq);
241 manifest_expected.add_entry(round, "IPA:evaluation", frs_per_Fq);
242 manifest_expected.add_challenge(round, "IPA:generator_challenge");
243
244 for (size_t i = 0; i < CONST_ECCVM_LOG_N; ++i) {
245 round++;
246 std::string idx = std::to_string(CONST_ECCVM_LOG_N - i - 1);
247 manifest_expected.add_entry(round, "IPA:L_" + idx, frs_per_G);
248 manifest_expected.add_entry(round, "IPA:R_" + idx, frs_per_G);
249 std::string label = "IPA:round_challenge_" + idx;
250 manifest_expected.add_challenge(round, label);
251 }
252
253 round++;
254 manifest_expected.add_entry(round, "IPA:G_0", frs_per_G);
255 manifest_expected.add_entry(round, "IPA:a_0", frs_per_Fq);
256 return manifest_expected;
257 }
258
260 {
262 using G1 = typename Flavor::CycleGroup;
263 using Fr = typename G1::Fr;
264
265 auto generators = G1::derive_generators("test generators", 3);
266
267 typename G1::element a = generators[0];
268 typename G1::element b = generators[1];
269 typename G1::element c = generators[2];
272
273 op_queue->add_accumulate(a);
274 op_queue->mul_accumulate(a, x);
275 op_queue->mul_accumulate(b, x);
276 op_queue->mul_accumulate(b, y);
277 op_queue->add_accumulate(a);
278 op_queue->mul_accumulate(b, x);
279 op_queue->eq_and_reset();
280 op_queue->add_accumulate(c);
281 op_queue->mul_accumulate(a, x);
282 op_queue->mul_accumulate(b, x);
283 op_queue->eq_and_reset();
284 op_queue->mul_accumulate(a, x);
285 op_queue->mul_accumulate(b, x);
286 op_queue->mul_accumulate(c, x);
287 op_queue->merge();
288 add_hiding_op_for_test(op_queue);
289
290 ECCVMCircuitBuilder builder{ op_queue };
291 return builder;
292 }
293};
294
296
301TEST_F(ECCVMTranscriptTests, ProverManifestConsistency)
302{
303 // Construct a simple circuit
304 auto builder = this->generate_trace(&engine);
305
306 // Automatically generate a transcript manifest by constructing a proof
307 std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
308 ECCVMProver prover(builder, prover_transcript);
309 prover.transcript->enable_manifest();
310 auto [proof, opening_claim] = prover.construct_proof();
311
312 // Compute IPA proof with manifest enabled
313 auto ipa_transcript = std::make_shared<Transcript>();
314 ipa_transcript->enable_manifest();
315 ECCVMFlavor::PCS::compute_opening_proof(prover.key->commitment_key, opening_claim, ipa_transcript);
316
317 // Check that the prover generated manifest agrees with the manifest hard coded in this suite
318 auto manifest_expected = this->construct_eccvm_honk_manifest();
319 auto prover_manifest = prover.transcript->get_manifest();
320
321 // Note: a manifest can be printed using manifest.print()
322 ASSERT_GT(manifest_expected.size(), 0);
323 for (size_t round = 0; round < manifest_expected.size(); ++round) {
324 ASSERT_EQ(prover_manifest[round], manifest_expected[round]) << "Prover manifest discrepency in round " << round;
325 }
326
327 auto ipa_manifest_expected = this->construct_eccvm_ipa_manifest();
328 auto prover_ipa_manifest = ipa_transcript->get_manifest();
329
330 // Note: a manifest can be printed using manifest.print()
331 ASSERT_GT(ipa_manifest_expected.size(), 0);
332 for (size_t round = 0; round < ipa_manifest_expected.size(); ++round) {
333 ASSERT_EQ(prover_ipa_manifest[round], ipa_manifest_expected[round])
334 << "IPA prover manifest discrepency in round " << round;
335 }
336}
337
343TEST_F(ECCVMTranscriptTests, VerifierManifestConsistency)
344{
345 // Construct a simple circuit
346 auto builder = this->generate_trace(&engine);
347
348 // Automatically generate a transcript manifest in the prover by constructing a proof
349 std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
350 ECCVMProver prover(builder, prover_transcript);
351 prover_transcript->enable_manifest();
352 auto [proof, opening_claim] = prover.construct_proof();
353
354 // Compute IPA proof with manifest enabled
355 auto prover_ipa_transcript = std::make_shared<Transcript>();
356 prover_ipa_transcript->enable_manifest();
357 ECCVMFlavor::PCS::compute_opening_proof(prover.key->commitment_key, opening_claim, prover_ipa_transcript);
358
359 // Automatically generate a transcript manifest in the verifier by verifying a proof
360 std::shared_ptr<Transcript> verifier_transcript = std::make_shared<Transcript>();
361 ECCVMVerifier verifier(verifier_transcript, proof);
362 verifier.transcript->enable_manifest();
363 auto verifier_opening_claim = verifier.verify_proof();
364
365 // Verify IPA with manifest enabled
366 auto verifier_ipa_transcript = std::make_shared<Transcript>(prover_ipa_transcript->export_proof());
367 verifier_ipa_transcript->enable_manifest();
368 ECCVMFlavor::PCS::reduce_verify(
369 verifier.key->pcs_verification_key, verifier_opening_claim, verifier_ipa_transcript);
370
371 // Check consistency between the manifests generated by the prover and verifier
372 auto prover_manifest = prover.transcript->get_manifest();
373 auto verifier_manifest = verifier.transcript->get_manifest();
374
375 // Note: a manifest can be printed using manifest.print()
376 // The last challenge generated by the ECCVM Prover is the translation univariate batching challenge and, on the
377 // verifier side, is only generated in the translator verifier hence the ECCVM prover's manifest will have one extra
378 // challenge
379 ASSERT_GT(prover_manifest.size(), 0);
380 for (size_t round = 0; round < prover_manifest.size() - 1; ++round) {
381 ASSERT_EQ(prover_manifest[round], verifier_manifest[round])
382 << "Prover/Verifier manifest discrepency in round " << round;
383 }
384
385 // Check consistency of IPA transcripts
386 auto prover_ipa_manifest = prover_ipa_transcript->get_manifest();
387 auto verifier_ipa_manifest = verifier_ipa_transcript->get_manifest();
388 ASSERT_GT(prover_ipa_manifest.size(), 0);
389 for (size_t round = 0; round < prover_ipa_manifest.size(); ++round) {
390 ASSERT_EQ(prover_ipa_manifest[round], verifier_ipa_manifest[round])
391 << "Prover/Verifier IPA manifest discrepency in round " << round;
392 }
393}
394
400TEST_F(ECCVMTranscriptTests, ChallengeGenerationTest)
401{
402 // initialized with random value sent to verifier
403 auto transcript = Flavor::Transcript::prover_init_empty();
404 // test a bunch of challenges
405 std::vector<std::string> challenge_labels{ "a", "b", "c", "d", "e", "f" };
406 auto challenges = transcript->template get_challenges<FF>(challenge_labels);
407 // check they are not 0
408 for (size_t i = 0; i < challenges.size(); ++i) {
409 ASSERT_NE(challenges[i], 0) << "Challenge " << i << " is 0";
410 }
411 constexpr uint32_t random_val{ 17 }; // arbitrary
412 transcript->send_to_verifier("random val", random_val);
413 // test more challenges
414 challenge_labels = { "a", "b", "c" };
415 challenges = transcript->template get_challenges<FF>(challenge_labels);
416
417 ASSERT_NE(challenges[0], 0) << "Challenge a is 0";
418 ASSERT_NE(challenges[1], 0) << "Challenge b is 0";
419 ASSERT_NE(challenges[2], 0) << "Challenge c is 0";
420}
ECCVMCircuitBuilder generate_trace(numeric::RNG *engine=nullptr)
TranscriptManifest construct_eccvm_honk_manifest()
Construct a manifest for a ECCVM Honk proof.
TranscriptManifest construct_eccvm_ipa_manifest()
Common transcript class for both parties. Stores the data for the current round, as well as the manif...
static constexpr size_t NUM_ALL_ENTITIES
NativeTranscript Transcript
std::shared_ptr< Transcript > transcript
std::pair< Proof, OpeningClaim > construct_proof()
std::shared_ptr< ProvingKey > key
Unified ECCVM verifier class for both native and recursive verification.
std::shared_ptr< Transcript > transcript
std::shared_ptr< VerificationKey > key
OpeningClaim< Curve > verify_proof()
Verifies an ECCVM Honk proof for given program settings.
void add_entry(size_t round, const std::string &element_label, size_t element_size)
void add_challenge(size_t round, const std::string &label)
Add a single challenge label to the manifest for the given round.
bb::fq BaseField
Definition bn254.hpp:19
AluTraceBuilder builder
Definition alu.test.cpp:124
FF a
FF b
numeric::RNG & engine
Base class templates for structures that contain data parameterized by the fundamental polynomials of...
RNG & get_debug_randomness(bool reset, std::uint_fast64_t seed)
Definition engine.cpp:190
std::filesystem::path bb_crs_path()
void init_file_crs_factory(const std::filesystem::path &path)
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
TEST_F(IPATest, ChallengesAreZero)
Definition ipa.test.cpp:185
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
std::string to_string(bb::avm2::ValueTag tag)
Curve::AffineElement G1
static field random_element(numeric::RNG *engine=nullptr) noexcept