Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
arithmetic_constraints.cpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Complete, auditors: [Federico], commit: 2094fd1467dd9a94803b2c5007cf60ac357aa7d2 }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
8
9namespace acir_format {
10
11template <typename Builder> void set_zero_idx(const Builder& builder, QuadConstraint& mul_quad)
12{
13 using FF = Builder::FF;
14
15 auto replace_and_check_zero_scaling = [&](uint32_t& index, const FF& scaling) {
16 if (index == bb::stdlib::IS_CONSTANT) {
17 index = builder.zero_idx();
18 BB_ASSERT_EQ(scaling, FF(0), "mul_quad_ gate with IS_CONSTANT witness index has non-zero scaling");
19 }
20 };
21
22 BB_ASSERT_NEQ(mul_quad.a,
23 bb::stdlib::IS_CONSTANT,
24 "mul_quad_ gate cannot have IS_CONSTANT for witness a. An error here probably means a conversion "
25 "issue in acir_to_constraint_buf.");
26 replace_and_check_zero_scaling(mul_quad.b, mul_quad.b_scaling);
27 replace_and_check_zero_scaling(mul_quad.c, mul_quad.c_scaling);
28 replace_and_check_zero_scaling(mul_quad.d, mul_quad.d_scaling);
29}
30
31template <typename Builder>
32void check_mul_add_gate(Builder& builder, const QuadConstraint& mul_quad, const typename Builder::FF next_wire_w4)
33{
34 using FF = Builder::FF;
35
36 if (builder.failed() || builder.is_write_vk_mode()) {
37 return;
38 }
39
40 FF result = mul_quad.const_scaling + next_wire_w4;
41 result += builder.get_variable(mul_quad.a) * builder.get_variable(mul_quad.b) * mul_quad.mul_scaling;
42 result += builder.get_variable(mul_quad.a) * mul_quad.a_scaling;
43 result += builder.get_variable(mul_quad.b) * mul_quad.b_scaling;
44 result += builder.get_variable(mul_quad.c) * mul_quad.c_scaling;
45 result += builder.get_variable(mul_quad.d) * mul_quad.d_scaling;
46
47 if (result != FF::zero()) {
48 builder.failure("mul_add_gate");
49 }
50}
51
52template <typename Builder>
54 const bilinear_batched_eq_gate_<typename Builder::FF>& bilinear_batched_eq)
55{
56 using FF = typename Builder::FF;
57
58 if (builder.failed() || builder.is_write_vk_mode()) {
59 return;
60 }
61
62 auto value_from_witness = [&](uint32_t w) { return builder.get_variable(w); };
63
64 FF half_1;
65 FF half_2;
66 if (bilinear_batched_eq.mode == BilinearBatchedEqMode::Bilinear) {
67 half_1 = bilinear_batched_eq.q_m * value_from_witness(bilinear_batched_eq.a) *
68 value_from_witness(bilinear_batched_eq.b) +
69 bilinear_batched_eq.q_5 * value_from_witness(bilinear_batched_eq.a) *
70 value_from_witness(bilinear_batched_eq.c) +
71 bilinear_batched_eq.q_l * value_from_witness(bilinear_batched_eq.a) +
72 bilinear_batched_eq.q_r * value_from_witness(bilinear_batched_eq.b) +
73 bilinear_batched_eq.q_o * value_from_witness(bilinear_batched_eq.c) +
74 bilinear_batched_eq.q_4 * value_from_witness(bilinear_batched_eq.d) + bilinear_batched_eq.q_c;
75 half_2 = FF::zero();
76 } else {
77 half_1 = bilinear_batched_eq.q_l * value_from_witness(bilinear_batched_eq.a) +
78 bilinear_batched_eq.q_r * value_from_witness(bilinear_batched_eq.b) + bilinear_batched_eq.q_c;
79 half_2 = bilinear_batched_eq.q_o * value_from_witness(bilinear_batched_eq.c) +
80 bilinear_batched_eq.q_4 * value_from_witness(bilinear_batched_eq.d) + bilinear_batched_eq.q_m;
81 }
82
83 if (half_1 != FF::zero() || half_2 != FF::zero()) {
84 builder.failure("bilinear_batched_eq_gate");
85 }
86}
87
88template <typename Builder> void create_quad_constraint(Builder& builder, QuadConstraint& mul_quad)
89{
90 // Replace IS_CONSTANT indices with zero indices
91 set_zero_idx(builder, mul_quad);
92 // Check if the gate is valid
93 check_mul_add_gate(builder, mul_quad);
94 // Create gate
95 builder.create_big_mul_add_gate(mul_quad);
96}
97
98template <typename Builder> void create_big_quad_constraint(Builder& builder, BigQuadConstraint& big_constraint)
99{
100 using FF = typename Builder::FF;
101
102 // The index/value of the 4-th witness in the next gate (not used in the first gate)
103 // It is result of the expression calculated on the current gate
104 uint32_t next_w4_wire_idx = 0;
105 FF next_w4_wire_value = FF::zero();
106
107 for (size_t j = 0; j < big_constraint.size() - 1; ++j) {
108 // Replace IS_CONSTANT indices with zero indices
109 set_zero_idx(builder, big_constraint[j]);
110 // Create the mul_add gate
111 builder.create_big_mul_add_gate(big_constraint[j], /*include_next_gate_w_4*/ true);
112 // Update the index/value of the 4-th wire
113 next_w4_wire_value = builder.get_variable(big_constraint[j].a) * builder.get_variable(big_constraint[j].b) *
114 big_constraint[j].mul_scaling +
115 builder.get_variable(big_constraint[j].a) * big_constraint[j].a_scaling +
116 builder.get_variable(big_constraint[j].b) * big_constraint[j].b_scaling +
117 builder.get_variable(big_constraint[j].c) * big_constraint[j].c_scaling +
118 builder.get_variable(big_constraint[j].d) * big_constraint[j].d_scaling +
119 big_constraint[j].const_scaling;
120 next_w4_wire_value = -next_w4_wire_value;
121 next_w4_wire_idx = builder.add_variable(next_w4_wire_value);
122 // Check if the gate is valid
123 check_mul_add_gate(builder, big_constraint[j], next_w4_wire_value);
124 // Set the 4-th wire of the next gate
125 big_constraint[j + 1].d = next_w4_wire_idx;
126 big_constraint[j + 1].d_scaling = fr(-1);
127 }
128 // Replace IS_CONSTANT indices with zero indices
129 set_zero_idx(builder, big_constraint.back());
130 // Create final gate
131 builder.create_big_mul_add_gate(big_constraint.back(), /*include_next_gate_w_4*/ false);
132 // Check if the gate is valid
133 check_mul_add_gate(builder, big_constraint.back());
134}
135
136template <typename Builder> void create_bilinear_constraint(Builder& builder, const BilinearConstraint& constraint)
137{
138 using FF = typename Builder::FF;
139 // The two products fill wires a, b, c with real witnesses. Wire d carries only a linear term and may
140 // be the IS_CONSTANT sentinel; substitute the builder's zero index so the row references a real slot.
141 BB_ASSERT(constraint.a != bb::stdlib::IS_CONSTANT && constraint.b != bb::stdlib::IS_CONSTANT &&
142 constraint.c != bb::stdlib::IS_CONSTANT,
143 "create_bilinear_constraint: the product wires a, b, c must be real witnesses.");
144 uint32_t d = constraint.d == bb::stdlib::IS_CONSTANT ? builder.zero_idx() : constraint.d;
145
147 .mode = BilinearBatchedEqMode::Bilinear,
148 .a = constraint.a,
149 .b = constraint.b,
150 .c = constraint.c,
151 .d = d,
152 .q_l = constraint.q_l,
153 .q_r = constraint.q_r,
154 .q_o = constraint.q_o,
155 .q_4 = constraint.q_4,
156 .q_c = constraint.q_c,
157 .q_m = constraint.q_m,
158 .q_5 = constraint.q_5,
159 };
161 builder.create_bilinear_batched_eq_gate(gate);
162}
163
164template <typename Builder>
166{
167 using FF = typename Builder::FF;
168 // A BATCHED_EQ row may leave wires as the IS_CONSTANT sentinel. Substitute the builder's zero index so each row
169 // references a real witness slot. Wire `a` is always a real witness.
170 BatchedEqCheckConstraint resolved = constraint;
171 BB_ASSERT(resolved.a != bb::stdlib::IS_CONSTANT,
172 "create_batched_eq_check_constraint: wire `a` must always be a real witness index.");
173 if (resolved.b == bb::stdlib::IS_CONSTANT) {
174 resolved.b = builder.zero_idx();
175 }
176 if (resolved.c == bb::stdlib::IS_CONSTANT) {
177 resolved.c = builder.zero_idx();
178 }
179 if (resolved.d == bb::stdlib::IS_CONSTANT) {
180 resolved.d = builder.zero_idx();
181 }
182
184 .mode = BilinearBatchedEqMode::BatchedEq,
185 .a = resolved.a,
186 .b = resolved.b,
187 .c = resolved.c,
188 .d = resolved.d,
189 .q_l = resolved.q_l,
190 .q_r = resolved.q_r,
191 .q_o = resolved.q_o,
192 .q_4 = resolved.q_4,
193 .q_c = resolved.q_c,
194 .q_m = resolved.q_m,
195 .q_5 = FF::zero(),
196 };
198 builder.create_bilinear_batched_eq_gate(gate);
199}
200
202
204
206 const QuadConstraint&,
207 const typename UltraCircuitBuilder::FF);
208
210 const QuadConstraint&,
211 const typename MegaCircuitBuilder::FF);
212
214
216
218 BigQuadConstraint& big_constraint);
219
221 BigQuadConstraint& big_constraint);
222
229
230} // namespace acir_format
#define BB_ASSERT(expression,...)
Definition assert.hpp:70
#define BB_ASSERT_NEQ(actual, expected,...)
Definition assert.hpp:98
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:83
Constraint representing a polynomial of degree 1 or 2 that does not fit into a standard UltraHonk ari...
typename ExecutionTrace::FF FF
AluTraceBuilder builder
Definition alu.test.cpp:124
FF a
FF b
void create_big_quad_constraint(Builder &builder, BigQuadConstraint &big_constraint)
void set_zero_idx(const Builder &builder, QuadConstraint &mul_quad)
Replace indices which are set to IS_CONSTANT with the zero index of the builder.
void check_bilinear_batched_eq_gate(Builder &builder, const bilinear_batched_eq_gate_< typename Builder::FF > &bilinear_batched_eq)
Check that a bilinear batched-eq gate is valid.
template void set_zero_idx< UltraCircuitBuilder >(const UltraCircuitBuilder &, QuadConstraint &)
void create_batched_eq_check_constraint(Builder &builder, const BatchedEqCheckConstraint &constraint)
Emit a BATCHED_EQ-mode bilinear_batched_eq gate row described by constraint on builder.
template void set_zero_idx< MegaCircuitBuilder >(const MegaCircuitBuilder &, QuadConstraint &)
template void create_bilinear_constraint< MegaCircuitBuilder >(MegaCircuitBuilder &, const BilinearConstraint &)
template void create_quad_constraint< UltraCircuitBuilder >(UltraCircuitBuilder &builder, QuadConstraint &constraint)
template void create_batched_eq_check_constraint< MegaCircuitBuilder >(MegaCircuitBuilder &, const BatchedEqCheckConstraint &)
template void create_bilinear_constraint< UltraCircuitBuilder >(UltraCircuitBuilder &, const BilinearConstraint &)
template void create_big_quad_constraint< UltraCircuitBuilder >(UltraCircuitBuilder &builder, BigQuadConstraint &big_constraint)
template void check_mul_add_gate< MegaCircuitBuilder >(MegaCircuitBuilder &, const QuadConstraint &, const typename MegaCircuitBuilder::FF)
template void create_big_quad_constraint< MegaCircuitBuilder >(MegaCircuitBuilder &builder, BigQuadConstraint &big_constraint)
template void create_quad_constraint< MegaCircuitBuilder >(MegaCircuitBuilder &builder, QuadConstraint &constraint)
void check_mul_add_gate(Builder &builder, const QuadConstraint &mul_quad, const typename Builder::FF next_wire_w4)
Check if a mul add gate is valid.
void create_quad_constraint(Builder &builder, QuadConstraint &mul_quad)
Create a simple width-4 Ultra arithmetic gate constraint representing the equation.
template void create_batched_eq_check_constraint< UltraCircuitBuilder >(UltraCircuitBuilder &, const BatchedEqCheckConstraint &)
void create_bilinear_constraint(Builder &builder, const BilinearConstraint &constraint)
Emit a BILINEAR-mode bilinear_batched_eq gate row.
template void check_mul_add_gate< UltraCircuitBuilder >(UltraCircuitBuilder &, const QuadConstraint &, const typename UltraCircuitBuilder::FF)
AvmFlavorSettings::FF FF
Definition field.hpp:10
field< Bn254FrParams > fr
Definition fr.hpp:155
BatchedEq constraint — BATCHED_EQ mode of the bilinear_batched_eq gate (see bilinear_or_batched_eq_ch...
Bilinear constraint — BILINEAR mode of the bilinear_batched_eq gate (see bilinear_or_batched_eq_check...
BilinearBatchedEqMode mode
Definition gate_data.hpp:61
VectorField result