barretenberg
Loading...
Searching...
No Matches
goblin_translator_circuit_builder.hpp
1#pragma once
11#include "barretenberg/common/constexpr_utils.hpp"
12#include "barretenberg/ecc/curves/bn254/fq.hpp"
13#include "barretenberg/numeric/uint256/uint256.hpp"
14#include "barretenberg/proof_system/arithmetization/arithmetization.hpp"
15#include "barretenberg/proof_system/op_queue/ecc_op_queue.hpp"
16#include "circuit_builder_base.hpp"
17#include <array>
18#include <cstddef>
19#include <cstdlib>
20#include <iterator>
21#include <tuple>
22namespace proof_system {
76class GoblinTranslatorCircuitBuilder : public CircuitBuilderBase<barretenberg::fr> {
77 // We don't need templating for Goblin
78 using Fr = barretenberg::fr;
79 using Fq = barretenberg::fq;
81
82 public:
83 static constexpr size_t NUM_WIRES = Arithmetization::NUM_WIRES;
84
89 void create_add_gate(const add_triple_<Fr>&) override{};
90 void create_mul_gate(const mul_triple_<Fr>&) override{};
91 void create_bool_gate(const uint32_t) override{};
92 void create_poly_gate(const poly_triple_<Fr>&) override{};
93 [[nodiscard]] size_t get_num_constant_gates() const override { return 0; };
94
98 enum WireIds : size_t {
99 OP, // The first 4 wires contain the standard values from the EccQueue wire
100 X_LOW_Y_HI,
101 X_HIGH_Z_1,
102 Y_LOW_Z_2,
103 P_X_LOW_LIMBS, // P.xₗₒ split into 2 68 bit limbs
104 P_X_LOW_LIMBS_RANGE_CONSTRAINT_0, // Low limbs split further into smaller chunks for range constraints
105 P_X_LOW_LIMBS_RANGE_CONSTRAINT_1,
106 P_X_LOW_LIMBS_RANGE_CONSTRAINT_2,
107 P_X_LOW_LIMBS_RANGE_CONSTRAINT_3,
108 P_X_LOW_LIMBS_RANGE_CONSTRAINT_4,
109 P_X_LOW_LIMBS_RANGE_CONSTRAINT_TAIL,
110 P_X_HIGH_LIMBS, // P.xₕᵢ split into a 68 and a 50 bit limb
111 P_X_HIGH_LIMBS_RANGE_CONSTRAINT_0, // High limbs split into chunks for range constraints
112 P_X_HIGH_LIMBS_RANGE_CONSTRAINT_1,
113 P_X_HIGH_LIMBS_RANGE_CONSTRAINT_2,
114 P_X_HIGH_LIMBS_RANGE_CONSTRAINT_3,
115 P_X_HIGH_LIMBS_RANGE_CONSTRAINT_4,
116 P_X_HIGH_LIMBS_RANGE_CONSTRAINT_TAIL,
117 P_Y_LOW_LIMBS, // P.yₗₒ split into 2 68 bit limbs
118 P_Y_LOW_LIMBS_RANGE_CONSTRAINT_0, // Low limbs split into chunks for range constraints
119 P_Y_LOW_LIMBS_RANGE_CONSTRAINT_1,
120 P_Y_LOW_LIMBS_RANGE_CONSTRAINT_2,
121 P_Y_LOW_LIMBS_RANGE_CONSTRAINT_3,
122 P_Y_LOW_LIMBS_RANGE_CONSTRAINT_4,
123 P_Y_LOW_LIMBS_RANGE_CONSTRAINT_TAIL,
124 P_Y_HIGH_LIMBS, // P.yₕᵢ split into a 68 and a 50 bit limb
125 P_Y_HIGH_LIMBS_RANGE_CONSTRAINT_0, // High limbs split into chunks for range constraints
126 P_Y_HIGH_LIMBS_RANGE_CONSTRAINT_1,
127 P_Y_HIGH_LIMBS_RANGE_CONSTRAINT_2,
128 P_Y_HIGH_LIMBS_RANGE_CONSTRAINT_3,
129 P_Y_HIGH_LIMBS_RANGE_CONSTRAINT_4,
130 P_Y_HIGH_LIMBS_RANGE_CONSTRAINT_TAIL,
131 Z_LOW_LIMBS, // Low limbs of z_1 and z_2 (68 bits each)
132 Z_LOW_LIMBS_RANGE_CONSTRAINT_0, // Range constraints for low limbs of z_1 and z_2
133 Z_LOW_LIMBS_RANGE_CONSTRAINT_1,
134 Z_LOW_LIMBS_RANGE_CONSTRAINT_2,
135 Z_LOW_LIMBS_RANGE_CONSTRAINT_3,
136 Z_LOW_LIMBS_RANGE_CONSTRAINT_4,
137 Z_LOW_LIMBS_RANGE_CONSTRAINT_TAIL,
138 Z_HIGH_LIMBS, // High Limbs of z_1 and z_2 (60 bits each)
139 Z_HIGH_LIMBS_RANGE_CONSTRAINT_0, // Range constraints for high limbs of z_1 and z_2
140 Z_HIGH_LIMBS_RANGE_CONSTRAINT_1,
141 Z_HIGH_LIMBS_RANGE_CONSTRAINT_2,
142 Z_HIGH_LIMBS_RANGE_CONSTRAINT_3,
143 Z_HIGH_LIMBS_RANGE_CONSTRAINT_4,
144 Z_HIGH_LIMBS_RANGE_CONSTRAINT_TAIL,
145 ACCUMULATORS_BINARY_LIMBS_0, // Contain 68-bit limbs of current and previous accumulator (previous at higher
146 // indices because of the nuances of KZG commitment).
147 ACCUMULATORS_BINARY_LIMBS_1,
148 ACCUMULATORS_BINARY_LIMBS_2,
149 ACCUMULATORS_BINARY_LIMBS_3, // Highest limb is 50 bits (254 mod 68)
150 ACCUMULATOR_LOW_LIMBS_RANGE_CONSTRAINT_0, // Range constraints for the current accumulator limbs (no need to
151 // redo previous accumulator)
152 ACCUMULATOR_LOW_LIMBS_RANGE_CONSTRAINT_1,
153 ACCUMULATOR_LOW_LIMBS_RANGE_CONSTRAINT_2,
154 ACCUMULATOR_LOW_LIMBS_RANGE_CONSTRAINT_3,
155 ACCUMULATOR_LOW_LIMBS_RANGE_CONSTRAINT_4,
156 ACCUMULATOR_LOW_LIMBS_RANGE_CONSTRAINT_TAIL,
157 ACCUMULATOR_HIGH_LIMBS_RANGE_CONSTRAINT_0,
158 ACCUMULATOR_HIGH_LIMBS_RANGE_CONSTRAINT_1,
159 ACCUMULATOR_HIGH_LIMBS_RANGE_CONSTRAINT_2,
160 ACCUMULATOR_HIGH_LIMBS_RANGE_CONSTRAINT_3,
161 ACCUMULATOR_HIGH_LIMBS_RANGE_CONSTRAINT_4,
162 ACCUMULATOR_HIGH_LIMBS_RANGE_CONSTRAINT_TAIL,
163 QUOTIENT_LOW_BINARY_LIMBS, // Quotient limbs
164 QUOTIENT_HIGH_BINARY_LIMBS,
165 QUOTIENT_LOW_LIMBS_RANGE_CONSTRAIN_0, // Range constraints for quotient
166 QUOTIENT_LOW_LIMBS_RANGE_CONSTRAIN_1,
167 QUOTIENT_LOW_LIMBS_RANGE_CONSTRAIN_2,
168 QUOTIENT_LOW_LIMBS_RANGE_CONSTRAIN_3,
169 QUOTIENT_LOW_LIMBS_RANGE_CONSTRAIN_4,
170 QUOTIENT_LOW_LIMBS_RANGE_CONSTRAIN_TAIL,
171 QUOTIENT_HIGH_LIMBS_RANGE_CONSTRAIN_0,
172 QUOTIENT_HIGH_LIMBS_RANGE_CONSTRAIN_1,
173 QUOTIENT_HIGH_LIMBS_RANGE_CONSTRAIN_2,
174 QUOTIENT_HIGH_LIMBS_RANGE_CONSTRAIN_3,
175 QUOTIENT_HIGH_LIMBS_RANGE_CONSTRAIN_4,
176 QUOTIENT_HIGH_LIMBS_RANGE_CONSTRAIN_TAIL,
177 RELATION_WIDE_LIMBS, // Limbs for checking the correctness of mod 2²⁷² relations.
178 RELATION_WIDE_LIMBS_RANGE_CONSTRAINT_0,
179 RELATION_WIDE_LIMBS_RANGE_CONSTRAINT_1,
180 RELATION_WIDE_LIMBS_RANGE_CONSTRAINT_2,
181 RELATION_WIDE_LIMBS_RANGE_CONSTRAINT_3,
182
183 TOTAL_COUNT
184
185 };
186
187 // Basic goblin translator has the minicircuit size of 2048, so optimize for that case
188 // For context, minicircuit is the part of the final polynomials fed into the proving system, where we have all the
189 // arithmetic logic. However, the full circuit is several times larger (we use a trick to bring down the degree of
190 // the permutation argument)
191 static constexpr size_t DEFAULT_TRANSLATOR_VM_LENGTH = 2048;
192
193 // Maximum size of a single limb is 68 bits
194 static constexpr size_t NUM_LIMB_BITS = 68;
195
196 // For soundness we need to constrain the highest limb so that the whole value is at most 50 bits
197 static constexpr size_t NUM_LAST_LIMB_BITS = Fq::modulus.get_msb() + 1 - 3 * NUM_LIMB_BITS;
198
199 // 128-bit z_1 and z_2 are split into 2 limbs each
200 static constexpr size_t NUM_Z_LIMBS = 2;
201
202 // Number of bits in the quotient representation
203 static constexpr size_t NUM_QUOTIENT_BITS = 256;
204
205 // Number of bits in the quotient highest limb
206 static constexpr size_t NUM_LAST_QUOTIENT_LIMB_BITS = 256 - 3 * NUM_LIMB_BITS;
207
208 // Number of bits in Z scalars
209 static constexpr size_t NUM_Z_BITS = 128;
210 // The circuit builder has a default range constraint mechanism that is used throughout. It range cosntrains the
211 // values to < 2¹⁴
212 static constexpr size_t MICRO_LIMB_BITS = 14;
213
214 // Maximum size of a micro limb used for range constraints
215 static constexpr auto MAX_MICRO_LIMB_SIZE = (uint256_t(1) << MICRO_LIMB_BITS) - 1;
216
217 // To range constrain a limb to 68 bits we need 6 limbs: 5 for 14-bit windowed chunks and 1 to range constrain the
218 // highest to a more restrictive range (0 <= a < 2¹⁴ && 0 <= 4*a < 2¹⁴ ) ~ ( 0 <= a < 2¹² )
219 static constexpr size_t NUM_MICRO_LIMBS = 6;
220
221 // How many limbs we split the 254-bit value in
222 static constexpr size_t NUM_BINARY_LIMBS = 4;
223
224 // How many limbs we use for computation of result modulo 2²⁷²
225 static constexpr size_t NUM_RELATION_WIDE_LIMBS = 2;
226
227 // Range constraint of relation limbs
228 static constexpr size_t RELATION_WIDE_LIMB_BITS = 84;
229
230 // Maximum size of each relation limb (in accordance with range constraints)
231 static constexpr uint256_t MAX_RELATION_WIDE_LIMB_SIZE = uint256_t(1) << RELATION_WIDE_LIMB_BITS;
232
233 // Shift of a single micro (range constraint) limb
234 static constexpr auto MICRO_SHIFT = uint256_t(1) << MICRO_LIMB_BITS;
235
236 // Maximum size of 2 lower limbs concatenated
237 static constexpr auto MAX_LOW_WIDE_LIMB_SIZE = (uint256_t(1) << (NUM_LIMB_BITS * 2)) - 1;
238
239 // Maximum size of 2 higher limbs concatenated
240 static constexpr auto MAX_HIGH_WIDE_LIMB_SIZE = (uint256_t(1) << (NUM_LIMB_BITS + NUM_LAST_LIMB_BITS)) - 1;
241
242 // How much you'd need to multiply a value by to perform a shift to a higher binary limb
243 static constexpr auto SHIFT_1 = uint256_t(1) << NUM_LIMB_BITS;
244
245 // Shift by 2 binary limbs
246 static constexpr auto SHIFT_2 = uint256_t(1) << (NUM_LIMB_BITS << 1);
247
248 // Precomputed inverse to easily divide by the shift by 2 limbs
249 static constexpr auto SHIFT_2_INVERSE = Fr(SHIFT_2).invert();
250
251 // Shift by 3 binary limbs
252 static constexpr auto SHIFT_3 = uint256_t(1) << (NUM_LIMB_BITS * 3);
253
254 // The modulus of the target emulated field as a 512-bit integer
255 static constexpr uint512_t MODULUS_U512 = uint512_t(Fq::modulus);
256
257 // The binary modulus used in the CRT computation
258 static constexpr uint512_t BINARY_BASIS_MODULUS = uint512_t(1) << (NUM_LIMB_BITS << 2);
259
260 // Negated modulus of the target emulated field in the binary modulus
261 static constexpr uint512_t NEGATIVE_PRIME_MODULUS = BINARY_BASIS_MODULUS - MODULUS_U512;
262
263 // Negated modulus of the target emulated field in the binary modulus split into 4 binary limbs + the final limb is
264 // the negated modulus of the target emulated field in the scalar field
265 static constexpr std::array<Fr, 5> NEGATIVE_MODULUS_LIMBS = {
266 Fr(NEGATIVE_PRIME_MODULUS.slice(0, NUM_LIMB_BITS).lo),
267 Fr(NEGATIVE_PRIME_MODULUS.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2).lo),
268 Fr(NEGATIVE_PRIME_MODULUS.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3).lo),
269 Fr(NEGATIVE_PRIME_MODULUS.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo),
270 -Fr(Fq::modulus)
271 };
281 // Members necessary for the gate creation
282 Fr op_code; // Operator
283 Fr P_x_lo;
284 Fr P_x_hi;
285 std::array<Fr, NUM_BINARY_LIMBS> P_x_limbs;
286 std::array<std::array<Fr, NUM_MICRO_LIMBS>, NUM_BINARY_LIMBS> P_x_microlimbs;
287 Fr P_y_lo;
288 Fr P_y_hi;
289 std::array<Fr, NUM_BINARY_LIMBS> P_y_limbs;
290 std::array<std::array<Fr, NUM_MICRO_LIMBS>, NUM_BINARY_LIMBS> P_y_microlimbs;
291
292 Fr z_1;
293 std::array<Fr, NUM_Z_LIMBS> z_1_limbs;
294 std::array<std::array<Fr, NUM_MICRO_LIMBS>, NUM_Z_LIMBS> z_1_microlimbs;
295 Fr z_2;
296 std::array<Fr, NUM_Z_LIMBS> z_2_limbs;
297 std::array<std::array<Fr, NUM_MICRO_LIMBS>, NUM_Z_LIMBS> z_2_microlimbs;
298
299 std::array<Fr, NUM_BINARY_LIMBS> previous_accumulator;
300 std::array<Fr, NUM_BINARY_LIMBS> current_accumulator;
301 std::array<std::array<Fr, NUM_MICRO_LIMBS>, NUM_BINARY_LIMBS> current_accumulator_microlimbs;
302 std::array<Fr, NUM_BINARY_LIMBS> quotient_binary_limbs;
303 std::array<std::array<Fr, NUM_MICRO_LIMBS>, NUM_BINARY_LIMBS> quotient_microlimbs;
304 std::array<Fr, NUM_RELATION_WIDE_LIMBS> relation_wide_limbs;
305 std::array<std::array<Fr, NUM_MICRO_LIMBS>, 2> relation_wide_microlimbs;
306
307 // Additional
308 std::array<Fr, NUM_BINARY_LIMBS> x_limbs;
309 std::array<Fr, NUM_BINARY_LIMBS> v_limbs;
310 std::array<Fr, NUM_BINARY_LIMBS> v_squared_limbs = { 0 };
311 std::array<Fr, NUM_BINARY_LIMBS> v_cubed_limbs = { 0 };
312 std::array<Fr, NUM_BINARY_LIMBS> v_quarted_limbs = { 0 };
313 };
315 std::array<Fr, NUM_BINARY_LIMBS> x_limbs;
316 std::array<Fr, NUM_BINARY_LIMBS> v_limbs;
317 std::array<Fr, NUM_BINARY_LIMBS> v_squared_limbs = { 0 };
318 std::array<Fr, NUM_BINARY_LIMBS> v_cubed_limbs = { 0 };
319 std::array<Fr, NUM_BINARY_LIMBS> v_quarted_limbs = { 0 };
320 };
321 static constexpr std::string_view NAME_STRING = "GoblinTranslatorArithmetization";
322
323 // The challenge that is used for batching together evaluations of several polynomials
324 Fq batching_challenge_v;
325
326 // The input we evaluate polynomials on
327 Fq evaluation_input_x;
328
329 std::array<std::vector<uint32_t, barretenberg::ContainerSlabAllocator<uint32_t>>, NUM_WIRES> wires;
330
340 GoblinTranslatorCircuitBuilder(Fq batching_challenge_v_, Fq evaluation_input_x_)
341 : CircuitBuilderBase(DEFAULT_TRANSLATOR_VM_LENGTH)
342 , batching_challenge_v(batching_challenge_v_)
343 , evaluation_input_x(evaluation_input_x_)
344 {
345 add_variable(Fr::zero());
346 for (auto& wire : wires) {
347 wire.emplace_back(0);
348 }
349 num_gates++;
350 };
351
362 GoblinTranslatorCircuitBuilder(Fq batching_challenge_v_,
363 Fq evaluation_input_x_,
364 std::shared_ptr<ECCOpQueue> op_queue)
365 : GoblinTranslatorCircuitBuilder(batching_challenge_v_, evaluation_input_x_)
366 {
368 }
369
373 : CircuitBuilderBase(std::move(other)){};
374 GoblinTranslatorCircuitBuilder& operator=(const GoblinTranslatorCircuitBuilder& other) = delete;
375 GoblinTranslatorCircuitBuilder& operator=(GoblinTranslatorCircuitBuilder&& other) noexcept
376 {
377 CircuitBuilderBase::operator=(std::move(other));
378 return *this;
379 };
380 ~GoblinTranslatorCircuitBuilder() override = default;
381
390 static RelationInputs compute_relation_inputs_limbs(Fq batching_challenge_v, Fq evaluation_input_x)
391 {
396 auto base_element_to_limbs = [](Fq& original) {
397 uint256_t original_uint = original;
398 return std::array<Fr, NUM_BINARY_LIMBS>({
399 Fr(original_uint.slice(0, NUM_LIMB_BITS)),
400 Fr(original_uint.slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS)),
401 Fr(original_uint.slice(2 * NUM_LIMB_BITS, 3 * NUM_LIMB_BITS)),
402 Fr(original_uint.slice(3 * NUM_LIMB_BITS, 4 * NUM_LIMB_BITS)),
403 });
404 };
405 Fq& v = batching_challenge_v;
406 Fq& x = evaluation_input_x;
407 Fq v_squared;
408 Fq v_cubed;
409 Fq v_quarted;
410 v_squared = v * v;
411 v_cubed = v_squared * v;
412 v_quarted = v_cubed * v;
413 RelationInputs result;
414 result.x_limbs = base_element_to_limbs(x);
415 result.v_limbs = base_element_to_limbs(v);
416 result.v_squared_limbs = base_element_to_limbs(v_squared);
417 result.v_cubed_limbs = base_element_to_limbs(v_cubed);
418 result.v_quarted_limbs = base_element_to_limbs(v_quarted);
419 return result;
420 }
421
430 void create_accumulation_gate(AccumulationInput acc_step);
431
438 {
439 const size_t RESULT_ROW = 1;
440 ASSERT(num_gates > RESULT_ROW);
441 return (uint256_t(get_variable(wires[WireIds::ACCUMULATORS_BINARY_LIMBS_0][RESULT_ROW])) +
442 uint256_t(get_variable(wires[WireIds::ACCUMULATORS_BINARY_LIMBS_1][RESULT_ROW])) * SHIFT_1 +
443 uint256_t(get_variable(wires[WireIds::ACCUMULATORS_BINARY_LIMBS_2][RESULT_ROW])) * SHIFT_2 +
444 uint256_t(get_variable(wires[WireIds::ACCUMULATORS_BINARY_LIMBS_3][RESULT_ROW])) * SHIFT_3);
445 }
452 void feed_ecc_op_queue_into_circuit(std::shared_ptr<ECCOpQueue> ecc_op_queue);
453
462 bool check_circuit();
463};
464template <typename Fq, typename Fr>
465GoblinTranslatorCircuitBuilder::AccumulationInput generate_witness_values(Fr op_code,
466 Fr p_x_lo,
467 Fr p_x_hi,
468 Fr p_y_lo,
469 Fr p_y_hi,
470 Fr z1,
471 Fr z2,
472 Fq previous_accumulator,
473 Fq batching_challenge_v,
474 Fq evaluation_input_x);
475extern template GoblinTranslatorCircuitBuilder::AccumulationInput generate_witness_values(barretenberg::fr,
485} // namespace proof_system
Definition: arithmetization.hpp:203
Definition: uint256.hpp:25
constexpr uint256_t slice(uint64_t start, uint64_t end) const
Definition: uint256_impl.hpp:157
Definition: circuit_builder_base.hpp:14
FF get_variable(const uint32_t index) const
Definition: circuit_builder_base.hpp:113
virtual uint32_t add_variable(const FF &in)
Definition: circuit_builder_base.hpp:163
GoblinTranslatorCircuitBuilder creates a circuit that evaluates the correctness of the evaluation of ...
Definition: goblin_translator_circuit_builder.hpp:76
void create_accumulation_gate(AccumulationInput acc_step)
Create a single accumulation gate.
Definition: goblin_translator_circuit_builder.cpp:375
GoblinTranslatorCircuitBuilder(Fq batching_challenge_v_, Fq evaluation_input_x_, std::shared_ptr< ECCOpQueue > op_queue)
Construct a new Goblin Translator Circuit Builder object and feed op_queue inside.
Definition: goblin_translator_circuit_builder.hpp:362
bool check_circuit()
Check the witness satisifies the circuit.
Definition: goblin_translator_circuit_builder.cpp:642
WireIds
There are so many wires that naming them has no sense, it is easier to access them with enums.
Definition: goblin_translator_circuit_builder.hpp:98
barretenberg::fq get_computation_result()
Get the result of accumulation.
Definition: goblin_translator_circuit_builder.hpp:437
static RelationInputs compute_relation_inputs_limbs(Fq batching_challenge_v, Fq evaluation_input_x)
Create limb representations of x and powers of v that are needed to compute the witness or check circ...
Definition: goblin_translator_circuit_builder.hpp:390
void create_add_gate(const add_triple_< Fr > &) override
Definition: goblin_translator_circuit_builder.hpp:89
GoblinTranslatorCircuitBuilder(Fq batching_challenge_v_, Fq evaluation_input_x_)
Construct a new Goblin Translator Circuit Builder object.
Definition: goblin_translator_circuit_builder.hpp:340
void feed_ecc_op_queue_into_circuit(std::shared_ptr< ECCOpQueue > ecc_op_queue)
Generate all the gates required to prove the correctness of batched evalution of polynomials represen...
Definition: goblin_translator_circuit_builder.cpp:602
The accumulation input structure contains all the necessary values to initalize an accumulation gate ...
Definition: goblin_translator_circuit_builder.hpp:280
Definition: goblin_translator_circuit_builder.hpp:314
Definition: gate_data.hpp:10
Definition: gate_data.hpp:43