Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
mega_circuit_builder.test.cpp
Go to the documentation of this file.
5#include <gtest/gtest.h>
6
7using namespace bb;
8
9namespace {
11}
12namespace bb {
13
14TEST(MegaCircuitBuilder, CopyConstructor)
15{
17 fr a = fr::one();
18 builder.add_public_variable(a);
19
20 for (size_t i = 0; i < 16; ++i) {
21 for (size_t j = 0; j < 16; ++j) {
22 uint64_t left = static_cast<uint64_t>(j);
23 uint64_t right = static_cast<uint64_t>(i);
24 uint32_t left_idx = builder.add_variable(fr(left));
25 uint32_t right_idx = builder.add_variable(fr(right));
26 uint32_t result_idx = builder.add_variable(fr(left ^ right));
27
28 uint32_t add_idx = builder.add_variable(fr(left) + fr(right) + builder.get_variable(result_idx));
29 builder.create_big_add_gate(
30 { left_idx, right_idx, result_idx, add_idx, fr(1), fr(1), fr(1), fr(-1), fr(0) });
31 }
32 }
33
34 // Compute a simple point accumulation natively
35 auto P1 = g1::affine_element::random_element();
36 auto P2 = g1::affine_element::random_element();
37 auto z = fr::random_element();
38
39 // Add gates corresponding to the above operations
40 builder.queue_ecc_add_accum(P1);
41 builder.queue_ecc_mul_accum(P2, z);
42 builder.queue_ecc_eq();
43
44 bool result = CircuitChecker::check(builder);
45 EXPECT_EQ(result, true);
46
47 MegaCircuitBuilder duplicate_builder{ builder };
48
49 EXPECT_EQ(duplicate_builder, builder);
50 EXPECT_TRUE(CircuitChecker::check(duplicate_builder));
51}
52
54{
56 fr a = fr::one();
57 builder.add_public_variable(a);
58 bool result = CircuitChecker::check(builder);
59 EXPECT_EQ(result, true);
60}
61
70{
71 const size_t CHUNK_SIZE = stdlib::NUM_LIMB_BITS_IN_FIELD_SIMULATION * 2;
72
74
75 // Compute a simple point accumulation natively
76 auto P1 = g1::affine_element::random_element();
77 auto P2 = g1::affine_element::random_element();
78 auto z = fr::random_element();
79 auto P_expected = P1 + P2 * z;
80
81 // Add gates corresponding to the above operations
82 builder.queue_ecc_add_accum(P1);
83 builder.queue_ecc_mul_accum(P2, z);
84
85 // Add equality op gates based on the internal accumulator
86 auto eq_op_tuple = builder.queue_ecc_eq();
87
88 // Check that we can reconstruct the coordinates of P_expected from the data in variables
89 auto P_result_x_lo = uint256_t(builder.get_variable(eq_op_tuple.x_lo));
90 auto P_result_x_hi = uint256_t(builder.get_variable(eq_op_tuple.x_hi));
91 auto P_result_x = P_result_x_lo + (P_result_x_hi << CHUNK_SIZE);
92 auto P_result_y_lo = uint256_t(builder.get_variable(eq_op_tuple.y_lo));
93 auto P_result_y_hi = uint256_t(builder.get_variable(eq_op_tuple.y_hi));
94 auto P_result_y = P_result_y_lo + (P_result_y_hi << CHUNK_SIZE);
95 EXPECT_EQ(P_result_x, uint256_t(P_expected.x));
96 EXPECT_EQ(P_result_y, uint256_t(P_expected.y));
97
98 // Check that the accumulator in the op queue has been reset to 0
99 auto accumulator = builder.op_queue->get_accumulator();
100 EXPECT_EQ(accumulator, g1::affine_point_at_infinity);
101
102 // Check number of ecc op "gates"/rows = 3 ops * 2 rows per op = 6
103 EXPECT_EQ(builder.blocks.ecc_op.size(), 6);
104
105 // Check that the expected op codes have been correctly recorded in the 1st op wires pointed by circuit indices
106 auto opcode_wire_indexes = builder.blocks.ecc_op.w_l();
107 EXPECT_EQ(builder.get_variable(opcode_wire_indexes[0]), (EccOpCode{ .add = true }).value());
108 EXPECT_EQ(builder.get_variable(opcode_wire_indexes[2]), (EccOpCode{ .mul = true }).value());
109 EXPECT_EQ(builder.get_variable(opcode_wire_indexes[4]), (EccOpCode{ .eq = true, .reset = true }).value());
110
111 // Check that we can reconstruct the coordinates of P1 from the op_wires
112 auto P1_x_lo = uint256_t(builder.get_variable(builder.blocks.ecc_op.w_r()[0]));
113 auto P1_x_hi = uint256_t(builder.get_variable(builder.blocks.ecc_op.w_o()[0]));
114 auto P1_x = P1_x_lo + (P1_x_hi << CHUNK_SIZE);
115 EXPECT_EQ(P1_x, uint256_t(P1.x));
116 auto P1_y_lo = uint256_t(builder.get_variable(builder.blocks.ecc_op.w_4()[0]));
117 auto P1_y_hi = uint256_t(builder.get_variable(builder.blocks.ecc_op.w_r()[1]));
118 auto P1_y = P1_y_lo + (P1_y_hi << CHUNK_SIZE);
119 EXPECT_EQ(P1_y, uint256_t(P1.y));
120
121 // Check that we can reconstruct the coordinates of P2 from the op_wires
122 auto P2_x_lo = uint256_t(builder.get_variable(builder.blocks.ecc_op.w_r()[2]));
123 auto P2_x_hi = uint256_t(builder.get_variable(builder.blocks.ecc_op.w_o()[2]));
124 auto P2_x = P2_x_lo + (P2_x_hi << CHUNK_SIZE);
125 EXPECT_EQ(P2_x, uint256_t(P2.x));
126 auto P2_y_lo = uint256_t(builder.get_variable(builder.blocks.ecc_op.w_4()[2]));
127 auto P2_y_hi = uint256_t(builder.get_variable(builder.blocks.ecc_op.w_r()[3]));
128 auto P2_y = P2_y_lo + (P2_y_hi << CHUNK_SIZE);
129 EXPECT_EQ(P2_y, uint256_t(P2.y));
130}
131
136TEST(MegaCircuitBuilder, GoblinEccOpQueueUltraOps)
137{
138 // Construct a simple circuit with op gates
140
141 // Compute a simple point accumulation natively
142 auto P1 = g1::affine_element::random_element();
143 auto P2 = g1::affine_element::random_element();
144 auto z = fr::random_element();
145
146 // Add gates corresponding to the above operations
147 builder.queue_ecc_add_accum(P1);
148 builder.queue_ecc_mul_accum(P2, z);
149 builder.queue_ecc_eq();
150
151 // Merge the ops of the incoming circuit
152 builder.op_queue->merge();
153
154 // Check that the ultra ops recorded in the EccOpQueue match the ops recorded in the wires
155 auto ultra_ops = builder.op_queue->construct_current_ultra_ops_subtable_columns();
156 for (size_t i = 1; i < 4; ++i) {
157 for (size_t j = 0; j < builder.blocks.ecc_op.size(); ++j) {
158 auto op_wire_val = builder.get_variable(builder.blocks.ecc_op.wires[i][j]);
159 auto ultra_op_val = ultra_ops[i][j];
160 ASSERT_EQ(op_wire_val, ultra_op_val);
161 }
162 }
163}
164
170TEST(MegaCircuitBuilder, CompleteSelectorPartitioningCheck)
171{
174 bool result = CircuitChecker::check(builder);
175 EXPECT_EQ(result, true);
176
177 // For each block, we want to check that all of the other selectors are zero on that block besides the one
178 // corresponding to the current block
179 for (auto& block : builder.blocks.get()) {
180 for (size_t i = 0; i < block.size(); ++i) {
181 if (&block != &builder.blocks.arithmetic) {
182 EXPECT_EQ(block.q_arith()[i], 0);
183 }
184 if (&block != &builder.blocks.delta_range) {
185 EXPECT_EQ(block.q_delta_range()[i], 0);
186 }
187 if (&block != &builder.blocks.elliptic) {
188 EXPECT_EQ(block.q_elliptic()[i], 0);
189 }
190 if (&block != &builder.blocks.memory) {
191 EXPECT_EQ(block.q_memory()[i], 0);
192 }
193 if (&block != &builder.blocks.nnf) {
194 EXPECT_EQ(block.q_nnf()[i], 0);
195 }
196 if (&block != &builder.blocks.lookup) {
197 EXPECT_EQ(block.q_lookup_type()[i], 0);
198 }
199 if (&block != &builder.blocks.busread) {
200 EXPECT_EQ(block.q_busread()[i], 0);
201 }
202 if (&block != &builder.blocks.poseidon2_external) {
203 EXPECT_EQ(block.q_poseidon2_external()[i], 0);
204 }
205 if (&block != &builder.blocks.poseidon2_internal) {
206 EXPECT_EQ(block.q_poseidon2_internal()[i], 0);
207 }
208 }
209 }
210}
211
212} // namespace bb
static void construct_simple_circuit(MegaBuilder &builder, bool last_circuit=false)
Generate a simple test circuit with some ECC op gates and conventional arithmetic gates.
static bool check(const Builder &circuit)
Check the witness satisifies the circuit.
static constexpr affine_element affine_point_at_infinity
Definition group.hpp:49
AluTraceBuilder builder
Definition alu.test.cpp:123
FF a
numeric::RNG & engine
RNG & get_debug_randomness(bool reset, std::uint_fast64_t seed)
Definition engine.cpp:190
Entry point for Barretenberg command-line interface.
TEST(MegaCircuitBuilder, CopyConstructor)
field< Bn254FrParams > fr
Definition fr.hpp:174
MegaCircuitBuilder_< field< Bn254FrParams > > MegaCircuitBuilder
Defines the opcodes for ECC operations used in both the Ultra and ECCVM formats. There are three opco...
static constexpr field one()
static field random_element(numeric::RNG *engine=nullptr) noexcept