Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
shplemini.test.cpp
Go to the documentation of this file.
11#include <gtest/gtest.h>
12
13using namespace bb;
14
15template <class PCS> class ShpleminiRecursionTest : public CommitmentTest<typename PCS::Curve::NativeCurve> {
16 public:
17 using Builder = typename PCS::Builder;
18 using Curve = typename PCS::Curve;
19 using NativeCurve = typename Curve::NativeCurve;
21 using NativePCS = typename PCS::PCSImpl;
22 using CommitmentKey = typename NativePCS::CK;
25 using Fr = typename Curve::ScalarField;
33
34 static constexpr size_t log_circuit_size = 10;
35
41
42 static std::vector<Fr> convert_elements_to_witnesses(Builder& builder, const std::vector<NativeFr>& elements)
43 {
44 std::vector<Fr> out(elements.size());
45 std::transform(elements.begin(), elements.end(), out.begin(), [&builder](const NativeFr& e) {
46 return Fr::from_witness(&builder, e);
47 });
48 return out;
49 }
50
51 static std::vector<Commitment> convert_commitments_to_witnesses(
52 Builder& builder, const std::vector<NativeCommitment>& native_commitments)
53 {
54 std::vector<Commitment> out(native_commitments.size());
55 std::transform(native_commitments.begin(),
56 native_commitments.end(),
57 out.begin(),
58 [&builder](const NativeCommitment& c) { return Commitment::from_witness(&builder, c); });
59 return out;
60 }
61
63 {
65 out.reserve(size);
66 for (size_t i = 0; i < size; ++i) {
67 out.emplace_back(NativeFr::random_element());
68 }
69 return out;
70 }
71
72 void validate_num_eccvm_rows(size_t num_polys, size_t num_shifted, bool short_scalars, Builder* builder)
73 {
74 size_t total_num_msm_rows = builder->op_queue->get_num_rows();
75
76 BB_ASSERT_LTE(total_num_msm_rows, 1UL << CONST_ECCVM_LOG_N, "ECCVM/Goblin: Too many ops in ecc op queue");
77
78 if (short_scalars) {
79
80 const size_t num_non_trivial_scalars_gemini_and_shplonk =
81 /* shifted + unshifted */ 2 + /* fold comms */ (log_circuit_size - 1) +
82 /* identity comm */ 1 + /*kzg comm */ 1;
83
84 const size_t num_msm_rows_unshifted = 33 * ((num_polys - 1 + 3) / 4) + 31;
85 const size_t num_msm_rows_shifted = 33 * ((num_shifted + 3) / 4) + 31;
86
87 EXPECT_EQ(total_num_msm_rows - num_msm_rows_shifted - num_msm_rows_unshifted,
88 33 * ((num_non_trivial_scalars_gemini_and_shplonk + 1) / 2) + 33);
89 } else {
90 const size_t num_non_trivial_scalars_gemini_and_shplonk =
91 /* fold comms */ (log_circuit_size - 1) +
92 /* identity comm */ 1 + /*kzg comm */ 1;
93
94 EXPECT_EQ(33 * ((num_polys + num_shifted + num_non_trivial_scalars_gemini_and_shplonk + 1) / 2) + 33,
95 total_num_msm_rows);
96 }
97 }
98
99 void run_shplemini_full_scalars(size_t num_polys, size_t num_shifted, bool prove_eccvm = false)
100 {
101 run_shplemini_generic(num_polys, num_shifted, false, prove_eccvm);
102 }
103 void run_shplemini_short_scalars(size_t num_polys, size_t num_shifted, bool prove_eccvm = false)
104 {
105 run_shplemini_generic(num_polys, num_shifted, true, prove_eccvm);
106 }
107
108 private:
109 void run_shplemini_generic(size_t num_polys, size_t num_shifted, bool short_scalars, bool prove_eccvm)
110 {
111 size_t N = 1 << log_circuit_size;
112
115
116 MockClaimGen mock_claims(N, num_polys, num_shifted, u_challenge, commitment_key);
117 auto prover_transcript = NativeTranscript::test_prover_init_empty();
118 // Initialize polys outside of `if` as they are used inside RefVector ClaimBatcher members.
119 Polynomial<NativeFr> squashed_unshifted(N);
121 // Labels are shared by Prover and Verifier
122 std::vector<std::string> unshifted_batching_challenge_labels;
123 std::vector<std::string> shifted_batching_challenge_labels;
124
125 for (size_t idx = 0; idx < num_polys - 1; idx++) {
126 unshifted_batching_challenge_labels.push_back("rho_" + std::to_string(idx));
127 }
128 for (size_t idx = 0; idx < num_shifted; idx++) {
129 shifted_batching_challenge_labels.push_back("rho_" + std::to_string(num_polys - 1 + idx));
130 }
131
132 if (short_scalars) {
133
134 auto unshifted_challenges =
135 prover_transcript->template get_challenges<NativeFr>(unshifted_batching_challenge_labels);
136 auto shifted_challenges =
137 prover_transcript->template get_challenges<NativeFr>(shifted_batching_challenge_labels);
138
139 squashed_unshifted += mock_claims.polynomial_batcher.unshifted[0];
140 for (size_t i = 0; i < unshifted_challenges.size(); ++i) {
141 squashed_unshifted.add_scaled(mock_claims.polynomial_batcher.unshifted[i + 1], unshifted_challenges[i]);
142 }
143
144 for (size_t i = 0; i < shifted_challenges.size(); ++i) {
145 squashed_shifted.add_scaled(mock_claims.polynomial_batcher.to_be_shifted_by_one[i],
146 shifted_challenges[i]);
147 }
148
149 mock_claims.polynomial_batcher.unshifted = RefVector{ squashed_unshifted };
150 mock_claims.polynomial_batcher.to_be_shifted_by_one = RefVector{ squashed_shifted };
151 }
152
153 auto prover_opening_claims =
154 ShpleminiProver::prove(N, mock_claims.polynomial_batcher, u_challenge, commitment_key, prover_transcript);
155
156 KZG<NativeCurve>::compute_opening_proof(commitment_key, prover_opening_claims, prover_transcript);
157
159 StdlibProof stdlib_proof(builder, prover_transcript->export_proof());
160 auto stdlib_verifier_transcript = std::make_shared<Transcript>(stdlib_proof);
161 [[maybe_unused]] auto _ = stdlib_verifier_transcript->template receive_from_prover<Fr>("Init");
162
163 // Execute Verifier protocol without the need for vk prior the final check
164 auto stdlib_unshifted_commitments =
166 auto stdlib_shifted_commitments =
168
169 auto stdlib_unshifted_evaluations =
171 auto stdlib_shifted_evaluations =
173
174 // Removing the free witness tag, since in the full scheme these are supposed to
175 // be fiat-shamirred earlier from the transcript
176 for (auto& comm : stdlib_unshifted_commitments) {
177 comm.unset_free_witness_tag();
178 }
179 for (auto& comm : stdlib_shifted_commitments) {
180 comm.unset_free_witness_tag();
181 }
182 for (auto& eval : stdlib_unshifted_evaluations) {
183 eval.unset_free_witness_tag();
184 }
185 for (auto& eval : stdlib_shifted_evaluations) {
186 eval.unset_free_witness_tag();
187 }
188
189 std::vector<Fr> u_challenge_in_circuit = convert_elements_to_witnesses(builder, u_challenge);
190 // Removing the free witness tag, since the u_challenge in the full scheme are supposed to
191 // be derived from the transcript earlier
192 for (auto& challenge : u_challenge_in_circuit) {
193 challenge.unset_free_witness_tag();
194 }
195
196 ClaimBatcher claim_batcher{
197 .unshifted = ClaimBatch{ RefVector(stdlib_unshifted_commitments), RefVector(stdlib_unshifted_evaluations) },
198 .shifted = ClaimBatch{ RefVector(stdlib_shifted_commitments), RefVector(stdlib_shifted_evaluations) }
199 };
200
201 if (short_scalars) {
202
203 // Helper that produces the vectors of batching challenges that will be fed to `batch_mul`
204 auto get_batching_challenges = [&](std::span<const std::string> unshifted_labels,
205 std::span<const std::string> shifted_labels) {
206 // `batch_mul` expects a vector of scalars.
207 std::vector<Fr> unshifted_challenges(num_polys);
208 // Except for the first commitment, each one of them is multiplied by a challenge, which is <= 128
209 // bits.
210 unshifted_challenges[0] = Fr(1);
211 // Get `num_polys - 1` short challenges to batch all unshifted commitments
212 auto tail = stdlib_verifier_transcript->template get_challenges<Fr>(unshifted_labels);
213 std::copy(tail.begin(), tail.end(), unshifted_challenges.begin() + 1);
214
215 // Get `num_shifted` short challenges to batch all shifted commitments
216 auto shifted_challenges = stdlib_verifier_transcript->template get_challenges<Fr>(shifted_labels);
217
218 return std::pair{ std::move(unshifted_challenges), std::move(shifted_challenges) };
219 };
220
221 auto [unshifted_challenges, shifted_challenges] =
222 get_batching_challenges(unshifted_batching_challenge_labels, shifted_batching_challenge_labels);
223
225 Commitment::batch_mul(claim_batcher.get_unshifted().commitments, unshifted_challenges, 128);
226
228 Commitment::batch_mul(claim_batcher.get_shifted().commitments, shifted_challenges, 128);
229
230 // Compute claimed evaluations
231 squashed_unshifted_eval = std::inner_product(unshifted_challenges.begin(),
232 unshifted_challenges.end(),
233 claim_batcher.get_unshifted().evaluations.begin(),
234 Fr(0));
235 squashed_shifted_eval = std::inner_product(shifted_challenges.begin(),
236 shifted_challenges.end(),
237 claim_batcher.get_shifted().evaluations.begin(),
238 Fr(0));
239
243 };
244 } else {
245 squashed_claim_batcher = claim_batcher;
246 }
247
248 auto opening_claim =
250 squashed_claim_batcher, u_challenge_in_circuit, Commitment::one(&builder), stdlib_verifier_transcript)
253 KZG<Curve>::reduce_verify_batch_opening_claim(std::move(opening_claim), stdlib_verifier_transcript));
254 EXPECT_TRUE(CircuitChecker::check(builder));
255
256 EXPECT_TRUE(pairing_points.check());
257
259 validate_num_eccvm_rows(num_polys, num_shifted, short_scalars, &builder);
260 if (prove_eccvm) {
261 // Add hiding op for ECCVM ZK (prepended to ECCVM ops at row 1)
263 builder.queue_ecc_hiding_op(Fq::random_element(), Fq::random_element());
264 builder.op_queue->merge();
265 using clock = std::chrono::steady_clock;
266 auto start_total = clock::now();
267
269
270 auto start_builder = clock::now();
271 ECCVMCircuitBuilder eccvm_builder(builder.op_queue);
272
273 ECCVMProver prover(eccvm_builder, eccvm_transcript);
274
275 auto end_builder = clock::now();
276
277 info("ECCVM prover construction took ",
278 std::chrono::duration_cast<std::chrono::milliseconds>(end_builder - start_builder).count(),
279 " ms");
280
281 auto start_prove = clock::now();
282 prover.construct_proof();
283 auto end_prove = clock::now();
284
285 info("ECCVM proof construction took ",
286 std::chrono::duration_cast<std::chrono::milliseconds>(end_prove - start_prove).count(),
287 " ms");
288
289 auto end_total = clock::now();
290 info("ECCVM total (builder + proof) time: ",
291 std::chrono::duration_cast<std::chrono::milliseconds>(end_total - start_total).count(),
292 " ms");
293 }
294 } else {
295 info("builder num gates ", builder.get_num_finalized_gates_inefficient());
296 }
297 }
298};
299
305
311
314
315TEST_F(ShpleminiUltraTest, ProveAndVerifySingleFullScalars)
316{
317 // In UltraRecursiveVerifier instantiations, we remove the scalar muls against the commitments to shifts.
318 run_shplemini_full_scalars(bb::UltraFlavor::NUM_ALL_ENTITIES, 0);
319}
320
321TEST_F(ShpleminiUltraTest, ProveAndVerifySingleShortScalars)
322{
323 // We don't hit any edge cases here, because all commitments are random. Note that we are paying for the shifts
324 // here.
326}
327
328TEST_F(ShpleminiMegaTest, ProveAndVerifySingleFullScalars)
329{
330 size_t num_polys = 100;
331 size_t num_shifted = 5;
332
333 for (size_t idx = 0; idx < 4; idx++) {
334 run_shplemini_full_scalars(num_polys + idx, num_shifted + idx);
335 }
336}
337
338TEST_F(ShpleminiMegaTest, GoblinProveAndVerifyShortScalars)
339{
340 size_t num_polys = 100;
341 size_t num_shifted = 5;
342
343 for (size_t idx = 0; idx < 4; idx++) {
344 run_shplemini_short_scalars(num_polys + idx, num_shifted + idx);
345 }
346}
347
348TEST_F(ShpleminiMegaTest, ManyCommitmentsWithECCVMProving)
349{
350 run_shplemini_full_scalars(1700, 175, true);
351 run_shplemini_short_scalars(3500, 350, true);
352}
#define BB_ASSERT_LTE(left, right,...)
Definition assert.hpp:158
static std::vector< Fr > convert_elements_to_witnesses(Builder &builder, const std::vector< NativeFr > &elements)
typename PCS::Builder Builder
typename NativePCS::CK CommitmentKey
typename Curve::NativeCurve NativeCurve
void validate_num_eccvm_rows(size_t num_polys, size_t num_shifted, bool short_scalars, Builder *builder)
void run_shplemini_full_scalars(size_t num_polys, size_t num_shifted, bool prove_eccvm=false)
static std::vector< Commitment > convert_commitments_to_witnesses(Builder &builder, const std::vector< NativeCommitment > &native_commitments)
static std::vector< NativeFr > random_challenge_vector(size_t size)
void run_shplemini_short_scalars(size_t num_polys, size_t num_shifted, bool prove_eccvm=false)
typename NativeCurve::AffineElement NativeCommitment
typename ClaimBatcher::Batch ClaimBatch
typename PCS::Curve Curve
typename PCS::PCSImpl NativePCS
typename Curve::ScalarField Fr
typename NativeCurve::ScalarField NativeFr
static constexpr size_t log_circuit_size
ClaimBatcher squashed_claim_batcher
void run_shplemini_generic(size_t num_polys, size_t num_shifted, bool short_scalars, bool prove_eccvm)
typename Curve::AffineElement Commitment
Common transcript class for both parties. Stores the data for the current round, as well as the manif...
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...
std::pair< Proof, OpeningClaim > construct_proof()
RefVector< Polynomial > to_be_shifted_by_one
Definition gemini.hpp:143
RefVector< Polynomial > unshifted
Definition gemini.hpp:142
Curve_ Curve
Definition ipa.hpp:88
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
Structured polynomial class that represents the coefficients 'a' of a_0 + a_1 x .....
void add_scaled(PolynomialSpan< const Fr > other, const Fr &scaling_factor)
adds the polynomial q(X) 'other', multiplied by a scaling factor.
A template class for a reference vector. Behaves as if std::vector<T&> was possible.
static OpeningClaim prove(size_t circuit_size, PolynomialBatcher &polynomial_batcher, std::span< FF > multilinear_challenge, const CommitmentKey< Curve > &commitment_key, const std::shared_ptr< Transcript > &transcript, const std::array< Polynomial, NUM_SMALL_IPA_EVALUATIONS > &libra_polynomials={}, const std::vector< Polynomial > &sumcheck_round_univariates={}, const std::vector< std::array< FF, 3 > > &sumcheck_round_evaluations={})
Definition shplemini.hpp:37
static ShpleminiVerifierOutput compute_batch_opening_claim(ClaimBatcher &claim_batcher, const std::vector< Fr > &multivariate_challenge, const Commitment &g1_identity, const std::shared_ptr< Transcript > &transcript, const RepeatedCommitmentsData &repeated_commitments={}, const std::array< Commitment, NUM_LIBRA_COMMITMENTS > &libra_commitments={}, const Fr &libra_univariate_evaluation=Fr{ 0 }, const std::vector< Commitment > &sumcheck_round_commitments={}, const std::vector< std::array< Fr, 3 > > &sumcheck_round_evaluations={})
This method receives commitments to all prover polynomials, their claimed evaluations,...
static bool check(const Builder &circuit)
Check the witness satisifies the circuit.
static constexpr size_t NUM_ALL_ENTITIES
static constexpr size_t NUM_WITNESS_ENTITIES
typename Group::affine_element AffineElement
Definition bn254.hpp:22
bb::fr ScalarField
Definition bn254.hpp:18
typename Group::affine_element AffineElement
Definition grumpkin.hpp:64
A simple wrapper around a vector of stdlib field elements representing a proof.
Definition proof.hpp:19
#define info(...)
Definition log.hpp:93
AluTraceBuilder builder
Definition alu.test.cpp:124
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
TEST_F(IPATest, ChallengesAreZero)
Definition ipa.test.cpp:155
UltraCircuitBuilder_< UltraExecutionTraceBlocks > UltraCircuitBuilder
MegaCircuitBuilder_< field< Bn254FrParams > > MegaCircuitBuilder
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
std::string to_string(bb::avm2::ValueTag tag)
RefVector< Commitment > commitments
RefVector< Fr > evaluations
Logic to support batching opening claims for unshifted and shifted polynomials in Shplemini.
std::optional< Batch > unshifted
Constructs random polynomials, computes commitments and corresponding evaluations.
BatchOpeningClaim< Curve > batch_opening_claim
static field random_element(numeric::RNG *engine=nullptr) noexcept
An object storing two EC points that represent the inputs to a pairing check.
bool check() const
Perform native pairing check on the witness values.