Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
arithmetic_constraints.test.cpp
Go to the documentation of this file.
2#include "acir_format.hpp"
3
8
9#include <cstdint>
10#include <gtest/gtest.h>
11#include <vector>
12
13using namespace acir_format;
14
15template <typename Builder_,
16 typename AcirConstraint_,
17 size_t num_multiplication_terms,
18 size_t num_linear_terms,
19 bool overlap_mul_and_linear,
20 bool overlap_linear>
22 public:
23 using Builder = Builder_;
24 using AcirConstraint = AcirConstraint_;
25 static constexpr size_t NUM_MULTIPLICATION_TERMS = num_multiplication_terms;
26 static constexpr size_t NUM_LINEAR_TERMS = num_linear_terms;
27 static constexpr bool OVERLAP_MUL_AND_LINEAR = overlap_mul_and_linear;
28 static constexpr bool OVERLAP_LINEAR = overlap_linear;
29};
30
31template <typename Builder_,
32 typename AcirConstraint_,
33 size_t num_multiplication_terms,
34 size_t num_linear_terms,
35 bool overlap_mul_and_linear,
36 bool overlap_linear>
38 public:
39 using Builder = Builder_;
40 using AcirConstraint = AcirConstraint_;
41
43
47 static constexpr size_t num_overlap_mul_and_linear()
48 {
49 size_t result = 0;
50
51 if constexpr (overlap_mul_and_linear) {
52 result++;
53 }
54
55 if constexpr (overlap_mul_and_linear && num_multiplication_terms > 1) {
56 result++;
57 }
58
59 if constexpr (overlap_mul_and_linear && num_multiplication_terms > 2) {
60 result++;
61 }
62
63 return result;
64 }
65
67 static constexpr size_t NUM_OVERLAP_LINEAR = 1;
68 static constexpr size_t LINEAR_OFFSET = overlap_mul_and_linear ? NUM_OVERLAP_MUL_AND_LINEAR : 0U;
69
70 static size_t expected_num_gates()
71 {
72 size_t num_gates = 0;
73
74 size_t num_multiplication_gates = num_multiplication_terms;
75 num_gates += num_multiplication_gates;
76
77 // Compute the number of witnesses that have to be put into wires on top of the multiplication terms
78 size_t num_witnesses_into_wires = num_linear_terms;
79 num_witnesses_into_wires -= overlap_mul_and_linear ? NUM_OVERLAP_MUL_AND_LINEAR : 0U;
80 num_witnesses_into_wires -= overlap_linear ? NUM_OVERLAP_LINEAR : 0U;
81
82 // Update the number of required gates
83
84 // The first gate uses all wires, so we fit two new witnesses when there are multiplication terms, 4 otherwise
85 size_t num_witnesses_first_wire = num_multiplication_gates != 0 ? 2U : 4U;
86 if (num_witnesses_into_wires <= num_witnesses_first_wire) {
87 return num_multiplication_gates != 0 ? num_multiplication_gates : 1U;
88 }
89 num_witnesses_into_wires -= num_witnesses_first_wire;
90 num_gates += num_multiplication_gates != 0 ? 0U : 1U;
91
92 // All other gates don't use the last wire, so we fit one new witness per gate
93 if (num_witnesses_into_wires + 1 <= num_gates) {
94 return num_gates;
95 }
96 num_witnesses_into_wires -= (num_multiplication_gates - 1);
97
98 // Now we add the remaining witnesses
99 size_t num_additional_gates = num_witnesses_into_wires / (Builder::NUM_WIRES - 1);
100 size_t diff = num_witnesses_into_wires - num_additional_gates * (Builder::NUM_WIRES - 1);
101 num_additional_gates += diff == 0 ? 0U : 1U;
102
103 return num_gates + num_additional_gates;
104 }
105
107 public:
113 static std::vector<std::string> get_labels() { return { "None", "InvalidateConstant", "InvalidateWitness" }; }
114 };
115
117 const std::vector<std::tuple<bb::fr, std::pair<uint32_t, bb::fr>, std::pair<uint32_t, bb::fr>>>& mul_terms,
118 const std::vector<std::pair<bb::fr, std::pair<uint32_t, bb::fr>>>& linear_terms,
119 const std::vector<bb::fr>& witness_values)
120 {
121 bb::fr result = 0;
122
123 for (const auto& mul_term : mul_terms) {
124 bb::fr scalar = std::get<0>(mul_term);
125 bb::fr lhs_value = witness_values[std::get<1>(mul_term).first];
126 bb::fr rhs_value = witness_values[std::get<2>(mul_term).first];
127 result += scalar * lhs_value * rhs_value;
128 }
129
130 for (const auto& linear_term : linear_terms) {
131 bb::fr scalar = linear_term.first;
132 bb::fr value = witness_values[linear_term.second.first];
133 result += scalar * value;
134 }
135
136 return result;
137 }
138
140
141 static void generate_constraints(AcirConstraint& arithmetic_constraint, WitnessVector& witness_values)
142 {
143 // (scalar, (lhs_index, lhs_value), (rhs_index, rhs_value))
145 // (scalar, (index, value)
147
148 mul_terms.reserve(num_multiplication_terms);
149 for (size_t idx = 0; idx < num_multiplication_terms; ++idx) {
150 bb::fr lhs_value = bb::fr::random_element();
151 bb::fr rhs_value = bb::fr::random_element();
153
154 uint32_t lhs_index = add_to_witness_and_track_indices(witness_values, lhs_value);
155 uint32_t rhs_index = add_to_witness_and_track_indices(witness_values, rhs_value);
156 mul_terms.push_back(
157 std::make_tuple(scalar, std::make_pair(lhs_index, lhs_value), std::make_pair(rhs_index, rhs_value)));
158 }
159
160 linear_terms.reserve(num_linear_terms);
161 for (size_t idx = 0; idx < num_linear_terms; ++idx) {
164
165 uint32_t index = add_to_witness_and_track_indices(witness_values, value);
166 linear_terms.push_back(std::make_pair(scalar, std::make_pair(index, value)));
167 }
168
169 // Expressions that would lead to these cases are:
170 // 1. w1 * w2 + w1
171 // 2. w1 * w2 + w3 * w4 + w1 + w4
172 // 3. w1 * w1 + w3 * w4 + w5 * w5 + w1 + w4 + w5
173 if constexpr (overlap_mul_and_linear) {
174 BB_ASSERT_GTE(num_linear_terms, 1U, "We need at least 1 linear terms when overlapping is turned on.");
176 num_multiplication_terms, 1U, "We need at least 1 multiplication terms when overlapping is turned on.");
177
178 // Overlap lhs of multiplication term with linear term
179 std::get<1>(mul_terms[0]).first = linear_terms[0].second.first;
180
181 if constexpr (num_multiplication_terms > 1 && num_linear_terms > 1) {
182 // Overlap rhs of multiplication term with linear term
183 std::get<2>(mul_terms[1]).first = linear_terms[1].second.first;
184 }
185
186 if constexpr (num_multiplication_terms > 2 && num_linear_terms > 2) {
187 // Overlap both terms in the multiplication term with linear term
188 std::get<1>(mul_terms[2]).first = linear_terms[2].second.first;
189 std::get<2>(mul_terms[2]).first = linear_terms[2].second.first;
190 }
191 }
192
193 // Expression that would lead to this case is:
194 // w1 + w1
195 if constexpr (overlap_linear) {
196 BB_ASSERT_GT(num_linear_terms,
198 "We need at least " << NUM_OVERLAP_LINEAR + LINEAR_OFFSET + 1
199 << " linear term when overlapping is turned on.");
200
201 // Overlap two linear terms
202 linear_terms[LINEAR_OFFSET].second.first = linear_terms[LINEAR_OFFSET + 1].second.first;
203 }
204
205 bb::fr result = -evaluate_expression_result(mul_terms, linear_terms, witness_values);
206
207 // Build the Acir::Expression
208 Acir::Expression expression;
209 for (const auto& mul_term : mul_terms) {
210 expression.mul_terms.push_back(std::make_tuple(std::get<0>(mul_term).to_buffer(),
211 Acir::Witness(std::get<1>(mul_term).first),
212 Acir::Witness(std::get<2>(mul_term).first)));
213 }
214 for (const auto& linear_term : linear_terms) {
215 expression.linear_combinations.push_back(
216 std::make_tuple(linear_term.first.to_buffer(), Acir::Witness(linear_term.second.first)));
217 }
218 expression.q_c = result.to_buffer();
219
220 // Construct the big quad constraint
221 Acir::Opcode::AssertZero acir_assert_zero{ .value = expression };
222 AcirFormat dummy_acir_format;
223 assert_zero_to_quad_constraints(acir_assert_zero, dummy_acir_format, 0);
224
225 // Check that the construction worked as expected
226 size_t EXPECTED_NUM_GATES = expected_num_gates();
227 if (EXPECTED_NUM_GATES > 1) {
228 BB_ASSERT(dummy_acir_format.quad_constraints.empty());
229 BB_ASSERT_EQ(dummy_acir_format.big_quad_constraints.size(), 1U);
230 BB_ASSERT_EQ(dummy_acir_format.big_quad_constraints[0].size(), EXPECTED_NUM_GATES);
231 } else {
232 BB_ASSERT(dummy_acir_format.big_quad_constraints.empty());
233 BB_ASSERT_EQ(dummy_acir_format.quad_constraints.size(), 1U);
234 }
235
236 if constexpr (IS_BIG_QUAD) {
237 arithmetic_constraint = dummy_acir_format.big_quad_constraints[0];
238 } else {
239 arithmetic_constraint = dummy_acir_format.quad_constraints[0];
240 }
241 }
242
244 AcirConstraint constraint,
245 WitnessVector witness_values,
246 const typename InvalidWitness::Target& invalid_witness_target)
247 {
248 switch (invalid_witness_target) {
250 break;
252 // Invalidate the equation by changing the constant term
253 if constexpr (IS_BIG_QUAD) {
254 constraint[0].const_scaling += bb::fr::one();
255 } else {
256 constraint.const_scaling += bb::fr::one();
257 }
258 break;
259 }
261 // Invalidate the equation by changing one of the witness values
262 if constexpr (IS_BIG_QUAD) {
263 witness_values[constraint[0].a] += bb::fr::one();
264 } else {
265 witness_values[constraint.a] += bb::fr::one();
266 }
267 break;
268 }
269 };
270
271 return { constraint, witness_values };
272 };
273};
274
275template <typename ArithmeticConstraintParams_>
277 : public ::testing::Test,
278 public TestClass<ArithmeticConstraintsTestingFunctions<typename ArithmeticConstraintParams_::Builder,
279 typename ArithmeticConstraintParams_::AcirConstraint,
280 ArithmeticConstraintParams_::NUM_MULTIPLICATION_TERMS,
281 ArithmeticConstraintParams_::NUM_LINEAR_TERMS,
282 ArithmeticConstraintParams_::OVERLAP_MUL_AND_LINEAR,
283 ArithmeticConstraintParams_::OVERLAP_LINEAR>> {
284 protected:
286};
287
288using BigQuadConstraintConfigs = testing::Types<
290 // requiring 2 gates
295 // requiring 2 gates
298 // requiring 2 gates
300 // requiring 2 gates
305 // requiring 2 gates
308 // requiring 2 gates
309
311
312TYPED_TEST(BigQuadConstraintTest, GenerateVKFromConstraints)
313{
314 using Flavor =
316 TestFixture::template test_vk_independence<Flavor>();
317}
318
320{
321 TestFixture::test_tampering();
322}
323
324template <typename ArithmeticConstraintParams_>
326 : public ::testing::Test,
327 public TestClass<ArithmeticConstraintsTestingFunctions<typename ArithmeticConstraintParams_::Builder,
328 typename ArithmeticConstraintParams_::AcirConstraint,
329 ArithmeticConstraintParams_::NUM_MULTIPLICATION_TERMS,
330 ArithmeticConstraintParams_::NUM_LINEAR_TERMS,
331 ArithmeticConstraintParams_::OVERLAP_MUL_AND_LINEAR,
332 ArithmeticConstraintParams_::OVERLAP_LINEAR>> {
333 protected:
335};
336
337using QuadConstraintConfigs = testing::Types<
352
354
355TYPED_TEST(QuadConstraintTest, GenerateVKFromConstraints)
356{
357 using Flavor =
359 TestFixture::template test_vk_independence<Flavor>();
360}
361
363{
364 TestFixture::test_tampering();
365}
366
367template <typename Builder> class BigQuadOpcodeGateCountTest : public ::testing::Test {};
368
369using BuilderTypes = testing::Types<UltraCircuitBuilder, MegaCircuitBuilder>;
371
373{
376
377 BigQuadConstraint big_quad_constraint;
378 WitnessVector witness_values;
379 BigQuadConstraintTest::generate_constraints(big_quad_constraint, witness_values);
380
381 AcirFormat constraint_system = constraint_to_acir_format(big_quad_constraint);
382 AcirProgram program{ constraint_system, witness_values };
383 const ProgramMetadata metadata{ .collect_gates_per_opcode = true };
384 auto builder = create_circuit<TypeParam>(program, metadata);
385
386 EXPECT_EQ(program.constraints.gates_per_opcode, std::vector<size_t>({ BIG_QUAD<TypeParam> }));
387}
testing::Types< ArithmeticConstraintParams< UltraCircuitBuilder, QuadConstraint, 1, 0, false, false >, ArithmeticConstraintParams< UltraCircuitBuilder, QuadConstraint, 1, 1, false, false >, ArithmeticConstraintParams< UltraCircuitBuilder, QuadConstraint, 1, 2, false, false >, ArithmeticConstraintParams< UltraCircuitBuilder, QuadConstraint, 1, 3, false, true >, ArithmeticConstraintParams< UltraCircuitBuilder, QuadConstraint, 1, 4, true, true >, ArithmeticConstraintParams< UltraCircuitBuilder, QuadConstraint, 0, 4, false, false >, ArithmeticConstraintParams< UltraCircuitBuilder, QuadConstraint, 0, 4, false, true >, ArithmeticConstraintParams< MegaCircuitBuilder, QuadConstraint, 1, 0, false, false >, ArithmeticConstraintParams< MegaCircuitBuilder, QuadConstraint, 1, 1, false, false >, ArithmeticConstraintParams< MegaCircuitBuilder, QuadConstraint, 1, 2, false, false >, ArithmeticConstraintParams< MegaCircuitBuilder, QuadConstraint, 1, 3, false, true >, ArithmeticConstraintParams< MegaCircuitBuilder, QuadConstraint, 1, 4, true, true >, ArithmeticConstraintParams< MegaCircuitBuilder, QuadConstraint, 0, 4, false, false >, ArithmeticConstraintParams< MegaCircuitBuilder, QuadConstraint, 0, 5, false, true > > QuadConstraintConfigs
testing::Types< ArithmeticConstraintParams< UltraCircuitBuilder, BigQuadConstraint, 1, 3, false, false >, ArithmeticConstraintParams< UltraCircuitBuilder, BigQuadConstraint, 0, 5, false, false >, ArithmeticConstraintParams< UltraCircuitBuilder, BigQuadConstraint, 2, 0, false, false >, ArithmeticConstraintParams< UltraCircuitBuilder, BigQuadConstraint, 3, 3, true, false >, ArithmeticConstraintParams< UltraCircuitBuilder, BigQuadConstraint, 1, 4, false, true >, ArithmeticConstraintParams< UltraCircuitBuilder, BigQuadConstraint, 5, 5, true, true >, ArithmeticConstraintParams< UltraCircuitBuilder, BigQuadConstraint, 0, 6, false, true >, ArithmeticConstraintParams< MegaCircuitBuilder, BigQuadConstraint, 1, 3, false, false >, ArithmeticConstraintParams< MegaCircuitBuilder, BigQuadConstraint, 0, 5, false, false >, ArithmeticConstraintParams< MegaCircuitBuilder, BigQuadConstraint, 2, 0, false, false >, ArithmeticConstraintParams< MegaCircuitBuilder, BigQuadConstraint, 3, 3, true, false >, ArithmeticConstraintParams< MegaCircuitBuilder, BigQuadConstraint, 1, 4, false, true >, ArithmeticConstraintParams< MegaCircuitBuilder, BigQuadConstraint, 5, 5, true, true >, ArithmeticConstraintParams< MegaCircuitBuilder, BigQuadConstraint, 0, 6, false, true > > BigQuadConstraintConfigs
#define BB_ASSERT(expression,...)
Definition assert.hpp:70
#define BB_ASSERT_GTE(left, right,...)
Definition assert.hpp:128
#define BB_ASSERT_GT(left, right,...)
Definition assert.hpp:113
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:83
static constexpr size_t NUM_MULTIPLICATION_TERMS
static void generate_constraints(AcirConstraint &arithmetic_constraint, WitnessVector &witness_values)
static std::pair< AcirConstraint, WitnessVector > invalidate_witness(AcirConstraint constraint, WitnessVector witness_values, const typename InvalidWitness::Target &invalid_witness_target)
static bb::fr evaluate_expression_result(const std::vector< std::tuple< bb::fr, std::pair< uint32_t, bb::fr >, std::pair< uint32_t, bb::fr > > > &mul_terms, const std::vector< std::pair< bb::fr, std::pair< uint32_t, bb::fr > > > &linear_terms, const std::vector< bb::fr > &witness_values)
static constexpr size_t num_overlap_mul_and_linear()
Compute the number of elements to overlap between multiplication and linear terms.
Constraint representing a polynomial of degree 1 or 2 that does not fit into a standard UltraHonk ari...
AluTraceBuilder builder
Definition alu.test.cpp:124
AcirFormat constraint_to_acir_format(const ConstraintType &constraint)
Convert an AcirConstraint (single or vector) to AcirFormat by going through the full ACIR serde flow.
std::vector< bb::fr > WitnessVector
std::vector< uint32_t > add_to_witness_and_track_indices(std::vector< bb::fr > &witness, const T &input)
Append values to a witness vector and track their indices.
Definition utils.hpp:90
void assert_zero_to_quad_constraints(Acir::Opcode::AssertZero const &arg, AcirFormat &af, size_t opcode_index)
Single entrypoint for processing arithmetic (AssertZero) opcodes.
std::filesystem::path bb_crs_path()
void init_file_crs_factory(const std::filesystem::path &path)
TYPED_TEST_SUITE(BoomerangRecursiveVerifierTest, Flavors)
TYPED_TEST(CommitmentKeyTest, CommitToZeroPoly)
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)
std::vector< std::tuple< std::vector< uint8_t >, Acir::Witness > > linear_combinations
Definition acir.hpp:2796
std::vector< uint8_t > q_c
Definition acir.hpp:2797
std::vector< std::tuple< std::vector< uint8_t >, Acir::Witness, Acir::Witness > > mul_terms
Definition acir.hpp:2795
Acir::Expression value
Definition acir.hpp:3047
Barretenberg's representation of ACIR constraints.
std::vector< QuadConstraint > quad_constraints
std::vector< BigQuadConstraint > big_quad_constraints
Struct containing both the constraints to be added to the circuit and the witness vector.
Metadata required to create a circuit.
static constexpr field one()
static field random_element(numeric::RNG *engine=nullptr) noexcept
BB_INLINE std::vector< uint8_t > to_buffer() const