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 size_t NUM_SUBRELATIONS = Flavor::NUM_SUBRELATIONS;
45
46 size_t frs_per_Fr = bb::field_conversion::calc_num_bn254_frs<FF>();
47 size_t frs_per_G = bb::field_conversion::calc_num_bn254_frs<Commitment>();
48 size_t frs_per_uni = MAX_PARTIAL_RELATION_LENGTH * frs_per_Fr;
49 size_t frs_per_evals = (Flavor::NUM_ALL_ENTITIES)*frs_per_Fr;
50
51 size_t round = 0;
52 manifest_expected.add_entry(round, "vk_hash", frs_per_Fr);
53 manifest_expected.add_entry(round, "public_input_0", frs_per_Fr);
54 for (size_t i = 0; i < NUM_PUBLIC_INPUTS; i++) {
55 manifest_expected.add_entry(round, "public_input_" + std::to_string(1 + i), frs_per_Fr);
56 }
57 manifest_expected.add_entry(round, "W_L", frs_per_G);
58 manifest_expected.add_entry(round, "W_R", frs_per_G);
59 manifest_expected.add_entry(round, "W_O", frs_per_G);
60 manifest_expected.add_entry(round, "ECC_OP_WIRE_1", frs_per_G);
61 manifest_expected.add_entry(round, "ECC_OP_WIRE_2", frs_per_G);
62 manifest_expected.add_entry(round, "ECC_OP_WIRE_3", frs_per_G);
63 manifest_expected.add_entry(round, "ECC_OP_WIRE_4", frs_per_G);
64 manifest_expected.add_entry(round, "CALLDATA", frs_per_G);
65 manifest_expected.add_entry(round, "CALLDATA_READ_COUNTS", frs_per_G);
66 manifest_expected.add_entry(round, "CALLDATA_READ_TAGS", frs_per_G);
67 manifest_expected.add_entry(round, "SECONDARY_CALLDATA", frs_per_G);
68 manifest_expected.add_entry(round, "SECONDARY_CALLDATA_READ_COUNTS", frs_per_G);
69 manifest_expected.add_entry(round, "SECONDARY_CALLDATA_READ_TAGS", frs_per_G);
70 manifest_expected.add_entry(round, "RETURN_DATA", frs_per_G);
71 manifest_expected.add_entry(round, "RETURN_DATA_READ_COUNTS", frs_per_G);
72 manifest_expected.add_entry(round, "RETURN_DATA_READ_TAGS", frs_per_G);
73 manifest_expected.add_challenge(round, "eta", "eta_two", "eta_three");
74
75 round++;
76 manifest_expected.add_entry(round, "LOOKUP_READ_COUNTS", frs_per_G);
77 manifest_expected.add_entry(round, "LOOKUP_READ_TAGS", frs_per_G);
78 manifest_expected.add_entry(round, "W_4", frs_per_G);
79 manifest_expected.add_challenge(round, "beta", "gamma");
80
81 round++;
82 manifest_expected.add_entry(round, "LOOKUP_INVERSES", frs_per_G);
83 manifest_expected.add_entry(round, "CALLDATA_INVERSES", frs_per_G);
84 manifest_expected.add_entry(round, "SECONDARY_CALLDATA_INVERSES", frs_per_G);
85 manifest_expected.add_entry(round, "RETURN_DATA_INVERSES", frs_per_G);
86 manifest_expected.add_entry(round, "Z_PERM", frs_per_G);
87
88 std::array<std::string, Flavor::NUM_SUBRELATIONS - 1> alpha_labels;
89 for (size_t i = 0; i < NUM_SUBRELATIONS - 1; i++) {
90 std::string label = "alpha_" + std::to_string(i);
91 alpha_labels[i] = label;
92 }
93
94 manifest_expected.add_challenge(round, alpha_labels);
95 round++;
96
97 manifest_expected.add_challenge(round, "Sumcheck:gate_challenge");
98 round++;
99
100 if constexpr (Flavor::HasZK) {
101 manifest_expected.add_entry(round, "Libra:concatenation_commitment", frs_per_G);
102 manifest_expected.add_entry(round, "Libra:Sum", frs_per_Fr);
103 manifest_expected.add_challenge(round, "Libra:Challenge");
104 round++;
105 }
106
107 for (size_t i = 0; i < virtual_log_n; ++i) {
108 std::string idx = std::to_string(i);
109 manifest_expected.add_entry(round, "Sumcheck:univariate_" + idx, frs_per_uni);
110 std::string label = "Sumcheck:u_" + idx;
111 manifest_expected.add_challenge(round, label);
112 round++;
113 }
114
115 manifest_expected.add_entry(round, "Sumcheck:evaluations", frs_per_evals);
116
117 if constexpr (Flavor::HasZK) {
118 manifest_expected.add_entry(round, "Libra:claimed_evaluation", frs_per_Fr);
119 manifest_expected.add_entry(round, "Libra:grand_sum_commitment", frs_per_G);
120 manifest_expected.add_entry(round, "Libra:quotient_commitment", frs_per_G);
121 manifest_expected.add_entry(round, "Gemini:masking_poly_comm", frs_per_G);
122 manifest_expected.add_entry(round, "Gemini:masking_poly_eval", frs_per_Fr);
123 }
124
125 manifest_expected.add_challenge(round, "rho");
126
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:FOLD_" + idx, frs_per_G);
131 }
132 manifest_expected.add_challenge(round, "Gemini:r");
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:a_" + idx, frs_per_Fr);
137 }
138 if constexpr (Flavor::HasZK) {
139 manifest_expected.add_entry(round, "Libra:concatenation_eval", frs_per_Fr);
140 manifest_expected.add_entry(round, "Libra:shifted_grand_sum_eval", frs_per_Fr);
141 manifest_expected.add_entry(round, "Libra:grand_sum_eval", frs_per_Fr);
142 manifest_expected.add_entry(round, "Libra:quotient_eval", frs_per_Fr);
143 }
144
145 manifest_expected.add_challenge(round, "Shplonk:nu");
146 round++;
147 manifest_expected.add_entry(round, "Shplonk:Q", frs_per_G);
148 manifest_expected.add_challenge(round, "Shplonk:z");
149
150 round++;
151 manifest_expected.add_entry(round, "KZG:W", frs_per_G);
152 manifest_expected.add_challenge(round); // no challenge
153
154 return manifest_expected;
155 }
156
158 {
159 // Add some ecc op gates
160 for (size_t i = 0; i < 3; ++i) {
161 auto point = Flavor::Curve::AffineElement::one() * FF::random_element();
162 auto scalar = FF::random_element();
163 builder.queue_ecc_mul_accum(point, scalar);
164 }
165 builder.queue_ecc_eq();
166
167 // Add one conventional gates that utilize public inputs
171 FF d = a + b + c;
172 uint32_t a_idx = builder.add_public_variable(a);
173 uint32_t b_idx = builder.add_variable(b);
174 uint32_t c_idx = builder.add_variable(c);
175 uint32_t d_idx = builder.add_variable(d);
176
177 builder.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, FF(1), FF(1), FF(1), FF(-1), FF(0) });
179 }
180};
186TYPED_TEST(MegaTranscriptTests, ProverManifestConsistency)
187{
188 using Flavor = TypeParam;
190
191 using Prover = UltraProver_<Flavor>;
192 // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size)
193 auto builder = typename Flavor::CircuitBuilder();
194 TestFixture::generate_test_circuit(builder);
195
196 // Automatically generate a transcript manifest by constructing a proof
198 auto verification_key = std::make_shared<typename Flavor::VerificationKey>(proving_key->get_precomputed());
199 Prover prover(proving_key, verification_key);
200 prover.transcript->enable_manifest();
201 auto proof = prover.construct_proof();
202
203 // Check that the prover generated manifest agrees with the manifest hard coded in this suite
204 auto manifest_expected = TestFixture::construct_mega_honk_manifest();
205 auto prover_manifest = prover.transcript->get_manifest();
206 // Note: a manifest can be printed using manifest.print()
207 ASSERT_GT(manifest_expected.size(), 0);
208 for (size_t round = 0; round < manifest_expected.size(); ++round) {
209 if (prover_manifest[round] != manifest_expected[round]) {
210 info("Prover manifest discrepency in round ", round);
211 info("Prover manifest:");
212 prover_manifest[round].print();
213 info("Expected manifest:");
214 manifest_expected[round].print();
215 FAIL();
216 }
217 }
218}
219
225TYPED_TEST(MegaTranscriptTests, VerifierManifestConsistency)
226{
227 using Flavor = TypeParam;
230 using Prover = UltraProver_<Flavor>;
231 using Verifier = UltraVerifier_<Flavor>;
232
233 // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size)
234 auto builder = typename Flavor::CircuitBuilder();
235 TestFixture::generate_test_circuit(builder);
236
237 // Automatically generate a transcript manifest in the prover by constructing a proof
239 auto verification_key = std::make_shared<VerificationKey>(proving_key->get_precomputed());
240 Prover prover(proving_key, verification_key);
241 prover.transcript->enable_manifest();
242 auto proof = prover.construct_proof();
243
244 // Automatically generate a transcript manifest in the verifier by verifying a proof
245 Verifier verifier(verification_key);
246 verifier.transcript->enable_manifest();
247 [[maybe_unused]] auto verifier_output = verifier.template verify_proof<DefaultIO>(proof);
248
249 // Check consistency between the manifests generated by the prover and verifier
250 auto prover_manifest = prover.transcript->get_manifest();
251
252 auto verifier_manifest = verifier.transcript->get_manifest();
253
254 // Note: a manifest can be printed using manifest.print()
255 ASSERT_GT(prover_manifest.size(), 0);
256 for (size_t round = 0; round < prover_manifest.size(); ++round) {
257 if (prover_manifest[round] != verifier_manifest[round]) {
258 info("Prover/Verifier manifest discrepency in round ", round);
259 prover_manifest[round].print();
260 verifier_manifest[round].print();
261 FAIL();
262 }
263 }
264}
265
271TYPED_TEST(MegaTranscriptTests, ChallengeGenerationTest)
272{
273 using Flavor = TypeParam;
274 using FF = Flavor::FF;
275 // initialized with random value sent to verifier
276 auto transcript = Flavor::Transcript::prover_init_empty();
277 // test a bunch of challenges
278 auto challenges = transcript->template get_challenges<FF>("a", "b", "c", "d", "e", "f");
279 // check they are not 0
280 for (size_t i = 0; i < challenges.size(); ++i) {
281 ASSERT_NE(challenges[i], 0) << "Challenge " << i << " is 0";
282 }
283 constexpr uint32_t random_val{ 17 }; // arbitrary
284 transcript->send_to_verifier("random val", random_val);
285 // test more challenges
286 auto [a, b, c] = transcript->template get_challenges<FF>("a", "b", "c");
287 ASSERT_NE(a, 0) << "Challenge a is 0";
288 ASSERT_NE(b, 0) << "Challenge b is 0";
289 ASSERT_NE(c, 0) << "Challenge c is 0";
290}
291
293{
294 using Flavor = TypeParam;
297 using FF = Flavor::FF;
298 using Commitment = typename Flavor::Commitment;
299 using Prover = UltraProver_<Flavor>;
300 using Verifier = UltraVerifier_<Flavor>;
301
302 if constexpr (IsAnyOf<Flavor, MegaZKFlavor, MegaFlavor>) {
303 // For compatibility with Goblin, MegaZKFlavor is using NativeTranscript which does not support
304 // serialize/deserialize full transcript methods.
305 GTEST_SKIP() << "Skipping StructureTest for MegaZKFlavor";
306 } else {
307 // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size)
309 this->generate_test_circuit(builder);
310
311 // Automatically generate a transcript manifest by constructing a proof
313 Prover prover(proving_key);
314 auto proof = prover.construct_proof();
315 auto verification_key = std::make_shared<VerificationKey>(proving_key->get_precomputed());
316 Verifier verifier(verification_key);
317 EXPECT_TRUE(verifier.verify_proof(proof));
318
319 // try deserializing and serializing with no changes and check proof is still valid
320 prover.transcript->deserialize_full_transcript(verification_key->num_public_inputs);
321 prover.transcript->serialize_full_transcript();
322 verifier.transcript = std::make_shared<typename Flavor::Transcript>(); // clear verifier transcript
323 EXPECT_TRUE(verifier.verify_proof(prover.export_proof())); // we have changed nothing so proof is still valid
324
325 Commitment one_group_val = Commitment::one();
326 FF rand_val = FF::random_element();
327 prover.transcript->z_perm_comm = one_group_val * rand_val; // choose random object to modify
328 verifier.transcript = std::make_shared<typename Flavor::Transcript>(); // clear verifier transcript
329 EXPECT_TRUE(verifier.verify_proof(
330 prover.export_proof())); // we have not serialized it back to the proof so it should still be fine
331
332 prover.transcript->serialize_full_transcript();
333 EXPECT_FALSE(verifier.verify_proof(prover.export_proof())); // the proof is now wrong after serializing it
334
335 prover.transcript->deserialize_full_transcript(verification_key->num_public_inputs);
336 EXPECT_EQ(static_cast<Commitment>(prover.transcript->z_perm_comm), one_group_val * rand_val);
337 }
338}
void generate_test_circuit(auto &builder)
static TranscriptManifest construct_mega_honk_manifest()
Construct a manifest for a Mega Honk proof.
A DeciderProvingKey is normally constructed from a finalized circuit and it contains all the informat...
The verification key is responsible for storing the commitments to the precomputed (non-witnessk) pol...
Curve::ScalarField FF
static constexpr size_t NUM_SUBRELATIONS
MegaCircuitBuilder CircuitBuilder
static constexpr size_t NUM_ALL_ENTITIES
static constexpr bool HasZK
static constexpr size_t VIRTUAL_LOG_N
Curve::AffineElement Commitment
static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH
void add_entry(size_t round, const std::string &element_label, size_t element_size)
void add_challenge(size_t round, Strings &... labels)
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:70
AluTraceBuilder builder
Definition alu.test.cpp:123
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.
TYPED_TEST_SUITE(ShpleminiTest, TestSettings)
typename Flavor::FF FF
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