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 "../pcs_test_utils.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::test_prover_init_empty();
45
46 PCS::compute_opening_proof(ck, { witness, opening_pair }, prover_transcript);
47
48 auto verifier_transcript = NativeTranscript::test_verifier_init_empty(prover_transcript);
49 const auto pairing_points = PCS::reduce_verify(opening_claim, verifier_transcript);
50
51 EXPECT_EQ(pairing_points.check(), 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 // compute_opening_proof internally divides (p(X) - claimed_eval) by (X - challenge) via factor_roots,
81 // which asserts exact divisibility. This test deliberately passes a wrong evaluation to exercise the
82 // verifier's rejection path, so downgrade that assert to a warning for the duration of the test.
84
85 auto witness = bb::Polynomial<Fr>::random(n);
86 const Fr challenge = Fr::random_element();
87 const Fr evaluation = witness.evaluate(challenge);
88 const Fr wrong_evaluation = evaluation + Fr::random_element();
89 // Prove with the wrong evaluation
90 Commitment commitment = ck.commit(witness);
91 auto prover_transcript = NativeTranscript::test_prover_init_empty();
92 PCS::compute_opening_proof(ck, { witness, { challenge, wrong_evaluation } }, prover_transcript);
93
94 auto opening_claim = OpeningClaim<Curve>{ { challenge, wrong_evaluation }, commitment };
95 // Run the verifier
96 auto verifier_transcript = NativeTranscript::test_verifier_init_empty(prover_transcript);
97 auto pairing_point = PCS::reduce_verify(opening_claim, verifier_transcript);
98 // Make sure that the pairing check fails
99 EXPECT_EQ(pairing_point.check(), false);
100}
101
102TEST_F(KZGTest, ZeroPolynomial)
103{
104 static constexpr size_t POLY_SIZE = 10;
105 bb::Polynomial<Fr> zero(POLY_SIZE);
106 for (size_t idx = 0; idx < POLY_SIZE; ++idx) {
107 zero.at(idx) = 0;
108 }
109
110 // Sanity check
111 ASSERT_TRUE(zero.is_zero());
112
113 const Fr challenge = Fr::random_element();
114 const Fr evaluation = zero.evaluate(challenge);
115
116 prove_and_verify({ challenge, evaluation }, zero);
117}
118
119TEST_F(KZGTest, EvalAtZero)
120{
121 // Check that the evaluation at zero matched the constant term
122 auto witness = bb::Polynomial<Fr>::random(n);
123 auto constant_term = witness.at(0);
124 const Fr challenge = Fr::zero();
125 prove_and_verify({ challenge, constant_term }, witness);
126}
127
128TEST_F(KZGTest, ConstantPolynomial)
129{
130 auto constant = bb::Polynomial<Fr>::random(1);
131 const Fr challenge = Fr::random_element();
132 const Fr evaluation = constant.evaluate(challenge);
133
134 prove_and_verify({ challenge, evaluation }, constant);
135}
136
137TEST_F(KZGTest, EmptyPolynomial)
138{
139 bb::Polynomial<Fr> empty_poly;
140 const Fr challenge = Fr::random_element();
141 const Fr evaluation = empty_poly.evaluate(challenge);
142
143 prove_and_verify({ challenge, evaluation }, empty_poly);
144}
145
151TEST_F(KZGTest, SingleInLagrangeBasis)
152{
153 const size_t n = 4;
154
155 // create a random univariate (coefficients are in Lagrange basis)
156 auto witness = bb::Univariate<Fr, n>::get_random();
157 // define the interpolation domain
158 std::array<Fr, 4> eval_points = { Fr(0), Fr(1), Fr(2), Fr(3) };
159 // compute the monomial coefficients
160 bb::Polynomial<Fr> witness_polynomial(std::span<Fr>(eval_points), std::span<Fr>(witness), n);
161 // commit to the polynomial in the monomial form
162 g1::element commitment = ck.commit(witness_polynomial);
163
164 const Fr challenge = Fr::random_element();
165 // evaluate the original univariate
166 const Fr evaluation = witness.evaluate(challenge);
167 auto opening_pair = OpeningPair<Curve>{ challenge, evaluation };
168 auto opening_claim = OpeningClaim<Curve>{ opening_pair, commitment };
169
170 auto prover_transcript = NativeTranscript::test_prover_init_empty();
171
172 PCS::compute_opening_proof(ck, { witness_polynomial, opening_pair }, prover_transcript);
173
174 auto verifier_transcript = NativeTranscript::test_verifier_init_empty(prover_transcript);
175 auto pairing_points = PCS::reduce_verify(opening_claim, verifier_transcript);
176
177 EXPECT_EQ(pairing_points.check(), true);
178}
179TEST_F(KZGTest, ShpleminiKzgWithShift)
180{
181 // Generate multilinear polynomials, their commitments (genuine and mocked) and evaluations (genuine) at a random
182 // point.
183 std::vector<Fr> mle_opening_point = random_evaluation_point(log_n); // sometimes denoted 'u'
184
185 MockClaimGenerator mock_claims(n,
186 /*num_polynomials*/ 4,
187 /*num_to_be_shifted*/ 2,
188 mle_opening_point,
189 ck);
190
191 auto prover_transcript = NativeTranscript::test_prover_init_empty();
192
193 // Run the full prover PCS protocol:
194
195 // Compute:
196 // - (d+1) opening pairs: {r, \hat{a}_0}, {-r^{2^i}, a_i}, i = 0, ..., d-1
197 // - (d+1) Fold polynomials Fold_{r}^(0), Fold_{-r}^(0), and Fold^(i), i = 0, ..., d-1
198 auto prover_opening_claims =
199 GeminiProver::prove(n, mock_claims.polynomial_batcher, mle_opening_point, ck, prover_transcript);
200
201 // Shplonk prover output:
202 // - opening pair: (z_challenge, 0)
203 // - witness: polynomial Q - Q_z
204 const auto opening_claim = ShplonkProver::prove(ck, prover_opening_claims, prover_transcript);
205
206 // KZG prover:
207 // - Adds commitment [W] to transcript
208 PCS::compute_opening_proof(ck, opening_claim, prover_transcript);
209
210 // Run the full verifier PCS protocol with genuine opening claims (genuine commitment, genuine evaluation)
211
212 auto verifier_transcript = NativeTranscript::test_verifier_init_empty(prover_transcript);
213
214 // Gemini verifier output:
215 // - 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
216 auto batch_opening_claim =
217 ShpleminiVerifier::compute_batch_opening_claim(
218 mock_claims.claim_batcher, mle_opening_point, vk.get_g1_identity(), 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(pairing_points.check(), 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
239 auto prover_transcript = NativeTranscript::test_prover_init_empty();
240
241 // Run the full prover PCS protocol:
242
243 // Compute:
244 // - (d+1) opening pairs: {r, \hat{a}_0}, {-r^{2^i}, a_i}, i = 0, ..., d-1
245 // - (d+1) Fold polynomials Fold_{r}^(0), Fold_{-r}^(0), and Fold^(i), i = 0, ..., d-1
246 auto prover_opening_claims =
247 GeminiProver::prove(n, mock_claims.polynomial_batcher, mle_opening_point, ck, prover_transcript);
248
249 // Shplonk prover output:
250 // - opening pair: (z_challenge, 0)
251 // - witness: polynomial Q - Q_z
252 const auto opening_claim = ShplonkProver::prove(ck, prover_opening_claims, prover_transcript);
253
254 // KZG prover:
255 // - Adds commitment [W] to transcript
256 PCS::compute_opening_proof(ck, opening_claim, prover_transcript);
257
258 // Run the full verifier PCS protocol with genuine opening claims (genuine commitment, genuine evaluation)
259
260 auto verifier_transcript = NativeTranscript::test_verifier_init_empty(prover_transcript);
261
262 // Gemini verifier output:
263 // - 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
264 auto batch_opening_claim = ShpleminiVerifier::compute_batch_opening_claim(mock_claims.claim_batcher,
265 mle_opening_point,
266 vk.get_g1_identity(),
267 verifier_transcript,
268 /* repeated commitments= */ {},
269 /* libra commitments = */ {},
270 /* libra evaluations = */ {},
271 {},
272 {})
273 .batch_opening_claim;
274 const auto pairing_points =
275 PCS::reduce_verify_batch_opening_claim(std::move(batch_opening_claim), verifier_transcript);
276 // Final pairing check: e([Q] - [Q_z] + z[W], [1]_2) = e([W], [x]_2)
277
278 EXPECT_EQ(pairing_points.check(), true);
279}
280TEST_F(KZGTest, ShpleminiKzgShiftsRemoval)
281{
282 std::vector<Fr> mle_opening_point = random_evaluation_point(log_n); // sometimes denoted 'u'
283 // Generate multilinear polynomials, their commitments (genuine and mocked) and evaluations (genuine) at a random
284 // point.
285 MockClaimGenerator mock_claims(n,
286 /*num_polynomials*/ 4,
287 /*num_to_be_shifted*/ 2,
288 mle_opening_point,
289 ck);
290
291 auto prover_transcript = NativeTranscript::test_prover_init_empty();
292
293 // Run the full prover PCS protocol:
294
295 // Compute:
296 // - (d+1) opening pairs: {r, \hat{a}_0}, {-r^{2^i}, a_i}, i = 0, ..., d-1
297 // - (d+1) Fold polynomials Fold_{r}^(0), Fold_{-r}^(0), and Fold^(i), i = 0, ..., d-1
298 auto prover_opening_claims =
299 GeminiProver::prove(n, mock_claims.polynomial_batcher, mle_opening_point, ck, prover_transcript);
300
301 // Shplonk prover output:
302 // - opening pair: (z_challenge, 0)
303 // - witness: polynomial Q - Q_z
304 const auto opening_claim = ShplonkProver::prove(ck, prover_opening_claims, prover_transcript);
305
306 // KZG prover:
307 // - Adds commitment [W] to transcript
308 PCS::compute_opening_proof(ck, opening_claim, prover_transcript);
309
310 // Run the full verifier PCS protocol with genuine opening claims (genuine commitment, genuine evaluation)
311
312 auto verifier_transcript = NativeTranscript::test_verifier_init_empty(prover_transcript);
313 // the index of the first commitment to a polynomial to be shifted in the union of unshifted_commitments and
314 // shifted_commitments. in our case, it is poly2
315 const size_t to_be_shifted_commitments_start = 2;
316 // the index of the first commitment to a shifted polynomial in the union of unshifted_commitments and
317 // shifted_commitments. in our case, it is the second occurence of poly2
318 const size_t shifted_commitments_start = 4;
319 // number of shifted polynomials
320 const size_t num_shifted_commitments = 2;
321 // since commitments to poly2, poly3 and their shifts are the same group elements, we simply combine the scalar
322 // multipliers of commitment2 and commitment3 in one place and remove the entries of the commitments and scalars
323 // vectors corresponding to the "shifted" commitment
324 const RepeatedCommitmentsData repeated_commitments =
325 RepeatedCommitmentsData(to_be_shifted_commitments_start, shifted_commitments_start, num_shifted_commitments);
326
327 // Gemini verifier output:
328 // - 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
329 auto batch_opening_claim = ShpleminiVerifier::compute_batch_opening_claim(mock_claims.claim_batcher,
330 mle_opening_point,
331 vk.get_g1_identity(),
332 verifier_transcript,
333 repeated_commitments)
334 .batch_opening_claim;
335
336 const auto pairing_points =
337 PCS::reduce_verify_batch_opening_claim(std::move(batch_opening_claim), verifier_transcript);
338
339 // Final pairing check: e([Q] - [Q_z] + z[W], [1]_2) = e([W], [x]_2)
340 EXPECT_EQ(pairing_points.check(), true);
341}
342
343} // namespace bb
#define BB_DISABLE_ASSERTS()
Definition assert.hpp:33
static std::shared_ptr< BaseTranscript > test_prover_init_empty()
For testing: initializes transcript with some arbitrary data so that a challenge can be generated aft...
static std::shared_ptr< BaseTranscript > test_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:79
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:55
Opening pair (r,v) for some witness polynomial p(X) such that p(r) = v.
Definition claim.hpp:21
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) 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:37
static Univariate get_random()
Representation of the Grumpkin Verifier Commitment Key inside a bn254 circuit.
typename Group::affine_element AffineElement
Definition grumpkin.hpp:64
element class. Implements ecc group arithmetic using Jacobian coordinates See https://hyperelliptic....
Definition element.hpp:35
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
TEST_F(IPATest, ChallengesAreZero)
Definition ipa.test.cpp:155
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()