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