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
28using FF = Flavor::FF;
29
40 const PCSCommitmentKey& commitment_key)
41 : proving_key(std::move(input_proving_key))
42 , vk(std::move(vk))
43 , prover_polynomials(*proving_key)
44 , commitment_key(commitment_key)
45{}
46
52{
53 FF vk_hash = vk->get_hash();
54 transcript->add_to_hash_buffer("avm_vk_hash", vk_hash);
55 vinfo("AVM vk hash in prover: ", vk_hash);
56}
57
66{
67 BB_BENCH_NAME("AvmProver::execute_public_inputs_round");
68
69 using C = ColumnAndShifts;
70 // Add the public inputs to the transcript so that the Sumcheck challenge depends both on the public inputs sent in
71 // the clear and the commitments to the columns that are purtported to contain them.
73 C::public_inputs_cols_0_,
74 C::public_inputs_cols_1_,
75 C::public_inputs_cols_2_,
76 C::public_inputs_cols_3_,
77 };
78
79 for (size_t i = 0; i < public_input_columns.size(); ++i) {
80 const Polynomial& public_input_col = prover_polynomials.get(public_input_columns[i]);
81 size_t public_input_col_size = public_input_col.size();
82 for (size_t j = 0; j < AVM_PUBLIC_INPUTS_COLUMNS_MAX_LENGTH; ++j) {
83 // The public inputs are added to the hash buffer, but do not increase the size of the proof
84 transcript->add_to_hash_buffer("public_input_" + std::to_string(i) + "_" + std::to_string(j),
85 j < public_input_col_size ? public_input_col.at(j) : FF(0));
86 }
87 }
88}
94{
95 BB_BENCH_NAME("AvmProver::execute_wire_commitments_round");
96 // Commit to all polynomials (apart from logderivative inverse polynomials, which are committed to in the later
97 // logderivative phase)
98 auto batch = commitment_key.start_batch();
99 for (const auto& [poly, label] : zip_view(prover_polynomials.get_wires(), prover_polynomials.get_wires_labels())) {
100 batch.add_to_batch(poly, label);
101 }
102 batch.commit_and_send_to_verifier(transcript);
103}
104
106{
107 BB_BENCH_NAME("AvmProver::execute_log_derivative_inverse_round");
108
109 auto [beta, gamma] = transcript->template get_challenges<FF>(std::array<std::string, 2>{ "beta", "gamma" });
112 std::vector<std::function<void()>> tasks;
113
114 // Iterate over all LookupRelations and for each relation create a task that:
115 // 1. Resizes the inverse polynomial based on the max end_index() of the source and destination selector
116 // 2. Computes the logderivative inverse
117 bb::constexpr_for<0, std::tuple_size_v<Flavor::LookupRelations>, 1>([&]<size_t relation_idx>() {
119 tasks.push_back([&]() {
120 // We need to resize the inverse polynomials for the relation, now that the selectors have been computed.
122 Relation::Settings::INVERSES,
123 Relation::Settings::SRC_SELECTOR,
124 Relation::Settings::DST_SELECTOR);
125
126 AVM_TRACK_TIME(std::string("prove/log_derivative_inverse_round/") + std::string(Relation::NAME),
127 (compute_logderivative_inverse<FF, Relation, Flavor::ProverPolynomials, false>(
129 });
130 });
131
132 // Execute all the tasks in parallel
133 bb::parallel_for(tasks.size(), [&](size_t i) { tasks[i](); });
134}
135
137{
138 BB_BENCH_NAME("AvmProver::execute_log_derivative_inverse_commitments_round");
139 auto batch = commitment_key.start_batch();
140 // Commit to all logderivative inverse polynomials and send to verifier
141 for (auto [derived_poly, label] :
142 zip_view(prover_polynomials.get_derived(), prover_polynomials.get_derived_labels())) {
143
144 batch.add_to_batch(derived_poly, label);
145 }
146 batch.commit_and_send_to_verifier(transcript);
147}
148
154{
155 BB_BENCH_NAME("AvmProver::execute_relation_check_rounds");
156 using Sumcheck = SumcheckProver<Flavor>;
157
158 // Multiply each linearly independent subrelation contribution by `alpha^i` for i = 0, ..., NUM_SUBRELATIONS - 1.
159 const FF alpha = transcript->template get_challenge<FF>("Sumcheck:alpha");
160
161 // Generate gate challenges
162 std::vector<FF> gate_challenges = transcript->template get_dyadic_powers_of_challenge<FF>(
163 "Sumcheck:gate_challenge", ProvingKey::log_circuit_size);
164
165 Sumcheck sumcheck(ProvingKey::circuit_size,
168 alpha,
169 gate_challenges,
172
173 sumcheck_output = sumcheck.prove();
174}
175
188{
189 BB_BENCH_NAME("AvmProver::execute_pcs_rounds");
190
192 using PolynomialBatcher = GeminiProver_<Curve>::PolynomialBatcher;
193 using Challenges = Flavor::AllEntities<FF>;
194
195 // Batch polynomials using short scalars
196 auto unshifted_polys = prover_polynomials.get_unshifted();
197 auto shifted_polys = prover_polynomials.get_to_be_shifted();
198
199 // Get short batching challenges from transcript
200 Challenges challenges;
201 auto unshifted_challenges_vec = transcript->template get_challenges<FF>(challenges.get_unshifted_labels());
202 std::ranges::move(unshifted_challenges_vec, challenges.get_unshifted().begin());
203 auto unshifted_challenges = challenges.get_unshifted();
204 auto shifted_challenges = challenges.get_to_be_shifted();
205
206 auto index_of_max_end_index = [](const auto& polys) {
207 // this assumes non-empty, returns an iterator
208 auto it = std::ranges::max_element(
209 polys.begin(), polys.end(), [](const auto& a, const auto& b) { return a.end_index() < b.end_index(); });
210
211 // retrieves the index of the max element
212 return static_cast<size_t>(std::distance(polys.begin(), it));
213 };
214
215 auto add_scaled_batched =
216 [](Polynomial& dst, const std::span<Polynomial>& sources, const std::span<FF>& scalars, const size_t skip_idx) {
217 const size_t num_slots = bb::get_num_cpus();
218 std::vector<Polynomial> batched_polys(num_slots);
219 for (auto& poly : batched_polys) {
220 poly = Polynomial(dst.size(), dst.virtual_size(), dst.start_index());
221 }
222
223 // Chunks are consumed dynamically via an atomic counter: faster threads naturally pick up
224 // more chunks while the slot they write to stays fixed for the life of their outer task.
225 std::atomic<size_t> next_poly(0);
226
227 // Accumulate polynomials: each thread picks up the next available polynomial
228 parallel_for(num_slots, [&](size_t slot_id) {
229 while (true) {
230 const size_t poly_id = next_poly.fetch_add(1, std::memory_order_relaxed);
231 if (poly_id >= sources.size()) {
232 break;
233 }
234 if (poly_id == skip_idx) {
235 continue;
236 }
237
238 const size_t start_idx = sources[poly_id].start_index();
239 const size_t end_idx = sources[poly_id].end_index();
240 for (size_t idx = start_idx; idx < end_idx; idx++) {
241 batched_polys[slot_id].at(idx) += scalars[poly_id] * sources[poly_id][idx];
242 }
243 }
244 });
245
246 for (const auto& poly : batched_polys) {
247 dst += poly;
248 }
249 };
250
251 // Batch to be shifted polys in their to_be_shifted form
252 // Search for poly with largest end index to avoid allocating a zero polynomial of circuit size
253 size_t max_idx = index_of_max_end_index(shifted_polys);
254
255 Polynomial batched_shifted = std::move(shifted_polys[max_idx]);
256 batched_shifted *= shifted_challenges[max_idx];
257 add_scaled_batched(batched_shifted, shifted_polys, shifted_challenges, max_idx);
258
259 // Batch unshifted polys (to avoid allocating a zero polynomial of circuit size, we initialize the batched
260 // polynomial with the polynomial of the largest size)
261 max_idx = index_of_max_end_index(unshifted_polys);
262
263 Polynomial batched_unshifted = std::move(unshifted_polys[max_idx]);
264 batched_unshifted *= unshifted_challenges[max_idx];
265 batched_unshifted += batched_shifted;
266 add_scaled_batched(batched_unshifted,
267 unshifted_polys.subspan(0, WIRES_TO_BE_SHIFTED_START_IDX),
268 unshifted_challenges.subspan(0, WIRES_TO_BE_SHIFTED_START_IDX),
269 max_idx);
270 add_scaled_batched(batched_unshifted,
271 unshifted_polys.subspan(WIRES_TO_BE_SHIFTED_END_IDX),
272 unshifted_challenges.subspan(WIRES_TO_BE_SHIFTED_END_IDX),
274 : unshifted_polys.size());
275
276 const size_t circuit_dyadic_size = numeric::round_up_power_2(batched_unshifted.end_index());
277
278 PolynomialBatcher polynomial_batcher(circuit_dyadic_size);
279 polynomial_batcher.set_unshifted(RefVector{ batched_unshifted });
280 polynomial_batcher.set_to_be_shifted_by_one(RefVector{ batched_shifted });
281
282 const OpeningClaim prover_opening_claim = ShpleminiProver_<Curve>::prove(
283 circuit_dyadic_size, polynomial_batcher, sumcheck_output.challenge, commitment_key, transcript);
284
286}
287
289{
290 return transcript->export_proof();
291}
292
294{
295 // Add vk hash to transcript.
297
298 // Add public inputs to transcript.
299 AVM_TRACK_TIME("prove/public_inputs_round", execute_public_inputs_round());
300
301 // Compute wire commitments.
302 AVM_TRACK_TIME("prove/wire_commitments_round", execute_wire_commitments_round());
303
304 // Compute log derivative inverses.
305 AVM_TRACK_TIME("prove/log_derivative_inverse_round", execute_log_derivative_inverse_round());
306
307 // Compute commitments to logderivative inverse polynomials.
308 AVM_TRACK_TIME("prove/log_derivative_inverse_commitments_round",
310
311 // Run sumcheck subprotocol.
313
314 // Execute PCS.
315 AVM_TRACK_TIME("prove/pcs_rounds", execute_pcs_rounds());
316
317 return export_proof();
318}
319} // 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:187
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:153
void execute_preamble_round()
Add vk hash to transcript.
Definition prover.cpp:51
ProverPolynomials prover_polynomials
Definition prover.hpp:56
Flavor::Polynomial Polynomial
Definition prover.hpp:24
void execute_log_derivative_inverse_commitments_round()
Definition prover.cpp:136
void execute_log_derivative_inverse_round()
Definition prover.cpp:105
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:38
HonkProof construct_proof()
Definition prover.cpp:293
void execute_public_inputs_round()
Add public inputs to transcript.
Definition prover.cpp:65
void execute_wire_commitments_round()
Compute commitments to all of the witness wires (apart from the logderivative inverse wires)
Definition prover.cpp:93
HonkProof export_proof()
Definition prover.cpp:288
#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
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, bool has_duplicates_hint=false)