Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
prover.cpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Completed, auditors: [Federico], commit: 0e37cb8}
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
7
8#include <algorithm>
9#include <cstdlib>
10
24
25namespace bb::avm2 {
26
27// Maximum number of polynomials to batch commit at once.
29 getenv("AVM_MAX_MSM_BATCH_SIZE") != nullptr ? std::stoul(getenv("AVM_MAX_MSM_BATCH_SIZE")) : 32;
30
32using FF = Flavor::FF;
33
44 const PCSCommitmentKey& commitment_key)
45 : proving_key(std::move(input_proving_key))
46 , vk(std::move(vk))
47 , prover_polynomials(*proving_key)
48 , commitment_key(commitment_key)
49{}
50
56{
57 FF vk_hash = vk->get_hash();
58 transcript->add_to_hash_buffer("avm_vk_hash", vk_hash);
59 vinfo("AVM vk hash in prover: ", vk_hash);
60}
61
70{
71 BB_BENCH_NAME("AvmProver::execute_public_inputs_round");
72
73 using C = ColumnAndShifts;
74 // Add the public inputs to the transcript so that the Sumcheck challenge depends both on the public inputs sent in
75 // the clear and the commitments to the columns that are purtported to contain them.
77 C::public_inputs_cols_0_,
78 C::public_inputs_cols_1_,
79 C::public_inputs_cols_2_,
80 C::public_inputs_cols_3_,
81 };
82
83 for (size_t i = 0; i < public_input_columns.size(); ++i) {
84 const Polynomial& public_input_col = prover_polynomials.get(public_input_columns[i]);
85 size_t public_input_col_size = public_input_col.size();
86 for (size_t j = 0; j < AVM_PUBLIC_INPUTS_COLUMNS_MAX_LENGTH; ++j) {
87 // The public inputs are added to the hash buffer, but do not increase the size of the proof
88 transcript->add_to_hash_buffer("public_input_" + std::to_string(i) + "_" + std::to_string(j),
89 j < public_input_col_size ? public_input_col.at(j) : FF(0));
90 }
91 }
92}
98{
99 BB_BENCH_NAME("AvmProver::execute_wire_commitments_round");
100 // Commit to all polynomials (apart from logderivative inverse polynomials, which are committed to in the later
101 // logderivative phase)
102 auto batch = commitment_key.start_batch();
103 for (const auto& [poly, label] : zip_view(prover_polynomials.get_wires(), prover_polynomials.get_wires_labels())) {
104 batch.add_to_batch(poly, label);
105 }
106 batch.commit_and_send_to_verifier(transcript, AVM_MAX_MSM_BATCH_SIZE);
107}
108
110{
111 BB_BENCH_NAME("AvmProver::execute_log_derivative_inverse_round");
112
113 auto [beta, gamma] = transcript->template get_challenges<FF>(std::array<std::string, 2>{ "beta", "gamma" });
116 std::vector<std::function<void()>> tasks;
117
118 // Iterate over all LookupRelations and for each relation create a task that:
119 // 1. Resizes the inverse polynomial based on the max end_index() of the source and destination selector
120 // 2. Computes the logderivative inverse
121 bb::constexpr_for<0, std::tuple_size_v<Flavor::LookupRelations>, 1>([&]<size_t relation_idx>() {
123 tasks.push_back([&]() {
124 // We need to resize the inverse polynomials for the relation, now that the selectors have been computed.
126 Relation::Settings::INVERSES,
127 Relation::Settings::SRC_SELECTOR,
128 Relation::Settings::DST_SELECTOR);
129
130 AVM_TRACK_TIME(std::string("prove/log_derivative_inverse_round/") + std::string(Relation::NAME),
131 (compute_logderivative_inverse<FF, Relation, Flavor::ProverPolynomials, false>(
133 });
134 });
135
136 // Execute all the tasks in parallel
137 bb::parallel_for(tasks.size(), [&](size_t i) { tasks[i](); });
138}
139
141{
142 BB_BENCH_NAME("AvmProver::execute_log_derivative_inverse_commitments_round");
143 auto batch = commitment_key.start_batch();
144 // Commit to all logderivative inverse polynomials and send to verifier
145 for (auto [derived_poly, label] :
146 zip_view(prover_polynomials.get_derived(), prover_polynomials.get_derived_labels())) {
147
148 batch.add_to_batch(derived_poly, label);
149 }
150 batch.commit_and_send_to_verifier(transcript, AVM_MAX_MSM_BATCH_SIZE);
151}
152
158{
159 BB_BENCH_NAME("AvmProver::execute_relation_check_rounds");
160 using Sumcheck = SumcheckProver<Flavor>;
161
162 // Multiply each linearly independent subrelation contribution by `alpha^i` for i = 0, ..., NUM_SUBRELATIONS - 1.
163 const FF alpha = transcript->template get_challenge<FF>("Sumcheck:alpha");
164
165 // Generate gate challenges
166 std::vector<FF> gate_challenges = transcript->template get_dyadic_powers_of_challenge<FF>(
167 "Sumcheck:gate_challenge", ProvingKey::log_circuit_size);
168
169 Sumcheck sumcheck(ProvingKey::circuit_size,
172 alpha,
173 gate_challenges,
176
177 sumcheck_output = sumcheck.prove();
178}
179
192{
193 BB_BENCH_NAME("AvmProver::execute_pcs_rounds");
194
196 using PolynomialBatcher = GeminiProver_<Curve>::PolynomialBatcher;
197 using Challenges = Flavor::AllEntities<FF>;
198
199 // Batch polynomials using short scalars
200 auto unshifted_polys = prover_polynomials.get_unshifted();
201 auto shifted_polys = prover_polynomials.get_to_be_shifted();
202
203 // Get short batching challenges from transcript
204 Challenges challenges;
205 auto unshifted_challenges_vec = transcript->template get_challenges<FF>(challenges.get_unshifted_labels());
206 std::ranges::move(unshifted_challenges_vec, challenges.get_unshifted().begin());
207 auto unshifted_challenges = challenges.get_unshifted();
208 auto shifted_challenges = challenges.get_to_be_shifted();
209
210 auto index_of_max_end_index = [](const auto& polys) {
211 // this assumes non-empty, returns an iterator
212 auto it = std::ranges::max_element(
213 polys.begin(), polys.end(), [](const auto& a, const auto& b) { return a.end_index() < b.end_index(); });
214
215 // retrieves the index of the max element
216 return static_cast<size_t>(std::distance(polys.begin(), it));
217 };
218
219 auto add_scaled_batched =
220 [](Polynomial& dst, const std::span<Polynomial>& sources, const std::span<FF>& scalars, const size_t skip_idx) {
221 const size_t num_slots = bb::get_num_cpus();
222 std::vector<Polynomial> batched_polys(num_slots);
223 for (auto& poly : batched_polys) {
224 poly = Polynomial(dst.size(), dst.virtual_size(), dst.start_index());
225 }
226
227 // Chunks are consumed dynamically via an atomic counter: faster threads naturally pick up
228 // more chunks while the slot they write to stays fixed for the life of their outer task.
229 std::atomic<size_t> next_poly(0);
230
231 // Accumulate polynomials: each thread picks up the next available polynomial
232 parallel_for(num_slots, [&](size_t slot_id) {
233 while (true) {
234 const size_t poly_id = next_poly.fetch_add(1, std::memory_order_relaxed);
235 if (poly_id >= sources.size()) {
236 break;
237 }
238 if (poly_id == skip_idx) {
239 continue;
240 }
241
242 const size_t start_idx = sources[poly_id].start_index();
243 const size_t end_idx = sources[poly_id].end_index();
244 for (size_t idx = start_idx; idx < end_idx; idx++) {
245 batched_polys[slot_id].at(idx) += scalars[poly_id] * sources[poly_id][idx];
246 }
247 }
248 });
249
250 for (const auto& poly : batched_polys) {
251 dst += poly;
252 }
253 };
254
255 // Batch to be shifted polys in their to_be_shifted form
256 // Search for poly with largest end index to avoid allocating a zero polynomial of circuit size
257 size_t max_idx = index_of_max_end_index(shifted_polys);
258
259 Polynomial batched_shifted = std::move(shifted_polys[max_idx]);
260 batched_shifted *= shifted_challenges[max_idx];
261 add_scaled_batched(batched_shifted, shifted_polys, shifted_challenges, max_idx);
262
263 // Batch unshifted polys (to avoid allocating a zero polynomial of circuit size, we initialize the batched
264 // polynomial with the polynomial of the largest size)
265 max_idx = index_of_max_end_index(unshifted_polys);
266
267 Polynomial batched_unshifted = std::move(unshifted_polys[max_idx]);
268 batched_unshifted *= unshifted_challenges[max_idx];
269 batched_unshifted += batched_shifted;
270 add_scaled_batched(batched_unshifted,
271 unshifted_polys.subspan(0, WIRES_TO_BE_SHIFTED_START_IDX),
272 unshifted_challenges.subspan(0, WIRES_TO_BE_SHIFTED_START_IDX),
273 max_idx);
274 add_scaled_batched(batched_unshifted,
275 unshifted_polys.subspan(WIRES_TO_BE_SHIFTED_END_IDX),
276 unshifted_challenges.subspan(WIRES_TO_BE_SHIFTED_END_IDX),
278 : unshifted_polys.size());
279
280 const size_t circuit_dyadic_size = numeric::round_up_power_2(batched_unshifted.end_index());
281
282 PolynomialBatcher polynomial_batcher(circuit_dyadic_size);
283 polynomial_batcher.set_unshifted(RefVector{ batched_unshifted });
284 polynomial_batcher.set_to_be_shifted_by_one(RefVector{ batched_shifted });
285
286 const OpeningClaim prover_opening_claim = ShpleminiProver_<Curve>::prove(
287 circuit_dyadic_size, polynomial_batcher, sumcheck_output.challenge, commitment_key, transcript);
288
290}
291
293{
294 return transcript->export_proof();
295}
296
298{
299 // Add vk hash to transcript.
301
302 // Add public inputs to transcript.
303 AVM_TRACK_TIME("prove/public_inputs_round", execute_public_inputs_round());
304
305 // Compute wire commitments.
306 AVM_TRACK_TIME("prove/wire_commitments_round", execute_wire_commitments_round());
307
308 // Compute log derivative inverses.
309 AVM_TRACK_TIME("prove/log_derivative_inverse_round", execute_log_derivative_inverse_round());
310
311 // Compute commitments to logderivative inverse polynomials.
312 AVM_TRACK_TIME("prove/log_derivative_inverse_commitments_round",
314
315 // Run sumcheck subprotocol.
317
318 // Execute PCS.
319 AVM_TRACK_TIME("prove/pcs_rounds", execute_pcs_rounds());
320
321 return export_proof();
322}
323} // namespace bb::avm2
#define AVM_PUBLIC_INPUTS_COLUMNS_MAX_LENGTH
#define BB_BENCH_NAME(name)
Definition bb_bench.hpp:264
CommitmentKey object over a pairing group 𝔾₁.
CommitBatch start_batch()
Class responsible for computation of the batched multilinear polynomials required by the Gemini proto...
Definition gemini.hpp:128
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
Unverified claim (C,r,v) for some witness polynomial p(X) such that.
Definition claim.hpp:55
size_t start_index() const
std::size_t virtual_size() const
size_t end_index() const
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
Polynomial p and an opening pair (r,v) such that p(r) = v.
Definition claim.hpp:36
A template class for a reference vector. Behaves as if std::vector<T&> was possible.
A wrapper for Relations to expose methods used by the Sumcheck prover or verifier to add the contribu...
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
The implementation of the sumcheck Prover for statements of the form for multilinear polynomials .
Definition sumcheck.hpp:294
DataType & get(ColumnAndShifts c)
Definition flavor.hpp:146
static constexpr size_t log_circuit_size
Definition flavor.hpp:207
static constexpr size_t circuit_size
Definition flavor.hpp:206
AvmFlavorSettings::FF FF
Definition flavor.hpp:43
void execute_pcs_rounds()
Run the PCS to prove that the claimed evaluations are correct.
Definition prover.cpp:191
std::shared_ptr< Transcript > transcript
Definition prover.hpp:46
SumcheckOutput< Flavor > sumcheck_output
Definition prover.hpp:58
PCSCommitmentKey commitment_key
Definition prover.hpp:60
std::shared_ptr< VerificationKey > vk
Definition prover.hpp:53
void execute_relation_check_rounds()
Run Sumcheck resulting in u = (u_1,...,u_d) challenges and all evaluations at u being calculated.
Definition prover.cpp:157
void execute_preamble_round()
Add vk hash to transcript.
Definition prover.cpp:55
ProverPolynomials prover_polynomials
Definition prover.hpp:56
Flavor::Polynomial Polynomial
Definition prover.hpp:24
void execute_log_derivative_inverse_commitments_round()
Definition prover.cpp:140
void execute_log_derivative_inverse_round()
Definition prover.cpp:109
bb::RelationParameters< FF > relation_parameters
Definition prover.hpp:50
Flavor::FF FF
Definition prover.hpp:18
AvmProver(std::shared_ptr< ProvingKey > input_proving_key, std::shared_ptr< VerificationKey > vk, const PCSCommitmentKey &commitment_key)
Definition prover.cpp:42
HonkProof construct_proof()
Definition prover.cpp:297
void execute_public_inputs_round()
Add public inputs to transcript.
Definition prover.cpp:69
void execute_wire_commitments_round()
Compute commitments to all of the witness wires (apart from the logderivative inverse wires)
Definition prover.cpp:97
HonkProof export_proof()
Definition prover.cpp:292
#define vinfo(...)
Definition log.hpp:94
FF a
FF b
void resize_inverses(AvmFlavor::ProverPolynomials &prover_polynomials, Column inverses_col, Column src_selector_col, Column dst_selector_col)
constexpr auto WIRES_TO_BE_SHIFTED_END_IDX
Definition columns.hpp:67
const size_t AVM_MAX_MSM_BATCH_SIZE
Definition prover.cpp:28
AvmFlavorSettings::FF FF
Definition field.hpp:10
constexpr auto WIRES_TO_BE_SHIFTED_START_IDX
Definition columns.hpp:66
ColumnAndShifts
Definition columns.hpp:34
constexpr T round_up_power_2(const T in)
Definition get_msb.hpp:76
std::vector< fr > HonkProof
Definition proof.hpp:15
size_t get_num_cpus()
Definition thread.cpp:33
void parallel_for(size_t num_iterations, const std::function< void(size_t)> &func)
Definition thread.cpp:111
VerifierCommitmentKey< Curve > vk
STL namespace.
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
std::string to_string(bb::avm2::ValueTag tag)
#define AVM_TRACK_TIME(key, body)
Definition stats.hpp:18
void add_to_batch(Polynomial< Fr > &poly, const std::string &label, const Polynomial< Fr > *tail=nullptr)