Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
eccvm.test.cpp
Go to the documentation of this file.
1#include <cstddef>
2#include <cstdint>
3#include <gtest/gtest.h>
4#include <vector>
5
19
20using namespace bb;
27
28class ECCVMTests : public ::testing::Test {
29 protected:
31};
32namespace {
34} // namespace
35
43{
44 using Curve = curve::BN254;
45 using G1 = Curve::Element;
46 using Fr = Curve::ScalarField;
47
49 G1 a = G1::random_element(engine);
50 G1 b = G1::random_element(engine);
51 G1 c = G1::random_element(engine);
54
55 op_queue->add_accumulate(a);
56 op_queue->mul_accumulate(a, x);
57 op_queue->mul_accumulate(b, x);
58 op_queue->mul_accumulate(b, y);
59 op_queue->add_accumulate(a);
60 op_queue->mul_accumulate(b, x);
61 op_queue->eq_and_reset();
62 op_queue->add_accumulate(c);
63 op_queue->mul_accumulate(a, x);
64 op_queue->mul_accumulate(b, x);
65 op_queue->eq_and_reset();
66 op_queue->mul_accumulate(a, x);
67 op_queue->mul_accumulate(b, x);
68 op_queue->mul_accumulate(c, x);
69 op_queue->merge();
70 add_hiding_op_for_test(op_queue);
71 ECCVMCircuitBuilder builder{ op_queue };
72 return builder;
73}
74
75// returns a CircuitBuilder consisting of mul_add ops of the following form: either 0*g, for a group element, or
76// x * e, where x is a scalar and e is the identity element of the group.
77ECCVMCircuitBuilder generate_zero_circuit([[maybe_unused]] numeric::RNG* engine = nullptr, bool zero_scalars = 1)
78{
79 using Curve = curve::BN254;
80 using G1 = Curve::Element;
81 using Fr = Curve::ScalarField;
82
84
85 if (!zero_scalars) {
86 for (auto i = 0; i < 8; i++) {
88 op_queue->mul_accumulate(Curve::Group::affine_point_at_infinity, x);
89 }
90 } else {
91 for (auto i = 0; i < 8; i++) {
92 G1 g = G1::random_element(engine);
93 op_queue->mul_accumulate(g, 0);
94 }
95 }
96 op_queue->merge();
97 add_hiding_op_for_test(op_queue);
98
99 ECCVMCircuitBuilder builder{ op_queue };
100 return builder;
101}
102
105 std::vector<FF>& gate_challenges)
106{
107 // Prepare the inputs for the sumcheck prover:
108 // Compute and add beta to relation parameters
109 const FF beta = FF::random_element();
110 const FF gamma = FF::random_element();
111 const FF beta_sqr = beta * beta;
112 relation_parameters.gamma = gamma;
113 relation_parameters.beta = beta;
114 relation_parameters.beta_sqr = beta_sqr;
115 relation_parameters.beta_cube = beta_sqr * beta;
116 relation_parameters.eccvm_set_permutation_delta =
117 gamma * (gamma + beta_sqr) * (gamma + beta_sqr + beta_sqr) * (gamma + beta_sqr + beta_sqr + beta_sqr);
118 relation_parameters.eccvm_set_permutation_delta = relation_parameters.eccvm_set_permutation_delta.invert();
119
120 const size_t unmasked_witness_size = pk->circuit_size - NUM_DISABLED_ROWS_IN_SUMCHECK;
121 // Compute z_perm and inverse polynomial for our logarithmic-derivative lookup method
122 compute_logderivative_inverse<FF, ECCVMFlavor::LookupRelation>(
123 pk->polynomials, relation_parameters, unmasked_witness_size);
124 compute_grand_products<ECCVMFlavor>(pk->polynomials, relation_parameters, unmasked_witness_size);
125
126 // Generate gate challenges
127 for (size_t idx = 0; idx < CONST_ECCVM_LOG_N; idx++) {
128 gate_challenges[idx] = FF::random_element();
129 }
130}
131TEST_F(ECCVMTests, ZeroesCoefficients)
132{
134
135 std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
136 ECCVMProver prover(builder, prover_transcript);
137 auto [proof, opening_claim] = prover.construct_proof();
138
139 // Compute IPA proof
140 auto ipa_transcript = std::make_shared<Transcript>();
141 PCS::compute_opening_proof(prover.key->commitment_key, opening_claim, ipa_transcript);
142
143 std::shared_ptr<Transcript> verifier_transcript = std::make_shared<Transcript>();
144 ECCVMVerifier verifier(verifier_transcript, proof);
145 auto eccvm_result = verifier.reduce_to_ipa_opening();
146
147 // Verify IPA
148 auto ipa_verifier_transcript = std::make_shared<Transcript>(ipa_transcript->export_proof());
150 bool ipa_verified = IPA<curve::Grumpkin>::reduce_verify(ipa_vk, eccvm_result.ipa_claim, ipa_verifier_transcript);
151
152 ASSERT_TRUE(ipa_verified && eccvm_result.reduction_succeeded);
153}
154// Calling get_eccvm_ops without a hiding op should throw
155TEST_F(ECCVMTests, MissingHidingOpThrows)
156{
158 // get_eccvm_ops() requires a hiding op to have been set; throws "Hiding op must be set before calling
159 // get_eccvm_ops()"
160 EXPECT_THROW(op_queue->get_eccvm_ops(), std::runtime_error);
161}
162
163// Note that `NullOpQueue` is somewhat misleading, as we add a hiding operation.
164TEST_F(ECCVMTests, NullOpQUeue)
165{
167 add_hiding_op_for_test(op_queue);
168 ECCVMCircuitBuilder builder{ op_queue };
169 std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
170 ECCVMProver prover(builder, prover_transcript);
171 auto [proof, opening_claim] = prover.construct_proof();
172
173 // Compute IPA proof
174 auto ipa_transcript = std::make_shared<Transcript>();
175 PCS::compute_opening_proof(prover.key->commitment_key, opening_claim, ipa_transcript);
176
177 std::shared_ptr<Transcript> verifier_transcript = std::make_shared<Transcript>();
178 ECCVMVerifier verifier(verifier_transcript, proof);
179 auto eccvm_result = verifier.reduce_to_ipa_opening();
180
181 // Verify IPA
182 auto ipa_verifier_transcript = std::make_shared<Transcript>(ipa_transcript->export_proof());
184 bool ipa_verified = IPA<curve::Grumpkin>::reduce_verify(ipa_vk, eccvm_result.ipa_claim, ipa_verifier_transcript);
185
186 ASSERT_TRUE(ipa_verified && eccvm_result.reduction_succeeded);
187}
188
189TEST_F(ECCVMTests, PointAtInfinity)
190{
192
193 std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
194 ECCVMProver prover(builder, prover_transcript);
195 auto [proof, opening_claim] = prover.construct_proof();
196
197 auto ipa_transcript = std::make_shared<Transcript>();
198 PCS::compute_opening_proof(prover.key->commitment_key, opening_claim, ipa_transcript);
199
200 std::shared_ptr<Transcript> verifier_transcript = std::make_shared<Transcript>();
201 ECCVMVerifier verifier(verifier_transcript, proof);
202 auto eccvm_result = verifier.reduce_to_ipa_opening();
203
204 auto ipa_verifier_transcript = std::make_shared<Transcript>(ipa_transcript->export_proof());
206 bool ipa_verified = IPA<curve::Grumpkin>::reduce_verify(ipa_vk, eccvm_result.ipa_claim, ipa_verifier_transcript);
207
208 ASSERT_TRUE(ipa_verified && eccvm_result.reduction_succeeded);
209}
210TEST_F(ECCVMTests, ScalarEdgeCase)
211{
212 using Curve = curve::BN254;
213 using G1 = Curve::Element;
214 using Fr = Curve::ScalarField;
215
217 G1 a = G1::one();
218
219 op_queue->mul_accumulate(a, Fr(uint256_t(1) << 128));
220 op_queue->eq_and_reset();
221 op_queue->merge();
222 add_hiding_op_for_test(op_queue);
223 ECCVMCircuitBuilder builder{ op_queue };
224
225 std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
226 ECCVMProver prover(builder, prover_transcript);
227 auto [proof, opening_claim] = prover.construct_proof();
228
229 auto ipa_transcript = std::make_shared<Transcript>();
230 PCS::compute_opening_proof(prover.key->commitment_key, opening_claim, ipa_transcript);
231
232 std::shared_ptr<Transcript> verifier_transcript = std::make_shared<Transcript>();
233 ECCVMVerifier verifier(verifier_transcript, proof);
234 auto eccvm_result = verifier.reduce_to_ipa_opening();
235
236 auto ipa_verifier_transcript = std::make_shared<Transcript>(ipa_transcript->export_proof());
238 bool ipa_verified = IPA<curve::Grumpkin>::reduce_verify(ipa_vk, eccvm_result.ipa_claim, ipa_verifier_transcript);
239
240 ASSERT_TRUE(ipa_verified && eccvm_result.reduction_succeeded);
241}
249TEST_F(ECCVMTests, ProofLengthCheck)
250{
252
253 std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
254 ECCVMProver prover(builder, prover_transcript);
255 auto [proof, opening_claim] = prover.construct_proof();
256 EXPECT_EQ(proof.size(), ECCVMFlavor::PROOF_LENGTH_WITHOUT_PUB_INPUTS);
257}
258
259TEST_F(ECCVMTests, BaseCaseFixedSize)
260{
262
263 std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
264 ECCVMProver prover(builder, prover_transcript);
265 auto [proof, opening_claim] = prover.construct_proof();
266
267 auto ipa_transcript = std::make_shared<Transcript>();
268 PCS::compute_opening_proof(prover.key->commitment_key, opening_claim, ipa_transcript);
269
270 std::shared_ptr<Transcript> verifier_transcript = std::make_shared<Transcript>();
271 ECCVMVerifier verifier(verifier_transcript, proof);
272 auto eccvm_result = verifier.reduce_to_ipa_opening();
273
274 auto ipa_verifier_transcript = std::make_shared<Transcript>(ipa_transcript->export_proof());
276 bool ipa_verified = IPA<curve::Grumpkin>::reduce_verify(ipa_vk, eccvm_result.ipa_claim, ipa_verifier_transcript);
277
278 ASSERT_TRUE(ipa_verified && eccvm_result.reduction_succeeded);
279}
280
281TEST_F(ECCVMTests, EqFailsFixedSize)
282{
284 // Tamper with the eq op such that the expected value is incorect
285 builder.op_queue->add_erroneous_equality_op_for_testing();
286 builder.op_queue->merge();
287
288 std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
289 ECCVMProver prover(builder, prover_transcript);
290
291 auto [proof, opening_claim] = prover.construct_proof();
292
293 auto ipa_transcript = std::make_shared<Transcript>();
294 PCS::compute_opening_proof(prover.key->commitment_key, opening_claim, ipa_transcript);
295
296 std::shared_ptr<Transcript> verifier_transcript = std::make_shared<Transcript>();
297 ECCVMVerifier verifier(verifier_transcript, proof);
298 auto eccvm_result = verifier.reduce_to_ipa_opening();
299
300 auto ipa_verifier_transcript = std::make_shared<Transcript>(ipa_transcript->export_proof());
302 bool ipa_verified = IPA<curve::Grumpkin>::reduce_verify(ipa_vk, eccvm_result.ipa_claim, ipa_verifier_transcript);
303
304 ASSERT_FALSE(ipa_verified && eccvm_result.reduction_succeeded);
305}
306
307TEST_F(ECCVMTests, CommittedSumcheck)
308{
309 using Flavor = ECCVMFlavor;
310 using ProvingKey = ECCVMFlavor::ProvingKey;
311 using FF = ECCVMFlavor::FF;
313 using ZKData = ZKSumcheckData<Flavor>;
314
315 bb::RelationParameters<FF> relation_parameters;
316 std::vector<FF> gate_challenges(CONST_ECCVM_LOG_N);
317
319 std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
320 ECCVMProver prover(builder, prover_transcript);
322
323 // Prepare the inputs for the sumcheck prover:
324 // Compute and add beta to relation parameters
325 const FF alpha = FF::random_element();
326 complete_proving_key_for_test(relation_parameters, pk, gate_challenges);
327
328 // Clear the transcript
329 prover_transcript = std::make_shared<Transcript>();
330
331 // Run Sumcheck on the ECCVM Prover polynomials
333 SumcheckProver sumcheck_prover(pk->circuit_size,
334 pk->polynomials,
335 prover_transcript,
336 alpha,
337 gate_challenges,
338 relation_parameters,
339 CONST_ECCVM_LOG_N);
340
341 ZKData zk_sumcheck_data = ZKData(CONST_ECCVM_LOG_N, prover_transcript);
342
343 auto prover_output = sumcheck_prover.prove(zk_sumcheck_data);
344
345 std::shared_ptr<Transcript> verifier_transcript = std::make_shared<Transcript>(prover_transcript->export_proof());
346
347 // Execute Sumcheck Verifier
348 SumcheckVerifier<Flavor> sumcheck_verifier(verifier_transcript, alpha, CONST_ECCVM_LOG_N);
349 std::vector<FF> padding_indicator_array(CONST_ECCVM_LOG_N, FF(1));
350 SumcheckOutput<ECCVMFlavor> verifier_output =
351 sumcheck_verifier.verify(relation_parameters, gate_challenges, padding_indicator_array);
352
353 // Evaluate prover's round univariates at corresponding challenges and compare them with the claimed evaluations
354 // computed by the verifier
355 for (size_t idx = 0; idx < CONST_ECCVM_LOG_N; idx++) {
356 FF true_eval_at_the_challenge = prover_output.round_univariates[idx].evaluate(prover_output.challenge[idx]);
357 FF verifier_eval_at_the_challenge = verifier_output.round_univariate_evaluations[idx][2];
358 EXPECT_TRUE(true_eval_at_the_challenge == verifier_eval_at_the_challenge);
359 }
360
361 // Check that the first sumcheck univariate is consistent with the claimed ZK Sumchek Sum
362 FF prover_target_sum = zk_sumcheck_data.libra_challenge * zk_sumcheck_data.libra_total_sum;
363
364 EXPECT_TRUE(prover_target_sum == verifier_output.round_univariate_evaluations[0][0] +
365 verifier_output.round_univariate_evaluations[0][1]);
366
367 EXPECT_TRUE(verifier_output.verified);
368}
369
377{
378 // Generate a circuit and its verification key (computed at runtime from the proving key)
380 std::shared_ptr<Transcript> prover_transcript = std::make_shared<Transcript>();
381 ECCVMProver prover(builder, prover_transcript);
382 auto [proof, opening_claim] = prover.construct_proof();
383
384 std::shared_ptr<Transcript> verifier_transcript = std::make_shared<Transcript>();
385 ECCVMVerifier verifier(verifier_transcript, proof);
386
387 // Generate the default fixed VK
389 // Generate a VK from PK
390 ECCVMFlavor::VerificationKey vk_computed_by_prover(prover.key);
391
392 const auto& labels = bb::ECCVMFlavor::VerificationKey::get_labels();
393 size_t index = 0;
394 for (auto [vk_commitment, fixed_commitment] : zip_view(vk_computed_by_prover.get_all(), fixed_vk.get_all())) {
395 EXPECT_EQ(vk_commitment, fixed_commitment)
396 << "Mismatch between vk_commitment and fixed_commitment at label: " << labels[index];
397 ++index;
398 }
399
400 // Check that the fixed VK is equal to the generated VK
401 EXPECT_EQ(fixed_vk, vk_computed_by_prover);
402}
void SetUp() override
Common transcript class for both parties. Stores the data for the current round, as well as the manif...
The proving key is responsible for storing the polynomials used by the prover.
The verification key is responsible for storing the commitments to the precomputed (non-witnessk) pol...
static constexpr size_t ECCVM_FIXED_SIZE
typename Curve::ScalarField FF
static constexpr size_t PROOF_LENGTH_WITHOUT_PUB_INPUTS
BaseTranscript< Codec, HashFunction > Transcript
std::pair< Proof, OpeningClaim > construct_proof()
std::shared_ptr< ProvingKey > key
Unified ECCVM verifier class for both native and recursive verification.
ReductionResult reduce_to_ipa_opening()
Reduce the ECCVM proof to an IPA opening claim.
IPA (inner product argument) commitment scheme class.
Definition ipa.hpp:93
The implementation of the sumcheck Prover for statements of the form for multilinear polynomials .
Definition sumcheck.hpp:289
SumcheckOutput< Flavor > prove()
Non-ZK version: Compute round univariate, place it in transcript, compute challenge,...
Definition sumcheck.hpp:398
Implementation of the sumcheck Verifier for statements of the form for multilinear polynomials .
Definition sumcheck.hpp:785
SumcheckOutput< Flavor > verify(const bb::RelationParameters< FF > &relation_parameters, const std::vector< FF > &gate_challenges, const std::vector< FF > &padding_indicator_array)
The Sumcheck verification method. First it extracts round univariate, checks sum (the sumcheck univar...
Definition sumcheck.hpp:843
Representation of the Grumpkin Verifier Commitment Key inside a bn254 circuit.
typename Group::element Element
Definition grumpkin.hpp:62
AluTraceBuilder builder
Definition alu.test.cpp:124
FF a
FF b
void complete_proving_key_for_test(bb::RelationParameters< FF > &relation_parameters, std::shared_ptr< PK > &pk, std::vector< FF > &gate_challenges)
ECCVMFlavor::FF FF
ECCVMCircuitBuilder generate_zero_circuit(numeric::RNG *engine=nullptr, bool zero_scalars=1)
ECCVMCircuitBuilder generate_circuit(numeric::RNG *engine=nullptr)
Adds operations in BN254 to the op_queue and then constructs and ECCVM circuit from the op_queue.
numeric::RNG & engine
void add_hiding_op_for_test(const std::shared_ptr< ECCOpQueue > &op_queue)
Set a hiding op on the op_queue for testing.
RNG & get_debug_randomness(bool reset, std::uint_fast64_t seed)
Definition engine.cpp:190
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
TEST_F(IPATest, ChallengesAreZero)
Definition ipa.test.cpp:185
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
Curve::ScalarField Fr
Curve::AffineElement G1
Container for parameters used by the grand product (permutation, lookup) Honk relations.
Contains the evaluations of multilinear polynomials at the challenge point . These are computed by S...
std::vector< std::array< FF, 3 > > round_univariate_evaluations
This structure is created to contain various polynomials and constants required by ZK Sumcheck.
static field random_element(numeric::RNG *engine=nullptr) noexcept