Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
opcode_gate_count.test.cpp
Go to the documentation of this file.
1#include <gtest/gtest.h>
2#include <memory>
3#include <vector>
4
5#include "acir_format.hpp"
10
12
13using namespace bb;
14using namespace bb::crypto;
15using namespace acir_format;
16
17// Gate count pinning test suite
18template <typename Builder> class OpcodeGateCountTests : public ::testing::Test {
19 protected:
21
22 // NOTE: Gate count constants are defined in gate_count_constants.hpp
23 // All constants below reference the shared definitions from that file
24
25 // NOTE: Recursion constraint gate counts are NOT included in this suite because they:
26 // 1. Require proof generation which is expensive and slow
27 // 2. Have different gate counts depending on the recursive flavor (Ultra vs UltraRollup vs ZK, etc.)
28 //
29 // Recursion constraint gate count tests are located in their respective test files:
30 // - Honk recursion: honk_recursion_constraint.test.cpp::GateCountSingleHonkRecursion
31 //
32 // - Chonk recursion: chonk_recursion_constraints.test.cpp::GateCountChonkRecursion
33 //
34 // - Hypernova recursion: hypernova_recursion_constraint.test.cpp
35 //
36 // - AVM recursion: Not tested (AVM is not compiled in standard bb builds)
37};
38
39using BuilderTypes = testing::Types<UltraCircuitBuilder, MegaCircuitBuilder>;
41
43{
44 static constexpr size_t EXPECTED_RESULT = IsMegaBuilder<TypeParam> ? ZERO_GATE + MEGA_OFFSET<TypeParam> : ZERO_GATE;
45
46 TypeParam builder;
47 EXPECT_EQ(builder.num_gates(), EXPECTED_RESULT);
48}
49
51{
53 .a = 0,
54 .b = 1,
55 .c = 2,
56 .d = 3,
57 .mul_scaling = fr::one(),
58 .a_scaling = 0,
59 .b_scaling = 0,
60 .c_scaling = 0,
61 .d_scaling = fr::neg_one(),
62 .const_scaling = 0,
63 };
64
65 WitnessVector witness(4, 0);
66
67 AcirFormat constraint_system{
68 .max_witness_index = static_cast<uint32_t>(witness.size()) - 1,
69 .num_acir_opcodes = 2,
70 .public_inputs = {},
71 .quad_constraints = { quad, quad }, // Test that gate counting works for multiple constraints
72 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .quad_constraints = { 0, 1 } },
73 };
74
75 AcirProgram program{ constraint_system, witness };
76 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
77 auto builder = create_circuit<TypeParam>(program, metadata);
78
79 // The first gate count incorporates the zero gate and mega offset adjustments, while the second doesn't
80 EXPECT_EQ(program.constraints.gates_per_opcode,
81 std::vector<size_t>({ QUAD<TypeParam>, QUAD<TypeParam> - ZERO_GATE - MEGA_OFFSET<TypeParam> }));
82}
83
85{
87 .mul_terms = { std::make_tuple(
89 std::make_tuple(
91 .linear_combinations = { std::make_tuple(bb::fr::one().to_buffer(), Acir::Witness{ .value = 2 }) },
92 .q_c = bb::fr(-2).to_buffer(),
93 };
94
95 WitnessVector witness_values = { fr(1), fr(1), fr(1), fr(-1) };
96
97 Acir::Opcode::AssertZero assert_zero{ .value = expr };
98
99 // Create an ACIR circuit with this opcode
100 Acir::Circuit circuit{
102 .opcodes = { Acir::Opcode{ .value = assert_zero } },
103 .return_values = {},
104 };
105
106 Acir::Program acir_program{ .functions = { circuit } };
107
108 // Serialize the program to bytes
109 auto acir_program_bytes = acir_program.bincodeSerialize();
110
111 // Process through circuit_buf_to_acir_format (this calls handle_arithmetic internally)
112 AcirFormat constraint_system = circuit_buf_to_acir_format(std::move(acir_program_bytes));
113
114 AcirProgram program{ constraint_system, witness_values };
115 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
116 auto builder = create_circuit<TypeParam>(program, metadata);
117
118 EXPECT_EQ(program.constraints.gates_per_opcode, std::vector<size_t>({ BIG_QUAD<TypeParam> }));
119}
120
122{
123 LogicConstraint logic_constraint{
126 .result = 2,
127 .num_bits = 32,
128 .is_xor_gate = true,
129 };
130
131 WitnessVector witness{ 5, 10, 15 };
132
133 AcirFormat constraint_system{
134 .max_witness_index = static_cast<uint32_t>(witness.size()) - 1,
135 .num_acir_opcodes = 1,
136 .public_inputs = {},
137 .logic_constraints = { logic_constraint },
138 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .logic_constraints = { 0 } },
139 };
140
141 AcirProgram program{ constraint_system, witness };
142 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
143 auto builder = create_circuit<TypeParam>(program, metadata);
144
145 // As of now, this is the only test we have for the XOR opcode, so we test that it works
146 EXPECT_TRUE(CircuitChecker::check(builder));
147 EXPECT_FALSE(builder.failed());
148
149 EXPECT_EQ(program.constraints.gates_per_opcode, std::vector<size_t>({ LOGIC_XOR_32<TypeParam> }));
150}
151
153{
154 LogicConstraint logic_constraint{
157 .result = 2,
158 .num_bits = 32,
159 .is_xor_gate = false,
160 };
161
162 WitnessVector witness{ 5, 10, 0 };
163
164 AcirFormat constraint_system{
165 .max_witness_index = static_cast<uint32_t>(witness.size()) - 1,
166 .num_acir_opcodes = 1,
167 .public_inputs = {},
168 .logic_constraints = { logic_constraint },
169 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .logic_constraints = { 0 } },
170 };
171
172 AcirProgram program{ constraint_system, witness };
173 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
174 auto builder = create_circuit<TypeParam>(program, metadata);
175
176 // As of now, this is the only test we have for the AND opcode, so we test that it works
177 EXPECT_TRUE(CircuitChecker::check(builder));
178 EXPECT_FALSE(builder.failed());
179
180 EXPECT_EQ(program.constraints.gates_per_opcode, std::vector<size_t>({ LOGIC_AND_32<TypeParam> }));
181}
182
184{
185 RangeConstraint range_constraint{
186 .witness = 0,
187 .num_bits = 32,
188 };
189
190 WitnessVector witness{ 100 };
191
192 AcirFormat constraint_system{
193 .max_witness_index = static_cast<uint32_t>(witness.size()) - 1,
194 .num_acir_opcodes = 1,
195 .public_inputs = {},
196 .range_constraints = { range_constraint },
197 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .range_constraints = { 0 } },
198 };
199
200 AcirProgram program{ constraint_system, witness };
201 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
202 auto builder = create_circuit<TypeParam>(program, metadata);
203
204 EXPECT_EQ(program.constraints.gates_per_opcode, std::vector<size_t>({ RANGE_32<TypeParam> }));
205}
206
208{
209 Keccakf1600 keccak_permutation;
210
211 for (size_t idx = 0; idx < 25; idx++) {
212 keccak_permutation.state[idx] = WitnessOrConstant<bb::fr>::from_index(static_cast<uint32_t>(idx));
213 keccak_permutation.result[idx] = static_cast<uint32_t>(idx) + 25;
214 }
215
216 // As of now, this is the only test for the Keccak permutation opcode, so we test that it works as expected
217 std::array<uint64_t, 25> native_state = { 0 };
218 std::array<uint64_t, 25> expected_state = native_state;
219 ethash_keccakf1600(expected_state.data());
220
221 WitnessVector witness(25, 0);
222 for (const auto& state : expected_state) {
223 witness.emplace_back(state);
224 }
225
226 AcirFormat constraint_system{
227 .max_witness_index = static_cast<uint32_t>(witness.size()) - 1,
228 .num_acir_opcodes = 1,
229 .public_inputs = {},
230 .keccak_permutations = { keccak_permutation },
231 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .keccak_permutations = { 0 } },
232 };
233
234 AcirProgram program{ constraint_system, witness };
235 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
236 auto builder = create_circuit<TypeParam>(program, metadata);
237
238 EXPECT_TRUE(CircuitChecker::check(builder));
239 EXPECT_FALSE(builder.failed());
240
241 EXPECT_EQ(program.constraints.gates_per_opcode, std::vector<size_t>({ KECCAK_PERMUTATION<TypeParam> }));
242}
243
245{
246 Poseidon2Constraint poseidon2_constraint;
247
248 for (size_t idx = 0; idx < 4; idx++) {
249 poseidon2_constraint.state.emplace_back(WitnessOrConstant<bb::fr>::from_index(static_cast<uint32_t>(idx)));
250 poseidon2_constraint.result.emplace_back(static_cast<uint32_t>(idx) + 5);
251 }
252
253 WitnessVector witness(8, 0);
254
255 AcirFormat constraint_system{
256 .max_witness_index = static_cast<uint32_t>(witness.size()) - 1,
257 .num_acir_opcodes = 1,
258 .public_inputs = {},
259 .poseidon2_constraints = { poseidon2_constraint },
260 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .poseidon2_constraints = { 0 } },
261 };
262
263 AcirProgram program{ constraint_system, witness };
264 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
265 auto builder = create_circuit<TypeParam>(program, metadata);
266
267 EXPECT_EQ(program.constraints.gates_per_opcode, std::vector<size_t>({ POSEIDON2_PERMUTATION<TypeParam> }));
268}
269
271{
272 Sha256Compression sha256_compression;
273
274 for (size_t i = 0; i < 16; ++i) {
275 sha256_compression.inputs[i] = WitnessOrConstant<bb::fr>::from_index(static_cast<uint32_t>(i));
276 }
277 for (size_t i = 0; i < 8; ++i) {
278 sha256_compression.hash_values[i] = WitnessOrConstant<bb::fr>::from_index(static_cast<uint32_t>(i));
279 }
280 for (size_t i = 0; i < 8; ++i) {
281 sha256_compression.result[i] = static_cast<uint32_t>(i) + 24;
282 }
283
284 WitnessVector witness(32, 0);
285
286 AcirFormat constraint_system{
287 .max_witness_index = static_cast<uint32_t>(witness.size()) - 1,
288 .num_acir_opcodes = 1,
289 .public_inputs = {},
290 .sha256_compression = { sha256_compression },
291 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .sha256_compression = { 0 } },
292 };
293
294 AcirProgram program{ constraint_system, witness };
295 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
296 auto builder = create_circuit<TypeParam>(program, metadata);
297
298 EXPECT_EQ(program.constraints.gates_per_opcode, std::vector<size_t>({ SHA256_COMPRESSION<TypeParam> }));
299}
300
302{
303 AES128Constraint aes128_constraint;
304
305 // Create a minimal AES128 constraint with 16 bytes of input
306 for (size_t i = 0; i < 16; ++i) {
307 aes128_constraint.inputs.push_back(WitnessOrConstant<bb::fr>::from_index(static_cast<uint32_t>(i)));
308 }
309
310 for (size_t i = 0; i < 16; ++i) {
311 aes128_constraint.iv[i] = WitnessOrConstant<bb::fr>::from_index(static_cast<uint32_t>(i + 16));
312 }
313
314 for (size_t i = 0; i < 16; ++i) {
315 aes128_constraint.key[i] = WitnessOrConstant<bb::fr>::from_index(static_cast<uint32_t>(i + 32));
316 }
317
318 for (size_t i = 0; i < 16; ++i) {
319 aes128_constraint.outputs.push_back(static_cast<uint32_t>(i + 48));
320 }
321
322 WitnessVector witness(64, fr(0));
323
324 AcirFormat constraint_system{
325 .max_witness_index = static_cast<uint32_t>(witness.size()) - 1,
326 .num_acir_opcodes = 1,
327 .public_inputs = {},
328 .aes128_constraints = { aes128_constraint },
329 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .aes128_constraints = { 0 } },
330 };
331
332 AcirProgram program{ constraint_system, witness };
333 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
334 auto builder = create_circuit<TypeParam>(program, metadata);
335
336 EXPECT_EQ(program.constraints.gates_per_opcode, std::vector<size_t>({ AES128_ENCRYPTION<TypeParam> }));
337}
338
340{
341 EcdsaConstraint ecdsa_constraint{ .type = bb::CurveType::SECP256K1 };
342 for (size_t i = 0; i < 32; ++i) {
343 ecdsa_constraint.hashed_message[i] = static_cast<uint32_t>(i);
344 }
345
346 for (size_t i = 0; i < 64; ++i) {
347 ecdsa_constraint.signature[i] = static_cast<uint32_t>(i + 32);
348 }
349
350 for (size_t i = 0; i < 32; ++i) {
351 ecdsa_constraint.pub_x_indices[i] = static_cast<uint32_t>(i + 96);
352 }
353
354 for (size_t i = 0; i < 32; ++i) {
355 ecdsa_constraint.pub_y_indices[i] = static_cast<uint32_t>(i + 128);
356 }
357
358 ecdsa_constraint.predicate = WitnessOrConstant<bb::fr>::from_index(static_cast<uint32_t>(160));
359 ecdsa_constraint.result = static_cast<uint32_t>(161);
360
361 WitnessVector witness(163, fr(0));
362 // Override public key values to avoid failures
363 auto point = bb::curve::SECP256K1::AffineElement::one();
364 auto x_buffer = point.x.to_buffer();
365 auto y_buffer = point.y.to_buffer();
366 for (size_t idx = 0; idx < 32; idx++) {
367 witness[idx + 96] = x_buffer[idx];
368 witness[idx + 128] = y_buffer[idx];
369 }
370
371 AcirFormat constraint_system{
372 .max_witness_index = static_cast<uint32_t>(witness.size()) - 1,
373 .num_acir_opcodes = 1,
374 .public_inputs = {},
375 .ecdsa_k1_constraints = { ecdsa_constraint },
376 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .ecdsa_k1_constraints = { 0 } },
377 };
378
379 AcirProgram program{ constraint_system, witness };
380 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
381 auto builder = create_circuit<TypeParam>(program, metadata);
382
383 EXPECT_EQ(program.constraints.gates_per_opcode, std::vector<size_t>({ ECDSA_SECP256K1<TypeParam> }));
384}
385
387{
388 EcdsaConstraint ecdsa_constraint{ .type = bb::CurveType::SECP256R1 };
389 for (size_t i = 0; i < 32; ++i) {
390 ecdsa_constraint.hashed_message[i] = static_cast<uint32_t>(i);
391 }
392
393 for (size_t i = 0; i < 64; ++i) {
394 ecdsa_constraint.signature[i] = static_cast<uint32_t>(i + 32);
395 }
396
397 for (size_t i = 0; i < 32; ++i) {
398 ecdsa_constraint.pub_x_indices[i] = static_cast<uint32_t>(i + 96);
399 }
400
401 for (size_t i = 0; i < 32; ++i) {
402 ecdsa_constraint.pub_y_indices[i] = static_cast<uint32_t>(i + 128);
403 }
404
405 ecdsa_constraint.predicate = WitnessOrConstant<bb::fr>::from_index(static_cast<uint32_t>(160));
406 ecdsa_constraint.result = static_cast<uint32_t>(161);
407
408 WitnessVector witness(163, fr(0));
409 // Override public key values to avoid failures
410 auto point = bb::curve::SECP256K1::AffineElement::one();
411 auto x_buffer = point.x.to_buffer();
412 auto y_buffer = point.y.to_buffer();
413 for (size_t idx = 0; idx < 32; idx++) {
414 witness[idx + 96] = x_buffer[idx];
415 witness[idx + 128] = y_buffer[idx];
416 }
417
418 AcirFormat constraint_system{
419 .max_witness_index = static_cast<uint32_t>(witness.size()) - 1,
420 .num_acir_opcodes = 1,
421 .public_inputs = {},
422 .ecdsa_r1_constraints = { ecdsa_constraint },
423 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .ecdsa_r1_constraints = { 0 } },
424 };
425
426 AcirProgram program{ constraint_system, witness };
427 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
428 auto builder = create_circuit<TypeParam>(program, metadata);
429
430 EXPECT_EQ(program.constraints.gates_per_opcode, std::vector<size_t>({ ECDSA_SECP256R1<TypeParam> }));
431}
432
434{
435 Blake2sConstraint blake2s_constraint;
436
437 blake2s_constraint.inputs.push_back(Blake2sInput{
439 .num_bits = 8,
440 });
441
442 for (size_t i = 0; i < 32; ++i) {
443 blake2s_constraint.result[i] = static_cast<uint32_t>(i + 1);
444 }
445
446 WitnessVector witness(33, fr(0));
447
448 AcirFormat constraint_system{
449 .max_witness_index = static_cast<uint32_t>(witness.size()) - 1,
450 .num_acir_opcodes = 1,
451 .public_inputs = {},
452 .blake2s_constraints = { blake2s_constraint },
453 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .blake2s_constraints = { 0 } },
454 };
455
456 AcirProgram program{ constraint_system, witness };
457 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
458 auto builder = create_circuit<TypeParam>(program, metadata);
459
460 EXPECT_EQ(program.constraints.gates_per_opcode, std::vector<size_t>({ BLAKE2S<TypeParam> }));
461}
462
464{
465 Blake3Constraint blake3_constraint;
466
467 blake3_constraint.inputs.push_back(Blake3Input{
469 .num_bits = 8,
470 });
471
472 for (size_t i = 0; i < 32; ++i) {
473 blake3_constraint.result[i] = static_cast<uint32_t>(i + 1);
474 }
475
476 WitnessVector witness(33, fr(0));
477
478 AcirFormat constraint_system{
479 .max_witness_index = static_cast<uint32_t>(witness.size()) - 1,
480 .num_acir_opcodes = 1,
481 .public_inputs = {},
482 .blake3_constraints = { blake3_constraint },
483 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .blake3_constraints = { 0 } },
484 };
485
486 AcirProgram program{ constraint_system, witness };
487 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
488 auto builder = create_circuit<TypeParam>(program, metadata);
489
490 EXPECT_EQ(program.constraints.gates_per_opcode, std::vector<size_t>({ BLAKE3<TypeParam> }));
491}
492
494{
495 using GrumpkinPoint = bb::grumpkin::g1::affine_element;
496
497 // Use a valid Grumpkin point (the generator)
498 auto point = GrumpkinPoint::one();
499
500 MultiScalarMul msm_constraint;
501
502 // Create a minimal MSM with one point and one scalar
503 msm_constraint.points.push_back(WitnessOrConstant<bb::fr>::from_index(0)); // x
504 msm_constraint.points.push_back(WitnessOrConstant<bb::fr>::from_index(1)); // y
505 msm_constraint.points.push_back(WitnessOrConstant<bb::fr>::from_index(2)); // is_infinite
506
507 msm_constraint.scalars.push_back(WitnessOrConstant<bb::fr>::from_index(3)); // scalar_lo
508 msm_constraint.scalars.push_back(WitnessOrConstant<bb::fr>::from_index(4)); // scalar_hi
509
511
512 msm_constraint.out_point_x = 6;
513 msm_constraint.out_point_y = 7;
514 msm_constraint.out_point_is_infinite = 8;
515
516 WitnessVector witness(9, fr(0));
517 // Set valid point coordinates
518 witness[0] = point.x;
519 witness[1] = point.y;
520 witness[2] = fr(0);
521 witness[6] = point.x;
522 witness[7] = point.y;
523 witness[8] = fr(0);
524
525 AcirFormat constraint_system{
526 .max_witness_index = static_cast<uint32_t>(witness.size()) - 1,
527 .num_acir_opcodes = 1,
528 .public_inputs = {},
529 .multi_scalar_mul_constraints = { msm_constraint },
530 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .multi_scalar_mul_constraints = { 0 } },
531 };
532
533 AcirProgram program{ constraint_system, witness };
534 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
535 auto builder = create_circuit<TypeParam>(program, metadata);
536
537 EXPECT_EQ(program.constraints.gates_per_opcode, std::vector<size_t>({ MULTI_SCALAR_MUL<TypeParam> }));
538}
539
541{
542 using GrumpkinPoint = bb::grumpkin::g1::affine_element;
543
544 // Use valid Grumpkin points (the generator)
545 auto point1 = GrumpkinPoint::one();
546 auto point2 = GrumpkinPoint::one();
547
548 EcAdd ec_add_constraint{
551 .input1_infinite = WitnessOrConstant<bb::fr>::from_index(2),
554 .input2_infinite = WitnessOrConstant<bb::fr>::from_index(5),
556 .result_x = 7,
557 .result_y = 8,
558 .result_infinite = 9,
559 };
560
561 WitnessVector witness(10, fr(0));
562 // Set valid point1 coordinates
563 witness[0] = point1.x;
564 witness[1] = point1.y;
565 witness[2] = fr(0);
566 // Set valid point2 coordinates
567 witness[3] = point2.x;
568 witness[4] = point2.y;
569 witness[5] = fr(0);
570 // Set valid result coordinates
571 witness[7] = point1.x;
572 witness[8] = point1.y;
573 witness[9] = fr(0);
574
575 AcirFormat constraint_system{
576 .max_witness_index = static_cast<uint32_t>(witness.size()) - 1,
577 .num_acir_opcodes = 1,
578 .public_inputs = {},
579 .ec_add_constraints = { ec_add_constraint },
580 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .ec_add_constraints = { 0 } },
581 };
582
583 AcirProgram program{ constraint_system, witness };
584 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
585 auto builder = create_circuit<TypeParam>(program, metadata);
586
587 EXPECT_EQ(program.constraints.gates_per_opcode, std::vector<size_t>({ EC_ADD<TypeParam> }));
588}
589
591{
592 WitnessVector witness{ 10, 20, 0, 10 };
593
594 // Create a simple ROM block with 2 elements and 1 read
595 std::vector<uint32_t> init;
596 init.push_back(0); // 10
597 init.push_back(1); // 20
598
600 trace.push_back(MemOp{
601 .access_type = AccessType::Read,
604 });
605
606 BlockConstraint block_constraint{
607 .init = init,
608 .trace = trace,
609 .type = BlockType::ROM,
610 .calldata_id = CallDataType::None,
611 };
612
613 AcirFormat constraint_system{
614 .max_witness_index = static_cast<uint32_t>(witness.size()) - 1,
615 .num_acir_opcodes = 1, // The block constraint creates 2 opcodes, but the first one doesn't add any gate, so we
616 // set num_acir_opcodes to 1 to track only the contribution from the second one
617 .public_inputs = {},
618 .block_constraints = { block_constraint },
619 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .block_constraints = { { 0 } } },
620 };
621
622 AcirProgram program{ constraint_system, witness };
623 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
624 auto builder = create_circuit<TypeParam>(program, metadata);
625
626 EXPECT_EQ(program.constraints.gates_per_opcode, std::vector<size_t>({ BLOCK_ROM_READ<TypeParam> }));
627}
628
630{
631 WitnessVector witness{ 10, 20, 0, 10 };
632
633 // Create a simple RAM block with 2 elements and 1 read
634 std::vector<uint32_t> init;
635 init.push_back(0); // 10
636 init.push_back(1); // 20
637
639 trace.push_back(MemOp{
640 .access_type = AccessType::Read,
643 });
644
645 BlockConstraint block_constraint{
646 .init = init,
647 .trace = trace,
648 .type = BlockType::RAM,
649 .calldata_id = CallDataType::None,
650 };
651
652 AcirFormat constraint_system{
653 .max_witness_index = static_cast<uint32_t>(witness.size()) - 1,
654 .num_acir_opcodes = 1, // The block constraint creates 2 opcodes, but the first one doesn't add any gate, so we
655 // set num_acir_opcodes to 1 to track only the contribution from the second one
656 .public_inputs = {},
657 .block_constraints = { block_constraint },
658 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .block_constraints = { { 0 } } },
659 };
660
661 AcirProgram program{ constraint_system, witness };
662 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
663 auto builder = create_circuit<TypeParam>(program, metadata);
664};
665
667{
668 WitnessVector witness{ 10, 20, 0, 10 };
669
670 // Create a simple RAM block with 2 elements and 1 read
671 std::vector<uint32_t> init;
672 init.push_back(0); // 10
673 init.push_back(1); // 20
674
676 trace.push_back(MemOp{
677 .access_type = AccessType::Write,
680 });
681
682 BlockConstraint block_constraint{
683 .init = init,
684 .trace = trace,
685 .type = BlockType::RAM,
686 .calldata_id = CallDataType::None,
687 };
688
689 AcirFormat constraint_system{
690 .max_witness_index = static_cast<uint32_t>(witness.size()) - 1,
691 .num_acir_opcodes = 1, // The block constraint creates 2 opcodes, but the first one doesn't add any gate, so we
692 // set num_acir_opcodes to 1 to track only the contribution from the second one
693 .public_inputs = {},
694 .block_constraints = { block_constraint },
695 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .block_constraints = { { 0 } } },
696 };
697
698 AcirProgram program{ constraint_system, witness };
699 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
700 auto builder = create_circuit<TypeParam>(program, metadata);
701
702 EXPECT_EQ(program.constraints.gates_per_opcode, std::vector<size_t>({ BLOCK_RAM_WRITE<TypeParam> }));
703}
704
706{
707 if constexpr (!IsMegaBuilder<TypeParam>) {
708 GTEST_SKIP() << "CallData only supported on MegaCircuitBuilder";
709 }
710
711 WitnessVector witness{ 10, 20, 0, 10 };
712
713 // Create a simple CallData block with 2 elements and 1 read
714 std::vector<uint32_t> init;
715 init.push_back(0); // 10
716 init.push_back(1); // 20
717
719 trace.push_back(MemOp{
720 .access_type = AccessType::Read,
723 });
724
725 // Primary calldata
726 {
727 BlockConstraint block_constraint{
728 .init = init,
729 .trace = trace,
730 .type = BlockType::CallData,
731 .calldata_id = CallDataType::Primary,
732 };
733
734 AcirFormat constraint_system{
735 .max_witness_index = static_cast<uint32_t>(witness.size()) - 1,
736 .num_acir_opcodes = 1, // The block constraint creates 2 opcodes, but the first one doesn't add any gate, so
737 // we set num_acir_opcodes to 1 to track only the contribution from the second one
738 .public_inputs = {},
739 .block_constraints = { block_constraint },
740 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .block_constraints = { { 0 } } },
741 };
742
743 AcirProgram program{ constraint_system, witness };
744 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
745 auto builder = create_circuit<TypeParam>(program, metadata);
746
747 EXPECT_EQ(program.constraints.gates_per_opcode, std::vector<size_t>({ BLOCK_CALLDATA<TypeParam> }));
748 }
749
750 // Secondary calldata
751 {
752 BlockConstraint block_constraint{
753 .init = init,
754 .trace = trace,
755 .type = BlockType::CallData,
756 .calldata_id = CallDataType::Secondary,
757 };
758
759 AcirFormat constraint_system{
760 .max_witness_index = static_cast<uint32_t>(witness.size()) - 1,
761 .num_acir_opcodes = 1, // The block constraint creates 2 opcodes, but the first one doesn't add any gate, so
762 // we set num_acir_opcodes to 1 to track only the contribution from the second one
763 .public_inputs = {},
764 .block_constraints = { block_constraint },
765 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .block_constraints = { { 0 } } },
766 };
767
768 AcirProgram program{ constraint_system, witness };
769 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
770 auto builder = create_circuit<TypeParam>(program, metadata);
771
772 EXPECT_EQ(program.constraints.gates_per_opcode, std::vector<size_t>({ BLOCK_CALLDATA<TypeParam> }));
773 }
774}
775
777{
778 if constexpr (!IsMegaBuilder<TypeParam>) {
779 GTEST_SKIP() << "ReturnData only supported on MegaCircuitBuilder";
780 }
781
782 WitnessVector witness{ 10, 20 };
783
784 // Create a simple ReturnData block with 2 elements
785 std::vector<uint32_t> init;
786 init.push_back(0); // 10
787 init.push_back(1); // 20
788
789 BlockConstraint block_constraint{
790 .init = init,
791 .trace = {},
792 .type = BlockType::ReturnData,
793 .calldata_id = CallDataType::None,
794 };
795
796 AcirFormat constraint_system{
797 .max_witness_index = static_cast<uint32_t>(witness.size()) - 1,
798 .num_acir_opcodes = 1, // The block constraint creates 2 opcodes, but the first one doesn't add any gate, so we
799 // set num_acir_opcodes to 1 to track only the contribution from the second one
800 .public_inputs = {},
801 .block_constraints = { block_constraint },
802 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .block_constraints = { { 0 } } },
803 };
804
805 AcirProgram program{ constraint_system, witness };
806 const ProgramMetadata metadata{
808 }; // We need to set it to false because ReturnData BlockConstraints do not have any trace, so we would be dividing
809 // by zero, and this would throw an error.
810 auto builder = create_circuit<TypeParam>(program, metadata);
811
812 EXPECT_EQ(builder.get_num_finalized_gates_inefficient(/*ensure_nonzero=*/false), BLOCK_RETURNDATA<TypeParam>);
813}
static bool check(const Builder &circuit)
Check the witness satisifies the circuit.
Applies the Poseidon2 permutation function from https://eprint.iacr.org/2023/323.
group_elements::affine_element< Fq, Fr, Params > affine_element
Definition group.hpp:42
AluTraceBuilder builder
Definition alu.test.cpp:124
TestTraceContainer trace
void ethash_keccakf1600(uint64_t state[KECCAKF1600_LANES]) NOEXCEPT
const auto init
Definition fr.bench.cpp:135
std::vector< bb::fr > WitnessVector
constexpr size_t ZERO_GATE
AcirFormat circuit_buf_to_acir_format(std::vector< uint8_t > &&buf)
Convert a buffer representing a circuit into Barretenberg's internal AcirFormat representation.
std::filesystem::path bb_crs_path()
void init_file_crs_factory(const std::filesystem::path &path)
TYPED_TEST_SUITE(BoomerangRecursiveVerifierTest, Flavors)
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
field< Bn254FrParams > fr
Definition fr.hpp:174
TYPED_TEST(ShpleminiTest, CorrectnessOfMultivariateClaimBatching)
@ SECP256K1
Definition types.hpp:10
@ SECP256R1
Definition types.hpp:10
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
::testing::Types< UltraCircuitBuilder, MegaCircuitBuilder > BuilderTypes
std::vector< uint8_t > to_buffer(T const &value)
uint32_t current_witness_index
Definition acir.hpp:5004
std::vector< std::tuple< std::vector< uint8_t >, Acir::Witness, Acir::Witness > > mul_terms
Definition acir.hpp:3999
Acir::Expression value
Definition acir.hpp:4359
std::variant< AssertZero, BlackBoxFuncCall, MemoryOp, MemoryInit, BrilligCall, Call > value
Definition acir.hpp:4546
std::vector< Acir::Circuit > functions
Definition acir.hpp:5087
uint32_t value
Definition acir.hpp:2901
std::array< WitnessOrConstant< bb::fr >, 16 > iv
std::vector< uint32_t > outputs
std::vector< WitnessOrConstant< bb::fr > > inputs
std::array< WitnessOrConstant< bb::fr >, 16 > key
Barretenberg's representation of ACIR constraints.
Indices of the original opcode that originated each constraint in AcirFormat.
std::vector< std::vector< size_t > > block_constraints
Struct containing both the constraints to be added to the circuit and the witness vector.
std::vector< Blake2sInput > inputs
std::array< uint32_t, 32 > result
WitnessOrConstant< bb::fr > blackbox_input
std::array< uint32_t, 32 > result
std::vector< Blake3Input > inputs
WitnessOrConstant< bb::fr > blackbox_input
Struct holding the data required to add memory constraints to a circuit.
std::vector< uint32_t > init
Constraints for addition of two points on the Grumpkin curve.
WitnessOrConstant< bb::fr > input1_x
std::array< uint32_t, 25 > result
std::array< WitnessOrConstant< bb::fr >, 25 > state
Logic constraint representation in ACIR format.
WitnessOrConstant< fr > a
Memory operation. Index and value store the index of the memory location, and value is the value to b...
std::vector< WitnessOrConstant< bb::fr > > scalars
WitnessOrConstant< bb::fr > predicate
std::vector< WitnessOrConstant< bb::fr > > points
std::vector< WitnessOrConstant< bb::fr > > state
Metadata required to create a circuit.
std::array< WitnessOrConstant< bb::fr >, 8 > hash_values
std::array< uint32_t, 8 > result
std::array< WitnessOrConstant< bb::fr >, 16 > inputs
static WitnessOrConstant from_index(uint32_t index)
static constexpr field neg_one()
static constexpr field one()
BB_INLINE std::vector< uint8_t > to_buffer() const