Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
ipa.test.cpp
Go to the documentation of this file.
1
7using namespace bb;
8
9namespace {
11
12class IPATest : public CommitmentTest<Curve> {
13 public:
14 using Fr = typename Curve::ScalarField;
15 using GroupElement = typename Curve::Element;
16 using CK = CommitmentKey<Curve>;
19 using Commitment = typename Curve::AffineElement;
20
21 using ShplonkProver = ShplonkProver_<Curve>;
22 using ShplonkVerifier = ShplonkVerifier_<Curve>;
23 using GeminiProver = GeminiProver_<Curve>;
24 using GeminiVerifier = GeminiVerifier_<Curve>;
25 using ShpleminiVerifier = ShpleminiVerifier_<Curve>;
26 using ClaimBatcher = ClaimBatcher_<Curve>;
27 using ClaimBatch = ClaimBatcher::Batch;
28
29 static CK ck;
30 static VK vk;
31
32 // For edge cases
33 static constexpr size_t log_n = 7;
34
36
37 static constexpr size_t n = 1UL << log_n;
38
39 static void SetUpTestSuite()
40 {
41 ck = create_commitment_key<CK>(n);
42 vk = create_verifier_commitment_key<VK>();
43 }
44};
45} // namespace
46
47#define IPA_TEST
48#include "ipa.hpp"
49
50TEST_F(IPATest, CommitOnManyZeroCoeffPolyWorks)
51{
52 constexpr size_t n = 4;
53 Polynomial p(n);
54 for (size_t i = 0; i < n - 1; i++) {
55 p.at(i) = Fr::zero();
56 }
57 p.at(3) = Fr::one();
58 GroupElement commitment = ck.commit(p);
59 auto srs_elements = ck.srs->get_monomial_points();
60 GroupElement expected = srs_elements[0] * p[0];
61 // The SRS stored in the commitment key is the result after applying the pippenger point table so the
62 // values at odd indices contain the point {srs[i-1].x * beta, srs[i-1].y}, where beta is the endomorphism
63 // G_vec_local should use only the original SRS thus we extract only the even indices.
64 for (size_t i = 1; i < n; i += 1) {
65 expected += srs_elements[i] * p[i];
66 }
67 EXPECT_EQ(expected.normalize(), commitment.normalize());
68}
69
70// This test checks that we can correctly open a zero polynomial. Since we often have point at infinity troubles, it
71// detects those.
72TEST_F(IPATest, OpenZeroPolynomial)
73{
74 Polynomial poly(n);
75 // Commit to a zero polynomial
76 Commitment commitment = ck.commit(poly);
77 EXPECT_TRUE(commitment.is_point_at_infinity());
78
79 auto [x, eval] = this->random_eval(poly);
80 EXPECT_EQ(eval, Fr::zero());
81 const OpeningPair<Curve> opening_pair = { x, eval };
82 const OpeningClaim<Curve> opening_claim{ opening_pair, commitment };
83
84 // initialize empty prover transcript
85 auto prover_transcript = std::make_shared<NativeTranscript>();
86 PCS::compute_opening_proof(ck, { poly, opening_pair }, prover_transcript);
87
88 // initialize verifier transcript from proof data
89 auto verifier_transcript = std::make_shared<NativeTranscript>();
90 verifier_transcript->load_proof(prover_transcript->export_proof());
91
92 bool result = PCS::reduce_verify(vk, opening_claim, verifier_transcript);
93 EXPECT_TRUE(result);
94}
95
96// This test makes sure that even if the whole vector \vec{b} generated from the x, at which we open the polynomial,
97// is zero, IPA behaves
98TEST_F(IPATest, OpenAtZero)
99{
100 // generate a random polynomial, degree needs to be a power of two
101 auto poly = Polynomial::random(n);
102 const Fr x = Fr::zero();
103 const Fr eval = poly.evaluate(x);
104 const Commitment commitment = ck.commit(poly);
105 const OpeningPair<Curve> opening_pair = { x, eval };
106 const OpeningClaim<Curve> opening_claim{ opening_pair, commitment };
107
108 // initialize empty prover transcript
109 auto prover_transcript = std::make_shared<NativeTranscript>();
110 PCS::compute_opening_proof(ck, { poly, opening_pair }, prover_transcript);
111
112 // initialize verifier transcript from proof data
113 auto verifier_transcript = std::make_shared<NativeTranscript>();
114 verifier_transcript->load_proof(prover_transcript->export_proof());
115
116 bool result = PCS::reduce_verify(vk, opening_claim, verifier_transcript);
117 EXPECT_TRUE(result);
118}
119
120namespace bb {
121#if !defined(__wasm__)
122// This test ensures that IPA throws or aborts when a challenge is zero, since it breaks the logic of the argument
123TEST_F(IPATest, ChallengesAreZero)
124{
125 // generate a random polynomial, degree needs to be a power of two
126 auto poly = Polynomial::random(n);
127 auto [x, eval] = this->random_eval(poly);
128 auto commitment = ck.commit(poly);
129 const OpeningPair<Curve> opening_pair = { x, eval };
130 const OpeningClaim<Curve> opening_claim{ opening_pair, commitment };
131
132 // initialize an empty mock transcript
133 auto transcript = std::make_shared<MockTranscript>();
134 const size_t num_challenges = numeric::get_msb(n) + 1;
135 std::vector<uint256_t> random_vector(num_challenges);
136
137 // Generate a random element vector with challenges
138 for (size_t i = 0; i < num_challenges; i++) {
139 random_vector[i] = Fr::random_element();
140 }
141
142 // Compute opening proofs several times, where each time a different challenge is equal to zero. Should cause
143 // exceptions
144 for (size_t i = 0; i < num_challenges; i++) {
145 auto new_random_vector = random_vector;
146 new_random_vector[i] = Fr::zero();
147 transcript->initialize(new_random_vector);
148 EXPECT_ANY_THROW(PCS::compute_opening_proof_internal(ck, { poly, opening_pair }, transcript));
149 }
150 // Fill out a vector of affine elements that the verifier receives from the prover with generators (we don't care
151 // about them right now)
152 std::vector<Curve::AffineElement> lrs(num_challenges * 2);
153 for (size_t i = 0; i < num_challenges * 2; i++) {
154 lrs[i] = Curve::AffineElement::one();
155 }
156 // Verify proofs several times, where each time a different challenge is equal to zero. Should cause
157 // exceptions
158 for (size_t i = 0; i < num_challenges; i++) {
159 auto new_random_vector = random_vector;
160 new_random_vector[i] = Fr::zero();
161 transcript->initialize(new_random_vector, lrs, { uint256_t(n) });
162 EXPECT_ANY_THROW(PCS::reduce_verify_internal_native(vk, opening_claim, transcript));
163 }
164}
165
166// This test checks that if the vector \vec{a_new} becomes zero after one round, it doesn't break IPA.
167TEST_F(IPATest, AIsZeroAfterOneRound)
168{
169 // generate a random polynomial of degree < n / 2
170 auto poly = Polynomial(n);
171 for (size_t i = 0; i < n / 2; i++) {
172 poly.at(i) = Fr::random_element();
173 poly.at(i + (n / 2)) = poly[i];
174 }
175 auto [x, eval] = this->random_eval(poly);
176 auto commitment = ck.commit(poly);
177 const OpeningPair<Curve> opening_pair = { x, eval };
178 const OpeningClaim<Curve> opening_claim{ opening_pair, commitment };
179
180 // initialize an empty mock transcript
181 auto transcript = std::make_shared<MockTranscript>();
182 // TODO(https://github.com/AztecProtocol/barretenberg/issues/1159): Decouple constant from IPA.
183 const size_t num_challenges = log_n + 1;
184 std::vector<uint256_t> random_vector(num_challenges);
185
186 // Generate a random element vector with challenges
187 for (size_t i = 0; i < num_challenges; i++) {
188 random_vector[i] = Fr::random_element();
189 }
190 // Substitute the first folding challenge with -1
191 random_vector[1] = -Fr::one();
192
193 // Put the challenges in the transcript
194 transcript->initialize(random_vector);
195
196 // Compute opening proof
197 PCS::compute_opening_proof_internal(ck, { poly, opening_pair }, transcript);
198
199 // Reset indices
200 transcript->reset_indices();
201
202 // Verify
203 EXPECT_TRUE(PCS::reduce_verify_internal_native(vk, opening_claim, transcript));
204}
205#endif
206} // namespace bb
207
208TEST_F(IPATest, Commit)
209{
210 auto poly = Polynomial::random(n);
211 const GroupElement commitment = ck.commit(poly);
212 auto srs_elements = ck.srs->get_monomial_points();
213 GroupElement expected = srs_elements[0] * poly[0];
214 // The SRS stored in the commitment key is the result after applying the pippenger point table so the
215 // values at odd indices contain the point {srs[i-1].x * beta, srs[i-1].y}, where beta is the endomorphism
216 // G_vec_local should use only the original SRS thus we extract only the even indices.
217 for (size_t i = 1; i < n; i += 1) {
218 expected += srs_elements[i] * poly[i];
219 }
220 EXPECT_EQ(expected.normalize(), commitment.normalize());
221}
222
223TEST_F(IPATest, Open)
224{
225 // generate a random polynomial, degree needs to be a power of two
226 auto poly = Polynomial::random(n);
227 auto [x, eval] = this->random_eval(poly);
228 auto commitment = ck.commit(poly);
229 const OpeningPair<Curve> opening_pair = { x, eval };
230 const OpeningClaim<Curve> opening_claim{ opening_pair, commitment };
231
232 // initialize empty prover transcript
233 auto prover_transcript = std::make_shared<NativeTranscript>();
234 PCS::compute_opening_proof(ck, { poly, opening_pair }, prover_transcript);
235
236 // initialize verifier transcript from proof data
237 auto verifier_transcript = std::make_shared<NativeTranscript>();
238 verifier_transcript->load_proof(prover_transcript->export_proof());
239
240 auto result = PCS::reduce_verify(vk, opening_claim, verifier_transcript);
241 EXPECT_TRUE(result);
242
243 EXPECT_EQ(prover_transcript->get_manifest(), verifier_transcript->get_manifest());
244}
245
246TEST_F(IPATest, GeminiShplonkIPAWithShift)
247{
248 // Generate multilinear polynomials, their commitments (genuine and mocked) and evaluations (genuine) at a random
249 // point.
250 auto mle_opening_point = this->random_evaluation_point(log_n); // sometimes denoted 'u'
251
252 MockClaimGenerator mock_claims(n,
253 /*num_polynomials*/ 2,
254 /*num_to_be_shifted*/ 0,
255 /*num_to_be_right_shifted_by_k*/ 0,
256 mle_opening_point,
257 ck);
258
259 auto prover_transcript = NativeTranscript::prover_init_empty();
260
261 // Run the full prover PCS protocol:
262 // Compute:
263 // - (d+1) opening pairs: {r, \hat{a}_0}, {-r^{2^i}, a_i}, i = 0, ..., d-1
264 // - (d+1) Fold polynomials Fold_{r}^(0), Fold_{-r}^(0), and Fold^(i), i = 0, ..., d-1
265 auto prover_opening_claims =
266 GeminiProver::prove(n, mock_claims.polynomial_batcher, mle_opening_point, ck, prover_transcript);
267
268 const auto opening_claim = ShplonkProver::prove(ck, prover_opening_claims, prover_transcript);
269 PCS::compute_opening_proof(ck, opening_claim, prover_transcript);
270
271 auto verifier_transcript = NativeTranscript::verifier_init_empty(prover_transcript);
272
273 auto gemini_verifier_claim =
274 GeminiVerifier::reduce_verification(mle_opening_point, mock_claims.claim_batcher, verifier_transcript);
275
276 const auto shplonk_verifier_claim =
277 ShplonkVerifier::reduce_verification(vk.get_g1_identity(), gemini_verifier_claim, verifier_transcript);
278 auto result = PCS::reduce_verify(vk, shplonk_verifier_claim, verifier_transcript);
279
280 EXPECT_EQ(result, true);
281}
282TEST_F(IPATest, ShpleminiIPAWithShift)
283{
284 // Generate multilinear polynomials, their commitments (genuine and mocked) and evaluations (genuine) at a random
285 // point.
286 auto mle_opening_point = this->random_evaluation_point(log_n); // sometimes denoted 'u'
287 MockClaimGenerator mock_claims(n,
288 /*num_polynomials*/ 2,
289 /*num_to_be_shifted*/ 0,
290 /*num_to_be_right_shifted_by_k*/ 0,
291 mle_opening_point,
292 ck);
293 auto prover_transcript = NativeTranscript::prover_init_empty();
294
295 // Run the full prover PCS protocol:
296
297 // Compute:
298 // - (d+1) opening pairs: {r, \hat{a}_0}, {-r^{2^i}, a_i}, i = 0, ..., d-1
299 // - (d+1) Fold polynomials Fold_{r}^(0), Fold_{-r}^(0), and Fold^(i), i = 0, ..., d-1
300 auto prover_opening_claims =
301 GeminiProver::prove(n, mock_claims.polynomial_batcher, mle_opening_point, ck, prover_transcript);
302 const auto opening_claim = ShplonkProver::prove(ck, prover_opening_claims, prover_transcript);
303 PCS::compute_opening_proof(ck, opening_claim, prover_transcript);
304
305 auto verifier_transcript = NativeTranscript::verifier_init_empty(prover_transcript);
306
307 std::array<Fr, log_n> padding_indicator_array;
308 std::ranges::fill(padding_indicator_array, Fr{ 1 });
309
310 const auto batch_opening_claim = ShpleminiVerifier::compute_batch_opening_claim(padding_indicator_array,
311 mock_claims.claim_batcher,
312 mle_opening_point,
314 verifier_transcript);
315
316 auto result = PCS::reduce_verify_batch_opening_claim(batch_opening_claim, vk, verifier_transcript);
317 // auto result = PCS::reduce_verify(vk, shplonk_verifier_claim, verifier_transcript);
318
319 EXPECT_EQ(result, true);
320}
325TEST_F(IPATest, ShpleminiIPAShiftsRemoval)
326{
327 // Generate multilinear polynomials, their commitments (genuine and mocked) and evaluations (genuine) at a random
328 // point.
329 auto mle_opening_point = this->random_evaluation_point(log_n); // sometimes denoted 'u'
330 MockClaimGenerator mock_claims(n,
331 /*num_polynomials*/ 4,
332 /*num_to_be_shifted*/ 2,
333 /*num_to_be_right_shifted_by_k*/ 0,
334 mle_opening_point,
335 ck);
336
337 auto prover_transcript = NativeTranscript::prover_init_empty();
338
339 // Run the full prover PCS protocol:
340
341 // Compute:
342 // - (d+1) opening pairs: {r, \hat{a}_0}, {-r^{2^i}, a_i}, i = 0, ..., d-1
343 // - (d+1) Fold polynomials Fold_{r}^(0), Fold_{-r}^(0), and Fold^(i), i = 0, ..., d-1
344 auto prover_opening_claims =
345 GeminiProver::prove(n, mock_claims.polynomial_batcher, mle_opening_point, ck, prover_transcript);
346
347 const auto opening_claim = ShplonkProver::prove(ck, prover_opening_claims, prover_transcript);
348 PCS::compute_opening_proof(ck, opening_claim, prover_transcript);
349
350 // the index of the first commitment to a polynomial to be shifted in the union of unshifted_commitments and
351 // shifted_commitments. in our case, it is poly2
352 const size_t to_be_shifted_commitments_start = 2;
353 // the index of the first commitment to a shifted polynomial in the union of unshifted_commitments and
354 // shifted_commitments. in our case, it is the second occurence of poly2
355 const size_t shifted_commitments_start = 4;
356 // number of shifted polynomials
357 const size_t num_shifted_commitments = 2;
358 const RepeatedCommitmentsData repeated_commitments =
359 RepeatedCommitmentsData(to_be_shifted_commitments_start, shifted_commitments_start, num_shifted_commitments);
360 // since commitments to poly2, poly3 and their shifts are the same group elements, we simply combine the scalar
361 // multipliers of commitment2 and commitment3 in one place and remove the entries of the commitments and scalars
362 // vectors corresponding to the "shifted" commitment
363 auto verifier_transcript = NativeTranscript::verifier_init_empty(prover_transcript);
364
365 std::array<Fr, log_n> padding_indicator_array;
366 std::ranges::fill(padding_indicator_array, Fr{ 1 });
367
368 const auto batch_opening_claim = ShpleminiVerifier::compute_batch_opening_claim(padding_indicator_array,
369 mock_claims.claim_batcher,
370 mle_opening_point,
372 verifier_transcript,
373 repeated_commitments);
374
375 auto result = PCS::reduce_verify_batch_opening_claim(batch_opening_claim, vk, verifier_transcript);
376 EXPECT_EQ(result, true);
377}
378typename IPATest::CK IPATest::ck;
379typename IPATest::VK IPATest::vk;
static std::shared_ptr< BaseTranscript > verifier_init_empty(const std::shared_ptr< BaseTranscript > &transcript)
For testing: initializes transcript based on proof data then receives junk data produced by BaseTrans...
static std::shared_ptr< BaseTranscript > prover_init_empty()
For testing: initializes transcript with some arbitrary data so that a challenge can be generated aft...
CommitmentKey object over a pairing group 𝔾₁.
IPA (inner product argument) commitment scheme class.
Definition ipa.hpp:95
Unverified claim (C,r,v) for some witness polynomial p(X) such that.
Definition claim.hpp:53
Opening pair (r,v) for some witness polynomial p(X) such that p(r) = v.
Definition claim.hpp:19
Structured polynomial class that represents the coefficients 'a' of a_0 + a_1 x .....
Fr & at(size_t index)
Our mutable accessor, unlike operator[]. We abuse precedent a bit to differentiate at() and operator[...
An efficient verifier for the evaluation proofs of multilinear polynomials and their shifts.
Shplonk Prover.
Definition shplonk.hpp:36
Shplonk Verifier.
Definition shplonk.hpp:343
Representation of the Grumpkin Verifier Commitment Key inside a bn254 circuit.
typename Group::element Element
Definition grumpkin.hpp:55
typename Group::affine_element AffineElement
Definition grumpkin.hpp:56
TEST_F(IPATest, CommitOnManyZeroCoeffPolyWorks)
Definition ipa.test.cpp:50
constexpr T get_msb(const T in)
Definition get_msb.hpp:47
Entry point for Barretenberg command-line interface.
TEST_F(IPATest, ChallengesAreZero)
Definition ipa.test.cpp:123
CommitmentKey< Curve > ck
VerifierCommitmentKey< Curve > vk
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
Logic to support batching opening claims for unshifted and shifted polynomials in Shplemini.
Constructs random polynomials, computes commitments and corresponding evaluations.
static constexpr field one()
static field random_element(numeric::RNG *engine=nullptr) noexcept
static constexpr field zero()