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.
10
11#include <gtest/gtest.h>
12
13using namespace bb;
14
15using FlavorTypes = ::testing::Types<MegaFlavor, MegaZKFlavor>;
16
17template <typename Flavor> class MegaTranscriptTests : public ::testing::Test {
18 public:
20
22 using FF = Flavor::FF;
35 {
36 using Commitment = typename Flavor::Commitment;
37 TranscriptManifest manifest_expected;
38
39 const size_t virtual_log_n = Flavor::VIRTUAL_LOG_N;
40
41 size_t NUM_PUBLIC_INPUTS =
43 size_t MAX_PARTIAL_RELATION_LENGTH = Flavor::BATCHED_RELATION_PARTIAL_LENGTH;
44
45 size_t frs_per_Fr = FrCodec::calc_num_fields<FF>();
46 size_t frs_per_G = FrCodec::calc_num_fields<Commitment>();
47 size_t frs_per_uni = MAX_PARTIAL_RELATION_LENGTH * frs_per_Fr;
48 size_t frs_per_evals = (Flavor::NUM_ALL_ENTITIES)*frs_per_Fr;
49
50 size_t round = 0;
51 manifest_expected.add_entry(round, "vk_hash", frs_per_Fr);
52 manifest_expected.add_entry(round, "public_input_0", frs_per_Fr);
53 for (size_t i = 0; i < NUM_PUBLIC_INPUTS; i++) {
54 manifest_expected.add_entry(round, "public_input_" + std::to_string(1 + i), frs_per_Fr);
55 }
56 if constexpr (Flavor::HasZK) {
57 manifest_expected.add_entry(round, "Gemini:masking_poly_comm", frs_per_G);
58 }
59 manifest_expected.add_entry(round, "W_L", frs_per_G);
60 manifest_expected.add_entry(round, "W_R", frs_per_G);
61 manifest_expected.add_entry(round, "W_O", frs_per_G);
62 manifest_expected.add_entry(round, "ECC_OP_WIRE_1", frs_per_G);
63 manifest_expected.add_entry(round, "ECC_OP_WIRE_2", frs_per_G);
64 manifest_expected.add_entry(round, "ECC_OP_WIRE_3", frs_per_G);
65 manifest_expected.add_entry(round, "ECC_OP_WIRE_4", frs_per_G);
66 manifest_expected.add_entry(round, "CALLDATA", frs_per_G);
67 manifest_expected.add_entry(round, "CALLDATA_READ_COUNTS", frs_per_G);
68 manifest_expected.add_entry(round, "CALLDATA_READ_TAGS", frs_per_G);
69 manifest_expected.add_entry(round, "SECONDARY_CALLDATA", frs_per_G);
70 manifest_expected.add_entry(round, "SECONDARY_CALLDATA_READ_COUNTS", frs_per_G);
71 manifest_expected.add_entry(round, "SECONDARY_CALLDATA_READ_TAGS", frs_per_G);
72 manifest_expected.add_entry(round, "RETURN_DATA", frs_per_G);
73 manifest_expected.add_entry(round, "RETURN_DATA_READ_COUNTS", frs_per_G);
74 manifest_expected.add_entry(round, "RETURN_DATA_READ_TAGS", frs_per_G);
75 manifest_expected.add_challenge(round, std::array{ "eta", "eta_two", "eta_three" });
76
77 round++;
78 manifest_expected.add_entry(round, "LOOKUP_READ_COUNTS", frs_per_G);
79 manifest_expected.add_entry(round, "LOOKUP_READ_TAGS", frs_per_G);
80 manifest_expected.add_entry(round, "W_4", frs_per_G);
81 manifest_expected.add_challenge(round, std::array{ "beta", "gamma" });
82
83 round++;
84 manifest_expected.add_entry(round, "LOOKUP_INVERSES", frs_per_G);
85 manifest_expected.add_entry(round, "CALLDATA_INVERSES", frs_per_G);
86 manifest_expected.add_entry(round, "SECONDARY_CALLDATA_INVERSES", frs_per_G);
87 manifest_expected.add_entry(round, "RETURN_DATA_INVERSES", frs_per_G);
88 manifest_expected.add_entry(round, "Z_PERM", frs_per_G);
89
90 manifest_expected.add_challenge(round, "alpha");
91 round++;
92
93 manifest_expected.add_challenge(round, "Sumcheck:gate_challenge");
94 round++;
95
96 if constexpr (Flavor::HasZK) {
97 manifest_expected.add_entry(round, "Libra:concatenation_commitment", frs_per_G);
98 manifest_expected.add_entry(round, "Libra:Sum", frs_per_Fr);
99 manifest_expected.add_challenge(round, "Libra:Challenge");
100 round++;
101 }
102
103 for (size_t i = 0; i < virtual_log_n; ++i) {
104 std::string idx = std::to_string(i);
105 manifest_expected.add_entry(round, "Sumcheck:univariate_" + idx, frs_per_uni);
106 std::string label = "Sumcheck:u_" + idx;
107 manifest_expected.add_challenge(round, label);
108 round++;
109 }
110
111 manifest_expected.add_entry(round, "Sumcheck:evaluations", frs_per_evals);
112
113 if constexpr (Flavor::HasZK) {
114 manifest_expected.add_entry(round, "Libra:claimed_evaluation", frs_per_Fr);
115 manifest_expected.add_entry(round, "Libra:grand_sum_commitment", frs_per_G);
116 manifest_expected.add_entry(round, "Libra:quotient_commitment", frs_per_G);
117 }
118
119 manifest_expected.add_challenge(round, "rho");
120
121 round++;
122 for (size_t i = 1; i < virtual_log_n; ++i) {
123 std::string idx = std::to_string(i);
124 manifest_expected.add_entry(round, "Gemini:FOLD_" + idx, frs_per_G);
125 }
126 manifest_expected.add_challenge(round, "Gemini:r");
127 round++;
128 for (size_t i = 1; i <= virtual_log_n; ++i) {
129 std::string idx = std::to_string(i);
130 manifest_expected.add_entry(round, "Gemini:a_" + idx, frs_per_Fr);
131 }
132 if constexpr (Flavor::HasZK) {
133 manifest_expected.add_entry(round, "Libra:concatenation_eval", frs_per_Fr);
134 manifest_expected.add_entry(round, "Libra:shifted_grand_sum_eval", frs_per_Fr);
135 manifest_expected.add_entry(round, "Libra:grand_sum_eval", frs_per_Fr);
136 manifest_expected.add_entry(round, "Libra:quotient_eval", frs_per_Fr);
137 }
138
139 manifest_expected.add_challenge(round, "Shplonk:nu");
140 round++;
141 manifest_expected.add_entry(round, "Shplonk:Q", frs_per_G);
142 manifest_expected.add_challenge(round, "Shplonk:z");
143
144 round++;
145 manifest_expected.add_entry(round, "KZG:W", frs_per_G);
146 manifest_expected.add_challenge(round, "KZG:masking_challenge");
147
148 return manifest_expected;
149 }
150
152 {
153 // Add some ecc op gates
154 for (size_t i = 0; i < 3; ++i) {
155 auto point = Flavor::Curve::AffineElement::one() * FF::random_element();
156 auto scalar = FF::random_element();
157 builder.queue_ecc_mul_accum(point, scalar);
158 }
159 builder.queue_ecc_eq();
160
161 // Add one conventional gates that utilize public inputs
165 FF d = a + b + c;
166 uint32_t a_idx = builder.add_public_variable(a);
167 uint32_t b_idx = builder.add_variable(b);
168 uint32_t c_idx = builder.add_variable(c);
169 uint32_t d_idx = builder.add_variable(d);
170
171 builder.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, FF(1), FF(1), FF(1), FF(-1), FF(0) });
173 }
174};
180TYPED_TEST(MegaTranscriptTests, ProverManifestConsistency)
181{
182 using Flavor = TypeParam;
184
185 using Prover = UltraProver_<Flavor>;
186 // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size)
187 auto builder = typename Flavor::CircuitBuilder();
188 TestFixture::generate_test_circuit(builder);
189
190 // Automatically generate a transcript manifest by constructing a proof
191 auto prover_instance = std::make_shared<ProverInstance>(builder);
192 auto verification_key = std::make_shared<typename Flavor::VerificationKey>(prover_instance->get_precomputed());
193 Prover prover(prover_instance, verification_key);
194 prover.transcript->enable_manifest();
195 auto proof = prover.construct_proof();
196
197 // Check that the prover generated manifest agrees with the manifest hard coded in this suite
198 auto manifest_expected = TestFixture::construct_mega_honk_manifest();
199 auto prover_manifest = prover.transcript->get_manifest();
200 // Note: a manifest can be printed using manifest.print()
201 ASSERT_GT(manifest_expected.size(), 0);
202 for (size_t round = 0; round < manifest_expected.size(); ++round) {
203 if (prover_manifest[round] != manifest_expected[round]) {
204 info("Prover manifest discrepency in round ", round);
205 info("Prover manifest:");
206 prover_manifest[round].print();
207 info("Expected manifest:");
208 manifest_expected[round].print();
209 FAIL();
210 }
211 }
212}
213
219TYPED_TEST(MegaTranscriptTests, VerifierManifestConsistency)
220{
221 using Flavor = TypeParam;
224 using Prover = UltraProver_<Flavor>;
225 using Verifier = UltraVerifier_<Flavor>;
226
227 // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size)
228 auto builder = typename Flavor::CircuitBuilder();
229 TestFixture::generate_test_circuit(builder);
230
231 // Automatically generate a transcript manifest in the prover by constructing a proof
232 auto prover_instance = std::make_shared<ProverInstance>(builder);
233 auto verification_key = std::make_shared<VerificationKey>(prover_instance->get_precomputed());
234 Prover prover(prover_instance, verification_key);
235 prover.transcript->enable_manifest();
236 auto proof = prover.construct_proof();
237
238 // Automatically generate a transcript manifest in the verifier by verifying a proof
239 Verifier verifier(verification_key);
240 verifier.transcript->enable_manifest();
241 [[maybe_unused]] auto verifier_output = verifier.template verify_proof<DefaultIO>(proof);
242
243 // Check consistency between the manifests generated by the prover and verifier
244 auto prover_manifest = prover.transcript->get_manifest();
245
246 auto verifier_manifest = verifier.transcript->get_manifest();
247
248 // Note: a manifest can be printed using manifest.print()
249 ASSERT_GT(prover_manifest.size(), 0);
250 for (size_t round = 0; round < prover_manifest.size(); ++round) {
251 if (prover_manifest[round] != verifier_manifest[round]) {
252 info("Prover/Verifier manifest discrepency in round ", round);
253 prover_manifest[round].print();
254 verifier_manifest[round].print();
255 FAIL();
256 }
257 }
258}
259
265TYPED_TEST(MegaTranscriptTests, ChallengeGenerationTest)
266{
267 using Flavor = TypeParam;
268 using FF = Flavor::FF;
269 // initialized with random value sent to verifier
270 auto transcript = Flavor::Transcript::prover_init_empty();
271 // test a bunch of challenges
272 std::vector<std::string> challenge_labels{ "a", "b", "c", "d", "e", "f" };
273 auto challenges = transcript->template get_challenges<FF>(challenge_labels);
274 // check they are not 0
275 for (size_t i = 0; i < challenges.size(); ++i) {
276 ASSERT_NE(challenges[i], 0) << "Challenge " << i << " is 0";
277 }
278 constexpr uint32_t random_val{ 17 }; // arbitrary
279 transcript->send_to_verifier("random val", random_val);
280 // test more challenges
281 challenge_labels = { "a", "b", "c" };
282 challenges = transcript->template get_challenges<FF>(challenge_labels);
283 ASSERT_NE(challenges[0], 0) << "Challenge a is 0";
284 ASSERT_NE(challenges[1], 0) << "Challenge b is 0";
285 ASSERT_NE(challenges[2], 0) << "Challenge c is 0";
286}
287
289{
290 using Flavor = TypeParam;
293 using FF = Flavor::FF;
294 using Commitment = typename Flavor::Commitment;
295 using Prover = UltraProver_<Flavor>;
296 using Verifier = UltraVerifier_<Flavor>;
297
298 if constexpr (IsAnyOf<Flavor, MegaZKFlavor, MegaFlavor>) {
299 // For compatibility with Goblin, MegaZKFlavor is using NativeTranscript which does not support
300 // serialize/deserialize full transcript methods.
301 GTEST_SKIP() << "Skipping StructureTest for MegaZKFlavor";
302 } else {
303 // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size)
305 this->generate_test_circuit(builder);
306
307 // Automatically generate a transcript manifest by constructing a proof
308 auto prover_instance = std::make_shared<ProverInstance>(builder);
309 Prover prover(prover_instance);
310 auto proof = prover.construct_proof();
311 auto verification_key = std::make_shared<VerificationKey>(prover_instance->get_precomputed());
312 Verifier verifier(verification_key);
313 EXPECT_TRUE(verifier.verify_proof(proof));
314
315 // try deserializing and serializing with no changes and check proof is still valid
316 prover.transcript->deserialize_full_transcript(verification_key->num_public_inputs);
317 prover.transcript->serialize_full_transcript();
318 verifier.transcript = std::make_shared<typename Flavor::Transcript>(); // clear verifier transcript
319 EXPECT_TRUE(verifier.verify_proof(prover.export_proof())); // we have changed nothing so proof is still valid
320
321 Commitment one_group_val = Commitment::one();
322 FF rand_val = FF::random_element();
323 prover.transcript->z_perm_comm = one_group_val * rand_val; // choose random object to modify
324 verifier.transcript = std::make_shared<typename Flavor::Transcript>(); // clear verifier transcript
325 EXPECT_TRUE(verifier.verify_proof(
326 prover.export_proof())); // we have not serialized it back to the proof so it should still be fine
327
328 prover.transcript->serialize_full_transcript();
329 EXPECT_FALSE(verifier.verify_proof(prover.export_proof())); // the proof is now wrong after serializing it
330
331 prover.transcript->deserialize_full_transcript(verification_key->num_public_inputs);
332 EXPECT_EQ(static_cast<Commitment>(prover.transcript->z_perm_comm), one_group_val * rand_val);
333 }
334}
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
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.
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:75
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...
UltraKeccakFlavor::VerificationKey VerificationKey
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)
static field random_element(numeric::RNG *engine=nullptr) noexcept