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.
19
20#include <gtest/gtest.h>
21using namespace bb;
22
23void ensure_non_zero(auto& polynomial)
24{
25 bool has_non_zero_coefficient = false;
26 for (auto& coeff : polynomial.coeffs()) {
27 has_non_zero_coefficient |= !coeff.is_zero();
28 }
29 ASSERT_TRUE(has_non_zero_coefficient);
30}
31
32template <typename Flavor> void create_some_add_gates(auto& circuit_builder)
33{
34 using FF = typename Flavor::FF;
35 auto a = FF::random_element();
36
37 // Add some basic add gates; incorporate a public input for non-trivial PI-delta
38 uint32_t a_idx = circuit_builder.add_public_variable(a);
40 FF c = a + b;
41 FF d = a + c;
42 uint32_t b_idx = circuit_builder.add_variable(b);
43 uint32_t c_idx = circuit_builder.add_variable(c);
44 uint32_t d_idx = circuit_builder.add_variable(d);
45 for (size_t i = 0; i < 16; i++) {
46 circuit_builder.create_add_gate({ a_idx, b_idx, c_idx, 1, 1, -1, 0 });
47 circuit_builder.create_add_gate({ d_idx, c_idx, a_idx, 1, -1, -1, 0 });
48 }
49
50 // Add an Ultra-style big add gate with use of next row to test q_arith = 2
51 FF e = a + b + c + d;
52 uint32_t e_idx = circuit_builder.add_variable(e);
53
54 uint32_t zero_idx = circuit_builder.zero_idx();
55 circuit_builder.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, -1, -1, -1, -1, 0 }, true); // use next row
56 circuit_builder.create_big_add_gate({ zero_idx, zero_idx, zero_idx, e_idx, 0, 0, 0, 0, 0 }, false);
57}
58
59template <typename Flavor> void create_some_lookup_gates(auto& circuit_builder)
60{
61 using FF = typename Flavor::FF;
62 // Add some lookup gates (related to pedersen hashing)
63 auto pedersen_input_value = FF::random_element();
64 const auto input_hi =
65 uint256_t(pedersen_input_value)
66 .slice(plookup::fixed_base::table::BITS_PER_LO_SCALAR,
67 plookup::fixed_base::table::BITS_PER_LO_SCALAR + plookup::fixed_base::table::BITS_PER_HI_SCALAR);
68 const auto input_lo = uint256_t(pedersen_input_value).slice(0, bb::plookup::fixed_base::table::BITS_PER_LO_SCALAR);
69 const auto input_hi_index = circuit_builder.add_variable(FF(input_hi));
70 const auto input_lo_index = circuit_builder.add_variable(FF(input_lo));
71
72 const auto sequence_data_hi =
74 const auto sequence_data_lo =
76
77 circuit_builder.create_gates_from_plookup_accumulators(
78 plookup::MultiTableId::FIXED_BASE_LEFT_HI, sequence_data_hi, input_hi_index);
79 circuit_builder.create_gates_from_plookup_accumulators(
80 plookup::MultiTableId::FIXED_BASE_LEFT_LO, sequence_data_lo, input_lo_index);
81}
82
83template <typename Flavor> void create_some_delta_range_constraint_gates(auto& circuit_builder)
84{
85 // Add a sort gate (simply checks that consecutive inputs have a difference of < 4)
86 using FF = typename Flavor::FF;
87 auto a_idx = circuit_builder.add_variable(FF(0));
88 auto b_idx = circuit_builder.add_variable(FF(1));
89 auto c_idx = circuit_builder.add_variable(FF(2));
90 auto d_idx = circuit_builder.add_variable(FF(3));
91 circuit_builder.create_sort_constraint({ a_idx, b_idx, c_idx, d_idx });
92}
93
94template <typename Flavor> void create_some_RAM_gates(auto& circuit_builder)
95{
96 using FF = typename Flavor::FF;
97 // Add some RAM gates
98 uint32_t ram_values[8]{
99 circuit_builder.add_variable(FF::random_element()), circuit_builder.add_variable(FF::random_element()),
100 circuit_builder.add_variable(FF::random_element()), circuit_builder.add_variable(FF::random_element()),
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 };
104
105 size_t ram_id = circuit_builder.create_RAM_array(8);
106
107 for (size_t i = 0; i < 8; ++i) {
108 circuit_builder.init_RAM_element(ram_id, i, ram_values[i]);
109 }
110
111 auto a_idx = circuit_builder.read_RAM_array(ram_id, circuit_builder.add_variable(FF(5)));
112 EXPECT_EQ(a_idx != ram_values[5], true);
113
114 auto b_idx = circuit_builder.read_RAM_array(ram_id, circuit_builder.add_variable(FF(4)));
115 auto c_idx = circuit_builder.read_RAM_array(ram_id, circuit_builder.add_variable(FF(1)));
116
117 circuit_builder.write_RAM_array(ram_id, circuit_builder.add_variable(FF(4)), circuit_builder.add_variable(FF(500)));
118 auto d_idx = circuit_builder.read_RAM_array(ram_id, circuit_builder.add_variable(FF(4)));
119
120 EXPECT_EQ(circuit_builder.get_variable(d_idx), 500);
121
122 // ensure these vars get used in another arithmetic gate
123 const auto e_value = circuit_builder.get_variable(a_idx) + circuit_builder.get_variable(b_idx) +
124 circuit_builder.get_variable(c_idx) + circuit_builder.get_variable(d_idx);
125 auto e_idx = circuit_builder.add_variable(e_value);
126
127 circuit_builder.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, -1, -1, -1, -1, 0 }, true);
128 circuit_builder.create_big_add_gate(
129 {
130 circuit_builder.zero_idx(),
131 circuit_builder.zero_idx(),
132 circuit_builder.zero_idx(),
133 e_idx,
134 0,
135 0,
136 0,
137 0,
138 0,
139 },
140 false);
141}
142
143template <typename Flavor> void create_some_elliptic_curve_addition_gates(auto& circuit_builder)
144{
145 // Add an elliptic curve addition gate
146 grumpkin::g1::affine_element p1 = grumpkin::g1::affine_element::random_element();
147 grumpkin::g1::affine_element p2 = grumpkin::g1::affine_element::random_element();
148
150
151 uint32_t x1 = circuit_builder.add_variable(p1.x);
152 uint32_t y1 = circuit_builder.add_variable(p1.y);
153 uint32_t x2 = circuit_builder.add_variable(p2.x);
154 uint32_t y2 = circuit_builder.add_variable(p2.y);
155 uint32_t x3 = circuit_builder.add_variable(p3.x);
156 uint32_t y3 = circuit_builder.add_variable(p3.y);
157
158 circuit_builder.create_ecc_add_gate({ x1, y1, x2, y2, x3, y3, -1 });
159}
160
161template <typename Flavor> void create_some_ecc_op_queue_gates(auto& circuit_builder)
162{
163 using G1 = typename Flavor::Curve::Group;
164 using FF = typename Flavor::FF;
165 static_assert(IsMegaFlavor<Flavor>);
166 const size_t num_ecc_operations = 10; // arbitrary
167 for (size_t i = 0; i < num_ecc_operations; ++i) {
168 auto point = G1::affine_one * FF::random_element();
169 auto scalar = FF::random_element();
170 circuit_builder.queue_ecc_mul_accum(point, scalar);
171 }
172}
173
174class UltraRelationCorrectnessTests : public ::testing::Test {
175 protected:
177};
178
189// TODO(luke): Add a gate that sets q_arith = 3 to check secondary arithmetic relation
191{
192 using Flavor = UltraFlavor;
193
194 // Create a builder and then add an assortment of gates designed to ensure that the constraint(s) represented
195 // by each relation are non-trivially exercised.
197
198 // Create an assortment of representative gates
199 create_some_add_gates<Flavor>(builder);
200 create_some_lookup_gates<Flavor>(builder);
201 create_some_delta_range_constraint_gates<Flavor>(builder);
202 create_some_elliptic_curve_addition_gates<Flavor>(builder);
203 create_some_RAM_gates<Flavor>(builder);
205
206 // Create a prover (it will compute proving key and witness)
208
210
211 // Check that selectors are nonzero to ensure corresponding relation has nontrivial contribution
212 for (auto selector : prover_inst->polynomials.get_gate_selectors()) {
213 ensure_non_zero(selector);
214 }
215
216 auto& prover_polynomials = prover_inst->polynomials;
217 auto params = prover_inst->relation_parameters;
218
219 auto relation_failures = RelationChecker<Flavor>::check_all(prover_polynomials, params);
220 EXPECT_TRUE(relation_failures.empty());
221}
222
224{
225 using Flavor = MegaFlavor;
226
227 // Create a composer and then add an assortment of gates designed to ensure that the constraint(s) represented
228 // by each relation are non-trivially exercised.
230
231 // Create an assortment of representative gates
232 create_some_add_gates<Flavor>(builder);
233 create_some_lookup_gates<Flavor>(builder);
234 create_some_delta_range_constraint_gates<Flavor>(builder);
235 create_some_elliptic_curve_addition_gates<Flavor>(builder);
236 create_some_RAM_gates<Flavor>(builder);
237 create_some_ecc_op_queue_gates<Flavor>(builder); // Goblin!
239
240 // Create a prover (it will compute proving key and witness)
242
244
245 // Check that selectors are nonzero to ensure corresponding relation has nontrivial contribution
246 for (auto selector : prover_inst->polynomials.get_gate_selectors()) {
247 ensure_non_zero(selector);
248 }
249
250 // Check the databus entities are non-zero
251 for (auto selector : prover_inst->polynomials.get_databus_entities()) {
252 ensure_non_zero(selector);
253 }
254 auto& prover_polynomials = prover_inst->polynomials;
255 auto params = prover_inst->relation_parameters;
256
257 auto relation_failures = RelationChecker<Flavor>::check_all(prover_polynomials, params);
258 EXPECT_TRUE(relation_failures.empty());
259}
typename Curve::ScalarField FF
static AllSubrelationFailures check_all(const auto &polynomials, const auto &params)
Check that the provided polynomials satisfy all relations for a given Flavor.
static void complete_prover_instance_for_test(const std::shared_ptr< ProverInstance_< Flavor > > &prover_inst)
TEST only method for completing computation of the prover polynomials using random challenges.
element class. Implements ecc group arithmetic using Jacobian coordinates See https://hyperelliptic....
Definition element.hpp:33
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
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:92
@ FIXED_BASE_LEFT_HI
Definition types.hpp:93
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:185
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_RAM_gates(auto &circuit_builder)
void create_some_ecc_op_queue_gates(auto &circuit_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)