Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
mega_transcript.test.cpp
Go to the documentation of this file.
11
12#include <gtest/gtest.h>
13
14using namespace bb;
15
16using FlavorTypes = ::testing::Types<MegaFlavor, MegaZKFlavor>;
17
18template <typename Flavor> class MegaTranscriptTests : public ::testing::Test {
19 public:
21
25 using FF = Flavor::FF;
26
27 static Proof export_serialized_proof(Prover& prover, const size_t num_public_inputs)
28 {
29 // reset internal variables needed for exporting the proof
30 // Note: compute_proof_length_for_export excludes IPA proof length since export_proof appends it separately
31 size_t proof_length = compute_proof_length_for_export<Flavor>(num_public_inputs);
32 prover.transcript->test_set_proof_parsing_state(0, proof_length);
33 return prover.export_proof();
34 }
47 {
48 using Commitment = typename Flavor::Commitment;
49 TranscriptManifest manifest_expected;
50
51 const size_t virtual_log_n = Flavor::VIRTUAL_LOG_N;
52
53 size_t NUM_PUBLIC_INPUTS =
55 size_t MAX_PARTIAL_RELATION_LENGTH = Flavor::BATCHED_RELATION_PARTIAL_LENGTH;
56
57 size_t frs_per_Fr = FrCodec::calc_num_fields<FF>();
58 size_t frs_per_G = FrCodec::calc_num_fields<Commitment>();
59 size_t frs_per_uni = MAX_PARTIAL_RELATION_LENGTH * frs_per_Fr;
60 size_t frs_per_evals = (Flavor::NUM_ALL_ENTITIES)*frs_per_Fr;
61
62 size_t round = 0;
63 manifest_expected.add_entry(round, "vk_hash", frs_per_Fr);
64 manifest_expected.add_entry(round, "public_input_0", frs_per_Fr);
65 for (size_t i = 0; i < NUM_PUBLIC_INPUTS; i++) {
66 manifest_expected.add_entry(round, "public_input_" + std::to_string(1 + i), frs_per_Fr);
67 }
68 if constexpr (Flavor::HasZK) {
69 manifest_expected.add_entry(round, "Gemini:masking_poly_comm", frs_per_G);
70 }
71 manifest_expected.add_entry(round, "W_L", frs_per_G);
72 manifest_expected.add_entry(round, "W_R", frs_per_G);
73 manifest_expected.add_entry(round, "W_O", frs_per_G);
74 manifest_expected.add_entry(round, "ECC_OP_WIRE_1", frs_per_G);
75 manifest_expected.add_entry(round, "ECC_OP_WIRE_2", frs_per_G);
76 manifest_expected.add_entry(round, "ECC_OP_WIRE_3", frs_per_G);
77 manifest_expected.add_entry(round, "ECC_OP_WIRE_4", frs_per_G);
78 manifest_expected.add_entry(round, "CALLDATA", frs_per_G);
79 manifest_expected.add_entry(round, "CALLDATA_READ_COUNTS", frs_per_G);
80 manifest_expected.add_entry(round, "CALLDATA_READ_TAGS", frs_per_G);
81 manifest_expected.add_entry(round, "SECONDARY_CALLDATA", frs_per_G);
82 manifest_expected.add_entry(round, "SECONDARY_CALLDATA_READ_COUNTS", frs_per_G);
83 manifest_expected.add_entry(round, "SECONDARY_CALLDATA_READ_TAGS", frs_per_G);
84 manifest_expected.add_entry(round, "RETURN_DATA", frs_per_G);
85 manifest_expected.add_entry(round, "RETURN_DATA_READ_COUNTS", frs_per_G);
86 manifest_expected.add_entry(round, "RETURN_DATA_READ_TAGS", frs_per_G);
87 manifest_expected.add_challenge(round, std::array{ "eta", "eta_two", "eta_three" });
88
89 round++;
90 manifest_expected.add_entry(round, "LOOKUP_READ_COUNTS", frs_per_G);
91 manifest_expected.add_entry(round, "LOOKUP_READ_TAGS", frs_per_G);
92 manifest_expected.add_entry(round, "W_4", frs_per_G);
93 manifest_expected.add_challenge(round, std::array{ "beta", "gamma" });
94
95 round++;
96 manifest_expected.add_entry(round, "LOOKUP_INVERSES", frs_per_G);
97 manifest_expected.add_entry(round, "CALLDATA_INVERSES", frs_per_G);
98 manifest_expected.add_entry(round, "SECONDARY_CALLDATA_INVERSES", frs_per_G);
99 manifest_expected.add_entry(round, "RETURN_DATA_INVERSES", frs_per_G);
100 manifest_expected.add_entry(round, "Z_PERM", frs_per_G);
101
102 manifest_expected.add_challenge(round, "alpha");
103 round++;
104
105 manifest_expected.add_challenge(round, "Sumcheck:gate_challenge");
106 round++;
107
108 if constexpr (Flavor::HasZK) {
109 manifest_expected.add_entry(round, "Libra:concatenation_commitment", frs_per_G);
110 manifest_expected.add_entry(round, "Libra:Sum", frs_per_Fr);
111 manifest_expected.add_challenge(round, "Libra:Challenge");
112 round++;
113 }
114
115 for (size_t i = 0; i < virtual_log_n; ++i) {
116 std::string idx = std::to_string(i);
117 manifest_expected.add_entry(round, "Sumcheck:univariate_" + idx, frs_per_uni);
118 std::string label = "Sumcheck:u_" + idx;
119 manifest_expected.add_challenge(round, label);
120 round++;
121 }
122
123 manifest_expected.add_entry(round, "Sumcheck:evaluations", frs_per_evals);
124
125 if constexpr (Flavor::HasZK) {
126 manifest_expected.add_entry(round, "Libra:claimed_evaluation", frs_per_Fr);
127 manifest_expected.add_entry(round, "Libra:grand_sum_commitment", frs_per_G);
128 manifest_expected.add_entry(round, "Libra:quotient_commitment", frs_per_G);
129 }
130
131 manifest_expected.add_challenge(round, "rho");
132
133 round++;
134 for (size_t i = 1; i < virtual_log_n; ++i) {
135 std::string idx = std::to_string(i);
136 manifest_expected.add_entry(round, "Gemini:FOLD_" + idx, frs_per_G);
137 }
138 manifest_expected.add_challenge(round, "Gemini:r");
139 round++;
140 for (size_t i = 1; i <= virtual_log_n; ++i) {
141 std::string idx = std::to_string(i);
142 manifest_expected.add_entry(round, "Gemini:a_" + idx, frs_per_Fr);
143 }
144 if constexpr (Flavor::HasZK) {
145 manifest_expected.add_entry(round, "Libra:concatenation_eval", frs_per_Fr);
146 manifest_expected.add_entry(round, "Libra:shifted_grand_sum_eval", frs_per_Fr);
147 manifest_expected.add_entry(round, "Libra:grand_sum_eval", frs_per_Fr);
148 manifest_expected.add_entry(round, "Libra:quotient_eval", frs_per_Fr);
149 }
150
151 manifest_expected.add_challenge(round, "Shplonk:nu");
152 round++;
153 manifest_expected.add_entry(round, "Shplonk:Q", frs_per_G);
154 manifest_expected.add_challenge(round, "Shplonk:z");
155
156 round++;
157 manifest_expected.add_entry(round, "KZG:W", frs_per_G);
158 manifest_expected.add_challenge(round, "KZG:masking_challenge");
159
160 return manifest_expected;
161 }
162
164 {
165 // Add some ecc op gates
166 for (size_t i = 0; i < 3; ++i) {
167 auto point = Flavor::Curve::AffineElement::one() * FF::random_element();
168 auto scalar = FF::random_element();
169 builder.queue_ecc_mul_accum(point, scalar);
170 }
171 builder.queue_ecc_eq();
172
173 // Add one conventional gates that utilize public inputs
177 FF d = a + b + c;
178 uint32_t a_idx = builder.add_public_variable(a);
179 uint32_t b_idx = builder.add_variable(b);
180 uint32_t c_idx = builder.add_variable(c);
181 uint32_t d_idx = builder.add_variable(d);
182
183 builder.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, FF(1), FF(1), FF(1), FF(-1), FF(0) });
185 }
186};
192TYPED_TEST(MegaTranscriptTests, ProverManifestConsistency)
193{
194 using Flavor = TypeParam;
196
197 using Prover = UltraProver_<Flavor>;
198 // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size)
199 auto builder = typename Flavor::CircuitBuilder();
200 TestFixture::generate_test_circuit(builder);
201
202 // Automatically generate a transcript manifest by constructing a proof
203 auto prover_instance = std::make_shared<ProverInstance>(builder);
204 auto verification_key = std::make_shared<typename Flavor::VerificationKey>(prover_instance->get_precomputed());
205 Prover prover(prover_instance, verification_key);
206 prover.transcript->enable_manifest();
207 auto proof = prover.construct_proof();
208
209 // Check that the prover generated manifest agrees with the manifest hard coded in this suite
210 auto manifest_expected = TestFixture::construct_mega_honk_manifest();
211 auto prover_manifest = prover.transcript->get_manifest();
212 // Note: a manifest can be printed using manifest.print()
213 ASSERT_GT(manifest_expected.size(), 0);
214 for (size_t round = 0; round < manifest_expected.size(); ++round) {
215 if (prover_manifest[round] != manifest_expected[round]) {
216 info("Prover manifest discrepency in round ", round);
217 info("Prover manifest:");
218 prover_manifest[round].print();
219 info("Expected manifest:");
220 manifest_expected[round].print();
221 FAIL();
222 }
223 }
224}
225
231TYPED_TEST(MegaTranscriptTests, VerifierManifestConsistency)
232{
233 using Flavor = TypeParam;
236 using Prover = UltraProver_<Flavor>;
237 using Verifier = UltraVerifier_<Flavor, DefaultIO>;
238
239 // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size)
240 auto builder = typename Flavor::CircuitBuilder();
241 TestFixture::generate_test_circuit(builder);
242
243 // Automatically generate a transcript manifest in the prover by constructing a proof
244 auto prover_instance = std::make_shared<ProverInstance>(builder);
245 auto verification_key = std::make_shared<VerificationKey>(prover_instance->get_precomputed());
246 auto vk_and_hash = std::make_shared<typename Flavor::VKAndHash>(verification_key);
247 Prover prover(prover_instance, verification_key);
248 prover.transcript->enable_manifest();
249 auto proof = prover.construct_proof();
250
251 // Automatically generate a transcript manifest in the verifier by verifying a proof
252 auto verifier_transcript = std::make_shared<typename Flavor::Transcript>();
253 verifier_transcript->enable_manifest();
254 Verifier verifier(vk_and_hash, verifier_transcript);
255 [[maybe_unused]] auto verifier_output = verifier.verify_proof(proof);
256
257 // Check consistency between the manifests generated by the prover and verifier
258 auto prover_manifest = prover.transcript->get_manifest();
259
260 auto verifier_manifest = verifier.get_transcript()->get_manifest();
261
262 // Note: a manifest can be printed using manifest.print()
263 ASSERT_GT(prover_manifest.size(), 0);
264 for (size_t round = 0; round < prover_manifest.size(); ++round) {
265 if (prover_manifest[round] != verifier_manifest[round]) {
266 info("Prover/Verifier manifest discrepency in round ", round);
267 prover_manifest[round].print();
268 verifier_manifest[round].print();
269 FAIL();
270 }
271 }
272}
273
279TYPED_TEST(MegaTranscriptTests, ChallengeGenerationTest)
280{
281 using Flavor = TypeParam;
282 using FF = Flavor::FF;
283 // initialized with random value sent to verifier
284 auto transcript = Flavor::Transcript::prover_init_empty();
285 // test a bunch of challenges
286 std::vector<std::string> challenge_labels{ "a", "b", "c", "d", "e", "f" };
287 auto challenges = transcript->template get_challenges<FF>(challenge_labels);
288 // check they are not 0
289 for (size_t i = 0; i < challenges.size(); ++i) {
290 ASSERT_NE(challenges[i], 0) << "Challenge " << i << " is 0";
291 }
292 constexpr uint32_t random_val{ 17 }; // arbitrary
293 transcript->send_to_verifier("random val", random_val);
294 // test more challenges
295 challenge_labels = { "a", "b", "c" };
296 challenges = transcript->template get_challenges<FF>(challenge_labels);
297 ASSERT_NE(challenges[0], 0) << "Challenge a is 0";
298 ASSERT_NE(challenges[1], 0) << "Challenge b is 0";
299 ASSERT_NE(challenges[2], 0) << "Challenge c is 0";
300}
301
303{
304 using Flavor = TypeParam;
307 using FF = Flavor::FF;
308 using Commitment = typename Flavor::Commitment;
309 using Prover = UltraProver_<Flavor>;
310 using Verifier = UltraVerifier_<Flavor, DefaultIO>;
311
312 // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size)
314 this->generate_test_circuit(builder);
315
316 // Automatically generate a transcript manifest by constructing a proof
317 auto prover_instance = std::make_shared<ProverInstance>(builder);
318 auto verification_key = std::make_shared<VerificationKey>(prover_instance->get_precomputed());
319 auto vk_and_hash = std::make_shared<typename Flavor::VKAndHash>(verification_key);
320 Prover prover(prover_instance, verification_key);
321 auto proof = prover.construct_proof();
322 Verifier verifier(vk_and_hash);
323 EXPECT_TRUE(verifier.verify_proof(proof).result);
324
325 const size_t virtual_log_n = Flavor::VIRTUAL_LOG_N;
326
327 // Use StructuredProof test utility to deserialize/serialize proof data
328 StructuredProof<Flavor> proof_structure;
329
330 // try deserializing and serializing with no changes and check proof is still valid
331 proof_structure.deserialize(
332 prover.transcript->test_get_proof_data(), verification_key->num_public_inputs, virtual_log_n);
333 proof_structure.serialize(prover.transcript->test_get_proof_data(), virtual_log_n);
334
335 proof = TestFixture::export_serialized_proof(prover, prover_instance->num_public_inputs());
336 // we have changed nothing so proof is still valid
337 Verifier verifier2(vk_and_hash);
338 EXPECT_TRUE(verifier2.verify_proof(proof).result);
339
340 Commitment one_group_val = Commitment::one();
341 FF rand_val = FF::random_element();
342 proof_structure.z_perm_comm = one_group_val * rand_val; // choose random object to modify
343 proof = TestFixture::export_serialized_proof(prover, prover_instance->num_public_inputs());
344 // we have not serialized it back to the proof so it should still be fine
345 Verifier verifier3(vk_and_hash);
346 EXPECT_TRUE(verifier3.verify_proof(proof).result);
347
348 proof_structure.serialize(prover.transcript->test_get_proof_data(), virtual_log_n);
349 proof = TestFixture::export_serialized_proof(prover, prover_instance->num_public_inputs());
350 // the proof is now wrong after serializing it
351 Verifier verifier4(vk_and_hash);
352 EXPECT_FALSE(verifier4.verify_proof(proof).result);
353
354 proof_structure.deserialize(
355 prover.transcript->test_get_proof_data(), verification_key->num_public_inputs, virtual_log_n);
356 EXPECT_EQ(static_cast<Commitment>(proof_structure.z_perm_comm), one_group_val * rand_val);
357}
typename Flavor::Transcript::Proof Proof
static Proof export_serialized_proof(Prover &prover, const size_t num_public_inputs)
void generate_test_circuit(auto &builder)
static TranscriptManifest construct_mega_honk_manifest()
Construct a manifest for a Mega Honk proof.
The verification key is responsible for storing the commitments to the precomputed (non-witnessk) pol...
static constexpr bool HasZK
typename Curve::ScalarField FF
static constexpr size_t NUM_ALL_ENTITIES
ECCVMCircuitBuilder CircuitBuilder
typename G1::affine_element Commitment
static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH
Base Native verification key class.
Definition flavor.hpp:141
A ProverInstance is normally constructed from a finalized circuit and it contains all the information...
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.
std::shared_ptr< Transcript > transcript
Manages the data that is propagated on the public inputs of an application/function circuit.
static void add_default(Builder &builder)
Add default public inputs when they are not present.
void info(Args... args)
Definition log.hpp:89
AluTraceBuilder builder
Definition alu.test.cpp:124
FF a
FF b
Base class templates for structures that contain data parameterized by the fundamental polynomials of...
testing::Types< MegaFlavor, UltraFlavor, UltraZKFlavor, UltraRollupFlavor > FlavorTypes
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
TYPED_TEST_SUITE(ShpleminiTest, TestSettings)
TYPED_TEST(ShpleminiTest, CorrectnessOfMultivariateClaimBatching)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
std::string to_string(bb::avm2::ValueTag tag)
Test utility for deserializing/serializing proof data into typed structures.
static field random_element(numeric::RNG *engine=nullptr) noexcept