Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
mega_honk.test.cpp
Go to the documentation of this file.
1#include <cstddef>
2#include <cstdint>
3#include <gtest/gtest.h>
4
15
16using namespace bb;
17
19
20using FlavorTypes = ::testing::Types<MegaFlavor, MegaZKFlavor>;
21
22template <typename Flavor> class MegaHonkTests : public ::testing::Test {
23 public:
25
35
41 {
42 auto prover_instance = std::make_shared<ProverInstance>(builder);
43 auto verification_key = std::make_shared<VerificationKey>(prover_instance->get_precomputed());
44 auto vk_and_hash = std::make_shared<typename Flavor::VKAndHash>(verification_key);
45 Prover prover(prover_instance, verification_key);
46 Verifier verifier(vk_and_hash);
47 auto proof = prover.construct_proof();
48 bool verified = verifier.verify_proof(proof).result;
49
50 return verified;
51 }
52};
53
55
65TYPED_TEST(MegaHonkTests, ProofLengthCheck)
66{
67 using Flavor = TypeParam;
70
71 auto builder = Builder{};
73
74 // Construct a mega proof and ensure its size matches expectation; if not, the constant may need to be updated
76 auto verification_key = std::make_shared<typename Flavor::VerificationKey>(prover_instance->get_precomputed());
77 UltraProver_<Flavor> prover(prover_instance, verification_key);
78 HonkProof mega_proof = prover.construct_proof();
79 EXPECT_EQ(mega_proof.size(),
82}
83
90{
91 using Flavor = TypeParam;
93
95
96 // Construct and verify Honk proof
97 bool honk_verified = this->construct_and_verify_honk_proof(builder);
98 EXPECT_TRUE(honk_verified);
99}
100
106TYPED_TEST(MegaHonkTests, DynamicVirtualSizeIncrease)
107{
108 using Flavor = TypeParam;
109
110 // In MegaZKFlavor, we mask witness polynomials by placing random values at the indices `dyadic_circuit_size`-i for
111 // i=1,2,3. This mechanism does not work with structured polynomials yet.
113 GTEST_SKIP() << "Skipping 'DynamicVirtualSizeIncrease' test for MegaZKFlavor.";
114 }
116 using Prover = UltraProver_<Flavor>;
117 using Verifier = UltraVerifier_<Flavor, DefaultIO>;
118
120
121 auto builder_copy = builder;
122
123 // Construct and verify Honk proof using a structured trace
124 auto prover_instance = std::make_shared<ProverInstance_<Flavor>>(builder);
125 auto prover_instance_copy = std::make_shared<ProverInstance_<Flavor>>(builder_copy);
126 auto circuit_size = prover_instance->dyadic_size();
127
128 auto doubled_circuit_size = 2 * circuit_size;
129 prover_instance_copy->polynomials.increase_polynomials_virtual_size(doubled_circuit_size);
130 // TODO(https://github.com/AztecProtocol/barretenberg/issues/1158)
131 // prover_instance_copy->dyadic_circuit_size = doubled_circuit_size;
132
133 auto verification_key = std::make_shared<typename Flavor::VerificationKey>(prover_instance->get_precomputed());
134 Prover prover(prover_instance, verification_key);
135
136 auto verification_key_copy = std::make_shared<typename Flavor::VerificationKey>(prover_instance->get_precomputed());
137 Prover prover_copy(prover_instance_copy, verification_key_copy);
138
139 for (auto [entry, entry_copy] : zip_view(verification_key->get_all(), verification_key_copy->get_all())) {
140 EXPECT_EQ(entry, entry_copy);
141 }
142
143 auto vk_and_hash = std::make_shared<typename Flavor::VKAndHash>(verification_key);
144 Verifier verifier(vk_and_hash);
145 auto proof = prover.construct_proof();
146
147 auto relation_failures =
148 RelationChecker<Flavor>::check_all(prover_instance->polynomials, prover_instance->relation_parameters);
149 EXPECT_TRUE(relation_failures.empty());
150 bool result = verifier.verify_proof(proof).result;
151 EXPECT_TRUE(result);
152
153 auto vk_and_hash_copy = std::make_shared<typename Flavor::VKAndHash>(verification_key_copy);
154 Verifier verifier_copy(vk_and_hash_copy);
155 auto proof_copy = prover_copy.construct_proof();
156
157 auto relation_failures_copy =
158 RelationChecker<Flavor>::check_all(prover_instance->polynomials, prover_instance->relation_parameters);
159 EXPECT_TRUE(relation_failures.empty());
160 bool result_copy = verifier_copy.verify_proof(proof_copy).result;
161 EXPECT_TRUE(result_copy);
162}
163
172{
173 using Flavor = TypeParam;
174 // In MegaZKFlavor, we mask witness polynomials by placing random values at the indices `dyadic_circuit_size`-i, for
175 // i=1,2,3. This mechanism does not work with structured polynomials yet.
177 GTEST_SKIP() << "Skipping 'PolySwap' test for MegaZKFlavor.";
178 }
180
181 // Construct a simple circuit and make a copy of it
184 auto builder_copy = builder;
185
186 // Construct two identical proving keys
188 auto prover_instance_2 = std::make_shared<typename TestFixture::ProverInstance>(builder_copy);
189
190 // Tamper with the polys of pkey 1 in such a way that verification should fail
191 for (size_t i = 0; i < prover_instance_1->dyadic_size(); ++i) {
192 if (prover_instance_1->polynomials.q_arith[i] != 0) {
193 prover_instance_1->polynomials.w_l.at(i) += 1;
194 break;
195 }
196 }
197
198 // Swap the polys of the two proving keys; result should be pkey 1 is valid and pkey 2 should fail
199 std::swap(prover_instance_1->polynomials, prover_instance_2->polynomials);
200
201 { // Verification based on pkey 1 should succeed
202 auto verification_key =
203 std::make_shared<typename TestFixture::VerificationKey>(prover_instance_1->get_precomputed());
204 auto vk_and_hash = std::make_shared<typename Flavor::VKAndHash>(verification_key);
205 typename TestFixture::Prover prover(prover_instance_1, verification_key);
206 typename TestFixture::Verifier verifier(vk_and_hash);
207 auto proof = prover.construct_proof();
208 bool result = verifier.verify_proof(proof).result;
209 EXPECT_TRUE(result);
210 }
211
212 { // Verification based on pkey 2 should fail
213 auto verification_key =
214 std::make_shared<typename TestFixture::VerificationKey>(prover_instance_2->get_precomputed());
215 auto vk_and_hash = std::make_shared<typename Flavor::VKAndHash>(verification_key);
216 typename TestFixture::Prover prover(prover_instance_2, verification_key);
217 typename TestFixture::Verifier verifier(vk_and_hash);
218 auto proof = prover.construct_proof();
219 bool result = verifier.verify_proof(proof).result;
220 EXPECT_FALSE(result);
221 }
222}
223
231TYPED_TEST(MegaHonkTests, DyadicSizeJumpsToProtectMaskingArea)
232{
233 using Flavor = TypeParam;
234 if constexpr (!Flavor::HasZK) {
235 GTEST_SKIP() << "Masking area only exists for ZK flavors";
236 } else {
237 using Builder = typename Flavor::CircuitBuilder;
239
240 // Determine the baseline dyadic size (with ECC ops + finalization overhead, no extra user gates)
241 Builder baseline_builder;
243 auto baseline_instance = std::make_shared<ProverInstance>(baseline_builder);
244 const size_t baseline_dyadic = baseline_instance->dyadic_size();
245
246 // The disabled head region is always present.
247 // Verify active trace starts after it and dyadic size doubles when tightly packed.
248 size_t prev_dyadic = 0;
249 bool found_jump = false;
250 for (size_t num_extra_gates = 0; num_extra_gates <= baseline_dyadic; num_extra_gates++) {
253 if (num_extra_gates > 0) {
255 }
256 auto prover_instance = std::make_shared<ProverInstance>(builder);
257
258 const size_t dyadic_size = prover_instance->dyadic_size();
259 const size_t final_active_idx = prover_instance->get_final_active_wire_idx();
260
261 // Invariant: active trace doesn't overlap the disabled head region
262 ASSERT_GE(final_active_idx, ProverInstance::TRACE_OFFSET)
263 << "final_active_idx (" << final_active_idx << ") is within the disabled head region";
264
265 if (prev_dyadic != 0 && dyadic_size > prev_dyadic) {
266 EXPECT_EQ(dyadic_size, 2 * prev_dyadic);
267
268 // Prove and verify at the tightest packing (right before the jump)
269 Builder tight_builder;
271 MockCircuits::add_arithmetic_gates(tight_builder, num_extra_gates - 1);
272 bool verified = this->construct_and_verify_honk_proof(tight_builder);
273 EXPECT_TRUE(verified);
274
275 found_jump = true;
276 break;
277 }
278
279 prev_dyadic = dyadic_size;
280 }
281
282 EXPECT_TRUE(found_jump) << "should have found a dyadic size jump within " << baseline_dyadic << " extra gates";
283 }
284}
285
291TYPED_TEST(MegaHonkTests, WitnessPolynomialsMasked)
292{
293 using Flavor = TypeParam;
294 if constexpr (!Flavor::HasZK) {
295 GTEST_SKIP() << "Masking only applies to ZK flavors";
296 } else {
297 using Builder = typename Flavor::CircuitBuilder;
298
301 auto prover_instance = std::make_shared<ProverInstance_<Flavor>>(builder);
302
303 auto check_masked = [](const auto& poly, const std::string& label) {
304 bool has_masking = false;
305 for (size_t j = 0; j < NUM_MASKED_ROWS; j++) {
306 has_masking |= !poly[NUM_ZERO_ROWS + j].is_zero();
307 }
308 EXPECT_TRUE(has_masking) << label << " should be masked";
309 };
310
311 auto check_unmasked = [](const auto& poly, const std::string& label) {
312 for (size_t j = 0; j < NUM_MASKED_ROWS; j++) {
313 EXPECT_TRUE(poly[NUM_ZERO_ROWS + j].is_zero()) << label << " should not be masked";
314 }
315 };
316
317 auto& polys = prover_instance->polynomials;
318 check_masked(polys.w_l, "w_l");
319 check_masked(polys.w_r, "w_r");
320 check_masked(polys.w_o, "w_o");
321 check_masked(polys.w_4, "w_4");
322 check_masked(polys.z_perm, "z_perm");
323 check_masked(polys.lookup_read_counts, "lookup_read_counts");
324 check_masked(polys.lookup_read_tags, "lookup_read_tags");
325 check_masked(polys.lookup_inverses, "lookup_inverses");
326 check_unmasked(polys.kernel_calldata, "kernel_calldata");
327 check_masked(polys.kernel_calldata_read_counts, "kernel_calldata_read_counts");
328 check_masked(polys.kernel_calldata_inverses, "kernel_calldata_inverses");
329 check_masked(polys.first_app_calldata, "first_app_calldata");
330 check_masked(polys.first_app_calldata_read_counts, "first_app_calldata_read_counts");
331 check_masked(polys.first_app_calldata_inverses, "first_app_calldata_inverses");
332 check_masked(polys.second_app_calldata, "second_app_calldata");
333 check_masked(polys.second_app_calldata_read_counts, "second_app_calldata_read_counts");
334 check_masked(polys.second_app_calldata_inverses, "second_app_calldata_inverses");
335 check_masked(polys.third_app_calldata, "third_app_calldata");
336 check_masked(polys.third_app_calldata_read_counts, "third_app_calldata_read_counts");
337 check_masked(polys.third_app_calldata_inverses, "third_app_calldata_inverses");
338 check_masked(polys.return_data, "return_data");
339 check_masked(polys.return_data_read_counts, "return_data_read_counts");
340 check_masked(polys.return_data_inverses, "return_data_inverses");
341 }
342}
343
349TYPED_TEST(MegaHonkTests, RepeatedCommitmentsIndicesCorrect)
350{
351 using Flavor = TypeParam;
352 using Builder = typename Flavor::CircuitBuilder;
354 using CommitmentKey = typename Flavor::CommitmentKey;
355 using Commitment = typename Flavor::Commitment;
356
357 auto builder = Builder{};
359 auto prover_instance = std::make_shared<ProverInstance_<Flavor>>(builder);
360 CommitmentKey ck(prover_instance->dyadic_size());
361
362 auto unshifted = prover_instance->polynomials.get_unshifted();
363 auto to_be_shifted = prover_instance->polynomials.get_to_be_shifted();
364
365 constexpr auto repeated = Flavor::REPEATED_COMMITMENTS;
366 ASSERT_EQ(to_be_shifted.size(), repeated.first.count);
367
368 // Build the commitment vector exactly as Shplemini does: [Q, unshifted..., to_be_shifted...]
369 std::vector<Commitment> commitments;
370 commitments.push_back(Commitment::one()); // dummy Q
371 for (auto& poly : unshifted) {
372 commitments.push_back(ck.commit(poly));
373 }
374 for (auto& poly : to_be_shifted) {
375 commitments.push_back(ck.commit(poly));
376 }
377
378 // Same offset logic as remove_repeated_commitments
379 constexpr size_t offset = Flavor::HasZK ? 2 : 1;
380 for (size_t i = 0; i < repeated.first.count; i++) {
381 EXPECT_EQ(commitments[repeated.first.original_start + offset + i],
382 commitments[repeated.first.duplicate_start + offset + i])
383 << "REPEATED_COMMITMENTS commitment mismatch at index " << i;
384 }
385}
Curve::AffineElement Point
typename Flavor::VerificationKey VerificationKey
static void SetUpTestSuite()
bool construct_and_verify_honk_proof(auto &builder)
Construct and a verify a Honk proof.
CommitmentKey object over a pairing group 𝔾₁.
Manages the data that is propagated on the public inputs of an application/function circuit.
static constexpr size_t PUBLIC_INPUTS_SIZE
static void add_default(Builder &builder)
Add default IO values to a circuit builder (for native tests)
static constexpr bool HasZK
ECCVMCircuitBuilder CircuitBuilder
typename G1::affine_element Commitment
bb::CommitmentKey< Curve > CommitmentKey
FixedVKAndHash_< PrecomputedEntities< Commitment >, BF, ECCVMHardcodedVKAndHash > VerificationKey
The verification key stores commitments to the precomputed polynomials used by the verifier.
static constexpr RepeatedCommitmentsData REPEATED_COMMITMENTS
static void construct_simple_circuit(MegaBuilder &builder)
Generate a simple test circuit with some ECC op gates and conventional arithmetic gates.
static void add_arithmetic_gates(Builder &builder, const size_t num_gates=4)
Add a specified number of arithmetic gates to the provided circuit.
Contains all the information required by a Honk prover to create a proof, constructed from a finalize...
static constexpr size_t TRACE_OFFSET
static AllSubrelationFailures check_all(const auto &polynomials, const auto &params)
Check that the provided polynomials satisfy all relations for a given Flavor.
Output verify_proof(const Proof &proof)
Perform ultra verification.
The VerifierInstance encapsulates all the necessary information for a Honk Verifier to verify a proof...
typename Group::affine_element AffineElement
Definition bn254.hpp:22
bb::fr ScalarField
Definition bn254.hpp:18
Manages the data that is propagated on the public inputs of an application/function circuit.
AluTraceBuilder builder
Definition alu.test.cpp:124
ssize_t offset
Definition engine.cpp:62
testing::Types< UltraFlavor, UltraKeccakFlavor, MegaFlavor > FlavorTypes
auto & engine
RNG & get_debug_randomness(bool reset, std::uint_fast64_t seed)
Definition engine.cpp:245
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
std::vector< fr > HonkProof
Definition proof.hpp:15
TYPED_TEST_SUITE(CommitmentKeyTest, Curves)
TYPED_TEST(CommitmentKeyTest, CommitToZeroPoly)
CommitmentKey< Curve > ck
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
Full Honk proof layout (used by UltraVerifier).