Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
ultra_transcript.test.cpp
Go to the documentation of this file.
14
15#include "gtest/gtest.h"
16
17using namespace bb;
18
19#ifdef STARKNET_GARAGA_FLAVORS
20using FlavorTypes = ::testing::Types<UltraFlavor,
22 UltraStarknetFlavor,
23 UltraStarknetZKFlavor,
27#else
29 ::testing::Types<UltraFlavor, UltraKeccakFlavor, UltraRollupFlavor, UltraZKFlavor, UltraKeccakZKFlavor>;
30#endif
31template <typename Flavor> class UltraTranscriptTests : public ::testing::Test {
32 public:
34
36 using FF = Flavor::FF;
44
57 {
58 TranscriptManifest manifest_expected;
59
60 const size_t virtual_log_n = Flavor::USE_PADDING ? CONST_PROOF_SIZE_LOG_N : log_n;
61
62 size_t MAX_PARTIAL_RELATION_LENGTH = Flavor::BATCHED_RELATION_PARTIAL_LENGTH;
63 // Size of types is number of bb::frs needed to represent the types
64 // UltraKeccak uses uint256_t for commitments and frs, so we need to handle that differently.
65 size_t data_types_per_Frs = [] {
66 if constexpr (IsKeccakFlavor<Flavor>) {
67 return U256Codec::calc_num_fields<FF>();
68 } else {
69 return FrCodec::calc_num_fields<FF>();
70 }
71 }();
72 size_t data_types_per_G = [] {
73 if constexpr (IsKeccakFlavor<Flavor>) {
74 return U256Codec::calc_num_fields<Commitment>();
75 } else {
76 return FrCodec::calc_num_fields<Commitment>();
77 }
78 }();
79 size_t frs_per_uni = MAX_PARTIAL_RELATION_LENGTH * data_types_per_Frs;
80 size_t frs_per_evals = (Flavor::NUM_ALL_ENTITIES)*data_types_per_Frs;
81
82 size_t round = 0;
83 manifest_expected.add_entry(round, "vk_hash", data_types_per_Frs);
84
85 manifest_expected.add_entry(round, "public_input_0", data_types_per_Frs);
86 constexpr size_t PUBLIC_INPUTS_SIZE =
88 for (size_t i = 0; i < PUBLIC_INPUTS_SIZE; i++) {
89 manifest_expected.add_entry(round, "public_input_" + std::to_string(1 + i), data_types_per_Frs);
90 }
91
92 // For ZK flavors: Gemini masking polynomial commitment is sent at end of oink
93 if constexpr (Flavor::HasZK) {
94 manifest_expected.add_entry(round, "Gemini:masking_poly_comm", data_types_per_G);
95 }
96 manifest_expected.add_entry(round, "W_L", data_types_per_G);
97 manifest_expected.add_entry(round, "W_R", data_types_per_G);
98 manifest_expected.add_entry(round, "W_O", data_types_per_G);
99 manifest_expected.add_challenge(round, std::array{ "eta", "eta_two", "eta_three" });
100
101 round++;
102 manifest_expected.add_entry(round, "LOOKUP_READ_COUNTS", data_types_per_G);
103 manifest_expected.add_entry(round, "LOOKUP_READ_TAGS", data_types_per_G);
104 manifest_expected.add_entry(round, "W_4", data_types_per_G);
105 manifest_expected.add_challenge(round, std::array{ "beta", "gamma" });
106
107 round++;
108 manifest_expected.add_entry(round, "LOOKUP_INVERSES", data_types_per_G);
109 manifest_expected.add_entry(round, "Z_PERM", data_types_per_G);
110
111 manifest_expected.add_challenge(round, "alpha");
112 round++;
113
114 manifest_expected.add_challenge(round, "Sumcheck:gate_challenge");
115 round++;
116
117 if constexpr (Flavor::HasZK) {
118 manifest_expected.add_entry(round, "Libra:concatenation_commitment", data_types_per_G);
119 manifest_expected.add_entry(round, "Libra:Sum", data_types_per_Frs);
120 manifest_expected.add_challenge(round, "Libra:Challenge");
121 round++;
122 }
123
124 for (size_t i = 0; i < virtual_log_n; ++i) {
125 std::string idx = std::to_string(i);
126 manifest_expected.add_entry(round, "Sumcheck:univariate_" + idx, frs_per_uni);
127 std::string label = "Sumcheck:u_" + idx;
128 manifest_expected.add_challenge(round, label);
129 round++;
130 }
131
132 manifest_expected.add_entry(round, "Sumcheck:evaluations", frs_per_evals);
133
134 if constexpr (Flavor::HasZK) {
135 manifest_expected.add_entry(round, "Libra:claimed_evaluation", data_types_per_Frs);
136 manifest_expected.add_entry(round, "Libra:grand_sum_commitment", data_types_per_G);
137 manifest_expected.add_entry(round, "Libra:quotient_commitment", data_types_per_G);
138 }
139
140 manifest_expected.add_challenge(round, "rho");
141
142 round++;
143 for (size_t i = 1; i < virtual_log_n; ++i) {
144 std::string idx = std::to_string(i);
145 manifest_expected.add_entry(round, "Gemini:FOLD_" + idx, data_types_per_G);
146 }
147 manifest_expected.add_challenge(round, "Gemini:r");
148 round++;
149 for (size_t i = 1; i <= virtual_log_n; ++i) {
150 std::string idx = std::to_string(i);
151 manifest_expected.add_entry(round, "Gemini:a_" + idx, data_types_per_Frs);
152 }
153
154 if constexpr (Flavor::HasZK) {
155 manifest_expected.add_entry(round, "Libra:concatenation_eval", data_types_per_Frs);
156 manifest_expected.add_entry(round, "Libra:shifted_grand_sum_eval", data_types_per_Frs);
157 manifest_expected.add_entry(round, "Libra:grand_sum_eval", data_types_per_Frs);
158 manifest_expected.add_entry(round, "Libra:quotient_eval", data_types_per_Frs);
159 }
160
161 manifest_expected.add_challenge(round, "Shplonk:nu");
162 round++;
163 manifest_expected.add_entry(round, "Shplonk:Q", data_types_per_G);
164 manifest_expected.add_challenge(round, "Shplonk:z");
165
166 round++;
167 manifest_expected.add_entry(round, "KZG:W", data_types_per_G);
168 manifest_expected.add_challenge(round, "KZG:masking_challenge");
169
170 return manifest_expected;
171 }
172
174 {
175 FF a = 1;
176 builder.add_variable(a);
177 builder.add_public_variable(a);
178 if constexpr (HasIPAAccumulator<Flavor>) {
180 } else {
182 }
183 }
184
186 {
187 auto a = FF::random_element();
188 auto b = FF::random_element();
189 builder.add_variable(a);
190 builder.add_public_variable(a);
191 builder.add_public_variable(b);
192
193 if constexpr (HasIPAAccumulator<Flavor>) {
194 auto [stdlib_opening_claim, ipa_proof] =
195 IPA<stdlib::grumpkin<Builder>>::create_random_valid_ipa_claim_and_proof(builder);
196 stdlib_opening_claim.set_public();
197 builder.ipa_proof = ipa_proof;
198 }
199 }
200
201 Proof export_serialized_proof(Prover& prover, const size_t num_public_inputs)
202 {
203 // reset internal variables needed for exporting the proof
204 size_t proof_length = Flavor::PROOF_LENGTH_WITHOUT_PUB_INPUTS() + num_public_inputs;
205 prover.transcript->test_set_proof_parsing_state(0, proof_length);
206 return prover.export_proof();
207 }
208};
209
211
216TYPED_TEST(UltraTranscriptTests, ProverManifestConsistency)
217{
218 // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size)
219 auto builder = typename TestFixture::Builder();
220 TestFixture::generate_test_circuit(builder);
221
222 // Automatically generate a transcript manifest by constructing a proof
224 auto verification_key = std::make_shared<typename TestFixture::VerificationKey>(prover_instance->get_precomputed());
225 typename TestFixture::Prover prover(prover_instance, verification_key);
226 prover.transcript->enable_manifest();
227 auto proof = prover.construct_proof();
228
229 // Check that the prover generated manifest agrees with the manifest hard coded in this suite
230 auto manifest_expected = TestFixture::construct_ultra_honk_manifest(prover.prover_instance->log_dyadic_size());
231 auto prover_manifest = prover.transcript->get_manifest();
232 // Note: a manifest can be printed using manifest.print()
233 manifest_expected.print();
234 prover_manifest.print();
235 ASSERT_GT(manifest_expected.size(), 0);
236 for (size_t round = 0; round < manifest_expected.size(); ++round) {
237 if (prover_manifest[round] != manifest_expected[round]) {
238 info("Prover manifest discrepency in round ", round);
239 info("Prover manifest:");
240 prover_manifest[round].print();
241 info("Expected manifest:");
242 manifest_expected[round].print();
243 FAIL();
244 }
245 }
246}
247
253TYPED_TEST(UltraTranscriptTests, VerifierManifestConsistency)
254{
255 // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size)
256 auto builder = typename TestFixture::Builder();
257 TestFixture::generate_test_circuit(builder);
258
259 // Automatically generate a transcript manifest in the prover by constructing a proof
261 auto verification_key = std::make_shared<typename TestFixture::VerificationKey>(prover_instance->get_precomputed());
262 typename TestFixture::Prover prover(prover_instance, verification_key);
263 prover.transcript->enable_manifest();
264 auto proof = prover.construct_proof();
265
266 // Automatically generate a transcript manifest in the verifier by verifying a proof
267 typename TestFixture::Verifier verifier(verification_key);
268 verifier.transcript->enable_manifest();
269 typename TestFixture::Proof honk_proof;
270 typename TestFixture::Proof ipa_proof;
271 if constexpr (HasIPAAccumulator<TypeParam>) {
272 verifier.ipa_verification_key = VerifierCommitmentKey<curve::Grumpkin>(1 << CONST_ECCVM_LOG_N);
273 const size_t HONK_PROOF_LENGTH = TypeParam::PROOF_LENGTH_WITHOUT_PUB_INPUTS() - IPA_PROOF_LENGTH;
274 const size_t num_public_inputs = static_cast<uint32_t>(verification_key->num_public_inputs);
275 // The extra calculation is for the IPA proof length.
276 // TODO(https://github.com/AztecProtocol/barretenberg/issues/1182): Handle in ProofSurgeon.
277 ASSERT_EQ(proof.size(), HONK_PROOF_LENGTH + IPA_PROOF_LENGTH + num_public_inputs);
278 // split out the ipa proof
279 const std::ptrdiff_t honk_proof_with_pub_inputs_length =
280 static_cast<std::ptrdiff_t>(HONK_PROOF_LENGTH + num_public_inputs);
281
282 honk_proof = typename TestFixture::Proof(proof.begin(), proof.begin() + honk_proof_with_pub_inputs_length);
283 ipa_proof = typename TestFixture::Proof(proof.begin() + honk_proof_with_pub_inputs_length, proof.end());
284 } else {
285 honk_proof = proof;
286 }
287 [[maybe_unused]] auto _ = verifier.template verify_proof<typename TestFixture::IO>(honk_proof, ipa_proof);
288
289 // Check consistency between the manifests generated by the prover and verifier
290 auto prover_manifest = prover.transcript->get_manifest();
291 auto verifier_manifest = verifier.transcript->get_manifest();
292
293 // Note: a manifest can be printed using manifest.print()
294 ASSERT_GT(prover_manifest.size(), 0);
295 for (size_t round = 0; round < prover_manifest.size(); ++round) {
296 ASSERT_EQ(prover_manifest[round], verifier_manifest[round])
297 << "Prover/Verifier manifest discrepency in round " << round;
298 }
299}
300
306TYPED_TEST(UltraTranscriptTests, ChallengeGenerationTest)
307{
308 using Flavor = TypeParam;
309 using FF = Flavor::FF;
310 // initialized with random value sent to verifier
311 auto transcript = TypeParam::Transcript::prover_init_empty();
312 // test a bunch of challenges
313 std::vector<std::string> challenge_labels{ "a", "b", "c", "d", "e", "f" };
314 auto challenges = transcript->template get_challenges<FF>(challenge_labels);
315 // check they are not 0
316 for (size_t i = 0; i < challenges.size(); ++i) {
317 ASSERT_NE(challenges[i], 0) << "Challenge " << i << " is 0";
318 }
319 constexpr uint32_t random_val{ 17 }; // arbitrary
320 transcript->send_to_verifier("random val", random_val);
321 // test more challenges
322 challenge_labels = { "a", "b", "c" };
323 challenges = transcript->template get_challenges<FF>(challenge_labels);
324 ASSERT_NE(challenges[0], 0) << "Challenge a is 0";
325 ASSERT_NE(challenges[1], 0) << "Challenge b is 0";
326 ASSERT_NE(challenges[2], 0) << "Challenge c is 0";
327}
328
330{
331 using Flavor = TypeParam;
332 using FF = Flavor::FF;
333 using Commitment = Flavor::Commitment;
334 // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size)
335 auto builder = typename TestFixture::Builder();
336 if constexpr (IsAnyOf<TypeParam, UltraRollupFlavor, UltraKeccakFlavor, UltraKeccakZKFlavor>) {
337 GTEST_SKIP() << "Not built for this parameter";
338 }
339 TestFixture::generate_test_circuit(builder);
340
341 // Automatically generate a transcript manifest by constructing a proof
343 auto verification_key = std::make_shared<typename TestFixture::VerificationKey>(prover_instance->get_precomputed());
344 typename TestFixture::Prover prover(prover_instance, verification_key);
345 auto proof = prover.construct_proof();
346 typename TestFixture::Verifier verifier(verification_key);
347 {
348 bool result = verifier.template verify_proof<typename TestFixture::IO>(proof).result;
349 EXPECT_TRUE(result);
350 }
351
352 const size_t virtual_log_n = Flavor::USE_PADDING ? CONST_PROOF_SIZE_LOG_N : prover_instance->log_dyadic_size();
353
354 // try deserializing and serializing with no changes and check proof is still valid
355 prover.transcript->deserialize_full_transcript(verification_key->num_public_inputs, virtual_log_n);
356 prover.transcript->serialize_full_transcript(virtual_log_n);
357 // reset verifier's transcript
358 verifier.transcript = std::make_shared<typename Flavor::Transcript>();
359
360 proof = TestFixture::export_serialized_proof(prover, prover_instance->num_public_inputs());
361 {
362 bool result = verifier.template verify_proof<typename TestFixture::IO>(proof).result;
363 EXPECT_TRUE(result); // we have changed nothing so proof is still valid
364 }
365
366 Commitment one_group_val = Commitment::one();
367 FF rand_val = FF::random_element();
368 prover.transcript->z_perm_comm = one_group_val * rand_val; // choose random object to modify
369 verifier.transcript = std::make_shared<typename Flavor::Transcript>(); // reset verifier's transcript
370 proof = TestFixture::export_serialized_proof(prover, prover_instance->num_public_inputs());
371 {
372 bool result = verifier.template verify_proof<typename TestFixture::IO>(proof).result;
373 EXPECT_TRUE(result); // we have not serialized it back to the proof so it should still be fine
374 }
375
376 prover.transcript->serialize_full_transcript();
377 verifier.transcript = std::make_shared<typename Flavor::Transcript>(); // reset verifier's transcript
378 proof = TestFixture::export_serialized_proof(prover, prover_instance->num_public_inputs());
379 {
380 bool result = verifier.template verify_proof<typename TestFixture::IO>(proof).result;
381 EXPECT_FALSE(result); // the proof is now wrong after serializing it
382 }
383
384 prover.transcript->deserialize_full_transcript(verification_key->num_public_inputs, virtual_log_n);
385 EXPECT_EQ(static_cast<Commitment>(prover.transcript->z_perm_comm), one_group_val * rand_val);
386}
void generate_random_test_circuit(Builder &builder)
Flavor::Commitment Commitment
Proof export_serialized_proof(Prover &prover, const size_t num_public_inputs)
typename Flavor::Transcript::Proof Proof
TranscriptManifest construct_ultra_honk_manifest(const size_t &log_n)
Construct a manifest for a Ultra Honk proof.
void generate_test_circuit(Builder &builder)
std::conditional_t< HasIPAAccumulator< Flavor >, RollupIO, DefaultIO > IO
Manages the data that is propagated on the public inputs of an application/function circuit.
static constexpr size_t PUBLIC_INPUTS_SIZE
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 PROOF_LENGTH_WITHOUT_PUB_INPUTS
static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH
static constexpr bool USE_PADDING
IPA (inner product argument) commitment scheme class.
Definition ipa.hpp:93
A ProverInstance is normally constructed from a finalized circuit and it contains all the information...
The data that is propagated on the public inputs of a rollup circuit.
static constexpr size_t PUBLIC_INPUTS_SIZE
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
Child class of UltraFlavor that runs with ZK Sumcheck.
Representation of the Grumpkin Verifier Commitment Key inside a bn254 circuit.
static void add_default(Builder &builder)
Add default public inputs when they are not present.
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...
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