Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
relation_correctness.test.cpp
Go to the documentation of this file.
21
22#include <gtest/gtest.h>
23using namespace bb;
24
25void ensure_non_zero(auto& polynomial)
26{
27 bool has_non_zero_coefficient = false;
28 for (auto& coeff : polynomial.coeffs()) {
29 has_non_zero_coefficient |= !coeff.is_zero();
30 }
31 ASSERT_TRUE(has_non_zero_coefficient);
32}
33
34template <typename Flavor> void create_some_add_gates(auto& circuit_builder)
35{
36 using FF = typename Flavor::FF;
37 auto a = FF::random_element();
38
39 // Add some basic add gates; incorporate a public input for non-trivial PI-delta
40 uint32_t a_idx = circuit_builder.add_public_variable(a);
42 FF c = a + b;
43 FF d = a + c;
44 uint32_t b_idx = circuit_builder.add_variable(b);
45 uint32_t c_idx = circuit_builder.add_variable(c);
46 uint32_t d_idx = circuit_builder.add_variable(d);
47 for (size_t i = 0; i < 16; i++) {
48 circuit_builder.create_add_gate({ a_idx, b_idx, c_idx, 1, 1, -1, 0 });
49 circuit_builder.create_add_gate({ d_idx, c_idx, a_idx, 1, -1, -1, 0 });
50 }
51
52 // Add an Ultra-style big add gate with use of next row to test q_arith = 2
53 FF e = a + b + c + d;
54 uint32_t e_idx = circuit_builder.add_variable(e);
55
56 uint32_t zero_idx = circuit_builder.zero_idx();
57 circuit_builder.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, -1, -1, -1, -1, 0 }, true); // use next row
58 circuit_builder.create_big_add_gate({ zero_idx, zero_idx, zero_idx, e_idx, 0, 0, 0, 0, 0 }, false);
59}
60
61template <typename Flavor> void create_some_lookup_gates(auto& circuit_builder)
62{
63 using FF = typename Flavor::FF;
64 // Add some lookup gates (related to pedersen hashing)
65 auto pedersen_input_value = FF::random_element();
66 const auto input_hi =
67 uint256_t(pedersen_input_value)
68 .slice(plookup::fixed_base::table::BITS_PER_LO_SCALAR,
69 plookup::fixed_base::table::BITS_PER_LO_SCALAR + plookup::fixed_base::table::BITS_PER_HI_SCALAR);
70 const auto input_lo = uint256_t(pedersen_input_value).slice(0, bb::plookup::fixed_base::table::BITS_PER_LO_SCALAR);
71 const auto input_hi_index = circuit_builder.add_variable(FF(input_hi));
72 const auto input_lo_index = circuit_builder.add_variable(FF(input_lo));
73
74 const auto sequence_data_hi =
76 const auto sequence_data_lo =
78
79 circuit_builder.create_gates_from_plookup_accumulators(
80 plookup::MultiTableId::FIXED_BASE_LEFT_HI, sequence_data_hi, input_hi_index);
81 circuit_builder.create_gates_from_plookup_accumulators(
82 plookup::MultiTableId::FIXED_BASE_LEFT_LO, sequence_data_lo, input_lo_index);
83}
84
85template <typename Flavor> void create_some_delta_range_constraint_gates(auto& circuit_builder)
86{
87 // Add an `enforce_small_deltas` gate (simply checks that consecutive inputs have a difference of < 4)
88 using FF = typename Flavor::FF;
89 auto a_idx = circuit_builder.add_variable(FF(0));
90 auto b_idx = circuit_builder.add_variable(FF(1));
91 auto c_idx = circuit_builder.add_variable(FF(2));
92 auto d_idx = circuit_builder.add_variable(FF(3));
93 circuit_builder.enforce_small_deltas({ a_idx, b_idx, c_idx, d_idx });
94}
95
96template <typename Flavor> void create_some_RAM_gates(auto& circuit_builder)
97{
98 using FF = typename Flavor::FF;
99 // Add some RAM gates
100 uint32_t ram_values[8]{
101 circuit_builder.add_variable(FF::random_element()), circuit_builder.add_variable(FF::random_element()),
102 circuit_builder.add_variable(FF::random_element()), circuit_builder.add_variable(FF::random_element()),
103 circuit_builder.add_variable(FF::random_element()), circuit_builder.add_variable(FF::random_element()),
104 circuit_builder.add_variable(FF::random_element()), circuit_builder.add_variable(FF::random_element()),
105 };
106
107 size_t ram_id = circuit_builder.create_RAM_array(8);
108
109 for (size_t i = 0; i < 8; ++i) {
110 circuit_builder.init_RAM_element(ram_id, i, ram_values[i]);
111 }
112
113 auto a_idx = circuit_builder.read_RAM_array(ram_id, circuit_builder.add_variable(FF(5)));
114 EXPECT_EQ(a_idx != ram_values[5], true);
115
116 auto b_idx = circuit_builder.read_RAM_array(ram_id, circuit_builder.add_variable(FF(4)));
117 auto c_idx = circuit_builder.read_RAM_array(ram_id, circuit_builder.add_variable(FF(1)));
118
119 circuit_builder.write_RAM_array(ram_id, circuit_builder.add_variable(FF(4)), circuit_builder.add_variable(FF(500)));
120 auto d_idx = circuit_builder.read_RAM_array(ram_id, circuit_builder.add_variable(FF(4)));
121
122 EXPECT_EQ(circuit_builder.get_variable(d_idx), 500);
123
124 // ensure these vars get used in another arithmetic gate
125 const auto e_value = circuit_builder.get_variable(a_idx) + circuit_builder.get_variable(b_idx) +
126 circuit_builder.get_variable(c_idx) + circuit_builder.get_variable(d_idx);
127 auto e_idx = circuit_builder.add_variable(e_value);
128
129 circuit_builder.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, -1, -1, -1, -1, 0 }, true);
130 circuit_builder.create_big_add_gate(
131 {
132 circuit_builder.zero_idx(),
133 circuit_builder.zero_idx(),
134 circuit_builder.zero_idx(),
135 e_idx,
136 0,
137 0,
138 0,
139 0,
140 0,
141 },
142 false);
143}
144
145template <typename Flavor> void create_some_elliptic_curve_addition_gates(auto& circuit_builder)
146{
147 // Add an elliptic curve addition gate
148 grumpkin::g1::affine_element p1 = grumpkin::g1::affine_element::random_element();
149 grumpkin::g1::affine_element p2 = grumpkin::g1::affine_element::random_element();
150
152
153 uint32_t x1 = circuit_builder.add_variable(p1.x);
154 uint32_t y1 = circuit_builder.add_variable(p1.y);
155 uint32_t x2 = circuit_builder.add_variable(p2.x);
156 uint32_t y2 = circuit_builder.add_variable(p2.y);
157 uint32_t x3 = circuit_builder.add_variable(p3.x);
158 uint32_t y3 = circuit_builder.add_variable(p3.y);
159
160 circuit_builder.create_ecc_add_gate({ x1, y1, x2, y2, x3, y3, /*is_addition=*/false });
161}
162
163template <typename Flavor>
164void create_some_ecc_op_queue_gates(auto& circuit_builder)
165 requires IsMegaFlavor<Flavor>
166{
167 using G1 = typename Flavor::Curve::Group;
168 using FF = typename Flavor::FF;
169 const size_t num_ecc_operations = 10; // arbitrary
170 for (size_t i = 0; i < num_ecc_operations; ++i) {
171 auto point = G1::affine_one * FF::random_element();
172 auto scalar = FF::random_element();
173 circuit_builder.queue_ecc_mul_accum(point, scalar);
174 }
175}
176
177template <typename Flavor>
179 requires HasDataBus<Flavor>
180{
181 using FF = typename Flavor::FF;
182 auto val = builder.add_variable(FF::random_element());
183 builder.add_public_calldata(BusId::KERNEL_CALLDATA, val);
184 builder.read_calldata(BusId::KERNEL_CALLDATA, builder.add_variable(FF(0)));
185 for (size_t app_idx = 0; app_idx < MAX_APPS_PER_KERNEL; ++app_idx) {
186 auto bus_id = static_cast<BusId>(static_cast<size_t>(BusId::APP_CALLDATA) + app_idx);
187 builder.add_public_calldata(bus_id, val);
188 builder.read_calldata(bus_id, builder.add_variable(FF(0)));
189 }
190 builder.add_public_return_data(val);
191 builder.read_return_data(builder.add_variable(FF(0)));
192}
193
194template <typename Flavor> void create_some_non_native_field_gates(auto& builder)
195{
196 using Builder = typename Flavor::CircuitBuilder;
198
199 auto a = fq_ct::from_witness(&builder, bb::fq::random_element());
200 auto b = fq_ct::from_witness(&builder, bb::fq::random_element());
201 [[maybe_unused]] auto c = a * b;
202}
203
216
217class UltraRelationCorrectnessTests : public ::testing::Test {
218 protected:
220};
221
232// TODO(luke): Add a gate that sets q_arith = 3 to check secondary arithmetic relation
234{
235 using Flavor = UltraFlavor;
236
237 // Create a builder and then add an assortment of gates designed to ensure that the constraint(s) represented
238 // by each relation are non-trivially exercised.
240
241 // Create an assortment of representative gates
242 create_some_add_gates<Flavor>(builder);
243 create_some_lookup_gates<Flavor>(builder);
244 create_some_delta_range_constraint_gates<Flavor>(builder);
245 create_some_elliptic_curve_addition_gates<Flavor>(builder);
246 create_some_RAM_gates<Flavor>(builder);
247 create_some_non_native_field_gates<Flavor>(builder);
248 create_some_poseidon2_gates<Flavor>(builder);
250
251 // Create a prover (it will compute proving key and witness)
253
254 complete_prover_instance_for_test<Flavor>(prover_inst);
255
256 // Check that selectors are nonzero to ensure corresponding relation has nontrivial contribution
257 for (auto selector : prover_inst->polynomials.get_gate_selectors()) {
258 ensure_non_zero(selector);
259 }
260
261 auto& prover_polynomials = prover_inst->polynomials;
262 auto params = prover_inst->relation_parameters;
263
264 auto relation_failures = RelationChecker<Flavor>::check_all(prover_polynomials, params);
265 EXPECT_TRUE(relation_failures.empty());
266}
267
269{
270 using Flavor = MegaFlavor;
271
272 // Create a composer and then add an assortment of gates designed to ensure that the constraint(s) represented
273 // by each relation are non-trivially exercised.
275
276 // Create an assortment of representative gates
277 create_some_add_gates<Flavor>(builder);
278 create_some_lookup_gates<Flavor>(builder);
279 create_some_delta_range_constraint_gates<Flavor>(builder);
280 create_some_elliptic_curve_addition_gates<Flavor>(builder);
281 create_some_RAM_gates<Flavor>(builder);
282 create_some_ecc_op_queue_gates<Flavor>(builder);
283 create_some_databus_gates<Flavor>(builder);
284 create_some_non_native_field_gates<Flavor>(builder);
285 create_some_poseidon2_gates<Flavor>(builder);
287
288 // Create a prover (it will compute proving key and witness)
290
291 complete_prover_instance_for_test<Flavor>(prover_inst);
292
293 // Check that selectors and databus inverses are nonzero to ensure relations are non-trivially exercised
294 for (auto selector : prover_inst->polynomials.get_gate_selectors()) {
295 ensure_non_zero(selector);
296 }
297
298 // Check the databus read counts/tags/inverses are non-zero (data columns may be zero with DEFAULT_VALUE=0)
299 for (auto poly : prover_inst->polynomials.get_databus_inverses()) {
300 ensure_non_zero(poly);
301 }
302
303 auto& prover_polynomials = prover_inst->polynomials;
304 auto params = prover_inst->relation_parameters;
305
306 auto relation_failures = RelationChecker<Flavor>::check_all(prover_polynomials, params);
307 EXPECT_TRUE(relation_failures.empty());
308}
typename Curve::ScalarField FF
ECCVMCircuitBuilder CircuitBuilder
static AllSubrelationFailures check_all(const auto &polynomials, const auto &params)
Check that the provided polynomials satisfy all relations for a given Flavor.
static FF hash(const std::vector< FF > &input)
Hashes a vector of field elements.
element class. Implements ecc group arithmetic using Jacobian coordinates See https://hyperelliptic....
Definition element.hpp:35
constexpr uint256_t slice(uint64_t start, uint64_t end) const
static void add_default(Builder &builder)
Add default public inputs when they are not present.
AluTraceBuilder builder
Definition alu.test.cpp:124
FF a
FF b
@ Ultra
bn254::BaseField fq_ct
stdlib::witness_t< Builder > witness_ct
AvmProvingInputs inputs
ReadData< bb::fr > get_lookup_accumulators(const MultiTableId id, const fr &key_a, const fr &key_b, const bool is_2_to_1_lookup)
Given a table ID and the key(s) for a key-value lookup, return the lookup accumulators.
@ FIXED_BASE_LEFT_LO
Definition types.hpp:104
@ FIXED_BASE_LEFT_HI
Definition types.hpp:105
std::filesystem::path bb_crs_path()
void init_file_crs_factory(const std::filesystem::path &path)
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
TEST_F(IPATest, ChallengesAreZero)
Definition ipa.test.cpp:155
BusId
Definition databus.hpp:75
UltraCircuitBuilder_< UltraExecutionTraceBlocks > UltraCircuitBuilder
MegaCircuitBuilder_< field< Bn254FrParams > > MegaCircuitBuilder
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
Curve::AffineElement G1
static field random_element(numeric::RNG *engine=nullptr) noexcept
static constexpr size_t BITS_PER_LO_SCALAR
void create_some_delta_range_constraint_gates(auto &circuit_builder)
void create_some_ecc_op_queue_gates(auto &circuit_builder)
void create_some_RAM_gates(auto &circuit_builder)
void create_some_poseidon2_gates(auto &builder)
void create_some_non_native_field_gates(auto &builder)
void create_some_databus_gates(auto &builder)
void create_some_elliptic_curve_addition_gates(auto &circuit_builder)
void create_some_lookup_gates(auto &circuit_builder)
void ensure_non_zero(auto &polynomial)
void create_some_add_gates(auto &circuit_builder)