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, const size_t log_n)
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, log_n);
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, "eta");
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 manifest_expected.add_challenge(round, "Sumcheck:gate_challenge");
104 round++;
105
106 if constexpr (Flavor::HasZK) {
107 manifest_expected.add_entry(round, "Libra:concatenation_commitment", frs_per_G);
108 manifest_expected.add_entry(round, "Libra:Sum", frs_per_Fr);
109 manifest_expected.add_challenge(round, "Libra:Challenge");
110 round++;
111 }
112
113 for (size_t i = 0; i < virtual_log_n; ++i) {
114 std::string idx = std::to_string(i);
115 manifest_expected.add_entry(round, "Sumcheck:univariate_" + idx, frs_per_uni);
116 std::string label = "Sumcheck:u_" + idx;
117 manifest_expected.add_challenge(round, label);
118 round++;
119 }
120
121 manifest_expected.add_entry(round, "Sumcheck:evaluations", frs_per_evals);
122
123 if constexpr (Flavor::HasZK) {
124 manifest_expected.add_entry(round, "Libra:claimed_evaluation", frs_per_Fr);
125 manifest_expected.add_entry(round, "Libra:grand_sum_commitment", frs_per_G);
126 manifest_expected.add_entry(round, "Libra:quotient_commitment", frs_per_G);
127 }
128
129 manifest_expected.add_challenge(round, "rho");
130
131 round++;
132 for (size_t i = 1; i < virtual_log_n; ++i) {
133 std::string idx = std::to_string(i);
134 manifest_expected.add_entry(round, "Gemini:FOLD_" + idx, frs_per_G);
135 }
136 manifest_expected.add_challenge(round, "Gemini:r");
137 round++;
138 for (size_t i = 1; i <= virtual_log_n; ++i) {
139 std::string idx = std::to_string(i);
140 manifest_expected.add_entry(round, "Gemini:a_" + idx, frs_per_Fr);
141 }
142 if constexpr (Flavor::HasZK) {
143 manifest_expected.add_entry(round, "Libra:concatenation_eval", frs_per_Fr);
144 manifest_expected.add_entry(round, "Libra:shifted_grand_sum_eval", frs_per_Fr);
145 manifest_expected.add_entry(round, "Libra:grand_sum_eval", frs_per_Fr);
146 manifest_expected.add_entry(round, "Libra:quotient_eval", frs_per_Fr);
147 }
148
149 manifest_expected.add_challenge(round, "Shplonk:nu");
150 round++;
151 manifest_expected.add_entry(round, "Shplonk:Q", frs_per_G);
152 manifest_expected.add_challenge(round, "Shplonk:z");
153
154 round++;
155 manifest_expected.add_entry(round, "KZG:W", frs_per_G);
156 manifest_expected.add_challenge(round, "KZG:masking_challenge");
157
158 return manifest_expected;
159 }
160
162 {
163 // Add some ecc op gates
164 for (size_t i = 0; i < 3; ++i) {
165 auto point = Flavor::Curve::AffineElement::one() * FF::random_element();
166 auto scalar = FF::random_element();
167 builder.queue_ecc_mul_accum(point, scalar);
168 }
169 builder.queue_ecc_eq();
170
171 // Add one conventional gates that utilize public inputs
175 FF d = a + b + c;
176 uint32_t a_idx = builder.add_public_variable(a);
177 uint32_t b_idx = builder.add_variable(b);
178 uint32_t c_idx = builder.add_variable(c);
179 uint32_t d_idx = builder.add_variable(d);
180
181 builder.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, FF(1), FF(1), FF(1), FF(-1), FF(0) });
183 }
184};
190TYPED_TEST(MegaTranscriptTests, ProverManifestConsistency)
191{
192 using Flavor = TypeParam;
194
195 using Prover = UltraProver_<Flavor>;
196 // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size)
197 auto builder = typename Flavor::CircuitBuilder();
198 TestFixture::generate_test_circuit(builder);
199
200 // Automatically generate a transcript manifest by constructing a proof
201 auto prover_instance = std::make_shared<ProverInstance>(builder);
202 auto verification_key = std::make_shared<typename Flavor::VerificationKey>(prover_instance->get_precomputed());
203 Prover prover(prover_instance, verification_key);
204 prover.transcript->enable_manifest();
205 auto proof = prover.construct_proof();
206
207 // Check that the prover generated manifest agrees with the manifest hard coded in this suite
208 auto manifest_expected = TestFixture::construct_mega_honk_manifest();
209 auto prover_manifest = prover.transcript->get_manifest();
210 // Note: a manifest can be printed using manifest.print()
211 ASSERT_GT(manifest_expected.size(), 0);
212 for (size_t round = 0; round < manifest_expected.size(); ++round) {
213 if (prover_manifest[round] != manifest_expected[round]) {
214 info("Prover manifest discrepency in round ", round);
215 info("Prover manifest:");
216 prover_manifest[round].print();
217 info("Expected manifest:");
218 manifest_expected[round].print();
219 FAIL();
220 }
221 }
222}
223
229TYPED_TEST(MegaTranscriptTests, VerifierManifestConsistency)
230{
231 using Flavor = TypeParam;
234 using Prover = UltraProver_<Flavor>;
235 using Verifier = UltraVerifier_<Flavor, DefaultIO>;
236
237 // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size)
238 auto builder = typename Flavor::CircuitBuilder();
239 TestFixture::generate_test_circuit(builder);
240
241 // Automatically generate a transcript manifest in the prover by constructing a proof
242 auto prover_instance = std::make_shared<ProverInstance>(builder);
243 auto verification_key = std::make_shared<VerificationKey>(prover_instance->get_precomputed());
244 auto vk_and_hash = std::make_shared<typename Flavor::VKAndHash>(verification_key);
245 Prover prover(prover_instance, verification_key);
246 prover.transcript->enable_manifest();
247 auto proof = prover.construct_proof();
248
249 // Automatically generate a transcript manifest in the verifier by verifying a proof
250 auto verifier_transcript = std::make_shared<typename Flavor::Transcript>();
251 verifier_transcript->enable_manifest();
252 Verifier verifier(vk_and_hash, verifier_transcript);
253 [[maybe_unused]] auto verifier_output = verifier.verify_proof(proof);
254
255 // Check consistency between the manifests generated by the prover and verifier
256 auto prover_manifest = prover.transcript->get_manifest();
257
258 auto verifier_manifest = verifier.get_transcript()->get_manifest();
259
260 // Note: a manifest can be printed using manifest.print()
261 ASSERT_GT(prover_manifest.size(), 0);
262 for (size_t round = 0; round < prover_manifest.size(); ++round) {
263 if (prover_manifest[round] != verifier_manifest[round]) {
264 info("Prover/Verifier manifest discrepency in round ", round);
265 prover_manifest[round].print();
266 verifier_manifest[round].print();
267 FAIL();
268 }
269 }
270}
271
277TYPED_TEST(MegaTranscriptTests, ChallengeGenerationTest)
278{
279 using Flavor = TypeParam;
280 using FF = Flavor::FF;
281 // initialized with random value sent to verifier
282 auto transcript = Flavor::Transcript::test_prover_init_empty();
283 // test a bunch of challenges
284 std::vector<std::string> challenge_labels{ "a", "b", "c", "d", "e", "f" };
285 auto challenges = transcript->template get_challenges<FF>(challenge_labels);
286 // check they are not 0
287 for (size_t i = 0; i < challenges.size(); ++i) {
288 ASSERT_NE(challenges[i], 0) << "Challenge " << i << " is 0";
289 }
290 constexpr uint32_t random_val{ 17 }; // arbitrary
291 transcript->send_to_verifier("random val", random_val);
292 // test more challenges
293 challenge_labels = { "a", "b", "c" };
294 challenges = transcript->template get_challenges<FF>(challenge_labels);
295 ASSERT_NE(challenges[0], 0) << "Challenge a is 0";
296 ASSERT_NE(challenges[1], 0) << "Challenge b is 0";
297 ASSERT_NE(challenges[2], 0) << "Challenge c is 0";
298}
299
301{
302 using Flavor = TypeParam;
305 using FF = Flavor::FF;
306 using Commitment = typename Flavor::Commitment;
307 using Prover = UltraProver_<Flavor>;
308 using Verifier = UltraVerifier_<Flavor, DefaultIO>;
309
310 // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size)
312 this->generate_test_circuit(builder);
313
314 // Automatically generate a transcript manifest by constructing a proof
315 auto prover_instance = std::make_shared<ProverInstance>(builder);
316 auto verification_key = std::make_shared<VerificationKey>(prover_instance->get_precomputed());
317 auto vk_and_hash = std::make_shared<typename Flavor::VKAndHash>(verification_key);
318 Prover prover(prover_instance, verification_key);
319 auto proof = prover.construct_proof();
320 Verifier verifier(vk_and_hash);
321 EXPECT_TRUE(verifier.verify_proof(proof).result);
322
323 const size_t virtual_log_n = Flavor::VIRTUAL_LOG_N;
324
325 // Use StructuredProof test utility to deserialize/serialize proof data
326 StructuredProof<Flavor> proof_structure;
327
328 // try deserializing and serializing with no changes and check proof is still valid
329 proof_structure.deserialize(
330 prover.transcript->test_get_proof_data(), verification_key->num_public_inputs, virtual_log_n);
331 proof_structure.serialize(prover.transcript->test_get_proof_data(), virtual_log_n);
332
333 proof = TestFixture::export_serialized_proof(prover, prover_instance->num_public_inputs(), virtual_log_n);
334 // we have changed nothing so proof is still valid
335 Verifier verifier2(vk_and_hash);
336 EXPECT_TRUE(verifier2.verify_proof(proof).result);
337
338 Commitment one_group_val = Commitment::one();
339 FF rand_val = FF::random_element();
340 proof_structure.z_perm_comm = one_group_val * rand_val; // choose random object to modify
341 proof = TestFixture::export_serialized_proof(prover, prover_instance->num_public_inputs(), virtual_log_n);
342 // we have not serialized it back to the proof so it should still be fine
343 Verifier verifier3(vk_and_hash);
344 EXPECT_TRUE(verifier3.verify_proof(proof).result);
345
346 proof_structure.serialize(prover.transcript->test_get_proof_data(), virtual_log_n);
347 proof = TestFixture::export_serialized_proof(prover, prover_instance->num_public_inputs(), virtual_log_n);
348 // the proof is now wrong after serializing it
349 Verifier verifier4(vk_and_hash);
350 EXPECT_FALSE(verifier4.verify_proof(proof).result);
351
352 proof_structure.deserialize(
353 prover.transcript->test_get_proof_data(), verification_key->num_public_inputs, virtual_log_n);
354 EXPECT_EQ(static_cast<Commitment>(proof_structure.z_perm_comm), one_group_val * rand_val);
355}
typename Flavor::Transcript::Proof Proof
static Proof export_serialized_proof(Prover &prover, const size_t num_public_inputs, const size_t log_n)
void generate_test_circuit(auto &builder)
static TranscriptManifest construct_mega_honk_manifest()
Construct a manifest for a Mega Honk proof.
static constexpr bool HasZK
typename Curve::ScalarField FF
static constexpr size_t NUM_ALL_ENTITIES
ECCVMCircuitBuilder CircuitBuilder
typename G1::affine_element Commitment
FixedVKAndHash_< PrecomputedEntities< Commitment >, BF, ECCVMHardcodedVKAndHash > VerificationKey
The verification key stores commitments to the precomputed polynomials used by the verifier.
static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH
Base Native verification key class.
Definition flavor.hpp:172
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
Proof export_proof()
Export the complete proof, including IPA proof for rollup circuits.
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.
#define info(...)
Definition log.hpp:93
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< UltraFlavor, UltraKeccakFlavor, MegaFlavor > 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(CommitmentKeyTest, Curves)
TYPED_TEST(CommitmentKeyTest, CommitToZeroPoly)
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