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.
13
14#include "gtest/gtest.h"
15
16using namespace bb;
17
18#ifdef STARKNET_GARAGA_FLAVORS
19using FlavorTypes = ::testing::Types<UltraFlavor,
21 UltraStarknetFlavor,
22 UltraStarknetZKFlavor,
26#else
28 ::testing::Types<UltraFlavor, UltraKeccakFlavor, UltraRollupFlavor, UltraZKFlavor, UltraKeccakZKFlavor>;
29#endif
30template <typename Flavor> class UltraTranscriptTests : public ::testing::Test {
31 public:
33
35 using FF = Flavor::FF;
41 using Proof = typename Flavor::Transcript::Proof;
43
56 {
57 TranscriptManifest manifest_expected;
58
59 const size_t virtual_log_n = Flavor::USE_PADDING ? CONST_PROOF_SIZE_LOG_N : log_n;
60
61 size_t MAX_PARTIAL_RELATION_LENGTH = Flavor::BATCHED_RELATION_PARTIAL_LENGTH;
62 size_t NUM_SUBRELATIONS = Flavor::NUM_SUBRELATIONS;
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 bb::field_conversion::calc_num_uint256_ts<FF>();
68 } else {
69 return bb::field_conversion::calc_num_bn254_frs<FF>();
70 }
71 }();
72 size_t data_types_per_G = [] {
73 if constexpr (IsKeccakFlavor<Flavor>) {
74 return bb::field_conversion::calc_num_uint256_ts<Commitment>();
75 } else {
76 return bb::field_conversion::calc_num_bn254_frs<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 manifest_expected.add_entry(round, "W_L", data_types_per_G);
93 manifest_expected.add_entry(round, "W_R", data_types_per_G);
94 manifest_expected.add_entry(round, "W_O", data_types_per_G);
95 manifest_expected.add_challenge(round, "eta", "eta_two", "eta_three");
96
97 round++;
98 manifest_expected.add_entry(round, "LOOKUP_READ_COUNTS", data_types_per_G);
99 manifest_expected.add_entry(round, "LOOKUP_READ_TAGS", data_types_per_G);
100 manifest_expected.add_entry(round, "W_4", data_types_per_G);
101 manifest_expected.add_challenge(round, "beta", "gamma");
102
103 round++;
104 manifest_expected.add_entry(round, "LOOKUP_INVERSES", data_types_per_G);
105 manifest_expected.add_entry(round, "Z_PERM", data_types_per_G);
106
107 std::array<std::string, Flavor::NUM_SUBRELATIONS - 1> alpha_labels;
108 for (size_t i = 0; i < NUM_SUBRELATIONS - 1; i++) {
109 std::string label = "alpha_" + std::to_string(i);
110 alpha_labels[i] = label;
111 }
112
113 manifest_expected.add_challenge(round, alpha_labels);
114 round++;
115
116 manifest_expected.add_challenge(round, "Sumcheck:gate_challenge");
117 round++;
118
119 if constexpr (Flavor::HasZK) {
120 manifest_expected.add_entry(round, "Libra:concatenation_commitment", data_types_per_G);
121 manifest_expected.add_entry(round, "Libra:Sum", data_types_per_Frs);
122 manifest_expected.add_challenge(round, "Libra:Challenge");
123 round++;
124 }
125
126 for (size_t i = 0; i < virtual_log_n; ++i) {
127 std::string idx = std::to_string(i);
128 manifest_expected.add_entry(round, "Sumcheck:univariate_" + idx, frs_per_uni);
129 std::string label = "Sumcheck:u_" + idx;
130 manifest_expected.add_challenge(round, label);
131 round++;
132 }
133
134 manifest_expected.add_entry(round, "Sumcheck:evaluations", frs_per_evals);
135
136 if constexpr (Flavor::HasZK) {
137 manifest_expected.add_entry(round, "Libra:claimed_evaluation", data_types_per_Frs);
138 manifest_expected.add_entry(round, "Libra:grand_sum_commitment", data_types_per_G);
139 manifest_expected.add_entry(round, "Libra:quotient_commitment", data_types_per_G);
140 manifest_expected.add_entry(round, "Gemini:masking_poly_comm", data_types_per_G);
141 manifest_expected.add_entry(round, "Gemini:masking_poly_eval", data_types_per_Frs);
142 }
143
144 manifest_expected.add_challenge(round, "rho");
145
146 round++;
147 for (size_t i = 1; i < virtual_log_n; ++i) {
148 std::string idx = std::to_string(i);
149 manifest_expected.add_entry(round, "Gemini:FOLD_" + idx, data_types_per_G);
150 }
151 manifest_expected.add_challenge(round, "Gemini:r");
152 round++;
153 for (size_t i = 1; i <= virtual_log_n; ++i) {
154 std::string idx = std::to_string(i);
155 manifest_expected.add_entry(round, "Gemini:a_" + idx, data_types_per_Frs);
156 }
157
158 if constexpr (Flavor::HasZK) {
159 manifest_expected.add_entry(round, "Libra:concatenation_eval", data_types_per_Frs);
160 manifest_expected.add_entry(round, "Libra:shifted_grand_sum_eval", data_types_per_Frs);
161 manifest_expected.add_entry(round, "Libra:grand_sum_eval", data_types_per_Frs);
162 manifest_expected.add_entry(round, "Libra:quotient_eval", data_types_per_Frs);
163 }
164
165 manifest_expected.add_challenge(round, "Shplonk:nu");
166 round++;
167 manifest_expected.add_entry(round, "Shplonk:Q", data_types_per_G);
168 manifest_expected.add_challenge(round, "Shplonk:z");
169
170 round++;
171 manifest_expected.add_entry(round, "KZG:W", data_types_per_G);
172 manifest_expected.add_challenge(round); // no challenge
173
174 return manifest_expected;
175 }
176
178 {
179 FF a = 1;
180 builder.add_variable(a);
181 builder.add_public_variable(a);
183 if constexpr (HasIPAAccumulator<Flavor>) {
184 auto [stdlib_opening_claim, ipa_proof] =
185 IPA<stdlib::grumpkin<Builder>>::create_fake_ipa_claim_and_proof(builder);
186 stdlib_opening_claim.set_public();
187 builder.ipa_proof = ipa_proof;
188 }
189 }
190
192 {
193 auto a = FF::random_element();
194 auto b = FF::random_element();
195 builder.add_variable(a);
196 builder.add_public_variable(a);
197 builder.add_public_variable(b);
198
199 if constexpr (HasIPAAccumulator<Flavor>) {
200 auto [stdlib_opening_claim, ipa_proof] =
201 IPA<stdlib::grumpkin<Builder>>::create_fake_ipa_claim_and_proof(builder);
202 stdlib_opening_claim.set_public();
203 builder.ipa_proof = ipa_proof;
204 }
205 }
206
207 Proof export_serialized_proof(Prover prover, const size_t num_public_inputs)
208 {
209 // reset internal variables needed for exporting the proof
210 prover.transcript->num_frs_written = Flavor::PROOF_LENGTH_WITHOUT_PUB_INPUTS() + num_public_inputs;
211 prover.transcript->proof_start = 0;
212 return prover.export_proof();
213 }
214};
215
217
222TYPED_TEST(UltraTranscriptTests, ProverManifestConsistency)
223{
224 // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size)
225 auto builder = typename TestFixture::Builder();
226 TestFixture::generate_test_circuit(builder);
227
228 // Automatically generate a transcript manifest by constructing a proof
230 auto verification_key = std::make_shared<typename TestFixture::VerificationKey>(proving_key->get_precomputed());
231 typename TestFixture::Prover prover(proving_key, verification_key);
232 prover.transcript->enable_manifest();
233 auto proof = prover.construct_proof();
234
235 // Check that the prover generated manifest agrees with the manifest hard coded in this suite
236 auto manifest_expected = TestFixture::construct_ultra_honk_manifest(prover.proving_key->log_dyadic_size());
237 auto prover_manifest = prover.transcript->get_manifest();
238 // Note: a manifest can be printed using manifest.print()
239 manifest_expected.print();
240 prover_manifest.print();
241 ASSERT_GT(manifest_expected.size(), 0);
242 for (size_t round = 0; round < manifest_expected.size(); ++round) {
243 if (prover_manifest[round] != manifest_expected[round]) {
244 info("Prover manifest discrepency in round ", round);
245 info("Prover manifest:");
246 prover_manifest[round].print();
247 info("Expected manifest:");
248 manifest_expected[round].print();
249 FAIL();
250 }
251 }
252}
253
259TYPED_TEST(UltraTranscriptTests, VerifierManifestConsistency)
260{
261 // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size)
262 auto builder = typename TestFixture::Builder();
263 TestFixture::generate_test_circuit(builder);
264
265 // Automatically generate a transcript manifest in the prover by constructing a proof
267 auto verification_key = std::make_shared<typename TestFixture::VerificationKey>(proving_key->get_precomputed());
268 typename TestFixture::Prover prover(proving_key, verification_key);
269 prover.transcript->enable_manifest();
270 auto proof = prover.construct_proof();
271
272 // Automatically generate a transcript manifest in the verifier by verifying a proof
273 typename TestFixture::Verifier verifier(verification_key);
274 verifier.transcript->enable_manifest();
275 typename TestFixture::Proof honk_proof;
276 typename TestFixture::Proof ipa_proof;
277 if constexpr (HasIPAAccumulator<TypeParam>) {
278 verifier.ipa_verification_key = VerifierCommitmentKey<curve::Grumpkin>(1 << CONST_ECCVM_LOG_N);
279 const size_t HONK_PROOF_LENGTH = TypeParam::PROOF_LENGTH_WITHOUT_PUB_INPUTS() - IPA_PROOF_LENGTH;
280 const size_t num_public_inputs = static_cast<uint32_t>(verification_key->num_public_inputs);
281 // The extra calculation is for the IPA proof length.
282 // TODO(https://github.com/AztecProtocol/barretenberg/issues/1182): Handle in ProofSurgeon.
283 ASSERT_EQ(proof.size(), HONK_PROOF_LENGTH + IPA_PROOF_LENGTH + num_public_inputs);
284 // split out the ipa proof
285 const std::ptrdiff_t honk_proof_with_pub_inputs_length =
286 static_cast<std::ptrdiff_t>(HONK_PROOF_LENGTH + num_public_inputs);
287
288 honk_proof = typename TestFixture::Proof(proof.begin(), proof.begin() + honk_proof_with_pub_inputs_length);
289 ipa_proof = typename TestFixture::Proof(proof.begin() + honk_proof_with_pub_inputs_length, proof.end());
290 } else {
291 honk_proof = proof;
292 }
293 [[maybe_unused]] auto _ = verifier.template verify_proof<typename TestFixture::IO>(honk_proof, ipa_proof);
294
295 // Check consistency between the manifests generated by the prover and verifier
296 auto prover_manifest = prover.transcript->get_manifest();
297 auto verifier_manifest = verifier.transcript->get_manifest();
298
299 // Note: a manifest can be printed using manifest.print()
300 ASSERT_GT(prover_manifest.size(), 0);
301 for (size_t round = 0; round < prover_manifest.size(); ++round) {
302 ASSERT_EQ(prover_manifest[round], verifier_manifest[round])
303 << "Prover/Verifier manifest discrepency in round " << round;
304 }
305}
306
312TYPED_TEST(UltraTranscriptTests, ChallengeGenerationTest)
313{
314 using Flavor = TypeParam;
315 using FF = Flavor::FF;
316 // initialized with random value sent to verifier
317 auto transcript = TypeParam::Transcript::prover_init_empty();
318 // test a bunch of challenges
319 auto challenges = transcript->template get_challenges<FF>("a", "b", "c", "d", "e", "f");
320 // check they are not 0
321 for (size_t i = 0; i < challenges.size(); ++i) {
322 ASSERT_NE(challenges[i], 0) << "Challenge " << i << " is 0";
323 }
324 constexpr uint32_t random_val{ 17 }; // arbitrary
325 transcript->send_to_verifier("random val", random_val);
326 // test more challenges
327 auto [a, b, c] = transcript->template get_challenges<FF>("a", "b", "c");
328 ASSERT_NE(a, 0) << "Challenge a is 0";
329 ASSERT_NE(b, 0) << "Challenge b is 0";
330 ASSERT_NE(c, 0) << "Challenge c is 0";
331}
332
334{
335 using Flavor = TypeParam;
336 using FF = Flavor::FF;
337 using Commitment = Flavor::Commitment;
338 // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size)
339 auto builder = typename TestFixture::Builder();
340 if constexpr (IsAnyOf<TypeParam, UltraRollupFlavor, UltraKeccakFlavor, UltraKeccakZKFlavor>) {
341 GTEST_SKIP() << "Not built for this parameter";
342 }
343 TestFixture::generate_test_circuit(builder);
344
345 // Automatically generate a transcript manifest by constructing a proof
347 auto verification_key = std::make_shared<typename TestFixture::VerificationKey>(proving_key->get_precomputed());
348 typename TestFixture::Prover prover(proving_key, verification_key);
349 auto proof = prover.construct_proof();
350 typename TestFixture::Verifier verifier(verification_key);
351 {
352 bool result = verifier.template verify_proof<typename TestFixture::IO>(proof).result;
353 EXPECT_TRUE(result);
354 }
355
356 const size_t virtual_log_n = Flavor::USE_PADDING ? CONST_PROOF_SIZE_LOG_N : proving_key->log_dyadic_size();
357
358 // try deserializing and serializing with no changes and check proof is still valid
359 prover.transcript->deserialize_full_transcript(verification_key->num_public_inputs, virtual_log_n);
360 prover.transcript->serialize_full_transcript(virtual_log_n);
361 // reset verifier's transcript
362 verifier.transcript = std::make_shared<typename Flavor::Transcript>();
363
364 proof = TestFixture::export_serialized_proof(prover, proving_key->num_public_inputs());
365 {
366 bool result = verifier.template verify_proof<typename TestFixture::IO>(proof).result;
367 EXPECT_TRUE(result); // we have changed nothing so proof is still valid
368 }
369
370 Commitment one_group_val = Commitment::one();
371 FF rand_val = FF::random_element();
372 prover.transcript->z_perm_comm = one_group_val * rand_val; // choose random object to modify
373 verifier.transcript = std::make_shared<typename Flavor::Transcript>(); // reset verifier's transcript
374 proof = TestFixture::export_serialized_proof(prover, proving_key->num_public_inputs());
375 {
376 bool result = verifier.template verify_proof<typename TestFixture::IO>(proof).result;
377 EXPECT_TRUE(result); // we have not serialized it back to the proof so it should still be fine
378 }
379
380 prover.transcript->serialize_full_transcript();
381 verifier.transcript = std::make_shared<typename Flavor::Transcript>(); // reset verifier's transcript
382 proof = TestFixture::export_serialized_proof(prover, proving_key->num_public_inputs());
383 {
384 bool result = verifier.template verify_proof<typename TestFixture::IO>(proof).result;
385 EXPECT_FALSE(result); // the proof is now wrong after serializing it
386 }
387
388 prover.transcript->deserialize_full_transcript(verification_key->num_public_inputs);
389 EXPECT_EQ(static_cast<Commitment>(prover.transcript->z_perm_comm), one_group_val * rand_val);
390}
void generate_random_test_circuit(Builder &builder)
Flavor::Commitment Commitment
typename Flavor::Transcript::Proof Proof
Proof export_serialized_proof(Prover prover, const size_t num_public_inputs)
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
A DeciderProvingKey is normally constructed from a finalized circuit and it contains all the informat...
Manages the data that is propagated on the public inputs of an application/function circuit.
static constexpr size_t PUBLIC_INPUTS_SIZE
static constexpr size_t PROOF_LENGTH_WITHOUT_PUB_INPUTS
IPA (inner product argument) commitment scheme class.
Definition ipa.hpp:95
The verification key is responsible for storing the commitments to the precomputed (non-witness) poly...
Curve::ScalarField FF
static constexpr size_t NUM_SUBRELATIONS
MegaCircuitBuilder CircuitBuilder
static constexpr size_t NUM_ALL_ENTITIES
static constexpr bool HasZK
Curve::AffineElement Commitment
static constexpr bool USE_PADDING
static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH
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, Strings &... labels)
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.
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...
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
static void add_default_to_public_inputs(Builder &builder)
Adds default public inputs to the builder.