Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
small_subgroup_ipa.test.cpp
Go to the documentation of this file.
2#include "../commitment_key.test.hpp"
5
6#include <array>
7#include <gtest/gtest.h>
8#include <vector>
9
10namespace bb {
11template <typename Flavor> class SmallSubgroupIPATest : public ::testing::Test {
12 public:
13 using Curve = typename Flavor::Curve;
15 using FF = typename Curve::ScalarField;
16
18
19 static constexpr size_t log_circuit_size = 7;
20 static constexpr size_t circuit_size = 1ULL << log_circuit_size;
21
23
25
26 static std::vector<FF> generate_random_vector(const size_t size)
27 {
28 std::vector<FF> multivariate_challenge(size);
29 for (auto& challenge : multivariate_challenge) {
30 challenge = FF::random_element();
31 }
32 return multivariate_challenge;
33 }
34
35 // A helper to evaluate the four IPA witness polynomials at x, x*g, x, x
37 const std::array<Polynomial<FF>, NUM_SMALL_IPA_EVALUATIONS>& witness_polynomials)
38 {
39 // Hard-coded pattern of evaluation: (x, x*g, x, x)
40 return { witness_polynomials[0].evaluate(evaluation_challenge),
41 witness_polynomials[1].evaluate(evaluation_challenge * subgroup_generator),
42 witness_polynomials[2].evaluate(evaluation_challenge),
43 witness_polynomials[3].evaluate(evaluation_challenge) };
44 }
45};
46
47using TestFlavors = ::testing::Types<BN254Settings, GrumpkinSettings>;
49
50// Check the correctness of the computation of the claimed inner product and various polynomials needed for the
51// SmallSubgroupIPA.
52TYPED_TEST(SmallSubgroupIPATest, ProverComputationsCorrectness)
53{
54 using ZKData = ZKSumcheckData<TypeParam>;
55 using SmallSubgroupIPA = SmallSubgroupIPAProver<TypeParam>;
56 using FF = typename TypeParam::FF;
57 static constexpr size_t SUBGROUP_SIZE = TypeParam::SUBGROUP_SIZE;
58
59 using CK = typename TypeParam::CommitmentKey;
60
61 // SmallSubgroupIPAProver requires at least CURVE::SUBGROUP_SIZE + 3 elements in the ck.
62 static constexpr size_t log_subgroup_size = static_cast<size_t>(numeric::get_msb(SUBGROUP_SIZE));
63 CK ck = create_commitment_key<CK>(std::max<size_t>(this->circuit_size, 1ULL << (log_subgroup_size + 1)));
64
65 auto prover_transcript = TypeParam::Transcript::prover_init_empty();
66
67 ZKData zk_sumcheck_data(this->log_circuit_size, prover_transcript, ck);
68 std::vector<FF> multivariate_challenge = this->generate_random_vector(this->log_circuit_size);
69
70 const FF claimed_inner_product = SmallSubgroupIPA::compute_claimed_inner_product(
71 zk_sumcheck_data, multivariate_challenge, this->log_circuit_size);
72
73 SmallSubgroupIPA small_subgroup_ipa_prover =
74 SmallSubgroupIPA(zk_sumcheck_data, multivariate_challenge, claimed_inner_product, prover_transcript, ck);
75
76 small_subgroup_ipa_prover.prove();
77
78 const Polynomial batched_polynomial = small_subgroup_ipa_prover.get_batched_polynomial();
79 const Polynomial libra_concatenated_polynomial = small_subgroup_ipa_prover.get_witness_polynomials()[0];
80 const Polynomial batched_quotient = small_subgroup_ipa_prover.get_witness_polynomials()[3];
81 const Polynomial challenge_polynomial = small_subgroup_ipa_prover.get_challenge_polynomial();
82
83 // Check that claimed inner product coincides with the inner product of libra_concatenated_polynomial and
84 // challenge_polynomial. Since libra_concatenated_polynomial is masked, we also check that masking does not affect
85 // the evaluations over H
86 FF inner_product = FF(0);
87 const std::array<FF, SUBGROUP_SIZE> domain = zk_sumcheck_data.interpolation_domain;
88 for (size_t idx = 0; idx < SUBGROUP_SIZE; idx++) {
89 inner_product +=
90 challenge_polynomial.evaluate(domain[idx]) * libra_concatenated_polynomial.evaluate(domain[idx]);
91 }
92 EXPECT_TRUE(inner_product == claimed_inner_product);
93
94 // Check that batched polynomial is divisible by Z_H(X)
95 bool ipa_claim_consistency = true;
96 for (size_t idx = 0; idx < SUBGROUP_SIZE; idx++) {
97 ipa_claim_consistency = (batched_polynomial.evaluate(zk_sumcheck_data.interpolation_domain[idx]) == FF{ 0 }) &&
98 ipa_claim_consistency;
99 }
100 EXPECT_EQ(ipa_claim_consistency, true);
101
102 // Check that Z_H(X) * Q(X) = batched_polynomial
103 std::vector<FF> Z_H(SUBGROUP_SIZE + 1);
104 Z_H[0] = -FF(1);
105 Z_H[SUBGROUP_SIZE] = FF(1);
106 Polynomial<FF> product(batched_polynomial.size());
107
108 for (size_t i = 0; i < Z_H.size(); i++) {
109 for (size_t j = 0; j < batched_quotient.size(); j++) {
110 product.at(i + j) += Z_H[i] * batched_quotient.at(j);
111 }
112 }
113 bool quotient_is_correct = true;
114 for (const auto& [coeff_expected, coeff] : zip_view(product.coeffs(), batched_polynomial.coeffs())) {
115 quotient_is_correct = (coeff_expected == coeff) && quotient_is_correct;
116 }
117 EXPECT_EQ(quotient_is_correct, true);
118}
119
120// Check the correctness of the evaluations of the challenge_polynomial, Lagrange first, and Lagrange last that the
121// verifier has to compute on its own. Compare the values against the evaluations obtaned by applying Lagrange
122// interpolation method used by Polynomial class constructor.
123TYPED_TEST(SmallSubgroupIPATest, VerifierEvaluations)
124{
125 using FF = typename TypeParam::FF;
126 using Curve = typename TypeParam::Curve;
127 using SmallSubgroupIPA = SmallSubgroupIPAVerifier<Curve>;
128
129 // Extract the constants
130 static constexpr size_t SUBGROUP_SIZE = TypeParam::SUBGROUP_SIZE;
131 const FF subgroup_generator_inverse = Curve::subgroup_generator_inverse;
132 const FF subgroup_generator = subgroup_generator_inverse.invert();
133
134 // Sample random Lagrange coefficients over H
135 std::vector<FF> challenge_poly_lagrange = this->generate_random_vector(SUBGROUP_SIZE);
136
137 // Evaluate Verifier's polynomials at the challenge
138 const FF vanishing_poly_eval = this->evaluation_challenge.pow(SUBGROUP_SIZE) - 1;
139
140 // Compute required evaluations using efficient batch evaluation
141 const auto [challenge_poly_eval, lagrange_first, lagrange_last] =
142 SmallSubgroupIPA::compute_batched_barycentric_evaluations(
143 challenge_poly_lagrange, this->evaluation_challenge, vanishing_poly_eval);
144
145 // Compute the evaluations differently, namely, using Lagrange interpolation
146 std::array<FF, SUBGROUP_SIZE> interpolation_domain;
147 interpolation_domain[0] = FF(1);
148 for (size_t idx = 1; idx < SUBGROUP_SIZE; idx++) {
149 interpolation_domain[idx] = interpolation_domain[idx - 1] * subgroup_generator;
150 }
151 Polynomial<FF> challenge_poly_monomial =
152 Polynomial<FF>(interpolation_domain, challenge_poly_lagrange, SUBGROUP_SIZE);
153
154 // Evaluate at the challenge
155 const FF challenge_poly_expected_eval = challenge_poly_monomial.evaluate(this->evaluation_challenge);
156
157 EXPECT_EQ(challenge_poly_eval, challenge_poly_expected_eval);
158
159 // Compute Lagrange polynomials using interpolation
160 std::vector<FF> lagrange_poly(SUBGROUP_SIZE);
161 lagrange_poly.at(0) = FF(1);
162 Polynomial<FF> lagrange_first_monomial = Polynomial<FF>(interpolation_domain, lagrange_poly, SUBGROUP_SIZE);
163 EXPECT_EQ(lagrange_first, lagrange_first_monomial.evaluate(this->evaluation_challenge));
164
165 lagrange_poly.at(0) = FF(0);
166 lagrange_poly.at(SUBGROUP_SIZE - 1) = FF(1);
167 Polynomial<FF> lagrange_last_monomial = Polynomial<FF>(interpolation_domain, lagrange_poly, SUBGROUP_SIZE);
168 EXPECT_EQ(lagrange_last, lagrange_last_monomial.evaluate(this->evaluation_challenge));
169}
170
171// Simulate the interaction between the prover and the verifier leading to the consistency check performed by the
172// verifier.
173TYPED_TEST(SmallSubgroupIPATest, LibraEvaluationsConsistency)
174{
175 using FF = typename TypeParam::FF;
176 using Curve = typename TypeParam::Curve;
177 using Verifier = SmallSubgroupIPAVerifier<Curve>;
179 using ZKData = ZKSumcheckData<TypeParam>;
180 using CK = typename TypeParam::CommitmentKey;
181
182 auto prover_transcript = TypeParam::Transcript::prover_init_empty();
183
184 // SmallSubgroupIPAProver requires at least CURVE::SUBGROUP_SIZE + 3 elements in the ck.
185 static constexpr size_t log_subgroup_size = static_cast<size_t>(numeric::get_msb(Curve::SUBGROUP_SIZE));
186 CK ck = create_commitment_key<CK>(std::max<size_t>(this->circuit_size, 1ULL << (log_subgroup_size + 1)));
187
188 ZKData zk_sumcheck_data(this->log_circuit_size, prover_transcript, ck);
189
190 std::vector<FF> multivariate_challenge = this->generate_random_vector(CONST_PROOF_SIZE_LOG_N);
191
192 const FF claimed_inner_product =
193 Prover::compute_claimed_inner_product(zk_sumcheck_data, multivariate_challenge, this->log_circuit_size);
194
195 Prover small_subgroup_ipa_prover =
196 Prover(zk_sumcheck_data, multivariate_challenge, claimed_inner_product, prover_transcript, ck);
197
198 small_subgroup_ipa_prover.prove();
199
200 const std::array<FF, NUM_SMALL_IPA_EVALUATIONS> small_ipa_evaluations =
201 this->evaluate_small_ipa_witnesses(small_subgroup_ipa_prover.get_witness_polynomials());
202
203 bool consistency_checked = Verifier::check_libra_evaluations_consistency(
204 small_ipa_evaluations, this->evaluation_challenge, multivariate_challenge, claimed_inner_product);
205
206 EXPECT_TRUE(consistency_checked);
207}
208
209// Check that consistency check fails when some of the prover's data is corrupted.
210TYPED_TEST(SmallSubgroupIPATest, LibraEvaluationsConsistencyFailure)
211{
212 using FF = typename TypeParam::FF;
213 using Curve = typename TypeParam::Curve;
214 using Verifier = SmallSubgroupIPAVerifier<Curve>;
216 using ZKData = ZKSumcheckData<TypeParam>;
217 using CK = typename TypeParam::CommitmentKey;
218
219 auto prover_transcript = TypeParam::Transcript::prover_init_empty();
220
221 // SmallSubgroupIPAProver requires at least CURVE::SUBGROUP_SIZE + 3 elements in the ck.
222 static constexpr size_t log_subgroup_size = static_cast<size_t>(numeric::get_msb(Curve::SUBGROUP_SIZE));
223 CK ck = create_commitment_key<CK>(std::max<size_t>(this->circuit_size, 1ULL << (log_subgroup_size + 1)));
224
225 ZKData zk_sumcheck_data(this->log_circuit_size, prover_transcript, ck);
226
227 std::vector<FF> multivariate_challenge = this->generate_random_vector(CONST_PROOF_SIZE_LOG_N);
228
229 const FF claimed_inner_product =
230 Prover::compute_claimed_inner_product(zk_sumcheck_data, multivariate_challenge, this->log_circuit_size);
231
232 Prover small_subgroup_ipa_prover =
233 Prover(zk_sumcheck_data, multivariate_challenge, claimed_inner_product, prover_transcript, ck);
234
235 small_subgroup_ipa_prover.prove();
236
237 std::array<Polynomial<FF>, NUM_SMALL_IPA_EVALUATIONS> witness_polynomials =
238 small_subgroup_ipa_prover.get_witness_polynomials();
239
240 // Tamper with witness polynomials
241 witness_polynomials[0].at(0) = FF::random_element();
242
243 const std::array<FF, NUM_SMALL_IPA_EVALUATIONS> small_ipa_evaluations =
244 this->evaluate_small_ipa_witnesses(witness_polynomials);
245
246 bool consistency_checked = Verifier::check_libra_evaluations_consistency(
247 small_ipa_evaluations, this->evaluation_challenge, multivariate_challenge, claimed_inner_product);
248
249 // Since witness polynomials were modified, the consistency check must fail
250 EXPECT_FALSE(consistency_checked);
251}
252
253// Simulate the interaction between the prover and the verifier leading to the consistency check performed by the
254// verifier.
255TYPED_TEST(SmallSubgroupIPATest, TranslationMaskingTermConsistency)
256{
257 // TranslationData class is Grumpkin-specific
259 GTEST_SKIP();
260 } else {
261 using Curve = typename TypeParam::Curve;
262 using FF = typename Curve::ScalarField;
263 using Verifier = SmallSubgroupIPAVerifier<Curve>;
265 using CK = typename TypeParam::CommitmentKey;
266
267 auto prover_transcript = TypeParam::Transcript::prover_init_empty();
268 // Must satisfy num_wires * NUM_DISABLED_ROWS_IN_SUMCHECK + 1 < SUBGROUP_SIZE
269 const size_t num_wires = 5;
270
271 // SmallSubgroupIPAProver requires at least CURVE::SUBGROUP_SIZE + 3 elements in the ck.
272 static constexpr size_t log_subgroup_size = static_cast<size_t>(numeric::get_msb(Curve::SUBGROUP_SIZE));
273 CK ck = create_commitment_key<CK>(std::max<size_t>(this->circuit_size, 1ULL << (log_subgroup_size + 1)));
274
275 // Generate transcript polynomials
276 std::vector<Polynomial<FF>> transcript_polynomials;
277
278 for (size_t idx = 0; idx < num_wires; idx++) {
279 transcript_polynomials.push_back(Polynomial<FF>::random(this->circuit_size));
280 }
281
283 RefVector<Polynomial<FF>>(transcript_polynomials), prover_transcript, ck);
284
285 const FF evaluation_challenge_x = FF::random_element();
286 const FF batching_challenge_v = FF::random_element();
287
288 Prover small_subgroup_ipa_prover(
289 translation_data, evaluation_challenge_x, batching_challenge_v, prover_transcript, ck);
290 small_subgroup_ipa_prover.prove();
291
292 const std::array<FF, NUM_SMALL_IPA_EVALUATIONS> small_ipa_evaluations =
293 this->evaluate_small_ipa_witnesses(small_subgroup_ipa_prover.get_witness_polynomials());
294
295 bool consistency_checked =
296 Verifier::check_eccvm_evaluations_consistency(small_ipa_evaluations,
297 this->evaluation_challenge,
298 evaluation_challenge_x,
299 batching_challenge_v,
300 small_subgroup_ipa_prover.claimed_inner_product);
301
302 EXPECT_TRUE(consistency_checked);
303 }
304};
305// Simulate the interaction between the prover and the verifier leading to the consistency check performed by the
306// verifier.
307TYPED_TEST(SmallSubgroupIPATest, TranslationMaskingTermConsistencyFailure)
308{
309 // TranslationData class is Grumpkin-specific
311 GTEST_SKIP();
312 } else {
313 using Curve = typename TypeParam::Curve;
314 using FF = typename Curve::ScalarField;
315 using Verifier = SmallSubgroupIPAVerifier<Curve>;
317 using CK = typename TypeParam::CommitmentKey;
318
319 auto prover_transcript = TypeParam::Transcript::prover_init_empty();
320 // Must satisfy num_wires * NUM_DISABLED_ROWS_IN_SUMCHECK + 1 < SUBGROUP_SIZE
321 const size_t num_wires = 5;
322
323 // SmallSubgroupIPAProver requires at least CURVE::SUBGROUP_SIZE + 3 elements in the ck.
324 static constexpr size_t log_subgroup_size = static_cast<size_t>(numeric::get_msb(Curve::SUBGROUP_SIZE));
325 CK ck = create_commitment_key<CK>(std::max<size_t>(this->circuit_size, 1ULL << (log_subgroup_size + 1)));
326
327 // Generate transcript polynomials
328 std::vector<Polynomial<FF>> transcript_polynomials;
329
330 for (size_t idx = 0; idx < num_wires; idx++) {
331 transcript_polynomials.push_back(Polynomial<FF>::random(this->circuit_size));
332 }
333
335 RefVector<Polynomial<FF>>(transcript_polynomials), prover_transcript, ck);
336
337 const FF evaluation_challenge_x = FF::random_element();
338 const FF batching_challenge_v = FF::random_element();
339
340 Prover small_subgroup_ipa_prover(
341 translation_data, evaluation_challenge_x, batching_challenge_v, prover_transcript, ck);
342 small_subgroup_ipa_prover.prove();
343
344 const std::array<FF, NUM_SMALL_IPA_EVALUATIONS> small_ipa_evaluations =
345 this->evaluate_small_ipa_witnesses(small_subgroup_ipa_prover.get_witness_polynomials());
346
347 bool consistency_checked =
348 Verifier::check_eccvm_evaluations_consistency(small_ipa_evaluations,
349 this->evaluation_challenge,
350 evaluation_challenge_x,
351 batching_challenge_v,
352 /*tampered claimed inner product = */ FF::random_element());
353
354 EXPECT_TRUE(!consistency_checked);
355 }
356}
357} // namespace bb
NativeTranscript Transcript
curve::BN254 Curve
Structured polynomial class that represents the coefficients 'a' of a_0 + a_1 x .....
Fr evaluate(const Fr &z, size_t target_size) const
std::span< Fr > coeffs(size_t offset=0)
Strictly iterates the defined region of the polynomial. We keep this explicit, instead of having an i...
Fr & at(size_t index)
Our mutable accessor, unlike operator[]. We abuse precedent a bit to differentiate at() and operator[...
std::size_t size() const
A template class for a reference vector. Behaves as if std::vector<T&> was possible.
A Curve-agnostic ZK protocol to prove inner products of small vectors.
typename Flavor::Transcript Transcript
static std::vector< FF > generate_random_vector(const size_t size)
std::array< FF, NUM_SMALL_IPA_EVALUATIONS > evaluate_small_ipa_witnesses(const std::array< Polynomial< FF >, NUM_SMALL_IPA_EVALUATIONS > &witness_polynomials)
static constexpr size_t circuit_size
static constexpr size_t log_circuit_size
typename Curve::ScalarField FF
Verifies the consistency of polynomial evaluations provided by the the prover.
A class designed to accept the ECCVM Transcript Polynomials, concatenate their masking terms in Lagra...
static constexpr size_t SUBGROUP_SIZE
Definition grumpkin.hpp:67
static constexpr ScalarField subgroup_generator_inverse
Definition grumpkin.hpp:74
static constexpr ScalarField subgroup_generator
Definition grumpkin.hpp:72
constexpr T get_msb(const T in)
Definition get_msb.hpp:47
Entry point for Barretenberg command-line interface.
TYPED_TEST_SUITE(ShpleminiTest, TestSettings)
::testing::Types< BN254Settings, GrumpkinSettings > TestFlavors
typename Flavor::FF FF
TYPED_TEST(ShpleminiTest, CorrectnessOfMultivariateClaimBatching)
CommitmentKey< Curve > ck
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
This structure is created to contain various polynomials and constants required by ZK Sumcheck.
constexpr field invert() const noexcept
static field random_element(numeric::RNG *engine=nullptr) noexcept