Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
kzg.test.cpp
Go to the documentation of this file.
1
2#include "kzg.hpp"
3#include "../commitment_key.test.hpp"
7
8namespace bb {
9using Curve = curve::BN254;
10
11class KZGTest : public CommitmentTest<Curve> {
12 public:
13 using Fr = typename Curve::ScalarField;
16
21
22 static constexpr size_t n = 16;
23 static constexpr size_t log_n = 4;
24
27 static CK ck;
28 static VK vk;
29
30 static constexpr Commitment g1_identity = Commitment::one();
31
32 static void SetUpTestSuite()
33 {
34 ck = create_commitment_key<CK>(n);
35 vk = create_verifier_commitment_key<VK>();
36 }
37
38 static void prove_and_verify(const OpeningPair<Curve>& opening_pair, bb::Polynomial<Fr>& witness)
39 {
40 const Commitment commitment = ck.commit(witness);
41
42 auto opening_claim = OpeningClaim<Curve>{ opening_pair, commitment };
43
44 auto prover_transcript = NativeTranscript::prover_init_empty();
45
46 PCS::compute_opening_proof(ck, { witness, opening_pair }, prover_transcript);
47
48 auto verifier_transcript = NativeTranscript::verifier_init_empty(prover_transcript);
49 const auto pairing_points = PCS::reduce_verify(opening_claim, verifier_transcript);
50
51 EXPECT_EQ(vk.pairing_check(pairing_points[0], pairing_points[1]), true);
52 }
53};
54
56{
57
58 auto witness = bb::Polynomial<Fr>::random(n);
59 const Fr challenge = Fr::random_element();
60 const Fr evaluation = witness.evaluate(challenge);
61
62 prove_and_verify({ challenge, evaluation }, witness);
63}
64
65TEST_F(KZGTest, ZeroEvaluation)
66{
67
68 auto witness = bb::Polynomial<Fr>::random(n);
69 const Fr challenge = Fr::random_element();
70 const Fr evaluation = witness.evaluate(challenge);
71
72 // Modify witness to achieve zero evaluation
73 witness.at(0) -= evaluation;
74
75 prove_and_verify({ challenge, Fr::zero() }, witness);
76}
77
78TEST_F(KZGTest, WrongEvaluationFails)
79{
80 auto witness = bb::Polynomial<Fr>::random(n);
81 const Fr challenge = Fr::random_element();
82 const Fr evaluation = witness.evaluate(challenge);
83 const Fr wrong_evaluation = evaluation + Fr::random_element();
84 // Prove with the wrong evaluation
85 Commitment commitment = ck.commit(witness);
86 auto prover_transcript = NativeTranscript::prover_init_empty();
87 PCS::compute_opening_proof(ck, { witness, { challenge, wrong_evaluation } }, prover_transcript);
88
89 auto opening_claim = OpeningClaim<Curve>{ { challenge, wrong_evaluation }, commitment };
90 // Run the verifier
91 auto verifier_transcript = NativeTranscript::verifier_init_empty(prover_transcript);
92 auto pairing_point = PCS::reduce_verify(opening_claim, verifier_transcript);
93 // Make sure that the pairing check fails
94 EXPECT_EQ(vk.pairing_check(pairing_point[0], pairing_point[1]), false);
95}
96
97TEST_F(KZGTest, ZeroPolynomial)
98{
99 static constexpr size_t POLY_SIZE = 10;
100 bb::Polynomial<Fr> zero(POLY_SIZE);
101 for (size_t idx = 0; idx < POLY_SIZE; ++idx) {
102 zero.at(idx) = 0;
103 }
104
105 // Sanity check
106 ASSERT_TRUE(zero.is_zero());
107
108 const Fr challenge = Fr::random_element();
109 const Fr evaluation = zero.evaluate(challenge);
110
111 prove_and_verify({ challenge, evaluation }, zero);
112}
113
114TEST_F(KZGTest, EvalAtZero)
115{
116 // Check that the evaluation at zero matched the constant term
117 auto witness = bb::Polynomial<Fr>::random(n);
118 auto constant_term = witness.at(0);
119 const Fr challenge = Fr::zero();
120 prove_and_verify({ challenge, constant_term }, witness);
121}
122
123TEST_F(KZGTest, ConstantPolynomial)
124{
125 auto constant = bb::Polynomial<Fr>::random(1);
126 const Fr challenge = Fr::random_element();
127 const Fr evaluation = constant.evaluate(challenge);
128
129 prove_and_verify({ challenge, evaluation }, constant);
130}
131
132TEST_F(KZGTest, EmptyPolynomial)
133{
134 bb::Polynomial<Fr> empty_poly;
135 const Fr challenge = Fr::random_element();
136 const Fr evaluation = empty_poly.evaluate(challenge);
137
138 prove_and_verify({ challenge, evaluation }, empty_poly);
139}
140
146TEST_F(KZGTest, SingleInLagrangeBasis)
147{
148 const size_t n = 4;
149
150 // create a random univariate (coefficients are in Lagrange basis)
151 auto witness = bb::Univariate<Fr, n>::get_random();
152 // define the interpolation domain
153 std::array<Fr, 4> eval_points = { Fr(0), Fr(1), Fr(2), Fr(3) };
154 // compute the monomial coefficients
155 bb::Polynomial<Fr> witness_polynomial(std::span<Fr>(eval_points), std::span<Fr>(witness), n);
156 // commit to the polynomial in the monomial form
157 g1::element commitment = ck.commit(witness_polynomial);
158
159 const Fr challenge = Fr::random_element();
160 // evaluate the original univariate
161 const Fr evaluation = witness.evaluate(challenge);
162 auto opening_pair = OpeningPair<Curve>{ challenge, evaluation };
163 auto opening_claim = OpeningClaim<Curve>{ opening_pair, commitment };
164
165 auto prover_transcript = NativeTranscript::prover_init_empty();
166
167 PCS::compute_opening_proof(ck, { witness_polynomial, opening_pair }, prover_transcript);
168
169 auto verifier_transcript = NativeTranscript::verifier_init_empty(prover_transcript);
170 auto pairing_points = PCS::reduce_verify(opening_claim, verifier_transcript);
171
172 EXPECT_EQ(vk.pairing_check(pairing_points[0], pairing_points[1]), true);
173}
174TEST_F(KZGTest, ShpleminiKzgWithShift)
175{
176 // Generate multilinear polynomials, their commitments (genuine and mocked) and evaluations (genuine) at a random
177 // point.
178 std::vector<Fr> mle_opening_point = random_evaluation_point(log_n); // sometimes denoted 'u'
179
180 MockClaimGenerator mock_claims(n,
181 /*num_polynomials*/ 4,
182 /*num_to_be_shifted*/ 2,
183 mle_opening_point,
184 ck);
185
186 auto prover_transcript = NativeTranscript::prover_init_empty();
187
188 // Run the full prover PCS protocol:
189
190 // Compute:
191 // - (d+1) opening pairs: {r, \hat{a}_0}, {-r^{2^i}, a_i}, i = 0, ..., d-1
192 // - (d+1) Fold polynomials Fold_{r}^(0), Fold_{-r}^(0), and Fold^(i), i = 0, ..., d-1
193 auto prover_opening_claims =
194 GeminiProver::prove(n, mock_claims.polynomial_batcher, mle_opening_point, ck, prover_transcript);
195
196 // Shplonk prover output:
197 // - opening pair: (z_challenge, 0)
198 // - witness: polynomial Q - Q_z
199 const auto opening_claim = ShplonkProver::prove(ck, prover_opening_claims, prover_transcript);
200
201 // KZG prover:
202 // - Adds commitment [W] to transcript
203 PCS::compute_opening_proof(ck, opening_claim, prover_transcript);
204
205 // Run the full verifier PCS protocol with genuine opening claims (genuine commitment, genuine evaluation)
206
207 auto verifier_transcript = NativeTranscript::verifier_init_empty(prover_transcript);
208
209 // Gemini verifier output:
210 // - claim: d+1 commitments to Fold_{r}^(0), Fold_{-r}^(0), Fold^(l), d+1 evaluations a_0_pos, a_l, l = 0:d-1
211 std::array<Fr, log_n> padding_indicator_array;
212 std::ranges::fill(padding_indicator_array, Fr{ 1 });
213
214 auto batch_opening_claim = ShpleminiVerifier::compute_batch_opening_claim(padding_indicator_array,
215 mock_claims.claim_batcher,
216 mle_opening_point,
217 vk.get_g1_identity(),
218 verifier_transcript)
219 .batch_opening_claim;
220
221 const auto pairing_points =
222 PCS::reduce_verify_batch_opening_claim(std::move(batch_opening_claim), verifier_transcript);
223 // Final pairing check: e([Q] - [Q_z] + z[W], [1]_2) = e([W], [x]_2)
224
225 EXPECT_EQ(vk.pairing_check(pairing_points[0], pairing_points[1]), true);
226}
227
228TEST_F(KZGTest, ShpleminiKzgWithShiftAndInterleaving)
229{
230 std::vector<Fr> mle_opening_point = random_evaluation_point(log_n); // sometimes denoted 'u'
231 // Generate multilinear polynomials, their commitments (genuine and mocked) and evaluations (genuine) at a random
232 // point.
233 MockClaimGenerator mock_claims(n,
234 /*num_polynomials*/ 4,
235 /*num_to_be_shifted*/ 2,
236 mle_opening_point,
237 ck,
238 /*num_interleaved*/ 3,
239 /*num_to_be_interleaved*/ 2);
240
241 auto prover_transcript = NativeTranscript::prover_init_empty();
242
243 // Run the full prover PCS protocol:
244
245 // Compute:
246 // - (d+1) opening pairs: {r, \hat{a}_0}, {-r^{2^i}, a_i}, i = 0, ..., d-1
247 // - (d+1) Fold polynomials Fold_{r}^(0), Fold_{-r}^(0), and Fold^(i), i = 0, ..., d-1
248 auto prover_opening_claims =
249 GeminiProver::prove(n, mock_claims.polynomial_batcher, mle_opening_point, ck, prover_transcript);
250
251 // Shplonk prover output:
252 // - opening pair: (z_challenge, 0)
253 // - witness: polynomial Q - Q_z
254 const auto opening_claim = ShplonkProver::prove(ck, prover_opening_claims, prover_transcript);
255
256 // KZG prover:
257 // - Adds commitment [W] to transcript
258 PCS::compute_opening_proof(ck, opening_claim, prover_transcript);
259
260 // Run the full verifier PCS protocol with genuine opening claims (genuine commitment, genuine evaluation)
261
262 auto verifier_transcript = NativeTranscript::verifier_init_empty(prover_transcript);
263
264 // Gemini verifier output:
265 // - claim: d+1 commitments to Fold_{r}^(0), Fold_{-r}^(0), Fold^(l), d+1 evaluations a_0_pos, a_l, l = 0:d-1
266 std::array<Fr, log_n> padding_indicator_array;
267 std::ranges::fill(padding_indicator_array, Fr{ 1 });
268
269 auto batch_opening_claim = ShpleminiVerifier::compute_batch_opening_claim(padding_indicator_array,
270 mock_claims.claim_batcher,
271 mle_opening_point,
272 vk.get_g1_identity(),
273 verifier_transcript,
274 /* repeated commitments= */ {},
275 /* libra commitments = */ {},
276 /* libra evaluations = */ {},
277 {},
278 {})
279 .batch_opening_claim;
280 const auto pairing_points =
281 PCS::reduce_verify_batch_opening_claim(std::move(batch_opening_claim), verifier_transcript);
282 // Final pairing check: e([Q] - [Q_z] + z[W], [1]_2) = e([W], [x]_2)
283
284 EXPECT_EQ(vk.pairing_check(pairing_points[0], pairing_points[1]), true);
285}
286TEST_F(KZGTest, ShpleminiKzgShiftsRemoval)
287{
288 std::vector<Fr> mle_opening_point = random_evaluation_point(log_n); // sometimes denoted 'u'
289 // Generate multilinear polynomials, their commitments (genuine and mocked) and evaluations (genuine) at a random
290 // point.
291 MockClaimGenerator mock_claims(n,
292 /*num_polynomials*/ 4,
293 /*num_to_be_shifted*/ 2,
294 mle_opening_point,
295 ck);
296
297 auto prover_transcript = NativeTranscript::prover_init_empty();
298
299 // Run the full prover PCS protocol:
300
301 // Compute:
302 // - (d+1) opening pairs: {r, \hat{a}_0}, {-r^{2^i}, a_i}, i = 0, ..., d-1
303 // - (d+1) Fold polynomials Fold_{r}^(0), Fold_{-r}^(0), and Fold^(i), i = 0, ..., d-1
304 auto prover_opening_claims =
305 GeminiProver::prove(n, mock_claims.polynomial_batcher, mle_opening_point, ck, prover_transcript);
306
307 // Shplonk prover output:
308 // - opening pair: (z_challenge, 0)
309 // - witness: polynomial Q - Q_z
310 const auto opening_claim = ShplonkProver::prove(ck, prover_opening_claims, prover_transcript);
311
312 // KZG prover:
313 // - Adds commitment [W] to transcript
314 PCS::compute_opening_proof(ck, opening_claim, prover_transcript);
315
316 // Run the full verifier PCS protocol with genuine opening claims (genuine commitment, genuine evaluation)
317
318 auto verifier_transcript = NativeTranscript::verifier_init_empty(prover_transcript);
319 // the index of the first commitment to a polynomial to be shifted in the union of unshifted_commitments and
320 // shifted_commitments. in our case, it is poly2
321 const size_t to_be_shifted_commitments_start = 2;
322 // the index of the first commitment to a shifted polynomial in the union of unshifted_commitments and
323 // shifted_commitments. in our case, it is the second occurence of poly2
324 const size_t shifted_commitments_start = 4;
325 // number of shifted polynomials
326 const size_t num_shifted_commitments = 2;
327 // since commitments to poly2, poly3 and their shifts are the same group elements, we simply combine the scalar
328 // multipliers of commitment2 and commitment3 in one place and remove the entries of the commitments and scalars
329 // vectors corresponding to the "shifted" commitment
330 const RepeatedCommitmentsData repeated_commitments =
331 RepeatedCommitmentsData(to_be_shifted_commitments_start, shifted_commitments_start, num_shifted_commitments);
332
333 // Gemini verifier output:
334 // - claim: d+1 commitments to Fold_{r}^(0), Fold_{-r}^(0), Fold^(l), d+1 evaluations a_0_pos, a_l, l = 0:d-1
335 std::array<Fr, log_n> padding_indicator_array;
336 std::ranges::fill(padding_indicator_array, Fr{ 1 });
337
338 auto batch_opening_claim = ShpleminiVerifier::compute_batch_opening_claim(padding_indicator_array,
339 mock_claims.claim_batcher,
340 mle_opening_point,
341 vk.get_g1_identity(),
342 verifier_transcript,
343 repeated_commitments)
344 .batch_opening_claim;
345
346 const auto pairing_points =
347 PCS::reduce_verify_batch_opening_claim(std::move(batch_opening_claim), verifier_transcript);
348
349 // Final pairing check: e([Q] - [Q_z] + z[W], [1]_2) = e([W], [x]_2)
350 EXPECT_EQ(vk.pairing_check(pairing_points[0], pairing_points[1]), true);
351}
352
353} // namespace bb
static std::shared_ptr< BaseTranscript > prover_init_empty()
For testing: initializes transcript with some arbitrary data so that a challenge can be generated aft...
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...
CommitmentKey object over a pairing group 𝔾₁.
Commitment commit(PolynomialSpan< const Fr > polynomial) const
Uses the ProverSRS to create a commitment to p(X)
static PairingPointsType reduce_verify(const OpeningClaim< Curve > &claim, const std::shared_ptr< Transcript > &verifier_transcript)
Computes the input points for the pairing check needed to verify a KZG opening claim of a single poly...
Definition kzg.hpp:82
static void compute_opening_proof(const CK &ck, const ProverOpeningClaim< Curve > &opening_claim, const std::shared_ptr< Transcript > &prover_trancript)
Computes the KZG commitment to an opening proof polynomial at a single evaluation point.
Definition kzg.hpp:43
typename Curve::ScalarField Fr
Definition kzg.test.cpp:13
static constexpr size_t log_n
Definition kzg.test.cpp:23
typename Curve::AffineElement Commitment
Definition kzg.test.cpp:14
static CK ck
Definition kzg.test.cpp:27
static VK vk
Definition kzg.test.cpp:28
static void prove_and_verify(const OpeningPair< Curve > &opening_pair, bb::Polynomial< Fr > &witness)
Definition kzg.test.cpp:38
static constexpr size_t n
Definition kzg.test.cpp:22
static void SetUpTestSuite()
Definition kzg.test.cpp:32
static constexpr Commitment g1_identity
Definition kzg.test.cpp:30
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 .....
static Polynomial random(size_t size, size_t start_index=0)
Fr evaluate(const Fr &z, size_t target_size) const
Fr & at(size_t index)
Our mutable accessor, unlike operator[]. We abuse precedent a bit to differentiate at() and operator[...
bool is_zero() const
Check whether or not a polynomial is identically zero.
Shplonk Prover.
Definition shplonk.hpp:36
static Univariate get_random()
Representation of the Grumpkin Verifier Commitment Key inside a bn254 circuit.
typename Group::affine_element AffineElement
Definition grumpkin.hpp:63
element class. Implements ecc group arithmetic using Jacobian coordinates See https://hyperelliptic....
Definition element.hpp:33
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
TEST_F(IPATest, ChallengesAreZero)
Definition ipa.test.cpp:185
CommitmentKey< Curve > ck
VerifierCommitmentKey< Curve > vk
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
Curve::ScalarField Fr
Constructs random polynomials, computes commitments and corresponding evaluations.
static field random_element(numeric::RNG *engine=nullptr) noexcept
static constexpr field zero()