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 = AcirFormatOriginalOpcodeIndices{ .quad_constraints = { 0, 1 } },
74 };
75
76 AcirProgram program{ constraint_system, witness };
77 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
78 auto builder = create_circuit<TypeParam>(program, metadata);
79
80 // The first gate count incorporates the zero gate and mega offset adjustments, while the second doesn't
81 EXPECT_EQ(program.constraints.gates_per_opcode,
82 std::vector<size_t>({ QUAD<TypeParam>, QUAD<TypeParam> - ZERO_GATE - MEGA_OFFSET<TypeParam> }));
83}
84
86{
87 LogicConstraint logic_constraint{
90 .result = 2,
91 .num_bits = 32,
92 .is_xor_gate = true,
93 };
94
95 WitnessVector witness{ 5, 10, 15 };
96
97 AcirFormat constraint_system{
98 .max_witness_index = static_cast<uint32_t>(witness.size()) - 1,
99 .num_acir_opcodes = 1,
100 .public_inputs = {},
101 .logic_constraints = { logic_constraint },
102 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .logic_constraints = { 0 } },
103 };
104
105 AcirProgram program{ constraint_system, witness };
106 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
107 auto builder = create_circuit<TypeParam>(program, metadata);
108
109 // As of now, this is the only test we have for the XOR opcode, so we test that it works
110 EXPECT_TRUE(CircuitChecker::check(builder));
111 EXPECT_FALSE(builder.failed());
112
113 EXPECT_EQ(program.constraints.gates_per_opcode, std::vector<size_t>({ LOGIC_XOR_32<TypeParam> }));
114}
115
117{
118 LogicConstraint logic_constraint{
121 .result = 2,
122 .num_bits = 32,
123 .is_xor_gate = false,
124 };
125
126 WitnessVector witness{ 5, 10, 0 };
127
128 AcirFormat constraint_system{
129 .max_witness_index = static_cast<uint32_t>(witness.size()) - 1,
130 .num_acir_opcodes = 1,
131 .public_inputs = {},
132 .logic_constraints = { logic_constraint },
133 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .logic_constraints = { 0 } },
134 };
135
136 AcirProgram program{ constraint_system, witness };
137 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
138 auto builder = create_circuit<TypeParam>(program, metadata);
139
140 // As of now, this is the only test we have for the AND opcode, so we test that it works
141 EXPECT_TRUE(CircuitChecker::check(builder));
142 EXPECT_FALSE(builder.failed());
143
144 EXPECT_EQ(program.constraints.gates_per_opcode, std::vector<size_t>({ LOGIC_AND_32<TypeParam> }));
145}
146
148{
149 RangeConstraint range_constraint{
150 .witness = 0,
151 .num_bits = 32,
152 };
153
154 WitnessVector witness{ 100 };
155
156 AcirFormat constraint_system{
157 .max_witness_index = static_cast<uint32_t>(witness.size()) - 1,
158 .num_acir_opcodes = 1,
159 .public_inputs = {},
160 .range_constraints = { range_constraint },
161 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .range_constraints = { 0 } },
162 };
163
164 AcirProgram program{ constraint_system, witness };
165 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
166 auto builder = create_circuit<TypeParam>(program, metadata);
167
168 EXPECT_EQ(program.constraints.gates_per_opcode, std::vector<size_t>({ RANGE_32<TypeParam> }));
169}
170
172{
173 Keccakf1600 keccak_permutation;
174
175 for (size_t idx = 0; idx < 25; idx++) {
176 keccak_permutation.state[idx] = WitnessOrConstant<bb::fr>::from_index(static_cast<uint32_t>(idx));
177 keccak_permutation.result[idx] = static_cast<uint32_t>(idx) + 25;
178 }
179
180 // As of now, this is the only test for the Keccak permutation opcode, so we test that it works as expected
181 std::array<uint64_t, 25> native_state = { 0 };
182 std::array<uint64_t, 25> expected_state = native_state;
183 ethash_keccakf1600(expected_state.data());
184
185 WitnessVector witness(25, 0);
186 for (const auto& state : expected_state) {
187 witness.emplace_back(state);
188 }
189
190 AcirFormat constraint_system{
191 .max_witness_index = static_cast<uint32_t>(witness.size()) - 1,
192 .num_acir_opcodes = 1,
193 .public_inputs = {},
194 .keccak_permutations = { keccak_permutation },
195 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .keccak_permutations = { 0 } },
196 };
197
198 AcirProgram program{ constraint_system, witness };
199 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
200 auto builder = create_circuit<TypeParam>(program, metadata);
201
202 EXPECT_TRUE(CircuitChecker::check(builder));
203 EXPECT_FALSE(builder.failed());
204
205 EXPECT_EQ(program.constraints.gates_per_opcode, std::vector<size_t>({ KECCAK_PERMUTATION<TypeParam> }));
206}
207
209{
210 Poseidon2Constraint poseidon2_constraint;
211
212 for (size_t idx = 0; idx < 4; idx++) {
213 poseidon2_constraint.state.emplace_back(WitnessOrConstant<bb::fr>::from_index(static_cast<uint32_t>(idx)));
214 poseidon2_constraint.result.emplace_back(static_cast<uint32_t>(idx) + 5);
215 }
216
217 WitnessVector witness(8, 0);
218
219 AcirFormat constraint_system{
220 .max_witness_index = static_cast<uint32_t>(witness.size()) - 1,
221 .num_acir_opcodes = 1,
222 .public_inputs = {},
223 .poseidon2_constraints = { poseidon2_constraint },
224 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .poseidon2_constraints = { 0 } },
225 };
226
227 AcirProgram program{ constraint_system, witness };
228 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
229 auto builder = create_circuit<TypeParam>(program, metadata);
230
231 EXPECT_EQ(program.constraints.gates_per_opcode, std::vector<size_t>({ POSEIDON2_PERMUTATION<TypeParam> }));
232}
233
235{
236 Sha256Compression sha256_compression;
237
238 for (size_t i = 0; i < 16; ++i) {
239 sha256_compression.inputs[i] = WitnessOrConstant<bb::fr>::from_index(static_cast<uint32_t>(i));
240 }
241 for (size_t i = 0; i < 8; ++i) {
242 sha256_compression.hash_values[i] = WitnessOrConstant<bb::fr>::from_index(static_cast<uint32_t>(i));
243 }
244 for (size_t i = 0; i < 8; ++i) {
245 sha256_compression.result[i] = static_cast<uint32_t>(i) + 24;
246 }
247
248 WitnessVector witness(32, 0);
249
250 AcirFormat constraint_system{
251 .max_witness_index = static_cast<uint32_t>(witness.size()) - 1,
252 .num_acir_opcodes = 1,
253 .public_inputs = {},
254 .sha256_compression = { sha256_compression },
255 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .sha256_compression = { 0 } },
256 };
257
258 AcirProgram program{ constraint_system, witness };
259 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
260 auto builder = create_circuit<TypeParam>(program, metadata);
261
262 EXPECT_EQ(program.constraints.gates_per_opcode, std::vector<size_t>({ SHA256_COMPRESSION<TypeParam> }));
263}
264
266{
267 AES128Constraint aes128_constraint;
268
269 // Create a minimal AES128 constraint with 16 bytes of input
270 for (size_t i = 0; i < 16; ++i) {
271 aes128_constraint.inputs.push_back(WitnessOrConstant<bb::fr>::from_index(static_cast<uint32_t>(i)));
272 }
273
274 for (size_t i = 0; i < 16; ++i) {
275 aes128_constraint.iv[i] = WitnessOrConstant<bb::fr>::from_index(static_cast<uint32_t>(i + 16));
276 }
277
278 for (size_t i = 0; i < 16; ++i) {
279 aes128_constraint.key[i] = WitnessOrConstant<bb::fr>::from_index(static_cast<uint32_t>(i + 32));
280 }
281
282 for (size_t i = 0; i < 16; ++i) {
283 aes128_constraint.outputs.push_back(static_cast<uint32_t>(i + 48));
284 }
285
286 WitnessVector witness(64, fr(0));
287
288 AcirFormat constraint_system{
289 .max_witness_index = static_cast<uint32_t>(witness.size()) - 1,
290 .num_acir_opcodes = 1,
291 .public_inputs = {},
292 .aes128_constraints = { aes128_constraint },
293 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .aes128_constraints = { 0 } },
294 };
295
296 AcirProgram program{ constraint_system, witness };
297 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
298 auto builder = create_circuit<TypeParam>(program, metadata);
299
300 EXPECT_EQ(program.constraints.gates_per_opcode, std::vector<size_t>({ AES128_ENCRYPTION<TypeParam> }));
301}
302
304{
305 EcdsaConstraint ecdsa_constraint{ .type = bb::CurveType::SECP256K1 };
306 for (size_t i = 0; i < 32; ++i) {
307 ecdsa_constraint.hashed_message[i] = static_cast<uint32_t>(i);
308 }
309
310 for (size_t i = 0; i < 64; ++i) {
311 ecdsa_constraint.signature[i] = static_cast<uint32_t>(i + 32);
312 }
313
314 for (size_t i = 0; i < 32; ++i) {
315 ecdsa_constraint.pub_x_indices[i] = static_cast<uint32_t>(i + 96);
316 }
317
318 for (size_t i = 0; i < 32; ++i) {
319 ecdsa_constraint.pub_y_indices[i] = static_cast<uint32_t>(i + 128);
320 }
321
322 ecdsa_constraint.predicate = WitnessOrConstant<bb::fr>::from_index(static_cast<uint32_t>(160));
323 ecdsa_constraint.result = static_cast<uint32_t>(161);
324
325 WitnessVector witness(163, fr(0));
326 // Override public key values to avoid failures
327 auto point = bb::curve::SECP256K1::AffineElement::one();
328 auto x_buffer = point.x.to_buffer();
329 auto y_buffer = point.y.to_buffer();
330 for (size_t idx = 0; idx < 32; idx++) {
331 witness[idx + 96] = x_buffer[idx];
332 witness[idx + 128] = y_buffer[idx];
333 }
334
335 AcirFormat constraint_system{
336 .max_witness_index = static_cast<uint32_t>(witness.size()) - 1,
337 .num_acir_opcodes = 1,
338 .public_inputs = {},
339 .ecdsa_k1_constraints = { ecdsa_constraint },
340 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .ecdsa_k1_constraints = { 0 } },
341 };
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>({ ECDSA_SECP256K1<TypeParam> }));
348}
349
351{
352 EcdsaConstraint ecdsa_constraint{ .type = bb::CurveType::SECP256R1 };
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_r1_constraints = { ecdsa_constraint },
387 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .ecdsa_r1_constraints = { 0 } },
388 };
389
390 AcirProgram program{ constraint_system, witness };
391 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
392 auto builder = create_circuit<TypeParam>(program, metadata);
393
394 EXPECT_EQ(program.constraints.gates_per_opcode, std::vector<size_t>({ ECDSA_SECP256R1<TypeParam> }));
395}
396
398{
399 Blake2sConstraint blake2s_constraint;
400
401 blake2s_constraint.inputs.push_back(WitnessOrConstant<bb::fr>::from_index(0));
402
403 for (size_t i = 0; i < 32; ++i) {
404 blake2s_constraint.result[i] = static_cast<uint32_t>(i + 1);
405 }
406
407 WitnessVector witness(33, fr(0));
408
409 AcirFormat constraint_system{
410 .max_witness_index = static_cast<uint32_t>(witness.size()) - 1,
411 .num_acir_opcodes = 1,
412 .public_inputs = {},
413 .blake2s_constraints = { blake2s_constraint },
414 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .blake2s_constraints = { 0 } },
415 };
416
417 AcirProgram program{ constraint_system, witness };
418 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
419 auto builder = create_circuit<TypeParam>(program, metadata);
420
421 EXPECT_EQ(program.constraints.gates_per_opcode, std::vector<size_t>({ BLAKE2S<TypeParam> }));
422}
423
425{
426 Blake3Constraint blake3_constraint;
427
428 blake3_constraint.inputs.push_back(WitnessOrConstant<bb::fr>::from_index(0));
429
430 for (size_t i = 0; i < 32; ++i) {
431 blake3_constraint.result[i] = static_cast<uint32_t>(i + 1);
432 }
433
434 WitnessVector witness(33, fr(0));
435
436 AcirFormat constraint_system{
437 .max_witness_index = static_cast<uint32_t>(witness.size()) - 1,
438 .num_acir_opcodes = 1,
439 .public_inputs = {},
440 .blake3_constraints = { blake3_constraint },
441 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .blake3_constraints = { 0 } },
442 };
443
444 AcirProgram program{ constraint_system, witness };
445 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
446 auto builder = create_circuit<TypeParam>(program, metadata);
447
448 EXPECT_EQ(program.constraints.gates_per_opcode, std::vector<size_t>({ BLAKE3<TypeParam> }));
449}
450
452{
453 using GrumpkinPoint = bb::grumpkin::g1::affine_element;
454
455 // Use a valid Grumpkin point (the generator)
456 auto point = GrumpkinPoint::one();
457
458 MultiScalarMul msm_constraint;
459
460 // Create a minimal MSM with one point and one scalar
461 msm_constraint.points.push_back(WitnessOrConstant<bb::fr>::from_index(0)); // x
462 msm_constraint.points.push_back(WitnessOrConstant<bb::fr>::from_index(1)); // y
463 msm_constraint.points.push_back(WitnessOrConstant<bb::fr>::from_index(2)); // is_infinite
464
465 msm_constraint.scalars.push_back(WitnessOrConstant<bb::fr>::from_index(3)); // scalar_lo
466 msm_constraint.scalars.push_back(WitnessOrConstant<bb::fr>::from_index(4)); // scalar_hi
467
469
470 msm_constraint.out_point_x = 6;
471 msm_constraint.out_point_y = 7;
472 msm_constraint.out_point_is_infinite = 8;
473
474 WitnessVector witness(9, fr(0));
475 // Set valid point coordinates
476 witness[0] = point.x;
477 witness[1] = point.y;
478 witness[2] = fr(0);
479 witness[6] = point.x;
480 witness[7] = point.y;
481 witness[8] = fr(0);
482
483 AcirFormat constraint_system{
484 .max_witness_index = static_cast<uint32_t>(witness.size()) - 1,
485 .num_acir_opcodes = 1,
486 .public_inputs = {},
487 .multi_scalar_mul_constraints = { msm_constraint },
488 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .multi_scalar_mul_constraints = { 0 } },
489 };
490
491 AcirProgram program{ constraint_system, witness };
492 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
493 auto builder = create_circuit<TypeParam>(program, metadata);
494
495 EXPECT_EQ(program.constraints.gates_per_opcode, std::vector<size_t>({ MULTI_SCALAR_MUL<TypeParam> }));
496}
497
499{
500 using GrumpkinPoint = bb::grumpkin::g1::affine_element;
501
502 // Use valid Grumpkin points (the generator)
503 auto point1 = GrumpkinPoint::one();
504 auto point2 = GrumpkinPoint::one();
505
506 EcAdd ec_add_constraint{
509 .input1_infinite = WitnessOrConstant<bb::fr>::from_index(2),
512 .input2_infinite = WitnessOrConstant<bb::fr>::from_index(5),
514 .result_x = 7,
515 .result_y = 8,
516 .result_infinite = 9,
517 };
518
519 WitnessVector witness(10, fr(0));
520 // Set valid point1 coordinates
521 witness[0] = point1.x;
522 witness[1] = point1.y;
523 witness[2] = fr(0);
524 // Set valid point2 coordinates
525 witness[3] = point2.x;
526 witness[4] = point2.y;
527 witness[5] = fr(0);
528 // Set valid result coordinates
529 witness[7] = point1.x;
530 witness[8] = point1.y;
531 witness[9] = fr(0);
532
533 AcirFormat constraint_system{
534 .max_witness_index = static_cast<uint32_t>(witness.size()) - 1,
535 .num_acir_opcodes = 1,
536 .public_inputs = {},
537 .ec_add_constraints = { ec_add_constraint },
538 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .ec_add_constraints = { 0 } },
539 };
540
541 AcirProgram program{ constraint_system, witness };
542 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
543 auto builder = create_circuit<TypeParam>(program, metadata);
544
545 EXPECT_EQ(program.constraints.gates_per_opcode, std::vector<size_t>({ EC_ADD<TypeParam> }));
546}
547
549{
550 WitnessVector witness{ 10, 20, 0, 10 };
551
552 // Create a simple ROM block with 2 elements and 1 read
553 std::vector<uint32_t> init;
554 init.push_back(0); // 10
555 init.push_back(1); // 20
556
558 trace.push_back(MemOp{
559 .access_type = AccessType::Read,
562 });
563
564 BlockConstraint block_constraint{
565 .init = init,
566 .trace = trace,
567 .type = BlockType::ROM,
568 .calldata_id = CallDataType::None,
569 };
570
571 AcirFormat constraint_system{
572 .max_witness_index = static_cast<uint32_t>(witness.size()) - 1,
573 .num_acir_opcodes = 1, // The block constraint creates 2 opcodes, but the first one doesn't add any gate, so we
574 // set num_acir_opcodes to 1 to track only the contribution from the second one
575 .public_inputs = {},
576 .block_constraints = { block_constraint },
577 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .block_constraints = { { 0 } } },
578 };
579
580 AcirProgram program{ constraint_system, witness };
581 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
582 auto builder = create_circuit<TypeParam>(program, metadata);
583
584 EXPECT_EQ(program.constraints.gates_per_opcode, std::vector<size_t>({ BLOCK_ROM_READ<TypeParam> }));
585}
586
588{
589 WitnessVector witness{ 10, 20, 0, 10 };
590
591 // Create a simple RAM block with 2 elements and 1 read
592 std::vector<uint32_t> init;
593 init.push_back(0); // 10
594 init.push_back(1); // 20
595
597 trace.push_back(MemOp{
598 .access_type = AccessType::Read,
601 });
602
603 BlockConstraint block_constraint{
604 .init = init,
605 .trace = trace,
606 .type = BlockType::RAM,
607 .calldata_id = CallDataType::None,
608 };
609
610 AcirFormat constraint_system{
611 .max_witness_index = static_cast<uint32_t>(witness.size()) - 1,
612 .num_acir_opcodes = 1, // The block constraint creates 2 opcodes, but the first one doesn't add any gate, so we
613 // set num_acir_opcodes to 1 to track only the contribution from the second one
614 .public_inputs = {},
615 .block_constraints = { block_constraint },
616 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .block_constraints = { { 0 } } },
617 };
618
619 AcirProgram program{ constraint_system, witness };
620 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
621 auto builder = create_circuit<TypeParam>(program, metadata);
622};
623
625{
626 WitnessVector witness{ 10, 20, 0, 10 };
627
628 // Create a simple RAM block with 2 elements and 1 read
629 std::vector<uint32_t> init;
630 init.push_back(0); // 10
631 init.push_back(1); // 20
632
634 trace.push_back(MemOp{
635 .access_type = AccessType::Write,
638 });
639
640 BlockConstraint block_constraint{
641 .init = init,
642 .trace = trace,
643 .type = BlockType::RAM,
644 .calldata_id = CallDataType::None,
645 };
646
647 AcirFormat constraint_system{
648 .max_witness_index = static_cast<uint32_t>(witness.size()) - 1,
649 .num_acir_opcodes = 1, // The block constraint creates 2 opcodes, but the first one doesn't add any gate, so we
650 // set num_acir_opcodes to 1 to track only the contribution from the second one
651 .public_inputs = {},
652 .block_constraints = { block_constraint },
653 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .block_constraints = { { 0 } } },
654 };
655
656 AcirProgram program{ constraint_system, witness };
657 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
658 auto builder = create_circuit<TypeParam>(program, metadata);
659
660 EXPECT_EQ(program.constraints.gates_per_opcode, std::vector<size_t>({ BLOCK_RAM_WRITE<TypeParam> }));
661}
662
664{
665 if constexpr (!IsMegaBuilder<TypeParam>) {
666 GTEST_SKIP() << "CallData only supported on MegaCircuitBuilder";
667 }
668
669 WitnessVector witness{ 10, 20, 0, 10 };
670
671 // Create a simple CallData block with 2 elements and 1 read
672 std::vector<uint32_t> init;
673 init.push_back(0); // 10
674 init.push_back(1); // 20
675
677 trace.push_back(MemOp{
678 .access_type = AccessType::Read,
681 });
682
683 // Primary calldata
684 {
685 BlockConstraint block_constraint{
686 .init = init,
687 .trace = trace,
688 .type = BlockType::CallData,
689 .calldata_id = CallDataType::Primary,
690 };
691
692 AcirFormat constraint_system{
693 .max_witness_index = static_cast<uint32_t>(witness.size()) - 1,
694 .num_acir_opcodes = 1, // The block constraint creates 2 opcodes, but the first one doesn't add any gate, so
695 // we set num_acir_opcodes to 1 to track only the contribution from the second one
696 .public_inputs = {},
697 .block_constraints = { block_constraint },
698 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .block_constraints = { { 0 } } },
699 };
700
701 AcirProgram program{ constraint_system, witness };
702 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
703 auto builder = create_circuit<TypeParam>(program, metadata);
704
705 EXPECT_EQ(program.constraints.gates_per_opcode, std::vector<size_t>({ BLOCK_CALLDATA<TypeParam> }));
706 }
707
708 // Secondary calldata
709 {
710 BlockConstraint block_constraint{
711 .init = init,
712 .trace = trace,
713 .type = BlockType::CallData,
714 .calldata_id = CallDataType::Secondary,
715 };
716
717 AcirFormat constraint_system{
718 .max_witness_index = static_cast<uint32_t>(witness.size()) - 1,
719 .num_acir_opcodes = 1, // The block constraint creates 2 opcodes, but the first one doesn't add any gate, so
720 // we set num_acir_opcodes to 1 to track only the contribution from the second one
721 .public_inputs = {},
722 .block_constraints = { block_constraint },
723 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .block_constraints = { { 0 } } },
724 };
725
726 AcirProgram program{ constraint_system, witness };
727 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
728 auto builder = create_circuit<TypeParam>(program, metadata);
729
730 EXPECT_EQ(program.constraints.gates_per_opcode, std::vector<size_t>({ BLOCK_CALLDATA<TypeParam> }));
731 }
732}
733
735{
736 if constexpr (!IsMegaBuilder<TypeParam>) {
737 GTEST_SKIP() << "ReturnData only supported on MegaCircuitBuilder";
738 }
739
740 WitnessVector witness{ 10, 20 };
741
742 // Create a simple ReturnData block with 2 elements
743 std::vector<uint32_t> init;
744 init.push_back(0); // 10
745 init.push_back(1); // 20
746
747 BlockConstraint block_constraint{
748 .init = init,
749 .trace = {},
750 .type = BlockType::ReturnData,
751 .calldata_id = CallDataType::None,
752 };
753
754 AcirFormat constraint_system{
755 .max_witness_index = static_cast<uint32_t>(witness.size()) - 1,
756 .num_acir_opcodes = 1, // The block constraint creates 2 opcodes, but the first one doesn't add any gate, so we
757 // set num_acir_opcodes to 1 to track only the contribution from the second one
758 .public_inputs = {},
759 .block_constraints = { block_constraint },
760 .original_opcode_indices = AcirFormatOriginalOpcodeIndices{ .block_constraints = { { 0 } } },
761 };
762
763 AcirProgram program{ constraint_system, witness };
764 const ProgramMetadata metadata{
766 }; // We need to set it to false because ReturnData BlockConstraints do not have any trace, so we would be dividing
767 // by zero, and this would throw an error.
768 auto builder = create_circuit<TypeParam>(program, metadata);
769
770 EXPECT_EQ(builder.get_num_finalized_gates_inefficient(/*ensure_nonzero=*/false), BLOCK_RETURNDATA<TypeParam>);
771}
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
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(CommitmentKeyTest, CommitToZeroPoly)
@ 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::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< WitnessOrConstant< bb::fr > > inputs
std::array< uint32_t, 32 > result
std::array< uint32_t, 32 > result
std::vector< WitnessOrConstant< bb::fr > > inputs
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()