Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
oink_prover.cpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Completed, auditors: [Sergei], commit: }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
21
22namespace bb {
23
24template <typename Relation> constexpr bool relation_computes_logderivative_inverse()
25{
26 if constexpr (requires { Relation::HAS_LOGDERIVATIVE_INVERSE_COMPUTATION; }) {
27 return Relation::HAS_LOGDERIVATIVE_INVERSE_COMPUTATION;
28 }
29 return false;
30}
31
35template <typename Flavor> void OinkProver<Flavor>::prove(bool emit_alpha)
36{
37 BB_BENCH_NAME("OinkProver::prove");
38 const size_t ck_size = prover_instance->polynomials.max_end_index();
39 commitment_key = CommitmentKey(ck_size);
40
41 send_vk_hash_and_public_inputs();
42 commit_to_masking_poly();
43
44 // All masked witness polynomials already have random masking values from allocation.
45 commit_to_wires();
46 commit_to_lookup_counts_and_w4();
47 commit_to_logderiv_inverses();
48 commit_to_z_perm();
49 if (emit_alpha) {
50 prover_instance->alpha = transcript->template get_challenge<FF>("alpha");
51 }
52}
53
59{
60 return transcript->export_proof();
61}
62
67{
68 BB_BENCH_NAME("OinkProver::send_vk_hash_and_public_inputs");
69 fr vk_hash = honk_vk->hash_with_origin_tagging(*transcript);
70 transcript->add_to_hash_buffer("vk_hash", vk_hash);
71 vinfo("vk hash in Oink prover: ", vk_hash);
72
73 for (size_t i = 0; i < prover_instance->num_public_inputs(); ++i) {
74 auto public_input_i = prover_instance->public_inputs[i];
75 transcript->send_to_verifier("public_input_" + std::to_string(i), public_input_i);
76 }
77}
78
83template <typename Flavor> void OinkProver<Flavor>::commit_to_wires()
84{
85 BB_BENCH_NAME("OinkProver::commit_to_wires");
86 auto batch = commitment_key.start_batch();
87
88 // Commit to the first three wire polynomials; w_4 is deferred until after memory records are added
89 // Masking values are already in the polynomials
90 batch.add_to_batch(prover_instance->polynomials.w_l(), commitment_labels.w_l(), /*has_duplicates_hint=*/true);
91 batch.add_to_batch(prover_instance->polynomials.w_r(), commitment_labels.w_r(), /*has_duplicates_hint=*/true);
92 batch.add_to_batch(prover_instance->polynomials.w_o(), commitment_labels.w_o(), /*has_duplicates_hint=*/true);
93
94 if constexpr (Flavor::HasEccOpQueue) {
95 for (auto [polynomial, label] :
96 zip_view(prover_instance->polynomials.get_ecc_op_wires(), commitment_labels.get_ecc_op_wires())) {
97 batch.add_to_batch(polynomial, label);
98 }
99 }
100 if constexpr (Flavor::HasDataBus) {
101 for (auto [polynomial, label] :
102 zip_view(prover_instance->polynomials.get_databus_entities(), commitment_labels.get_databus_entities())) {
103 batch.add_to_batch(polynomial, label);
104 }
105 }
106
107 auto computed_commitments = batch.commit_and_send_to_verifier(transcript);
108 prover_instance->commitments.w_l() = computed_commitments[0];
109 prover_instance->commitments.w_r() = computed_commitments[1];
110 prover_instance->commitments.w_o() = computed_commitments[2];
111
112 size_t commitment_idx = 3;
113 if constexpr (Flavor::HasEccOpQueue) {
114 for (auto& commitment : prover_instance->commitments.get_ecc_op_wires()) {
115 commitment = computed_commitments[commitment_idx++];
116 }
117 }
118 if constexpr (Flavor::HasDataBus) {
119 for (auto& commitment : prover_instance->commitments.get_databus_entities()) {
120 commitment = computed_commitments[commitment_idx++];
121 }
122 }
123}
124
130{
131 BB_BENCH_NAME("OinkProver::commit_to_lookup_counts_and_w4");
132 // The memory relation is the sole consumer of the eta powers and the ROM-LogUp offset
133 // `rom_logup_gamma`, so `Flavor::HasMemory` gates their FS samples and the power computation.
134 // When false, skip them so the verifier (which gates on the same flag) stays in lockstep on the
135 // FS state.
136 if constexpr (Flavor::HasMemory) {
137 auto [eta, rom_logup_gamma] =
138 transcript->template get_challenges<FF>(std::array<std::string, 2>{ "eta", "rom_logup_gamma" });
139 prover_instance->relation_parameters.eta = eta;
140 prover_instance->relation_parameters.eta_two = eta * eta;
141 prover_instance->relation_parameters.eta_three = prover_instance->relation_parameters.eta_two * eta;
142 prover_instance->relation_parameters.rom_logup_gamma = rom_logup_gamma;
143 }
144
145 // Memory record and ROM-LogUp row indices are in the active trace region (after disabled rows), so
146 // masking is preserved
147 add_ram_rom_memory_records_to_wire_4(*prover_instance);
148 add_rom_logup_inverses_to_wire_4(*prover_instance);
149
150 auto batch = commitment_key.start_batch();
151 if constexpr (Flavor::HasLogDerivLookup) {
152 batch.add_to_batch(prover_instance->polynomials.lookup_read_counts(), commitment_labels.lookup_read_counts());
153 batch.add_to_batch(prover_instance->polynomials.lookup_read_tags(), commitment_labels.lookup_read_tags());
154 }
155 batch.add_to_batch(prover_instance->polynomials.w_4(), commitment_labels.w_4(), /*has_duplicates_hint=*/true);
156 auto computed_commitments = batch.commit_and_send_to_verifier(transcript);
157
158 size_t idx = 0;
159 if constexpr (Flavor::HasLogDerivLookup) {
160 prover_instance->commitments.lookup_read_counts() = computed_commitments[idx++];
161 prover_instance->commitments.lookup_read_tags() = computed_commitments[idx++];
162 }
163 prover_instance->commitments.w_4() = computed_commitments[idx++];
164}
165
170template <typename Flavor> void OinkProver<Flavor>::commit_to_logderiv_inverses()
171{
172 BB_BENCH_NAME("OinkProver::commit_to_logderiv_inverses");
173 auto [beta, gamma] = transcript->template get_challenges<FF>(std::array<std::string, 2>{ "beta", "gamma" });
174 prover_instance->relation_parameters.beta = beta;
175 prover_instance->relation_parameters.gamma = gamma;
176 // The log-derivative lookup relation is the sole consumer of the squared/cubed beta powers, so
177 // `Flavor::HasLogDerivLookup` gates their computation. When false, skip the extra multiplications
178 // to stay symmetric with the verifier.
179 if constexpr (Flavor::HasLogDerivLookup) {
180 prover_instance->relation_parameters.beta_sqr = beta * beta;
181 prover_instance->relation_parameters.beta_cube = prover_instance->relation_parameters.beta_sqr * beta;
182 }
183
184 // Compute the inverses used in log-derivative lookup relations
185 // For ZK, computation starts after the disabled head region to preserve masking values
186 compute_logderivative_inverses(*prover_instance);
187
188 auto batch = commitment_key.start_batch();
189 if constexpr (Flavor::HasLogDerivLookup) {
190 batch.add_to_batch(prover_instance->polynomials.lookup_inverses(), commitment_labels.lookup_inverses());
191 }
192
193 if constexpr (Flavor::HasDataBus) {
194 for (auto [polynomial, label] :
195 zip_view(prover_instance->polynomials.get_databus_inverses(), commitment_labels.get_databus_inverses())) {
196 batch.add_to_batch(polynomial, label);
197 };
198 }
199 auto computed_commitments = batch.commit_and_send_to_verifier(transcript);
200
201 size_t commitment_idx = 0;
202 if constexpr (Flavor::HasLogDerivLookup) {
203 prover_instance->commitments.lookup_inverses() = computed_commitments[commitment_idx++];
204 }
205 if constexpr (Flavor::HasDataBus) {
206 for (auto& commitment : prover_instance->commitments.get_databus_inverses()) {
207 commitment = computed_commitments[commitment_idx];
208 commitment_idx++;
209 };
210 }
211}
212
216template <typename Flavor> void OinkProver<Flavor>::commit_to_z_perm()
217{
218 BB_BENCH_NAME("OinkProver::commit_to_z_perm");
219
220 // Grand product computation already starts after the disabled region (gp_start), preserving masking values.
221 // It also measures the adjacent-duplicate z_perm coefficients (rows where the per-row grand-product ratio is
222 // 1, so z_perm is unchanged) as a by-product, avoiding a second full pass over z_perm for the MSM dedup hint.
223 uint32_t z_perm_dup_count = 0;
224 compute_grand_product_polynomial(*prover_instance, z_perm_dup_count);
225
226 auto& z_perm = prover_instance->polynomials.z_perm();
227 auto batch = commitment_key.start_batch();
228 batch.add_to_batch(z_perm, commitment_labels.z_perm(), /*has_duplicates_hint=*/true, z_perm_dup_count);
229 auto commitments = batch.commit_and_send_to_verifier(transcript);
230 prover_instance->commitments.z_perm() = commitments[0];
231}
232
233template <typename Flavor> void OinkProver<Flavor>::commit_to_masking_poly()
234{
235 if constexpr (flavor_has_gemini_masking<Flavor>()) {
236 // Sparse 2d-coefficient mask on the tail-halving support (dense random for tiny circuits).
237 // See SHPLEMINI_ZK_MASKING.md for the rank / ZK argument.
238 const size_t dyadic_size = prover_instance->dyadic_size();
239 const size_t d = numeric::get_msb(dyadic_size);
240 prover_instance->polynomials.gemini_masking_poly() =
241 build_gemini_masking_poly<FF>(d, prover_instance->polynomials.max_end_index(), dyadic_size);
242
243 typename Flavor::Commitment masking_commitment;
244 {
245 BB_BENCH_NAME("Oink::commit_masking_poly_msm");
246 masking_commitment = commitment_key.commit(prover_instance->polynomials.gemini_masking_poly());
247 }
248 transcript->send_to_verifier("Gemini:masking_poly_comm", masking_commitment);
249 }
250};
251
262{
263 BB_BENCH_NAME("OinkProver::add_ram_rom_memory_records_to_wire_4");
264 // The memory record values are computed at the indicated indices as
265 // w4 = w3 * eta^3 + w2 * eta^2 + w1 * eta + read_write_flag;
266 // (See the Memory relation for details)
267 auto wires = instance.polynomials.get_wires();
268 const auto& eta = instance.relation_parameters.eta;
269 const auto& eta_two = instance.relation_parameters.eta_two;
270 const auto& eta_three = instance.relation_parameters.eta_three;
271
272 // Compute read record values
273 for (const auto& gate_idx : instance.memory_read_records) {
274 wires[3].at(gate_idx) = wires[2][gate_idx] * eta_three;
275 wires[3].at(gate_idx) += wires[1][gate_idx] * eta_two;
276 wires[3].at(gate_idx) += wires[0][gate_idx] * eta;
277 }
278
279 // Compute write record values
280 for (const auto& gate_idx : instance.memory_write_records) {
281 wires[3].at(gate_idx) = wires[2][gate_idx] * eta_three;
282 wires[3].at(gate_idx) += wires[1][gate_idx] * eta_two;
283 wires[3].at(gate_idx) += wires[0][gate_idx] * eta;
284 wires[3].at(gate_idx) += 1;
285 }
286}
287
299{
300 BB_BENCH_NAME("OinkProver::add_rom_logup_inverses_to_wire_4");
301 if (instance.rom_logup_records.empty()) {
302 return;
303 }
304 auto wires = instance.polynomials.get_wires();
305 const auto& q_c = instance.polynomials.q_c();
306 const auto& eta = instance.relation_parameters.eta;
307 const auto& eta_two = instance.relation_parameters.eta_two;
308 const auto& rom_logup_gamma = instance.relation_parameters.rom_logup_gamma;
309
310 // The denominators are nonzero with overwhelming probability over the choice of rom_logup_gamma
311 std::vector<FF> denominators;
312 denominators.reserve(instance.rom_logup_records.size());
313 for (const auto& gate_idx : instance.rom_logup_records) {
314 const FF index_val = wires[0][gate_idx];
315 const FF value_val = wires[1][gate_idx];
316 const FF array_id = q_c[gate_idx]; // q_c carries the ROM array id
317 denominators.emplace_back(rom_logup_gamma + index_val + eta * value_val + eta_two * array_id);
318 }
319 FF::batch_invert(denominators);
320 for (size_t i = 0; i < instance.rom_logup_records.size(); ++i) {
321 wires[3].at(instance.rom_logup_records[i]) = denominators[i];
322 }
323}
324
332{
333 BB_BENCH_NAME("compute_logderivative_inverses");
334
335 auto& polynomials = instance.polynomials;
336 auto& relation_parameters = instance.relation_parameters;
337 const size_t circuit_size = instance.dyadic_size();
338
339 // Skip the disabled head region to preserve masking values
340 constexpr size_t start = ProverInstance::TRACE_OFFSET;
341
342 // Iterate the flavor's relation tuple at compile time. Relations that explicitly opt into
343 // inverse-polynomial computation participate, so the TS relation list determines the work
344 // without Oink knowing how many bus columns a flavor declares.
345 using Relations = typename Flavor::template Relations_<FF>;
346 bb::constexpr_for<0, std::tuple_size_v<Relations>, 1>([&]<size_t i>() {
348 if constexpr (relation_computes_logderivative_inverse<Relation>()) {
349 Relation::compute_logderivative_inverse(polynomials, relation_parameters, circuit_size, start);
350 }
351 });
352}
353
359template <typename Flavor>
361{
362 BB_BENCH_NAME("OinkProver::compute_grand_product_polynomial");
363 auto& relation_parameters = instance.relation_parameters;
364 relation_parameters.public_input_delta = compute_public_input_delta<Flavor>(
365 instance.public_inputs, relation_parameters.beta, relation_parameters.gamma, instance.pub_inputs_offset());
366
367 // Compute permutation grand product polynomial, measuring adjacent-duplicate z_perm coefficients
368 // (rows where the per-row ratio is 1) into `z_perm_dup_count` for the MSM dedup hint, as a
369 // by-product of Step 1.
370 compute_grand_product<Flavor, UltraPermutationRelation<FF>>(
371 instance.polynomials, relation_parameters, instance.get_final_active_wire_idx() + 1, &z_perm_dup_count);
372}
373
374template class OinkProver<UltraFlavor>;
375template class OinkProver<UltraZKFlavor>;
376template class OinkProver<UltraKeccakFlavor>;
377#ifdef STARKNET_GARAGA_FLAVORS
380#endif
382template class OinkProver<MegaFlavor>;
383template class OinkProver<MegaZKFlavor>;
384template class OinkProver<MegaAvmFlavor>;
385template class OinkProver<MegaAppFlavor>;
386template class OinkProver<MegaKernelFlavor>;
387
388} // namespace bb
#define BB_BENCH_NAME(name)
Definition bb_bench.hpp:264
typename G1::affine_element Commitment
Executes the "Oink" phase of the Honk proving protocol: the initial rounds that commit to witness dat...
void prove(bool emit_alpha=true)
Commit to witnesses, compute relation parameters, and prepare for Sumcheck.
Proof export_proof()
Export the Oink proof.
static void compute_logderivative_inverses(ProverInstance &instance)
Compute the inverse polynomials used in the log derivative lookup relations.
void commit_to_logderiv_inverses()
Compute log derivative inverse polynomial and its commitment, if required.
void send_vk_hash_and_public_inputs()
Hash the verification key and send public inputs to the transcript.
static void add_rom_logup_inverses_to_wire_4(ProverInstance &instance)
Populate the inverse helper w_4 = 1 / (rom_logup_gamma + w_1 + eta * w_2 + eta_two * q_c) at every RO...
static void add_ram_rom_memory_records_to_wire_4(ProverInstance &instance)
Add RAM/ROM memory records to the fourth wire polynomial.
typename Flavor::CommitmentKey CommitmentKey
static void compute_grand_product_polynomial(ProverInstance &instance, uint32_t &z_perm_dup_count)
Computes public_input_delta and the permutation grand product polynomial.
typename Flavor::FF FF
void commit_to_lookup_counts_and_w4()
Compute sorted witness-table accumulator and commit to the resulting polynomials.
void commit_to_z_perm()
Compute the permutation grand product polynomial and commit to it.
void commit_to_masking_poly()
void commit_to_wires()
Commit to the wire polynomials (part of the witness), with the exception of the fourth wire,...
typename Transcript::Proof Proof
Contains all the information required by a Honk prover to create a proof, constructed from a finalize...
size_t pub_inputs_offset() const
std::vector< uint32_t > memory_write_records
static constexpr size_t TRACE_OFFSET
RelationParameters< FF > relation_parameters
size_t get_final_active_wire_idx() const
ProverPolynomials polynomials
size_t dyadic_size() const
std::vector< FF > public_inputs
std::vector< uint32_t > memory_read_records
std::vector< uint32_t > rom_logup_records
A wrapper for Relations to expose methods used by the Sumcheck prover or verifier to add the contribu...
#define vinfo(...)
Definition log.hpp:94
std::string label
constexpr T get_msb(const T in)
Definition get_msb.hpp:50
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
constexpr bool relation_computes_logderivative_inverse()
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
std::string to_string(bb::avm2::ValueTag tag)
static void batch_invert(C &coeffs) noexcept
Batch invert a collection of field elements using Montgomery's trick.