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: not started, auditors: [], date: YYYY-MM-DD }
3// external_1: { status: not started, auditors: [], date: YYYY-MM-DD }
4// external_2: { status: not started, auditors: [], date: YYYY-MM-DD }
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 : size_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 // Index at which the accumulation result is stored in the circuit, preceeded by one no-op that ensures translator
234 // polynomials are shiftable and three random ops that contribute to ensuring the Translator proof does not leak
235 // information about the op queue content linked to the circuits being proven
236 static constexpr size_t RESULT_ROW = 8;
237 static constexpr size_t NUM_NO_OPS_START = 1;
238
239 // Number of random ops at the beginning of Translator trace
240 static constexpr size_t NUM_RANDOM_OPS_START = 3;
241 static_assert(NUM_RANDOM_OPS_START == 3);
242
243 // Number of random ops at the end of Translator trace
244 static constexpr size_t NUM_RANDOM_OPS_END = 2;
245 static_assert(NUM_RANDOM_OPS_END == 2);
246
247 // How much you'd need to multiply a value by to perform a shift to a higher binary limb
248 static constexpr auto SHIFT_1 = uint256_t(1) << NUM_LIMB_BITS;
249
250 // Shift by 2 binary limbs
251 static constexpr auto SHIFT_2 = uint256_t(1) << (NUM_LIMB_BITS << 1);
252
253 // Precomputed inverse to easily divide by the shift by 2 limbs
254 static constexpr auto SHIFT_2_INVERSE = Fr(SHIFT_2).invert();
255
256 // Shift by 3 binary limbs
257 static constexpr auto SHIFT_3 = uint256_t(1) << (NUM_LIMB_BITS * 3);
258
259 // The modulus of the target emulated field as a 512-bit integer
261
262 // The binary modulus used in the CRT computation
263 static constexpr uint512_t BINARY_BASIS_MODULUS = uint512_t(1) << (NUM_LIMB_BITS << 2);
264
265 // Negated modulus of the target emulated field in the binary modulus
267
268 // Negated modulus of the target emulated field in the binary modulus split into 4 binary limbs + the final limb is
269 // the negated modulus of the target emulated field in the scalar field
277
307
308 static constexpr std::string_view NAME_STRING = "TranslatorCircuitBuilder";
309
310 // The challenge that is used for batching together evaluations of several polynomials
312
313 // The input we evaluate polynomials on
315
316 bool avm_mode = false;
317
319
328 TranslatorCircuitBuilder(Fq batching_challenge_v_, Fq evaluation_input_x_, bool avm_mode_ = false)
330 , batching_challenge_v(batching_challenge_v_)
331 , evaluation_input_x(evaluation_input_x_)
332 , avm_mode(avm_mode_)
333 {
335 };
336
347 TranslatorCircuitBuilder(Fq batching_challenge_v_,
348 Fq evaluation_input_x_,
350 bool avm_mode = false)
351 : TranslatorCircuitBuilder(batching_challenge_v_, evaluation_input_x_, avm_mode)
352
353 {
354 BB_BENCH_NAME("TranslatorCircuitBuilder::constructor");
356 }
357
364 {
366 return *this;
367 };
368 ~TranslatorCircuitBuilder() override = default;
369
377 {
378 uint256_t base_uint = base;
380 Fr(base_uint.slice(0, NUM_LIMB_BITS)),
381 Fr(base_uint.slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS)),
382 Fr(base_uint.slice(2 * NUM_LIMB_BITS, 3 * NUM_LIMB_BITS)),
383 Fr(base_uint.slice(3 * NUM_LIMB_BITS, 4 * NUM_LIMB_BITS)),
384 });
385 }
386
387 static void assert_well_formed_ultra_op(const UltraOp& ultra_op);
388
397 static void assert_well_formed_accumulation_input(const AccumulationInput& acc_step);
398
407 void create_accumulation_gate(const AccumulationInput& acc_step);
408
409 void populate_wires_from_ultra_op(const UltraOp& ultra_op);
410
411 void insert_pair_into_wire(WireIds wire_index, Fr first, Fr second)
412 {
413 auto& current_wire = wires[wire_index];
414 current_wire.push_back(add_variable(first));
415 current_wire.push_back(add_variable(second));
416 }
417
424
425 static AccumulationInput generate_witness_values(const UltraOp& ultra_op,
426 const Fq& previous_accumulator,
428 const Fq& evaluation_input_x);
429};
430
431} // namespace bb
#define BB_BENCH_NAME(name)
Definition bb_bench.hpp:219
virtual uint32_t add_variable(const FF &in)
Add a variable to variables.
CircuitBuilderBase & operator=(const CircuitBuilderBase &other)=default
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.
TranslatorCircuitBuilder(TranslatorCircuitBuilder &&other) noexcept
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 void assert_well_formed_ultra_op(const UltraOp &ultra_op)
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
static constexpr size_t DEFAULT_TRANSLATOR_VM_LENGTH
~TranslatorCircuitBuilder() override=default
static constexpr std::string_view NAME_STRING
static constexpr uint256_t MAX_RELATION_WIDE_LIMB_SIZE
static constexpr uint512_t NEGATIVE_PRIME_MODULUS
TranslatorCircuitBuilder & operator=(TranslatorCircuitBuilder &&other) noexcept
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.
std::array< std::vector< uint32_t >, NUM_WIRES > wires
TranslatorCircuitBuilder & operator=(const TranslatorCircuitBuilder &other)=delete
static constexpr size_t NUM_RELATION_WIDE_LIMBS
TranslatorCircuitBuilder(const TranslatorCircuitBuilder &other)=delete
WireIds
There are so many wires that naming them has no sense, it is easier to access them with enums.
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:82
uintx< uint256_t > uint512_t
Definition uintx.hpp:307
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
field< Bn254FqParams > fq
Definition fq.hpp:169
field< Bn254FrParams > fr
Definition fr.hpp:174
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_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 >, 2 > relation_wide_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()