Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
acir_format.cpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: not started, auditors: [], date: YYYY-MM-DD }
3// external_1: { status: not started, auditors: [], date: YYYY-MM-DD }
4// external_2: { status: not started, auditors: [], date: YYYY-MM-DD }
5// =====================
6
7#include "acir_format.hpp"
8
30
31#include <cstddef>
32#include <cstdint>
33#include <memory>
34
35namespace acir_format {
36
37using namespace bb;
38
39template <typename Builder>
41 const std::vector<OpeningClaim<stdlib::grumpkin<Builder>>>& nested_ipa_claims,
42 const std::vector<stdlib::Proof<Builder>>& nested_ipa_proofs);
43
44template <typename Builder>
47 const std::vector<OpeningClaim<stdlib::grumpkin<Builder>>>& nested_ipa_claims,
48 const std::vector<stdlib::Proof<Builder>>& nested_ipa_proofs);
49
50template <typename Builder> struct HonkRecursionConstraintsOutput {
55 bool is_root_rollup = false;
56
57 template <class T>
58 void update(T& other, bool update_ipa_data)
61 {
62 // Update points accumulator
63 if (this->points_accumulator.has_data) {
64 this->points_accumulator.aggregate(other.points_accumulator);
65 } else {
66 this->points_accumulator = other.points_accumulator;
67 }
68
69 if (update_ipa_data) {
71 // Update ipa proofs and claims
72 this->nested_ipa_proofs.push_back(other.ipa_proof);
73 this->nested_ipa_claims.push_back(other.ipa_claim);
74 } else {
75 // Update ipa proofs and claims (if other has no proofs/claims, we are not appending anything)
76 this->nested_ipa_proofs.insert(
77 this->nested_ipa_proofs.end(), other.nested_ipa_proofs.begin(), other.nested_ipa_proofs.end());
78 this->nested_ipa_claims.insert(
79 this->nested_ipa_claims.end(), other.nested_ipa_claims.begin(), other.nested_ipa_claims.end());
80 }
81 }
82 }
83};
84
85template <typename Builder>
87{
89 bool has_valid_witness_assignments = !program.witness.empty();
90 bool collect_gates_per_opcode = metadata.collect_gates_per_opcode;
91 AcirFormat& constraint_system = program.constraints;
92
93 if (collect_gates_per_opcode) {
94 constraint_system.gates_per_opcode.resize(constraint_system.num_acir_opcodes, 0);
95 }
96
97 GateCounter gate_counter{ &builder, collect_gates_per_opcode };
98
99 // Add arithmetic gates
100 for (size_t i = 0; i < constraint_system.poly_triple_constraints.size(); ++i) {
101 const auto& constraint = constraint_system.poly_triple_constraints.at(i);
102 builder.create_poly_gate(constraint);
103 gate_counter.track_diff(constraint_system.gates_per_opcode,
104 constraint_system.original_opcode_indices.poly_triple_constraints.at(i));
105 }
106
107 for (size_t i = 0; i < constraint_system.quad_constraints.size(); ++i) {
108 const auto& constraint = constraint_system.quad_constraints.at(i);
109 builder.create_big_mul_gate(constraint);
110 gate_counter.track_diff(constraint_system.gates_per_opcode,
111 constraint_system.original_opcode_indices.quad_constraints.at(i));
112 }
113 // Oversize gates are a vector of mul_quad gates.
114 for (size_t i = 0; i < constraint_system.big_quad_constraints.size(); ++i) {
115 auto& big_constraint = constraint_system.big_quad_constraints.at(i);
116 fr next_w4_wire_value = fr(0);
117 // Define the 4th wire of these mul_quad gates, which is implicitly used by the previous gate.
118 for (size_t j = 0; j < big_constraint.size() - 1; ++j) {
119 if (j == 0) {
120 next_w4_wire_value = builder.get_variable(big_constraint[0].d);
121 } else {
122 uint32_t next_w4_wire = builder.add_variable(next_w4_wire_value);
123 big_constraint[j].d = next_w4_wire;
124 big_constraint[j].d_scaling = fr(-1);
125 }
126 builder.create_big_mul_add_gate(big_constraint[j], true);
127 next_w4_wire_value = builder.get_variable(big_constraint[j].a) * builder.get_variable(big_constraint[j].b) *
128 big_constraint[j].mul_scaling +
129 builder.get_variable(big_constraint[j].a) * big_constraint[j].a_scaling +
130 builder.get_variable(big_constraint[j].b) * big_constraint[j].b_scaling +
131 builder.get_variable(big_constraint[j].c) * big_constraint[j].c_scaling +
132 next_w4_wire_value * big_constraint[j].d_scaling + big_constraint[j].const_scaling;
133 next_w4_wire_value = -next_w4_wire_value;
134 }
135 uint32_t next_w4_wire = builder.add_variable(next_w4_wire_value);
136 big_constraint.back().d = next_w4_wire;
137 big_constraint.back().d_scaling = fr(-1);
138 builder.create_big_mul_add_gate(big_constraint.back(), false);
139 }
140
141 // Add logic constraint
142 for (size_t i = 0; i < constraint_system.logic_constraints.size(); ++i) {
143 const auto& constraint = constraint_system.logic_constraints.at(i);
145 builder, constraint.a, constraint.b, constraint.result, constraint.num_bits, constraint.is_xor_gate);
146 gate_counter.track_diff(constraint_system.gates_per_opcode,
147 constraint_system.original_opcode_indices.logic_constraints.at(i));
148 }
149
150 // Add range constraint
151 // preprocessing: remove range constraints if they are implied by memory operations
152 for (auto const& index_range : constraint_system.index_range) {
153 if (constraint_system.minimal_range[index_range.first] == index_range.second) {
154 constraint_system.minimal_range.erase(index_range.first);
155 }
156 }
157 for (size_t i = 0; i < constraint_system.range_constraints.size(); ++i) {
158 const auto& constraint = constraint_system.range_constraints.at(i);
159 uint32_t range = constraint.num_bits;
160 if (constraint_system.minimal_range.contains(constraint.witness)) {
161 range = constraint_system.minimal_range[constraint.witness];
162 builder.create_range_constraint(constraint.witness, range, "");
163 gate_counter.track_diff(constraint_system.gates_per_opcode,
164 constraint_system.original_opcode_indices.range_constraints.at(i));
165 // no need to add more range constraints for this witness.
166 constraint_system.minimal_range.erase(constraint.witness);
167 }
168 }
169
170 // Add aes128 constraints
171 for (size_t i = 0; i < constraint_system.aes128_constraints.size(); ++i) {
172 const auto& constraint = constraint_system.aes128_constraints.at(i);
174 gate_counter.track_diff(constraint_system.gates_per_opcode,
175 constraint_system.original_opcode_indices.aes128_constraints.at(i));
176 }
177
178 // Add sha256 constraints
179 for (size_t i = 0; i < constraint_system.sha256_compression.size(); ++i) {
180 const auto& constraint = constraint_system.sha256_compression[i];
182 gate_counter.track_diff(constraint_system.gates_per_opcode,
183 constraint_system.original_opcode_indices.sha256_compression[i]);
184 }
185
186 // Add ECDSA k1 constraints
187 for (size_t i = 0; i < constraint_system.ecdsa_k1_constraints.size(); ++i) {
188 const auto& constraint = constraint_system.ecdsa_k1_constraints.at(i);
189 create_ecdsa_verify_constraints<stdlib::secp256k1<Builder>>(builder, constraint, has_valid_witness_assignments);
190 gate_counter.track_diff(constraint_system.gates_per_opcode,
191 constraint_system.original_opcode_indices.ecdsa_k1_constraints.at(i));
192 }
193
194 // Add ECDSA r1 constraints
195 for (size_t i = 0; i < constraint_system.ecdsa_r1_constraints.size(); ++i) {
196 const auto& constraint = constraint_system.ecdsa_r1_constraints.at(i);
197 create_ecdsa_verify_constraints<stdlib::secp256r1<Builder>>(builder, constraint, has_valid_witness_assignments);
198 gate_counter.track_diff(constraint_system.gates_per_opcode,
199 constraint_system.original_opcode_indices.ecdsa_r1_constraints.at(i));
200 }
201
202 // Add blake2s constraints
203 for (size_t i = 0; i < constraint_system.blake2s_constraints.size(); ++i) {
204 const auto& constraint = constraint_system.blake2s_constraints.at(i);
206 gate_counter.track_diff(constraint_system.gates_per_opcode,
207 constraint_system.original_opcode_indices.blake2s_constraints.at(i));
208 }
209
210 // Add blake3 constraints
211 for (size_t i = 0; i < constraint_system.blake3_constraints.size(); ++i) {
212 const auto& constraint = constraint_system.blake3_constraints.at(i);
214 gate_counter.track_diff(constraint_system.gates_per_opcode,
215 constraint_system.original_opcode_indices.blake3_constraints.at(i));
216 }
217
218 // Add keccak permutations
219 for (size_t i = 0; i < constraint_system.keccak_permutations.size(); ++i) {
220 const auto& constraint = constraint_system.keccak_permutations[i];
222 gate_counter.track_diff(constraint_system.gates_per_opcode,
223 constraint_system.original_opcode_indices.keccak_permutations[i]);
224 }
225
226 for (size_t i = 0; i < constraint_system.poseidon2_constraints.size(); ++i) {
227 const auto& constraint = constraint_system.poseidon2_constraints.at(i);
229 gate_counter.track_diff(constraint_system.gates_per_opcode,
230 constraint_system.original_opcode_indices.poseidon2_constraints.at(i));
231 }
232
233 // Add multi scalar mul constraints
234 for (size_t i = 0; i < constraint_system.multi_scalar_mul_constraints.size(); ++i) {
235 const auto& constraint = constraint_system.multi_scalar_mul_constraints.at(i);
236 create_multi_scalar_mul_constraint(builder, constraint, has_valid_witness_assignments);
237 gate_counter.track_diff(constraint_system.gates_per_opcode,
239 }
240
241 // Add ec add constraints
242 for (size_t i = 0; i < constraint_system.ec_add_constraints.size(); ++i) {
243 const auto& constraint = constraint_system.ec_add_constraints.at(i);
244 create_ec_add_constraint(builder, constraint, has_valid_witness_assignments);
245 gate_counter.track_diff(constraint_system.gates_per_opcode,
246 constraint_system.original_opcode_indices.ec_add_constraints.at(i));
247 }
248
249 // Add block constraints
250 for (size_t i = 0; i < constraint_system.block_constraints.size(); ++i) {
251 const auto& constraint = constraint_system.block_constraints.at(i);
252 create_block_constraints(builder, constraint, has_valid_witness_assignments);
253 if (collect_gates_per_opcode) {
254 size_t avg_gates_per_opcode =
255 gate_counter.compute_diff() / constraint_system.original_opcode_indices.block_constraints.at(i).size();
256 for (size_t opcode_index : constraint_system.original_opcode_indices.block_constraints.at(i)) {
257 constraint_system.gates_per_opcode[opcode_index] = avg_gates_per_opcode;
258 }
259 }
260 }
261
262 // assert equals
263 for (size_t i = 0; i < constraint_system.assert_equalities.size(); ++i) {
264 const auto& constraint = constraint_system.assert_equalities.at(i);
265 builder.assert_equal(constraint.a, constraint.b);
266 gate_counter.track_diff(constraint_system.gates_per_opcode,
267 constraint_system.original_opcode_indices.assert_equalities.at(i));
268 }
269
270 // RecursionConstraints
271 bool has_honk_recursion_constraints = !constraint_system.honk_recursion_constraints.empty();
272 bool has_avm_recursion_constraints = !constraint_system.avm_recursion_constraints.empty();
273 bool has_pg_recursion_constraints = !constraint_system.pg_recursion_constraints.empty();
274 bool has_civc_recursion_constraints = !constraint_system.civc_recursion_constraints.empty();
275
276 if constexpr (IsMegaBuilder<Builder>) {
277 // We shouldn't have both honk recursion constraints and pg recursion constraints.
278 BB_ASSERT_EQ(!has_honk_recursion_constraints || !has_pg_recursion_constraints,
279 true,
280 "Invalid circuit: both honk and ivc recursion constraints present.");
281
282 // AVM constraints are not handled when using MegaBuilder
283 if (has_avm_recursion_constraints) {
284 info("WARNING: this circuit contains unhandled avm_recursion_constraints!");
285 }
286
287 if (has_honk_recursion_constraints) {
289 builder, constraint_system, has_valid_witness_assignments, gate_counter);
290
291 // Propagate pairing points
293 inputs.pairing_inputs = output.points_accumulator;
294 inputs.set_public();
295 } else if (has_pg_recursion_constraints) {
297 builder, constraint_system, metadata.ivc, has_valid_witness_assignments, gate_counter);
298 } else {
299 // If its an app circuit that has no recursion constraints, add default pairing points to public inputs.
301 }
302 } else {
303 bool is_recursive_circuit = metadata.honk_recursion != 0;
304 bool has_pairing_points =
305 has_honk_recursion_constraints || has_civc_recursion_constraints || has_avm_recursion_constraints;
306
307 // We only handle:
308 // - CIVC recursion constraints (Private Base Rollup)
309 // - HONK + AVM recursion constraints (Public Base Rollup)
310 // - HONK recursion constraints
311 // - AVM recursion constraints
312 // However, as mock protocol circuits use CIVC + AVM (mock Public Base Rollup), instead of throwing an assert we
313 // return a vinfo for the case of CIVC + AVM
314 BB_ASSERT_EQ(has_pg_recursion_constraints,
315 false,
316 "Invalid circuit: pg recursion constraints are present with UltraBuilder.");
317 BB_ASSERT_EQ(!(has_civc_recursion_constraints && has_honk_recursion_constraints),
318 true,
319 "Invalid circuit: both honk and civc recursion constraints are present.");
321 !(has_honk_recursion_constraints || has_civc_recursion_constraints || has_avm_recursion_constraints) ||
322 is_recursive_circuit,
323 true,
324 "Invalid circuit: honk, civc, or avm recursion constraints present but the circuit is not recursive.");
325 if (has_civc_recursion_constraints && has_avm_recursion_constraints) {
326 vinfo("WARNING: both civc and avm recursion constraints are present. While we support this combination, we "
327 "expect to see it only in a mock "
328 "circuit.");
329 }
330
331 // Container for data to be propagated
333
334 if (has_honk_recursion_constraints) {
336 builder, constraint_system, has_valid_witness_assignments, gate_counter);
337 }
338
339 if (has_civc_recursion_constraints) {
341 builder, constraint_system, has_valid_witness_assignments, gate_counter);
342 }
343
344#ifndef DISABLE_AZTEC_VM
345 if (has_avm_recursion_constraints) {
347 builder, constraint_system, has_valid_witness_assignments, gate_counter);
348
349 // Update honk_output: append (potentially 0) ipa claims and proofs.
350 // If honk output has points accumulator, aggregate it with the one coming from the avm. Otherwise, override
351 // it with the avm's one.
352 honk_output.update(avm_output, /*update_ipa_data=*/!avm_output.nested_ipa_claims.empty());
353 }
354#endif
355
356 if (metadata.honk_recursion == 2) {
357 // Proving with UltraRollupFlavor
358
359 // Propagate pairing points
360 if (has_pairing_points) {
361 honk_output.points_accumulator.set_public();
362 } else {
364 }
365
366 // Handle IPA
367 auto [ipa_claim, ipa_proof] =
369
370 // Set proof
371 builder.ipa_proof = ipa_proof;
372
373 // Propagate IPA claim
374 ipa_claim.set_public();
375 } else {
376 // If it is a recursive circuit, propagate pairing points
377 if (metadata.honk_recursion == 1) {
379
380 if (has_pairing_points) {
381 IO inputs;
382 inputs.pairing_inputs = honk_output.points_accumulator;
383 inputs.set_public();
384 } else {
385 IO::add_default(builder);
386 }
387 }
388
389 // Handle IPA
390 if (honk_output.is_root_rollup) {
392 } else {
393 // We shouldn't accidentally have IPA proofs otherwise.
394 BB_ASSERT_EQ(honk_output.nested_ipa_proofs.size(),
395 static_cast<size_t>(0),
396 "IPA proofs present when not expected.");
397 }
398 }
399 }
400} // namespace acir_format
401
410template <typename Builder>
412 const std::vector<OpeningClaim<stdlib::grumpkin<Builder>>>& nested_ipa_claims,
413 const std::vector<stdlib::Proof<Builder>>& nested_ipa_proofs)
414{
416
418 nested_ipa_claims.size(), nested_ipa_proofs.size(), "Mismatched number of nested IPA claims and proofs.");
419 BB_ASSERT_EQ(nested_ipa_claims.size(), 2U, "Root rollup must have two nested IPA claims.");
420
421 auto [ipa_claim, ipa_proof] = handle_IPA_accumulation(builder, nested_ipa_claims, nested_ipa_proofs);
422
423 // IPA verification
425 &builder, 1 << CONST_ECCVM_LOG_N, VerifierCommitmentKey<curve::Grumpkin>(1 << CONST_ECCVM_LOG_N));
426
427 auto accumulated_ipa_transcript = std::make_shared<StdlibTranscript>();
428 accumulated_ipa_transcript->load_proof(stdlib::Proof<Builder>(builder, ipa_proof));
429 IPA<stdlib::grumpkin<Builder>>::full_verify_recursive(
430 verifier_commitment_key, ipa_claim, accumulated_ipa_transcript);
431}
432
441template <typename Builder>
444 const std::vector<OpeningClaim<stdlib::grumpkin<Builder>>>& nested_ipa_claims,
445 const std::vector<stdlib::Proof<Builder>>& nested_ipa_proofs)
446{
448 nested_ipa_claims.size(), nested_ipa_proofs.size(), "Mismatched number of nested IPA claims and proofs.");
449
451 HonkProof final_ipa_proof;
452
453 if (nested_ipa_claims.size() == 2) {
454 // If we have two claims, accumulate.
455 CommitmentKey<curve::Grumpkin> commitment_key(1 << CONST_ECCVM_LOG_N);
457
458 auto ipa_transcript_1 = std::make_shared<StdlibTranscript>();
459 ipa_transcript_1->load_proof(nested_ipa_proofs[0]);
460 auto ipa_transcript_2 = std::make_shared<StdlibTranscript>();
461 ipa_transcript_2->load_proof(nested_ipa_proofs[1]);
462 auto [ipa_claim, ipa_proof] = IPA<stdlib::grumpkin<Builder>>::accumulate(
463 commitment_key, ipa_transcript_1, nested_ipa_claims[0], ipa_transcript_2, nested_ipa_claims[1]);
464
465 final_ipa_claim = ipa_claim;
466 final_ipa_proof = ipa_proof;
467 } else if (nested_ipa_claims.size() == 1) {
468 // If we have one claim, just forward it along.
469 final_ipa_claim = nested_ipa_claims[0];
470 // This conversion looks suspicious but there's no need to make this an output of the circuit since
471 // its a proof that will be checked anyway.
472 final_ipa_proof = nested_ipa_proofs[0].get_value();
473 } else if (nested_ipa_claims.empty()) {
474 // If we don't have any claims, we may need to inject a fake one if we're proving with
475 // UltraRollupHonk, indicated by the manual setting of the honk_recursion metadata to 2.
476 info("Proving with UltraRollupHonk but no IPA claims exist.");
477 auto [stdlib_opening_claim, ipa_proof] =
478 IPA<stdlib::grumpkin<Builder>>::create_random_valid_ipa_claim_and_proof(builder);
479
480 final_ipa_claim = stdlib_opening_claim;
481 final_ipa_proof = ipa_proof;
482 } else {
483 // We don't support and shouldn't expect to support circuits with 3+ IPA recursive verifiers.
484 throw_or_abort("Too many nested IPA claims to accumulate");
485 }
486
487 BB_ASSERT_EQ(final_ipa_proof.size(), IPA_PROOF_LENGTH);
488
489 // Return the IPA claim and proof
490 return { final_ipa_claim, final_ipa_proof };
491}
492
493template <typename Builder>
494[[nodiscard("IPA claim and Pairing points should be accumulated")]] HonkRecursionConstraintsOutput<Builder>
496 AcirFormat& constraint_system,
497 bool has_valid_witness_assignments,
498 GateCounter<Builder>& gate_counter)
499{
501 // Add recursion constraints
502 size_t idx = 0;
503 for (auto& constraint : constraint_system.honk_recursion_constraints) {
504 HonkRecursionConstraintOutput<Builder> honk_recursion_constraint;
505
506 if (constraint.proof_type == HONK_ZK) {
507 honk_recursion_constraint = create_honk_recursion_constraints<UltraZKRecursiveFlavor_<Builder>>(
508 builder, constraint, has_valid_witness_assignments);
509 } else if (constraint.proof_type == HONK) {
510 honk_recursion_constraint = create_honk_recursion_constraints<UltraRecursiveFlavor_<Builder>>(
511 builder, constraint, has_valid_witness_assignments);
512 } else if (constraint.proof_type == ROLLUP_HONK || constraint.proof_type == ROOT_ROLLUP_HONK) {
513 if constexpr (!IsUltraBuilder<Builder>) {
514 throw_or_abort("Rollup Honk proof type not supported on MegaBuilder");
515 } else {
516 honk_recursion_constraint = create_honk_recursion_constraints<UltraRollupRecursiveFlavor_<Builder>>(
517 builder, constraint, has_valid_witness_assignments);
518 }
519 } else {
520 throw_or_abort("Invalid Honk proof type");
521 }
522
523 // Update output
524 output.update(honk_recursion_constraint,
525 /*update_ipa_data=*/constraint.proof_type == ROLLUP_HONK ||
526 constraint.proof_type == ROOT_ROLLUP_HONK);
527 output.is_root_rollup = constraint.proof_type == ROOT_ROLLUP_HONK;
528
529 gate_counter.track_diff(constraint_system.gates_per_opcode,
530 constraint_system.original_opcode_indices.honk_recursion_constraints.at(idx++));
531 }
532 ASSERT(!(output.is_root_rollup && output.nested_ipa_claims.size() != 2),
533 "Root rollup must accumulate two IPA proofs.");
534 return output;
535}
536
538 AcirFormat& constraints,
540 bool has_valid_witness_assignments,
542{
543 using StdlibVerificationKey = ClientIVC::RecursiveVerificationKey;
544 using StdlibVKAndHash = ClientIVC::RecursiveVKAndHash;
545 using StdlibFF = ClientIVC::RecursiveFlavor::FF;
546
547 // Lambda template to handle both ClientIVC and SumcheckClientIVC with the same code
548 auto process_with_ivc = [&]<typename IVCType>(const std::shared_ptr<IVCType>& ivc) {
549 // We expect the length of the internal verification queue to match the number of ivc recursion constraints
550 BB_ASSERT_EQ(constraints.pg_recursion_constraints.size(),
551 ivc->verification_queue.size(),
552 "WARNING: Mismatch in number of recursive verifications during kernel creation!");
553
554 // If no witness is provided, populate the VK and public inputs in the recursion constraint with dummy values
555 // so that the present kernel circuit is constructed correctly. (Used for constructing VKs without witnesses).
556 if (!has_valid_witness_assignments) {
557 // Create stdlib representations of each {proof, vkey} pair to be recursively verified
558 for (auto [constraint, queue_entry] :
559 zip_view(constraints.pg_recursion_constraints, ivc->verification_queue)) {
560 populate_dummy_vk_in_constraint(builder, queue_entry.honk_vk, constraint.key);
561 builder.set_variable(constraint.key_hash, queue_entry.honk_vk->hash());
562 }
563 }
564
565 // Construct a stdlib verification key for each constraint based on the verification key witness indices
566 // therein
568 stdlib_vk_and_hashs.reserve(constraints.pg_recursion_constraints.size());
569 for (const auto& constraint : constraints.pg_recursion_constraints) {
570 stdlib_vk_and_hashs.push_back(std::make_shared<StdlibVKAndHash>(
572 StdlibVerificationKey::from_witness_indices(builder, constraint.key)),
573 StdlibFF::from_witness_index(&builder, constraint.key_hash)));
574 }
575 // Create stdlib representations of each {proof, vkey} pair to be recursively verified
576 ivc->instantiate_stdlib_verification_queue(builder, stdlib_vk_and_hashs);
577
578 // Connect the public_input witnesses in each constraint to the corresponding public input witnesses in the
579 // internal verification queue. This ensures that the witnesses utilized in constraints generated based on acir
580 // are properly connected to the constraints generated herein via the ivc scheme (e.g. recursive
581 // verifications).
582 for (auto [constraint, queue_entry] :
583 zip_view(constraints.pg_recursion_constraints, ivc->stdlib_verification_queue)) {
584
585 // Get the witness indices for the public inputs contained within the proof in the verification queue
586 std::vector<uint32_t> public_input_indices =
588 constraint.public_inputs.size());
589
590 // Assert equality between the internal public input witness indices and those in the acir constraint
591 for (auto [witness_idx, constraint_witness_idx] :
592 zip_view(public_input_indices, constraint.public_inputs)) {
593 builder.assert_equal(witness_idx, constraint_witness_idx);
594 }
595 }
596
597 // Complete the kernel circuit with all required recursive verifications, databus consistency checks etc.
598 ivc->complete_kernel_circuit_logic(builder);
599
600 // Note: we can't easily track the gate contribution from each individual pg_recursion_constraint since they
601 // are handled simultaneously in the above function call; instead we track the total contribution
602 gate_counter.track_diff(constraints.gates_per_opcode,
604 };
605
606 // If an ivc instance is not provided, we mock one with the state required to construct the recursion
607 // constraints present in the program. This is for when we write_vk.
608 if (ivc_base == nullptr) {
611 process_with_ivc(mock_ivc);
612 } else {
613 auto mock_ivc =
614 create_mock_ivc_from_constraints(constraints.pg_recursion_constraints, { AZTEC_TRACE_STRUCTURE });
615 process_with_ivc(mock_ivc);
616 }
617 } else {
618 // Use the global flag to cast to the correct IVC type
620 auto sumcheck_ivc = std::static_pointer_cast<SumcheckClientIVC>(ivc_base);
621 process_with_ivc(sumcheck_ivc);
622 } else {
623 auto ivc = std::static_pointer_cast<ClientIVC>(ivc_base);
624 process_with_ivc(ivc);
625 }
626 }
627}
628
629[[nodiscard("IPA claim and Pairing points should be accumulated")]] HonkRecursionConstraintsOutput<Builder>
631 AcirFormat& constraint_system,
632 bool has_valid_witness_assignments,
633 GateCounter<Builder>& gate_counter)
634{
636 // Add recursion constraints
637 size_t idx = 0;
638 for (auto& constraint : constraint_system.civc_recursion_constraints) {
640 create_civc_recursion_constraints(builder, constraint, has_valid_witness_assignments);
641
642 // Update the output
643 output.update(honk_output, /*update_ipa_data=*/true);
644
645 gate_counter.track_diff(constraint_system.gates_per_opcode,
646 constraint_system.original_opcode_indices.civc_recursion_constraints.at(idx++));
647 }
648
649 return output;
650}
651
652#ifndef DISABLE_AZTEC_VM
653[[nodiscard("IPA claim and Pairing points should be accumulated")]] HonkRecursionConstraintsOutput<Builder>
655 AcirFormat& constraint_system,
656 bool has_valid_witness_assignments,
657 GateCounter<Builder>& gate_counter)
658{
660 // Add recursion constraints
661 size_t idx = 0;
662 for (auto& constraint : constraint_system.avm_recursion_constraints) {
663 HonkRecursionConstraintOutput<Builder> avm2_recursion_output =
664 create_avm2_recursion_constraints_goblin(builder, constraint, has_valid_witness_assignments);
665
666 // Update the output
667 output.update(avm2_recursion_output, /*update_ipa_data=*/true);
668
669 gate_counter.track_diff(constraint_system.gates_per_opcode,
670 constraint_system.original_opcode_indices.avm_recursion_constraints.at(idx++));
671 }
672 return output;
673}
674#endif // DISABLE_AZTEC_VM
675
682template <> UltraCircuitBuilder create_circuit(AcirProgram& program, const ProgramMetadata& metadata)
683{
684 BB_BENCH();
685 AcirFormat& constraints = program.constraints;
686 WitnessVector& witness = program.witness;
687
688 Builder builder{ metadata.size_hint, witness, constraints.public_inputs, constraints.varnum };
689
690 build_constraints(builder, program, metadata);
691
692 vinfo("created circuit");
693
694 return builder;
695};
696
703template <> MegaCircuitBuilder create_circuit(AcirProgram& program, const ProgramMetadata& metadata)
704{
705 BB_BENCH();
706 AcirFormat& constraints = program.constraints;
707 WitnessVector& witness = program.witness;
708
709 auto op_queue = (metadata.ivc == nullptr) ? std::make_shared<ECCOpQueue>() : metadata.ivc->get_goblin().op_queue;
710
711 // Construct a builder using the witness and public input data from acir and with the goblin-owned op_queue
712 auto builder = MegaCircuitBuilder{ op_queue, witness, constraints.public_inputs, constraints.varnum };
713
714 // Populate constraints in the builder via the data in constraint_system
715 build_constraints(builder, program, metadata);
716
717 return builder;
718};
719
721
722} // namespace acir_format
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:88
#define ASSERT(expression,...)
Definition assert.hpp:77
#define BB_BENCH()
Definition bb_bench.hpp:222
Shared type definitions for the Barretenberg RPC API.
Utility class for tracking the gate count of acir constraints.
void track_diff(std::vector< size_t > &gates_per_opcode, size_t opcode_index)
static std::vector< uint32_t > get_public_inputs_witness_indices_from_proof(const bb::stdlib::Proof< bb::MegaCircuitBuilder > &proof, const size_t num_public_inputs_to_extract)
Get the witness indices for a given number of public inputs contained within a stdlib proof.
Common transcript class for both parties. Stores the data for the current round, as well as the manif...
RecursiveFlavor::VKAndHash RecursiveVKAndHash
RecursiveFlavor::VerificationKey RecursiveVerificationKey
CommitmentKey object over a pairing group 𝔾₁.
IPA (inner product argument) commitment scheme class.
Definition ipa.hpp:93
typename Curve::ScalarField FF
Unverified claim (C,r,v) for some witness polynomial p(X) such that.
Definition claim.hpp:53
An object storing two bn254 points that represent the inputs to a pairing check.
Representation of the Grumpkin Verifier Commitment Key inside a bn254 circuit.
A simple wrapper around a vector of stdlib field elements representing a proof.
Definition proof.hpp:19
Manages the data that is propagated on the public inputs of an application/function circuit.
void set_public()
Set each IO component to be a public input of the underlying circuit.
static void add_default(Builder &builder)
Add default public inputs when they are not present.
#define vinfo(...)
Definition log.hpp:79
void info(Args... args)
Definition log.hpp:74
AluTraceBuilder builder
Definition alu.test.cpp:123
FF a
FF b
Base class templates for structures that contain data parameterized by the fundamental polynomials of...
void perform_full_IPA_verification(Builder &builder, const std::vector< OpeningClaim< stdlib::grumpkin< Builder > > > &nested_ipa_claims, const std::vector< stdlib::Proof< Builder > > &nested_ipa_proofs)
Perform full recursive IPA verification.
template void build_constraints< MegaCircuitBuilder >(MegaCircuitBuilder &, AcirProgram &, const ProgramMetadata &)
void process_pg_recursion_constraints(MegaCircuitBuilder &builder, AcirFormat &constraints, std::shared_ptr< IVCBase > ivc_base, bool has_valid_witness_assignments, GateCounter< MegaCircuitBuilder > &gate_counter)
void build_constraints(Builder &builder, AcirProgram &program, const ProgramMetadata &metadata)
void create_block_constraints(UltraCircuitBuilder &builder, const BlockConstraint &constraint, bool has_valid_witness_assignments)
Create block constraints; Specialization for Ultra arithmetization.
void create_ec_add_constraint(Builder &builder, const EcAdd &input, bool has_valid_witness_assignments)
void create_blake3_constraints(Builder &builder, const Blake3Constraint &constraint)
void create_multi_scalar_mul_constraint(Builder &builder, const MultiScalarMul &input, bool has_valid_witness_assignments)
HonkRecursionConstraintsOutput< Builder > process_civc_recursion_constraints(Builder &builder, AcirFormat &constraint_system, bool has_valid_witness_assignments, GateCounter< Builder > &gate_counter)
void create_keccak_permutations(Builder &builder, const Keccakf1600 &constraint)
void create_blake2s_constraints(Builder &builder, const Blake2sConstraint &constraint)
HonkRecursionConstraintOutput< Builder > create_civc_recursion_constraints(Builder &builder, const RecursionConstraint &input, bool has_valid_witness_assignments)
Add constraints associated with recursive verification of an CIVC proof.
std::pair< OpeningClaim< stdlib::grumpkin< Builder > >, HonkProof > handle_IPA_accumulation(Builder &builder, const std::vector< OpeningClaim< stdlib::grumpkin< Builder > > > &nested_ipa_claims, const std::vector< stdlib::Proof< Builder > > &nested_ipa_proofs)
Set the IPA claim and proof.
UltraCircuitBuilder create_circuit(AcirProgram &program, const ProgramMetadata &metadata)
Specialization for creating an Ultra circuit from an acir program.
HonkRecursionConstraintOutput< Builder > create_avm2_recursion_constraints_goblin(Builder &builder, const RecursionConstraint &input, bool has_valid_witness_assignments)
Add constraints associated with recursive verification of an AVM2 proof using Goblin.
std::shared_ptr< SumcheckClientIVC > create_mock_sumcheck_ivc_from_constraints(const std::vector< RecursionConstraint > &constraints)
std::shared_ptr< ClientIVC > create_mock_ivc_from_constraints(const std::vector< RecursionConstraint > &constraints, const TraceSettings &trace_settings)
Create an IVC object with mocked state corresponding to a set of IVC recursion constraints.
void create_sha256_compression_constraints(Builder &builder, const Sha256Compression &constraint)
HonkRecursionConstraintsOutput< Builder > process_honk_recursion_constraints(Builder &builder, AcirFormat &constraint_system, bool has_valid_witness_assignments, GateCounter< Builder > &gate_counter)
void populate_dummy_vk_in_constraint(MegaCircuitBuilder &builder, const std::shared_ptr< MegaFlavor::VerificationKey > &mock_verification_key, std::vector< uint32_t > &key_witness_indices)
Populate VK witness fields from a recursion constraint from a provided VerificationKey.
void create_aes128_constraints(Builder &builder, const AES128Constraint &constraint)
HonkRecursionConstraintsOutput< Builder > process_avm_recursion_constraints(Builder &builder, AcirFormat &constraint_system, bool has_valid_witness_assignments, GateCounter< Builder > &gate_counter)
bb::SlabVector< bb::fr > WitnessVector
void create_poseidon2_permutations(Builder &builder, const Poseidon2Constraint &constraint)
void create_logic_gate(Builder &builder, const WitnessOrConstant< bb::fr > a, const WitnessOrConstant< bb::fr > b, const uint32_t result, const size_t num_bits, const bool is_xor_gate)
bool USE_SUMCHECK_IVC
Global flag to control whether to use SumcheckClientIVC instead of ClientIVC.
Entry point for Barretenberg command-line interface.
std::vector< fr > HonkProof
Definition proof.hpp:15
field< Bn254FrParams > fr
Definition fr.hpp:174
BaseTranscript< stdlib::StdlibCodec< stdlib::field_t< UltraCircuitBuilder > >, stdlib::poseidon2< UltraCircuitBuilder > > UltraStdlibTranscript
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
std::vector< MultiScalarMul > multi_scalar_mul_constraints
std::vector< Blake2sConstraint > blake2s_constraints
std::vector< Sha256Compression > sha256_compression
bb::SlabVector< PolyTripleConstraint > poly_triple_constraints
bb::SlabVector< std::vector< bb::mul_quad_< bb::curve::BN254::ScalarField > > > big_quad_constraints
std::vector< Poseidon2Constraint > poseidon2_constraints
std::vector< LogicConstraint > logic_constraints
std::vector< EcAdd > ec_add_constraints
std::vector< RecursionConstraint > pg_recursion_constraints
std::map< uint32_t, uint32_t > index_range
std::vector< Keccakf1600 > keccak_permutations
std::vector< RecursionConstraint > honk_recursion_constraints
std::vector< Blake3Constraint > blake3_constraints
std::vector< EcdsaConstraint > ecdsa_r1_constraints
std::vector< RangeConstraint > range_constraints
std::vector< bb::poly_triple_< bb::curve::BN254::ScalarField > > assert_equalities
std::vector< AES128Constraint > aes128_constraints
std::map< uint32_t, uint32_t > minimal_range
AcirFormatOriginalOpcodeIndices original_opcode_indices
bb::SlabVector< bb::mul_quad_< bb::curve::BN254::ScalarField > > quad_constraints
std::vector< BlockConstraint > block_constraints
std::vector< EcdsaConstraint > ecdsa_k1_constraints
std::vector< uint32_t > public_inputs
std::vector< size_t > gates_per_opcode
std::vector< RecursionConstraint > avm_recursion_constraints
std::vector< RecursionConstraint > civc_recursion_constraints
std::vector< std::vector< size_t > > block_constraints
void update(T &other, bool update_ipa_data)
std::vector< stdlib::Proof< Builder > > nested_ipa_proofs
std::vector< OpeningClaim< stdlib::grumpkin< Builder > > > nested_ipa_claims
std::shared_ptr< bb::IVCBase > ivc
Curve grumpkin in circuit setting.
Definition grumpkin.hpp:21
static void add_default_to_public_inputs(Builder &builder)
Adds default public inputs to the builder.
void aggregate(PairingPoints const &other)
Compute a linear combination of the present pairing points with an input set of pairing points.
void throw_or_abort(std::string const &err)