Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
translator_circuit_builder.hpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Planned, auditors: [], commit: }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
7#pragma once
14
15namespace bb {
70
71 // The scalar field of BN254
72 using Fr = bb::fr;
73 // The base (coordinate) field of BN254
74 using Fq = bb::fq;
75
76 public:
77 static constexpr size_t NUM_WIRES = 81;
78 static constexpr size_t NUM_SELECTORS = 0;
79
80 [[nodiscard]] size_t get_num_constant_gates() const override { return 0; };
81
85 enum WireIds : uint8_t {
86 OP, // The first 4 wires contain the standard values from the EccQueue wire
90 P_X_LOW_LIMBS, // P.xₗₒ split into 2 68 bit limbs
91 P_X_HIGH_LIMBS, // P.xₕᵢ split into a 68 and a 50 bit limb
92 P_Y_LOW_LIMBS, // P.yₗₒ split into 2 68 bit limbs
93 P_Y_HIGH_LIMBS, // P.yₕᵢ split into a 68 and a 50 bit limb
94 Z_LOW_LIMBS, // Low limbs of z_1 and z_2 (68 bits each)
95 Z_HIGH_LIMBS, // High Limbs of z_1 and z_2 (60 bits each)
96 ACCUMULATORS_BINARY_LIMBS_0, // Contain 68-bit limbs of current and previous accumulator (previous at higher
97 // indices because of the nuances of KZG commitment).
100 ACCUMULATORS_BINARY_LIMBS_3, // Highest limb is 50 bits (254 mod 68) P_X_LOW_LIMBS_RANGE_CONSTRAINT_0, // Low
101 // limbs split further into smaller chunks for range constraints
102 QUOTIENT_LOW_BINARY_LIMBS, // Quotient limbs
104 RELATION_WIDE_LIMBS, // Limbs for checking the correctness of mod 2²⁷² relations.
105 P_X_LOW_LIMBS_RANGE_CONSTRAINT_0, // Low limbs split further into smaller chunks for range constraints
111 P_X_HIGH_LIMBS_RANGE_CONSTRAINT_0, // High limbs split into chunks for range constraints
117 P_Y_LOW_LIMBS_RANGE_CONSTRAINT_0, // Low limbs split into chunks for range constraints
123 P_Y_HIGH_LIMBS_RANGE_CONSTRAINT_0, // High limbs split into chunks for range constraints
129 Z_LOW_LIMBS_RANGE_CONSTRAINT_0, // Range constraints for low limbs of z_1 and z_2
135 Z_HIGH_LIMBS_RANGE_CONSTRAINT_0, // Range constraints for high limbs of z_1 and z_2
141
142 ACCUMULATOR_LOW_LIMBS_RANGE_CONSTRAINT_0, // Range constraints for the current accumulator limbs (no need to
143 // redo previous accumulator)
155
156 QUOTIENT_LOW_LIMBS_RANGE_CONSTRAIN_0, // Range constraints for quotient
172
174
175 };
176
177 // Basic goblin translator has the minimum minicircuit size of 2048, so optimize for that case
178 // For context, minicircuit is the part of the final polynomials fed into the proving system, where we have all the
179 // arithmetic logic. However, the full circuit is several times larger (we use a trick to bring down the degree of
180 // the permutation argument)
181 static constexpr size_t DEFAULT_TRANSLATOR_VM_LENGTH = 2048;
182
183 // Maximum size of a single limb is 68 bits
184 static constexpr size_t NUM_LIMB_BITS = 68;
185
186 // For soundness we need to constrain the highest limb so that the whole value is at most 50 bits
187 static constexpr size_t NUM_LAST_LIMB_BITS = Fq::modulus.get_msb() + 1 - (3 * NUM_LIMB_BITS);
188
189 // 128-bit z_1 and z_2 are split into 2 limbs each
190 static constexpr size_t NUM_Z_LIMBS = 2;
191
192 // Number of bits in the quotient representation
193 static constexpr size_t NUM_QUOTIENT_BITS = 256;
194
195 // Number of bits in the quotient highest limb
196 static constexpr size_t NUM_LAST_QUOTIENT_LIMB_BITS = 256 - (3 * NUM_LIMB_BITS);
197
198 // Number of bits in Z scalars
199 static constexpr size_t NUM_Z_BITS = 128;
200 // The circuit builder has a default range constraint mechanism that is used throughout. It range cosntrains the
201 // values to < 2¹⁴
202 static constexpr size_t MICRO_LIMB_BITS = 14;
203
204 // Maximum size of a micro limb used for range constraints
205 static constexpr auto MAX_MICRO_LIMB_SIZE = (uint256_t(1) << MICRO_LIMB_BITS) - 1;
206
207 // To range constrain a limb to 68 bits we need 6 limbs: 5 for 14-bit windowed chunks and 1 to range constrain the
208 // highest to a more restrictive range (0 <= a < 2¹⁴ && 0 <= 4*a < 2¹⁴ ) ~ ( 0 <= a < 2¹² )
209 static constexpr size_t NUM_MICRO_LIMBS = 6;
210
211 // Number of limbs used to decompose a 254-bit value for modular arithmetic. This will represent an Fq value as 4 Fr
212 // limbs to be representable inside a circuit defined overF r.
213 static constexpr size_t NUM_BINARY_LIMBS = 4;
214
215 // Number of limbs used for computation of a result modulo 2²⁷²
216 static constexpr size_t NUM_RELATION_WIDE_LIMBS = 2;
217
218 // Range constraint of relation limbs
219 static constexpr size_t RELATION_WIDE_LIMB_BITS = 84;
220
221 // Maximum size of each relation limb (in accordance with range constraints)
223
224 // Shift of a single micro (range constraint) limb
225 static constexpr auto MICRO_SHIFT = uint256_t(1) << MICRO_LIMB_BITS;
226
227 // Maximum size of 2 lower limbs concatenated
228 static constexpr auto MAX_LOW_WIDE_LIMB_SIZE = (uint256_t(1) << (NUM_LIMB_BITS * 2)) - 1;
229
230 // Maximum size of 2 higher limbs concatenated
231 static constexpr auto MAX_HIGH_WIDE_LIMB_SIZE = (uint256_t(1) << (NUM_LIMB_BITS + NUM_LAST_LIMB_BITS)) - 1;
232
233 // Maximum size of z limbs
234 static constexpr auto MAX_Z_LIMB_SIZE = (uint256_t(1) << NUM_Z_BITS) - 1;
235
236 // Index at which the accumulation result is stored in the circuit, preceded by 2 shiftability zeros
237 // and three random ops that contribute to ensuring the Translator proof does not leak
238 // information about the op queue content linked to the circuits being proven
239 static constexpr size_t RESULT_ROW = 8;
240
241 // Number of no-ops at the beginning of Translator trace (provides the 2 leading zero rows required for
242 // polynomial shiftability of op queue wires). Contributed by the tail kernel's queue_ecc_no_op().
243 static constexpr size_t NUM_NO_OPS_START = 1;
244 static_assert(NUM_NO_OPS_START == 1);
245
246 // Number of random ops at the beginning of Translator trace
247 static constexpr size_t NUM_RANDOM_OPS_START = 3;
248 static_assert(NUM_RANDOM_OPS_START == 3);
249 static_assert(NUM_RANDOM_OPS_START == ECC_NUM_RANDOM_OPS_START);
250
251 // Number of random ops at the end of Translator trace
252 static constexpr size_t NUM_RANDOM_OPS_END = 2;
253 static_assert(NUM_RANDOM_OPS_END == 2);
254
255 // How much you'd need to multiply a value by to perform a shift to a higher binary limb
256 static constexpr auto SHIFT_1 = uint256_t(1) << NUM_LIMB_BITS;
257
258 // Shift by 2 binary limbs
259 static constexpr auto SHIFT_2 = uint256_t(1) << (NUM_LIMB_BITS << 1);
260
261 // Precomputed inverse to easily divide by the shift by 2 limbs
262 static constexpr auto SHIFT_2_INVERSE = Fr(SHIFT_2).invert();
263
264 // Shift by 3 binary limbs
265 static constexpr auto SHIFT_3 = uint256_t(1) << (NUM_LIMB_BITS * 3);
266
267 // The modulus of the target emulated field as a 512-bit integer
269
270 // The binary modulus used in the CRT computation (2²⁷²)
271 static constexpr uint512_t BINARY_BASIS_MODULUS = uint512_t(1) << (NUM_LIMB_BITS << 2);
272
273 // Negated modulus of the target emulated field in the binary modulus (2²⁷² - q)
275
276 // Negated modulus of the target emulated field in the binary modulus split into 4 binary limbs + the final limb is
277 // the negated modulus of the target emulated field in the scalar field.
285
297
327
328 static constexpr std::string_view NAME_STRING = "TranslatorCircuitBuilder";
329
330 // The challenge that is used for batching together evaluations of several polynomials
332
333 // The input we evaluate polynomials on
335
336 bool avm_mode = false;
337
339
348 TranslatorCircuitBuilder(Fq batching_challenge_v_, Fq evaluation_input_x_, bool avm_mode_ = false)
349 : batching_challenge_v(batching_challenge_v_)
350 , evaluation_input_x(evaluation_input_x_)
351 , avm_mode(avm_mode_)
352 {
354 };
355
366 TranslatorCircuitBuilder(Fq batching_challenge_v_,
367 Fq evaluation_input_x_,
369 bool avm_mode = false)
370 : TranslatorCircuitBuilder(batching_challenge_v_, evaluation_input_x_, avm_mode)
371
372 {
373 BB_BENCH_NAME("TranslatorCircuitBuilder::constructor");
375 }
376
382 ~TranslatorCircuitBuilder() override = default;
383
392 {
393 uint256_t base_uint = base;
395 Fr(base_uint.slice(0, NUM_LIMB_BITS)),
396 Fr(base_uint.slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS)),
397 Fr(base_uint.slice(2 * NUM_LIMB_BITS, 3 * NUM_LIMB_BITS)),
398 Fr(base_uint.slice(3 * NUM_LIMB_BITS, 4 * NUM_LIMB_BITS)),
399 });
400 }
401
410 static void assert_well_formed_ultra_op(const UltraOp& ultra_op);
411
421 static void assert_well_formed_accumulation_input(const AccumulationInput& acc_step);
422
431 void create_accumulation_gate(const AccumulationInput& acc_step);
432
433 void populate_wires_from_ultra_op(const UltraOp& ultra_op);
434
435 void insert_pair_into_wire(WireIds wire_index, Fr first, Fr second)
436 {
437 auto& current_wire = wires[wire_index];
438 current_wire.push_back(add_variable(first));
439 current_wire.push_back(add_variable(second));
440 }
441
448
449 static AccumulationInput generate_witness_values(const UltraOp& ultra_op,
450 const Fq& previous_accumulator,
452 const Fq& evaluation_input_x);
453
454 private:
459 {
460 return { Fr(original.slice(0, NUM_LIMB_BITS).lo),
461 Fr(original.slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS).lo),
462 Fr(original.slice(2 * NUM_LIMB_BITS, 3 * NUM_LIMB_BITS).lo),
463 Fr(original.slice(3 * NUM_LIMB_BITS, 4 * NUM_LIMB_BITS).lo) };
464 }
465
470 {
471 return { Fr(uint256_t(wide_limb).slice(0, NUM_LIMB_BITS)),
472 Fr(uint256_t(wide_limb).slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS)) };
473 }
474
478 static std::array<Fr, NUM_MICRO_LIMBS> split_limb_into_microlimbs(const Fr& limb, size_t num_bits);
479
483 template <size_t total_limbs>
485 const uint256_t& MAX_LAST_LIMB = (uint256_t(1) << NUM_LAST_LIMB_BITS))
486 {
487 for (size_t i = 0; i < total_limbs - 1; i++) {
488 BB_ASSERT_LT(uint256_t(limbs[i]), SHIFT_1);
489 }
490 BB_ASSERT_LT(uint256_t(limbs[total_limbs - 1]), MAX_LAST_LIMB);
491 }
492
496 template <size_t binary_limb_count, size_t micro_limb_count>
498 const std::array<std::array<Fr, micro_limb_count>, binary_limb_count>& limbs)
499 {
500 for (size_t i = 0; i < binary_limb_count; i++) {
501 for (size_t j = 0; j < micro_limb_count; j++) {
502 BB_ASSERT_LT(uint256_t(limbs[i][j]), MICRO_SHIFT);
503 }
504 }
505 }
506
510 template <size_t array_size> void lay_limbs_in_row(std::array<Fr, array_size> input, WireIds starting_wire)
511 {
512 size_t wire_index = starting_wire;
513 for (auto element : input) {
514 wires[wire_index].push_back(add_variable(element));
515 wire_index++;
516 }
517 }
518
522 void process_random_op(const UltraOp& ultra_op);
523};
524
525} // namespace bb
#define BB_ASSERT_LT(left, right,...)
Definition assert.hpp:143
#define BB_BENCH_NAME(name)
Definition bb_bench.hpp:264
virtual uint32_t add_variable(const FF &in)
Add a variable to variables.
TranslatorCircuitBuilder creates a circuit that evaluates the correctness of the evaluation of EccOpQ...
size_t get_num_constant_gates() const override
TranslatorCircuitBuilder(Fq batching_challenge_v_, Fq evaluation_input_x_, std::shared_ptr< ECCOpQueue > op_queue, bool avm_mode=false)
Construct a new Translator Circuit Builder object and feed op_queue inside.
static constexpr std::array< Fr, 5 > NEGATIVE_MODULUS_LIMBS
static AccumulationInput generate_witness_values(const UltraOp &ultra_op, const Fq &previous_accumulator, const Fq &batching_challenge_v, const Fq &evaluation_input_x)
Given the transcript values from the EccOpQueue, the values of the previous accumulator,...
TranslatorCircuitBuilder(Fq batching_challenge_v_, Fq evaluation_input_x_, bool avm_mode_=false)
Construct a new Translator Circuit Builder object.
void feed_ecc_op_queue_into_circuit(const std::shared_ptr< ECCOpQueue > &ecc_op_queue)
Generate all the gates required to prove the correctness of batched evalution of column polynomials r...
static std::array< FF, 5 > compute_negative_modulus_limbs()
Compute ((-q) mod 2^4L) for an arbitrary field type FF where L = 68.
static void check_binary_limbs_maximum_values(const std::array< Fr, total_limbs > &limbs, const uint256_t &MAX_LAST_LIMB=(uint256_t(1)<< NUM_LAST_LIMB_BITS))
Assert that all standard limbs are < 2^68 and the last limb is < MAX_LAST_LIMB.
static void assert_well_formed_ultra_op(const UltraOp &ultra_op)
Ensures the ultra op is well-formed and can be used to create a gate.
WireIds
There are so many wires that naming them has no sense, it is easier to access them with enums.
void create_accumulation_gate(const AccumulationInput &acc_step)
Create a single accumulation gate.
static std::array< Fr, NUM_BINARY_LIMBS > split_fq_into_limbs(const Fq &base)
A small function to transform a native element Fq into its bigfield representation in Fr scalars.
static constexpr size_t RELATION_WIDE_LIMB_BITS
static constexpr uint512_t BINARY_BASIS_MODULUS
static constexpr size_t NUM_LAST_QUOTIENT_LIMB_BITS
void lay_limbs_in_row(std::array< Fr, array_size > input, WireIds starting_wire)
Place array_size Fr values into consecutive wire slots starting at starting_wire.
static constexpr size_t DEFAULT_TRANSLATOR_VM_LENGTH
~TranslatorCircuitBuilder() override=default
static constexpr std::string_view NAME_STRING
void process_random_op(const UltraOp &ultra_op)
Populate wires for a random op (op wire filled, all other wires zero-filled).
static void check_micro_limbs_maximum_values(const std::array< std::array< Fr, micro_limb_count >, binary_limb_count > &limbs)
Assert that all micro-limbs are < 2^14.
static constexpr uint256_t MAX_RELATION_WIDE_LIMB_SIZE
static std::array< Fr, NUM_MICRO_LIMBS > split_limb_into_microlimbs(const Fr &limb, size_t num_bits)
Split a limb of arbitrary bit size into 14-bit micro-limbs for range constraints.
static constexpr uint512_t NEGATIVE_PRIME_MODULUS
void populate_wires_from_ultra_op(const UltraOp &ultra_op)
static void assert_well_formed_accumulation_input(const AccumulationInput &acc_step)
Ensures the accumulation input is well-formed and can be used to create a gate.
static std::array< Fr, NUM_BINARY_LIMBS > uint512_t_to_limbs(const uint512_t &original)
Convert a uint512_t value into its 4 68-bit limbs as Fr scalars.
std::array< std::vector< uint32_t >, NUM_WIRES > wires
TranslatorCircuitBuilder & operator=(const TranslatorCircuitBuilder &other)=delete
static std::array< Fr, NUM_Z_LIMBS > split_wide_limb_into_2_limbs(const Fr &wide_limb)
Split a 136-bit Fr value (wide limb) into two 68-bit limbs.
TranslatorCircuitBuilder(TranslatorCircuitBuilder &&other)=delete
TranslatorCircuitBuilder & operator=(TranslatorCircuitBuilder &&other)=delete
static constexpr size_t NUM_RELATION_WIDE_LIMBS
TranslatorCircuitBuilder(const TranslatorCircuitBuilder &other)=delete
void insert_pair_into_wire(WireIds wire_index, Fr first, Fr second)
constexpr uint256_t slice(uint64_t start, uint64_t end) const
constexpr uint64_t get_msb() const
constexpr uintx slice(const uint64_t start, const uint64_t end) const
Definition uintx.hpp:81
uintx< uint256_t > uint512_t
Definition uintx.hpp:309
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
field< Bn254FqParams > fq
Definition fq.hpp:153
field< Bn254FrParams > fr
Definition fr.hpp:155
C slice(C const &container, size_t start)
Definition container.hpp:9
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
The accumulation input structure contains all the necessary values to initalize an accumulation gate ...
std::array< std::array< Fr, NUM_MICRO_LIMBS >, NUM_RELATION_WIDE_LIMBS > relation_wide_microlimbs
std::array< std::array< Fr, NUM_MICRO_LIMBS >, NUM_Z_LIMBS > z_1_microlimbs
std::array< std::array< Fr, NUM_MICRO_LIMBS >, NUM_BINARY_LIMBS > P_y_microlimbs
std::array< std::array< Fr, NUM_MICRO_LIMBS >, NUM_BINARY_LIMBS > current_accumulator_microlimbs
std::array< std::array< Fr, NUM_MICRO_LIMBS >, NUM_BINARY_LIMBS > P_x_microlimbs
std::array< std::array< Fr, NUM_MICRO_LIMBS >, NUM_BINARY_LIMBS > quotient_microlimbs
std::array< std::array< Fr, NUM_MICRO_LIMBS >, NUM_Z_LIMBS > z_2_microlimbs
std::array< Fr, NUM_RELATION_WIDE_LIMBS > relation_wide_limbs
static constexpr uint256_t modulus
constexpr field invert() const noexcept
static constexpr field zero()