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
29
30#include <cstddef>
31#include <cstdint>
32#include <memory>
33
34namespace acir_format {
35
36using namespace bb;
37
40
41template <typename Builder>
43 const std::vector<OpeningClaim<stdlib::grumpkin<Builder>>>& nested_ipa_claims,
44 const std::vector<stdlib::Proof<Builder>>& nested_ipa_proofs);
45
46template <typename Builder>
49 const std::vector<OpeningClaim<stdlib::grumpkin<Builder>>>& nested_ipa_claims,
50 const std::vector<stdlib::Proof<Builder>>& nested_ipa_proofs);
51
52template <typename Builder> struct HonkRecursionConstraintsOutput {
57 bool is_root_rollup = false;
58
59 template <class T>
60 void update(T& other, bool update_ipa_data)
63 {
64 // Update points accumulator
65 if (this->points_accumulator.has_data) {
66 this->points_accumulator.aggregate(other.points_accumulator);
67 } else {
68 this->points_accumulator = other.points_accumulator;
69 }
70
71 if (update_ipa_data) {
73 // Update ipa proofs and claims
74 this->nested_ipa_proofs.push_back(other.ipa_proof);
75 this->nested_ipa_claims.push_back(other.ipa_claim);
76 } else {
77 // Update ipa proofs and claims (if other has no proofs/claims, we are not appending anything)
78 this->nested_ipa_proofs.insert(
79 this->nested_ipa_proofs.end(), other.nested_ipa_proofs.begin(), other.nested_ipa_proofs.end());
80 this->nested_ipa_claims.insert(
81 this->nested_ipa_claims.end(), other.nested_ipa_claims.begin(), other.nested_ipa_claims.end());
82 }
83 }
84 }
85};
86
87template <typename Builder>
89{
91 bool has_valid_witness_assignments = !program.witness.empty();
92 bool collect_gates_per_opcode = metadata.collect_gates_per_opcode;
93 AcirFormat& constraint_system = program.constraints;
94
95 if (collect_gates_per_opcode) {
96 constraint_system.gates_per_opcode.resize(constraint_system.num_acir_opcodes, 0);
97 }
98
99 GateCounter gate_counter{ &builder, collect_gates_per_opcode };
100
101 // Add arithmetic gates
102 for (size_t i = 0; i < constraint_system.poly_triple_constraints.size(); ++i) {
103 const auto& constraint = constraint_system.poly_triple_constraints.at(i);
104 builder.create_poly_gate(constraint);
105 gate_counter.track_diff(constraint_system.gates_per_opcode,
106 constraint_system.original_opcode_indices.poly_triple_constraints.at(i));
107 }
108
109 for (size_t i = 0; i < constraint_system.quad_constraints.size(); ++i) {
110 const auto& constraint = constraint_system.quad_constraints.at(i);
111 builder.create_big_mul_gate(constraint);
112 gate_counter.track_diff(constraint_system.gates_per_opcode,
113 constraint_system.original_opcode_indices.quad_constraints.at(i));
114 }
115 // Oversize gates are a vector of mul_quad gates.
116 for (size_t i = 0; i < constraint_system.big_quad_constraints.size(); ++i) {
117 auto& big_constraint = constraint_system.big_quad_constraints.at(i);
118 fr next_w4_wire_value = fr(0);
119 // Define the 4th wire of these mul_quad gates, which is implicitly used by the previous gate.
120 for (size_t j = 0; j < big_constraint.size() - 1; ++j) {
121 if (j == 0) {
122 next_w4_wire_value = builder.get_variable(big_constraint[0].d);
123 } else {
124 uint32_t next_w4_wire = builder.add_variable(next_w4_wire_value);
125 big_constraint[j].d = next_w4_wire;
126 big_constraint[j].d_scaling = fr(-1);
127 }
128 builder.create_big_mul_add_gate(big_constraint[j], true);
129 next_w4_wire_value = builder.get_variable(big_constraint[j].a) * builder.get_variable(big_constraint[j].b) *
130 big_constraint[j].mul_scaling +
131 builder.get_variable(big_constraint[j].a) * big_constraint[j].a_scaling +
132 builder.get_variable(big_constraint[j].b) * big_constraint[j].b_scaling +
133 builder.get_variable(big_constraint[j].c) * big_constraint[j].c_scaling +
134 next_w4_wire_value * big_constraint[j].d_scaling + big_constraint[j].const_scaling;
135 next_w4_wire_value = -next_w4_wire_value;
136 }
137 uint32_t next_w4_wire = builder.add_variable(next_w4_wire_value);
138 big_constraint.back().d = next_w4_wire;
139 big_constraint.back().d_scaling = fr(-1);
140 builder.create_big_mul_add_gate(big_constraint.back(), false);
141 }
142
143 // Add logic constraint
144 for (size_t i = 0; i < constraint_system.logic_constraints.size(); ++i) {
145 const auto& constraint = constraint_system.logic_constraints.at(i);
147 builder, constraint.a, constraint.b, constraint.result, constraint.num_bits, constraint.is_xor_gate);
148 gate_counter.track_diff(constraint_system.gates_per_opcode,
149 constraint_system.original_opcode_indices.logic_constraints.at(i));
150 }
151
152 // Add range constraint
153 // preprocessing: remove range constraints if they are implied by memory operations
154 for (auto const& index_range : constraint_system.index_range) {
155 if (constraint_system.minimal_range[index_range.first] == index_range.second) {
156 constraint_system.minimal_range.erase(index_range.first);
157 }
158 }
159 for (size_t i = 0; i < constraint_system.range_constraints.size(); ++i) {
160 const auto& constraint = constraint_system.range_constraints.at(i);
161 uint32_t range = constraint.num_bits;
162 if (constraint_system.minimal_range.contains(constraint.witness)) {
163 range = constraint_system.minimal_range[constraint.witness];
164 builder.create_range_constraint(constraint.witness, range, "");
165 gate_counter.track_diff(constraint_system.gates_per_opcode,
166 constraint_system.original_opcode_indices.range_constraints.at(i));
167 // no need to add more range constraints for this witness.
168 constraint_system.minimal_range.erase(constraint.witness);
169 }
170 }
171
172 // Add aes128 constraints
173 for (size_t i = 0; i < constraint_system.aes128_constraints.size(); ++i) {
174 const auto& constraint = constraint_system.aes128_constraints.at(i);
176 gate_counter.track_diff(constraint_system.gates_per_opcode,
177 constraint_system.original_opcode_indices.aes128_constraints.at(i));
178 }
179
180 // Add sha256 constraints
181 for (size_t i = 0; i < constraint_system.sha256_compression.size(); ++i) {
182 const auto& constraint = constraint_system.sha256_compression[i];
184 gate_counter.track_diff(constraint_system.gates_per_opcode,
185 constraint_system.original_opcode_indices.sha256_compression[i]);
186 }
187
188 // Add ECDSA k1 constraints
189 for (size_t i = 0; i < constraint_system.ecdsa_k1_constraints.size(); ++i) {
190 const auto& constraint = constraint_system.ecdsa_k1_constraints.at(i);
191 create_ecdsa_verify_constraints<stdlib::secp256k1<Builder>>(builder, constraint, has_valid_witness_assignments);
192 gate_counter.track_diff(constraint_system.gates_per_opcode,
193 constraint_system.original_opcode_indices.ecdsa_k1_constraints.at(i));
194 }
195
196 // Add ECDSA r1 constraints
197 for (size_t i = 0; i < constraint_system.ecdsa_r1_constraints.size(); ++i) {
198 const auto& constraint = constraint_system.ecdsa_r1_constraints.at(i);
199 create_ecdsa_verify_constraints<stdlib::secp256r1<Builder>>(builder, constraint, has_valid_witness_assignments);
200 gate_counter.track_diff(constraint_system.gates_per_opcode,
201 constraint_system.original_opcode_indices.ecdsa_r1_constraints.at(i));
202 }
203
204 // Add blake2s constraints
205 for (size_t i = 0; i < constraint_system.blake2s_constraints.size(); ++i) {
206 const auto& constraint = constraint_system.blake2s_constraints.at(i);
208 gate_counter.track_diff(constraint_system.gates_per_opcode,
209 constraint_system.original_opcode_indices.blake2s_constraints.at(i));
210 }
211
212 // Add blake3 constraints
213 for (size_t i = 0; i < constraint_system.blake3_constraints.size(); ++i) {
214 const auto& constraint = constraint_system.blake3_constraints.at(i);
216 gate_counter.track_diff(constraint_system.gates_per_opcode,
217 constraint_system.original_opcode_indices.blake3_constraints.at(i));
218 }
219
220 // Add keccak permutations
221 for (size_t i = 0; i < constraint_system.keccak_permutations.size(); ++i) {
222 const auto& constraint = constraint_system.keccak_permutations[i];
224 gate_counter.track_diff(constraint_system.gates_per_opcode,
225 constraint_system.original_opcode_indices.keccak_permutations[i]);
226 }
227
228 for (size_t i = 0; i < constraint_system.poseidon2_constraints.size(); ++i) {
229 const auto& constraint = constraint_system.poseidon2_constraints.at(i);
231 gate_counter.track_diff(constraint_system.gates_per_opcode,
232 constraint_system.original_opcode_indices.poseidon2_constraints.at(i));
233 }
234
235 // Add multi scalar mul constraints
236 for (size_t i = 0; i < constraint_system.multi_scalar_mul_constraints.size(); ++i) {
237 const auto& constraint = constraint_system.multi_scalar_mul_constraints.at(i);
238 create_multi_scalar_mul_constraint(builder, constraint, has_valid_witness_assignments);
239 gate_counter.track_diff(constraint_system.gates_per_opcode,
241 }
242
243 // Add ec add constraints
244 for (size_t i = 0; i < constraint_system.ec_add_constraints.size(); ++i) {
245 const auto& constraint = constraint_system.ec_add_constraints.at(i);
246 create_ec_add_constraint(builder, constraint, has_valid_witness_assignments);
247 gate_counter.track_diff(constraint_system.gates_per_opcode,
248 constraint_system.original_opcode_indices.ec_add_constraints.at(i));
249 }
250
251 // Add block constraints
252 for (size_t i = 0; i < constraint_system.block_constraints.size(); ++i) {
253 const auto& constraint = constraint_system.block_constraints.at(i);
254 create_block_constraints(builder, constraint, has_valid_witness_assignments);
255 if (collect_gates_per_opcode) {
256 size_t avg_gates_per_opcode =
257 gate_counter.compute_diff() / constraint_system.original_opcode_indices.block_constraints.at(i).size();
258 for (size_t opcode_index : constraint_system.original_opcode_indices.block_constraints.at(i)) {
259 constraint_system.gates_per_opcode[opcode_index] = avg_gates_per_opcode;
260 }
261 }
262 }
263
264 // Add big_int constraints
265 DSLBigInts<Builder> dsl_bigints;
266 dsl_bigints.set_builder(&builder);
267 for (size_t i = 0; i < constraint_system.bigint_from_le_bytes_constraints.size(); ++i) {
268 const auto& constraint = constraint_system.bigint_from_le_bytes_constraints.at(i);
269 create_bigint_from_le_bytes_constraint(builder, constraint, dsl_bigints);
270 gate_counter.track_diff(constraint_system.gates_per_opcode,
272 }
273
274 for (size_t i = 0; i < constraint_system.bigint_operations.size(); ++i) {
275 const auto& constraint = constraint_system.bigint_operations[i];
276 create_bigint_operations_constraint<Builder>(constraint, dsl_bigints, has_valid_witness_assignments);
277 gate_counter.track_diff(constraint_system.gates_per_opcode,
278 constraint_system.original_opcode_indices.bigint_operations[i]);
279 }
280
281 for (size_t i = 0; i < constraint_system.bigint_to_le_bytes_constraints.size(); ++i) {
282 const auto& constraint = constraint_system.bigint_to_le_bytes_constraints.at(i);
283 create_bigint_to_le_bytes_constraint(builder, constraint, dsl_bigints);
284 gate_counter.track_diff(constraint_system.gates_per_opcode,
286 }
287
288 // assert equals
289 for (size_t i = 0; i < constraint_system.assert_equalities.size(); ++i) {
290 const auto& constraint = constraint_system.assert_equalities.at(i);
291 builder.assert_equal(constraint.a, constraint.b);
292 gate_counter.track_diff(constraint_system.gates_per_opcode,
293 constraint_system.original_opcode_indices.assert_equalities.at(i));
294 }
295
296 // RecursionConstraints
297 bool has_honk_recursion_constraints = !constraint_system.honk_recursion_constraints.empty();
298 bool has_avm_recursion_constraints = !constraint_system.avm_recursion_constraints.empty();
299 bool has_pg_recursion_constraints = !constraint_system.pg_recursion_constraints.empty();
300 bool has_civc_recursion_constraints = !constraint_system.civc_recursion_constraints.empty();
301
302 if constexpr (IsMegaBuilder<Builder>) {
303 // We shouldn't have both honk recursion constraints and pg recursion constraints.
304 BB_ASSERT_EQ(!has_honk_recursion_constraints || !has_pg_recursion_constraints,
305 true,
306 "Invalid circuit: both honk and ivc recursion constraints present.");
307
308 // AVM constraints are not handled when using MegaBuilder
309 if (has_avm_recursion_constraints) {
310 info("WARNING: this circuit contains unhandled avm_recursion_constraints!");
311 }
312
313 if (has_honk_recursion_constraints) {
315 builder, constraint_system, has_valid_witness_assignments, gate_counter);
316
317 // Propagate pairing points
319 inputs.pairing_inputs = output.points_accumulator;
320 inputs.set_public();
321 } else if (has_pg_recursion_constraints) {
323 builder, constraint_system, metadata.ivc, has_valid_witness_assignments, gate_counter);
324 } else {
325 // If its an app circuit that has no recursion constraints, add default pairing points to public inputs.
327 }
328 } else {
329 bool is_recursive_circuit = metadata.honk_recursion != 0;
330 bool has_pairing_points =
331 has_honk_recursion_constraints || has_civc_recursion_constraints || has_avm_recursion_constraints;
332
333 // TODO(https://github.com/AztecProtocol/barretenberg/issues/1523): Only handle either HONK or CIVC + AVM and
334 // fail fast otherwise
335 BB_ASSERT_EQ(has_pg_recursion_constraints,
336 false,
337 "Invalid circuit: pg recursion constraints are present with UltraBuilder.");
338 BB_ASSERT_EQ(!(has_honk_recursion_constraints && has_civc_recursion_constraints),
339 true,
340 "Invalid circuit: both honk and civc recursion constraints are present.");
342 !(has_honk_recursion_constraints || has_civc_recursion_constraints || has_avm_recursion_constraints) ||
343 is_recursive_circuit,
344 true,
345 "Invalid circuit: honk, civc, or avm recursion constraints present but the circuit is not recursive.");
346
347 // Container for data to be propagated
349
350 if (has_honk_recursion_constraints) {
352 builder, constraint_system, has_valid_witness_assignments, gate_counter);
353 }
354
355 if (has_civc_recursion_constraints) {
357 builder, constraint_system, has_valid_witness_assignments, gate_counter);
358 }
359
360#ifndef DISABLE_AZTEC_VM
361 if (has_avm_recursion_constraints) {
363 builder, constraint_system, has_valid_witness_assignments, gate_counter);
364
365 // Update honk_output: append (potentially 0) ipa claims and proofs.
366 // If honk output has points accumulator, aggregate it with the one coming from the avm. Otherwise, override
367 // it with the avm's one.
368 honk_output.update(avm_output, /*update_ipa_data=*/!avm_output.nested_ipa_claims.empty());
369 }
370#endif
371
372 if (metadata.honk_recursion == 2) {
373 // Proving with UltraRollupFlavor
374
375 // Propagate pairing points
376 if (has_pairing_points) {
377 honk_output.points_accumulator.set_public();
378 } else {
380 }
381
382 // Handle IPA
383 auto [ipa_claim, ipa_proof] =
385
386 // Set proof
387 builder.ipa_proof = ipa_proof;
388
389 // Propagate IPA claim
390 ipa_claim.set_public();
391 } else {
392 // If it is a recursive circuit, propagate pairing points
393 if (metadata.honk_recursion == 1) {
395
396 if (has_pairing_points) {
397 IO inputs;
398 inputs.pairing_inputs = honk_output.points_accumulator;
399 inputs.set_public();
400 } else {
401 IO::add_default(builder);
402 }
403 }
404
405 // Handle IPA
406 if (honk_output.is_root_rollup) {
408 } else {
409 // We shouldn't accidentally have IPA proofs otherwise.
410 BB_ASSERT_EQ(honk_output.nested_ipa_proofs.size(),
411 static_cast<size_t>(0),
412 "IPA proofs present when not expected.");
413 }
414 }
415 }
416} // namespace acir_format
417
426template <typename Builder>
428 const std::vector<OpeningClaim<stdlib::grumpkin<Builder>>>& nested_ipa_claims,
429 const std::vector<stdlib::Proof<Builder>>& nested_ipa_proofs)
430{
432
434 nested_ipa_claims.size(), nested_ipa_proofs.size(), "Mismatched number of nested IPA claims and proofs.");
435 BB_ASSERT_EQ(nested_ipa_claims.size(), 2U, "Root rollup must have two nested IPA claims.");
436
437 auto [ipa_claim, ipa_proof] = handle_IPA_accumulation(builder, nested_ipa_claims, nested_ipa_proofs);
438
439 // IPA verification
441 &builder, 1 << CONST_ECCVM_LOG_N, VerifierCommitmentKey<curve::Grumpkin>(1 << CONST_ECCVM_LOG_N));
442
443 auto accumulated_ipa_transcript = std::make_shared<StdlibTranscript>();
444 accumulated_ipa_transcript->load_proof(stdlib::Proof<Builder>(builder, ipa_proof));
445 IPA<stdlib::grumpkin<Builder>>::full_verify_recursive(
446 verifier_commitment_key, ipa_claim, accumulated_ipa_transcript);
447}
448
457template <typename Builder>
460 const std::vector<OpeningClaim<stdlib::grumpkin<Builder>>>& nested_ipa_claims,
461 const std::vector<stdlib::Proof<Builder>>& nested_ipa_proofs)
462{
464 nested_ipa_claims.size(), nested_ipa_proofs.size(), "Mismatched number of nested IPA claims and proofs.");
465
467 HonkProof final_ipa_proof;
468
469 if (nested_ipa_claims.size() == 2) {
470 // If we have two claims, accumulate.
471 CommitmentKey<curve::Grumpkin> commitment_key(1 << CONST_ECCVM_LOG_N);
473
474 auto ipa_transcript_1 = std::make_shared<StdlibTranscript>();
475 ipa_transcript_1->load_proof(nested_ipa_proofs[0]);
476 auto ipa_transcript_2 = std::make_shared<StdlibTranscript>();
477 ipa_transcript_2->load_proof(nested_ipa_proofs[1]);
478 auto [ipa_claim, ipa_proof] = IPA<stdlib::grumpkin<Builder>>::accumulate(
479 commitment_key, ipa_transcript_1, nested_ipa_claims[0], ipa_transcript_2, nested_ipa_claims[1]);
480
481 final_ipa_claim = ipa_claim;
482 final_ipa_proof = ipa_proof;
483 } else if (nested_ipa_claims.size() == 1) {
484 // If we have one claim, just forward it along.
485 final_ipa_claim = nested_ipa_claims[0];
486 // This conversion looks suspicious but there's no need to make this an output of the circuit since
487 // its a proof that will be checked anyway.
488 final_ipa_proof = nested_ipa_proofs[0].get_value();
489 } else if (nested_ipa_claims.empty()) {
490 // If we don't have any claims, we may need to inject a fake one if we're proving with
491 // UltraRollupHonk, indicated by the manual setting of the honk_recursion metadata to 2.
492 info("Proving with UltraRollupHonk but no IPA claims exist.");
493 auto [stdlib_opening_claim, ipa_proof] =
494 IPA<stdlib::grumpkin<Builder>>::create_fake_ipa_claim_and_proof(builder);
495
496 final_ipa_claim = stdlib_opening_claim;
497 final_ipa_proof = ipa_proof;
498 } else {
499 // We don't support and shouldn't expect to support circuits with 3+ IPA recursive verifiers.
500 throw_or_abort("Too many nested IPA claims to accumulate");
501 }
502
503 BB_ASSERT_EQ(final_ipa_proof.size(), IPA_PROOF_LENGTH);
504
505 // Return the IPA claim and proof
506 return { final_ipa_claim, final_ipa_proof };
507}
508
509template <typename Builder>
510[[nodiscard("IPA claim and Pairing points should be accumulated")]] HonkRecursionConstraintsOutput<Builder>
512 AcirFormat& constraint_system,
513 bool has_valid_witness_assignments,
514 GateCounter<Builder>& gate_counter)
515{
517 // Add recursion constraints
518 size_t idx = 0;
519 for (auto& constraint : constraint_system.honk_recursion_constraints) {
520 HonkRecursionConstraintOutput<Builder> honk_recursion_constraint;
521
522 if (constraint.proof_type == HONK_ZK) {
523 honk_recursion_constraint = create_honk_recursion_constraints<UltraZKRecursiveFlavor_<Builder>>(
524 builder, constraint, has_valid_witness_assignments);
525 } else if (constraint.proof_type == HONK) {
526 honk_recursion_constraint = create_honk_recursion_constraints<UltraRecursiveFlavor_<Builder>>(
527 builder, constraint, has_valid_witness_assignments);
528 } else if (constraint.proof_type == ROLLUP_HONK || constraint.proof_type == ROOT_ROLLUP_HONK) {
529 if constexpr (!IsUltraBuilder<Builder>) {
530 throw_or_abort("Rollup Honk proof type not supported on MegaBuilder");
531 } else {
532 honk_recursion_constraint = create_honk_recursion_constraints<UltraRollupRecursiveFlavor_<Builder>>(
533 builder, constraint, has_valid_witness_assignments);
534 }
535 } else {
536 throw_or_abort("Invalid Honk proof type");
537 }
538
539 // Update output
540 output.update(honk_recursion_constraint,
541 /*update_ipa_data=*/constraint.proof_type == ROLLUP_HONK ||
542 constraint.proof_type == ROOT_ROLLUP_HONK);
543 output.is_root_rollup = constraint.proof_type == ROOT_ROLLUP_HONK;
544
545 gate_counter.track_diff(constraint_system.gates_per_opcode,
546 constraint_system.original_opcode_indices.honk_recursion_constraints.at(idx++));
547 }
548 ASSERT(!(output.is_root_rollup && output.nested_ipa_claims.size() != 2),
549 "Root rollup must accumulate two IPA proofs.");
550 return output;
551}
552
554 AcirFormat& constraints,
556 bool has_valid_witness_assignments,
558{
559 using StdlibVerificationKey = ClientIVC::RecursiveVerificationKey;
560 using StdlibVKAndHash = ClientIVC::RecursiveVKAndHash;
561 using StdlibFF = ClientIVC::RecursiveFlavor::FF;
562
563 // If an ivc instance is not provided, we mock one with the state required to construct the recursion
564 // constraints present in the program. This is for when we write_vk.
565 if (ivc == nullptr) {
566 ivc = create_mock_ivc_from_constraints(constraints.pg_recursion_constraints, { AZTEC_TRACE_STRUCTURE });
567 }
568
569 // We expect the length of the internal verification queue to match the number of ivc recursion constraints
570 BB_ASSERT_EQ(constraints.pg_recursion_constraints.size(),
571 ivc->verification_queue.size(),
572 "WARNING: Mismatch in number of recursive verifications during kernel creation!");
573
574 // If no witness is provided, populate the VK and public inputs in the recursion constraint with dummy values so
575 // that the present kernel circuit is constructed correctly. (Used for constructing VKs without witnesses).
576 if (!has_valid_witness_assignments) {
577 // Create stdlib representations of each {proof, vkey} pair to be recursively verified
578 for (auto [constraint, queue_entry] : zip_view(constraints.pg_recursion_constraints, ivc->verification_queue)) {
579 populate_dummy_vk_in_constraint(builder, queue_entry.honk_vk, constraint.key);
580 builder.set_variable(constraint.key_hash, queue_entry.honk_vk->hash());
581 }
582 }
583
584 // Construct a stdlib verification key for each constraint based on the verification key witness indices therein
586 stdlib_vk_and_hashs.reserve(constraints.pg_recursion_constraints.size());
587 for (const auto& constraint : constraints.pg_recursion_constraints) {
588 stdlib_vk_and_hashs.push_back(
590 StdlibVerificationKey::from_witness_indices(builder, constraint.key)),
591 StdlibFF::from_witness_index(&builder, constraint.key_hash)));
592 }
593 // Create stdlib representations of each {proof, vkey} pair to be recursively verified
594 ivc->instantiate_stdlib_verification_queue(builder, stdlib_vk_and_hashs);
595
596 // Connect the public_input witnesses in each constraint to the corresponding public input witnesses in the
597 // internal verification queue. This ensures that the witnesses utilized in constraints generated based on acir
598 // are properly connected to the constraints generated herein via the ivc scheme (e.g. recursive verifications).
599 for (auto [constraint, queue_entry] :
600 zip_view(constraints.pg_recursion_constraints, ivc->stdlib_verification_queue)) {
601
602 // Get the witness indices for the public inputs contained within the proof in the verification queue
603 std::vector<uint32_t> public_input_indices =
605 constraint.public_inputs.size());
606
607 // Assert equality between the internal public input witness indices and those in the acir constraint
608 for (auto [witness_idx, constraint_witness_idx] : zip_view(public_input_indices, constraint.public_inputs)) {
609 builder.assert_equal(witness_idx, constraint_witness_idx);
610 }
611 }
612
613 // Complete the kernel circuit with all required recursive verifications, databus consistency checks etc.
614 ivc->complete_kernel_circuit_logic(builder);
615
616 // Note: we can't easily track the gate contribution from each individual pg_recursion_constraint since they
617 // are handled simultaneously in the above function call; instead we track the total contribution
618 gate_counter.track_diff(constraints.gates_per_opcode,
620}
621
622[[nodiscard("IPA claim and Pairing points should be accumulated")]] HonkRecursionConstraintsOutput<Builder>
624 AcirFormat& constraint_system,
625 bool has_valid_witness_assignments,
626 GateCounter<Builder>& gate_counter)
627{
629 // Add recursion constraints
630 size_t idx = 0;
631 for (auto& constraint : constraint_system.civc_recursion_constraints) {
633 create_civc_recursion_constraints(builder, constraint, has_valid_witness_assignments);
634
635 // Update the output
636 output.update(honk_output, /*update_ipa_data=*/true);
637
638 gate_counter.track_diff(constraint_system.gates_per_opcode,
639 constraint_system.original_opcode_indices.civc_recursion_constraints.at(idx++));
640 }
641
642 return output;
643}
644
645#ifndef DISABLE_AZTEC_VM
646[[nodiscard("IPA claim and Pairing points should be accumulated")]] HonkRecursionConstraintsOutput<Builder>
648 AcirFormat& constraint_system,
649 bool has_valid_witness_assignments,
650 GateCounter<Builder>& gate_counter)
651{
653 // Add recursion constraints
654 size_t idx = 0;
655 for (auto& constraint : constraint_system.avm_recursion_constraints) {
656 HonkRecursionConstraintOutput<Builder> avm2_recursion_output =
657 create_avm2_recursion_constraints_goblin(builder, constraint, has_valid_witness_assignments);
658
659 // Update the output
660 output.update(avm2_recursion_output, /*update_ipa_data=*/true);
661
662 gate_counter.track_diff(constraint_system.gates_per_opcode,
663 constraint_system.original_opcode_indices.avm_recursion_constraints.at(idx++));
664 }
665 return output;
666}
667#endif // DISABLE_AZTEC_VM
668
675template <> UltraCircuitBuilder create_circuit(AcirProgram& program, const ProgramMetadata& metadata)
676{
677 PROFILE_THIS();
678 AcirFormat& constraints = program.constraints;
679 WitnessVector& witness = program.witness;
680
681 Builder builder{ metadata.size_hint, witness, constraints.public_inputs, constraints.varnum, metadata.recursive };
682
683 build_constraints(builder, program, metadata);
684
685 vinfo("created circuit");
686
687 return builder;
688};
689
696template <> MegaCircuitBuilder create_circuit(AcirProgram& program, const ProgramMetadata& metadata)
697{
698 PROFILE_THIS();
699 AcirFormat& constraints = program.constraints;
700 WitnessVector& witness = program.witness;
701
702 auto op_queue = (metadata.ivc == nullptr) ? std::make_shared<ECCOpQueue>() : metadata.ivc->goblin.op_queue;
703
704 // Construct a builder using the witness and public input data from acir and with the goblin-owned op_queue
705 auto builder = MegaCircuitBuilder{ op_queue, witness, constraints.public_inputs, constraints.varnum };
706
707 // Populate constraints in the builder via the data in constraint_system
708 build_constraints(builder, program, metadata);
709
710 return builder;
711};
712
714
715} // namespace acir_format
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:59
#define ASSERT(expression,...)
Definition assert.hpp:49
void set_builder(Builder *ctx)
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:95
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.
void vinfo(Args... args)
Definition log.hpp:76
void info(Args... args)
Definition log.hpp:70
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 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_bigint_from_le_bytes_constraint(Builder &builder, const BigIntFromLeBytes &input, DSLBigInts< Builder > &dsl_bigints)
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_bigint_to_le_bytes_constraint(Builder &builder, const BigIntToLeBytes &input, DSLBigInts< Builder > &dsl_bigints)
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< 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 process_pg_recursion_constraints(MegaCircuitBuilder &builder, AcirFormat &constraints, std::shared_ptr< ClientIVC > ivc, bool has_valid_witness_assignments, GateCounter< MegaCircuitBuilder > &gate_counter)
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)
BaseTranscript< StdlibTranscriptParams< UltraCircuitBuilder > > UltraStdlibTranscript
Entry point for Barretenberg command-line interface.
std::vector< fr > HonkProof
Definition proof.hpp:15
field< Bn254FrParams > fr
Definition fr.hpp:174
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
#define PROFILE_THIS()
Definition op_count.hpp:15
std::vector< BigIntToLeBytes > bigint_to_le_bytes_constraints
std::vector< MultiScalarMul > multi_scalar_mul_constraints
std::vector< Blake2sConstraint > blake2s_constraints
std::vector< Sha256Compression > sha256_compression
std::vector< BigIntFromLeBytes > bigint_from_le_bytes_constraints
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< BigIntOperation > bigint_operations
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
std::vector< size_t > bigint_to_le_bytes_constraints
std::vector< size_t > bigint_from_le_bytes_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< ClientIVC > 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)