Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
ecc_op_queue.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
8
14namespace bb {
15
29 using Fq = Curve::BaseField; // Grumpkin's scalar field
31 Point point_at_infinity = Curve::Group::affine_point_at_infinity;
32
33 // The operations written to the queue are also performed natively; the result is stored in accumulator
35
36 EccvmOpsTable eccvm_ops_table; // table of ops in the ECCVM format
37 UltraEccOpsTable ultra_ops_table; // table of ops in the Ultra-arithmetization format
38
39 // Storage for the reconstructed eccvm ops table in contiguous memory. (Intended to be constructed once and for all
40 // prior to ECCVM construction to avoid repeated prepending of subtables in physical memory).
41 std::vector<ECCVMOperation> eccvm_ops_reconstructed;
42
43 // Storage for the reconstructed ultra ops table in contiguous memory. (Intended to be constructed once and for all
44 // prior to Translator circuit construction to avoid repeated prepending of subtables in physical memory).
45 std::vector<UltraOp> ultra_ops_reconstructed;
46
47 // Tracks number of muls and size of eccvm in real time as the op queue is updated
49
50 public:
51 static const size_t OP_QUEUE_SIZE = 1 << CONST_OP_QUEUE_LOG_SIZE;
56
66
68
70 {
71 eccvm_ops_table.merge(settings);
72 ultra_ops_table.merge(settings, ultra_fixed_offset);
73 }
74
75 // Construct polynomials corresponding to the columns of the full aggregate ultra ecc ops table
80
81 // Construct polys corresponding to the columns of the aggregate ultra ops table, excluding the most recent
82 // subtable
87
88 // Construct polynomials corresponding to the columns of the current subtable of ultra ecc ops
93
94 // Reconstruct the full table of eccvm ops in contiguous memory from the independent subtables
96
97 // Reconstruct the full table of ultra ops in contiguous memory from the independent subtables
99
101 size_t get_ultra_ops_count() const { return ultra_ops_table.size(); } // actual operation count without padding
104
105 // TODO(https://github.com/AztecProtocol/barretenberg/issues/1339): Consider making the ultra and eccvm ops
106 // getters more memory efficient
107
108 // Get the full table of ECCVM ops in contiguous memory; construct it if it has not been constructed already.
109 // The hiding op (set via append_hiding_op) is always prepended at index 0.
110 std::vector<ECCVMOperation>& get_eccvm_ops()
111 {
112 if (eccvm_ops_reconstructed.empty()) {
114 // Prepend the hiding op at index 0 (required for ZK)
115 if (!has_hiding_op) {
116 throw_or_abort("Hiding op must be set before calling get_eccvm_ops()");
117 }
119 }
121 }
122
123 std::vector<UltraOp>& get_ultra_ops()
124 {
125 if (ultra_ops_reconstructed.empty()) {
127 }
129 }
130
135
139 size_t get_num_rows() const { return eccvm_row_tracker.get_num_rows(); }
140
145
150 void set_eccvm_ops_for_fuzzing(std::vector<ECCVMOperation>& eccvm_ops_in)
151 {
152 eccvm_ops_reconstructed = eccvm_ops_in;
153 }
154
161 {
162 EccOpCode op_code{ .eq = true, .reset = true };
163 append_eccvm_op(ECCVMOperation{ .op_code = op_code, .base_point = Point::random_element() });
164 }
165
172 {
174 accumulator.self_set_infinity();
175 }
176
178
185 {
186 // Update the accumulator natively
187 accumulator = accumulator + to_add;
188 EccOpCode op_code{ .add = true };
189 // Store the eccvm operation
190 append_eccvm_op(ECCVMOperation{ .op_code = op_code, .base_point = to_add });
191
192 // Construct and store the operation in the ultra op format
193 return construct_and_populate_ultra_ops(op_code, to_add);
194 }
195
201 UltraOp mul_accumulate(const Point& to_mul, const Fr& scalar)
202 {
203 // Update the accumulator natively
204 accumulator = accumulator + to_mul * scalar;
205 EccOpCode op_code{ .mul = true };
206
207 // Construct and store the operation in the ultra op format
208 UltraOp ultra_op = construct_and_populate_ultra_ops(op_code, to_mul, scalar);
209
210 // Store the eccvm operation
212 .op_code = op_code,
213 .base_point = to_mul,
214 .z1 = ultra_op.z_1,
215 .z2 = ultra_op.z_2,
216 .mul_scalar_full = scalar,
217 });
218
219 return ultra_op;
220 }
221
229 {
230 UltraOp no_op{};
231 ultra_ops_table.push(no_op);
232 return no_op;
233 }
234
243 {
244 UltraOp random_op{ .op_code = EccOpCode{ .is_random_op = true,
245 .random_value_1 = Fr::random_element(),
246 .random_value_2 = Fr::random_element() },
247 .x_lo = Fr::random_element(),
248 .x_hi = Fr::random_element(),
249 .y_lo = Fr::random_element(),
250 .y_hi = Fr::random_element(),
251 .z_1 = Fr::random_element(),
252 .z_2 = Fr::random_element(),
253 .return_is_infinity = false };
254 ultra_ops_table.push(random_op);
255 return random_op;
256 }
257
264 {
265 auto expected = accumulator;
266 accumulator.self_set_infinity();
267 EccOpCode op_code{ .eq = true, .reset = true };
268 // Store eccvm operation
269 append_eccvm_op(ECCVMOperation{ .op_code = op_code, .base_point = expected });
270
271 // Construct and store the operation in the ultra op format
272 return construct_and_populate_ultra_ops(op_code, expected);
273 }
274
300 UltraOp append_hiding_op(const Fq& Px, const Fq& Py)
301 {
302 // Create an ECCVM operation with q_eq = 1, q_reset = 1 (opcode = 3) and the random Px, Py values.
303 // We construct the base_point directly with the raw coordinates - it may not be on the curve.
304 // Note: reset = true is required for Translator compatibility (only opcodes {0,3,4,8} are allowed)
305 EccOpCode op_code{ .eq = true, .reset = true }; // q_eq = 1, q_reset = 1
306 Point base_point;
307 base_point.x = Px;
308 base_point.y = Py;
309 // Note: We don't call is_point_at_infinity() or any curve operations on this point
310
311 // Store the hiding op for ECCVM - it will be prepended to the front during reconstruction (index 0 -> row 1)
312 hiding_op_for_eccvm = ECCVMOperation{ .op_code = op_code, .base_point = base_point };
313 has_hiding_op = true;
314
315 // Push to Ultra ops through normal flow (appends to current subtable)
316 // Decompose Px, Py (Fq) into hi-lo chunks (Fr)
317 const size_t CHUNK_SIZE = 2 * stdlib::NUM_LIMB_BITS_IN_FIELD_SIMULATION;
318 uint256_t x_256(Px);
319 uint256_t y_256(Py);
320 UltraOp ultra_op{
321 .op_code = op_code,
322 .x_lo = Fr(x_256.slice(0, CHUNK_SIZE)),
323 .x_hi = Fr(x_256.slice(CHUNK_SIZE, CHUNK_SIZE * 2)),
324 .y_lo = Fr(y_256.slice(0, CHUNK_SIZE)),
325 .y_hi = Fr(y_256.slice(CHUNK_SIZE, CHUNK_SIZE * 2)),
326 .z_1 = Fr(0),
327 .z_2 = Fr(0),
328 .return_is_infinity = false,
329 };
330 ultra_ops_table.push(ultra_op);
331
332 // Do NOT update the accumulator - the hiding op doesn't perform any actual EC computation
333 return ultra_op;
334 }
335
336 private:
337 // Storage for the hiding op (prepended to eccvm ops during reconstruction)
339 bool has_hiding_op = false;
340
358 UltraOp construct_and_populate_ultra_ops(EccOpCode op_code, const Point& point, const Fr& scalar = Fr::zero())
359 {
360 UltraOp ultra_op;
361 ultra_op.op_code = op_code;
362
363 // Decompose point coordinates (Fq) into hi-lo chunks (Fr)
364 const size_t CHUNK_SIZE = 2 * stdlib::NUM_LIMB_BITS_IN_FIELD_SIMULATION;
365 uint256_t x_256(point.x);
366 uint256_t y_256(point.y);
367 ultra_op.return_is_infinity = point.is_point_at_infinity();
368 // if we have a point at infinity, set x/y to zero
369 // in the biggroup_goblin class we use `assert_equal` statements to validate
370 // the original in-circuit coordinate values are also zero
371 if (point.is_point_at_infinity()) {
372 x_256 = 0;
373 y_256 = 0;
374 }
375 ultra_op.x_lo = Fr(x_256.slice(0, CHUNK_SIZE));
376 ultra_op.x_hi = Fr(x_256.slice(CHUNK_SIZE, CHUNK_SIZE * 2));
377 ultra_op.y_lo = Fr(y_256.slice(0, CHUNK_SIZE));
378 ultra_op.y_hi = Fr(y_256.slice(CHUNK_SIZE, CHUNK_SIZE * 2));
379
380 // Split scalar into 128 bit endomorphism scalars
381 Fr z_1 = 0;
382 Fr z_2 = 0;
383 auto converted = scalar.from_montgomery_form();
384 uint256_t converted_u256(scalar);
385 if (converted_u256.get_msb() < 128) {
386 ultra_op.z_1 = scalar;
387 ultra_op.z_2 = 0;
388 } else {
389 Fr::split_into_endomorphism_scalars(converted, z_1, z_2);
390 ultra_op.z_1 = z_1.to_montgomery_form();
391 ultra_op.z_2 = z_2.to_montgomery_form();
392 }
393
394 ultra_ops_table.push(ultra_op);
395
396 return ultra_op;
397 }
398};
399
400} // namespace bb
Used to construct execution trace representations of elliptic curve operations.
Curve::ScalarField Fr
Curve::AffineElement Point
size_t get_num_rows() const
Get the number of rows for the current ECCVM circuit.
EccvmOpsTable eccvm_ops_table
std::vector< ECCVMOperation > eccvm_ops_reconstructed
void construct_full_eccvm_ops_table()
UltraOp add_accumulate(const Point &to_add)
Write point addition op to queue and natively perform addition.
std::array< Polynomial< Fr >, ULTRA_TABLE_WIDTH > construct_ultra_ops_table_columns() const
void initialize_new_subtable()
Initialize a new subtable for eccvm and ultra ops with the given merge settings.
Point get_accumulator()
size_t get_ultra_ops_table_num_rows() const
void merge(MergeSettings settings=MergeSettings::PREPEND, std::optional< size_t > ultra_fixed_offset=std::nullopt)
void construct_full_ultra_ops_table()
UltraOp append_hiding_op(const Fq &Px, const Fq &Py)
Add a hiding op with random Px, Py values to both ECCVM and Ultra ops tables.
ECCVMOperation hiding_op_for_eccvm
UltraEccOpsTable ultra_ops_table
void append_eccvm_op(const ECCVMOperation &op)
Append an eccvm operation to the eccvm ops table; update the eccvm row tracker.
uint32_t get_number_of_muls() const
get number of muls for the current ECCVM circuit
std::vector< ECCVMOperation > & get_eccvm_ops()
size_t get_num_msm_rows() const
Get the number of rows in the 'msm' column section, for all msms in the circuit.
std::vector< UltraOp > ultra_ops_reconstructed
std::array< Polynomial< Fr >, ULTRA_TABLE_WIDTH > construct_current_ultra_ops_subtable_columns() const
size_t get_current_ultra_ops_subtable_num_rows() const
UltraOp construct_and_populate_ultra_ops(EccOpCode op_code, const Point &point, const Fr &scalar=Fr::zero())
Given an ecc operation and its inputs, decompose into ultra format and populate ultra_ops.
UltraOp mul_accumulate(const Point &to_mul, const Fr &scalar)
Write multiply and add op to queue and natively perform operation.
std::vector< UltraOp > & get_ultra_ops()
std::array< Polynomial< Fr >, ULTRA_TABLE_WIDTH > construct_previous_ultra_ops_table_columns() const
UltraOp random_op_ultra_only()
Writes randomness to the ultra ops table but adds no eccvm operations.
UltraOp no_op_ultra_only()
Writes a no op (i.e. two zero rows) to the ultra ops table but adds no eccvm operations.
static const size_t OP_QUEUE_SIZE
UltraOp eq_and_reset()
Write equality op using internal accumulator point.
size_t get_current_subtable_size() const
void empty_row_for_testing()
Write empty row to queue.
ECCOpQueue()
Instantiate an initial ECC op subtable.
void set_eccvm_ops_for_fuzzing(std::vector< ECCVMOperation > &eccvm_ops_in)
A fuzzing only method for setting eccvm ops directly.
EccvmRowTracker eccvm_row_tracker
size_t get_ultra_ops_count() const
void add_erroneous_equality_op_for_testing()
A testing only method that adds an erroneous equality op to the eccvm ops.
size_t get_previous_ultra_ops_table_num_rows() const
static constexpr size_t ULTRA_TABLE_WIDTH
void create_new_subtable(size_t size_hint=0)
std::vector< OpFormat > get_reconstructed() const
void merge(MergeSettings settings=MergeSettings::PREPEND)
void push(const OpFormat &op)
Class for tracking the number of rows in the ECCVM circuit and the number of muls performed as the op...
size_t get_num_rows() const
Get the number of rows for the current ECCVM circuit.
size_t get_num_msm_rows() const
Get the number of rows in the 'msm' column section, for all msms in the circuit.
uint32_t get_number_of_muls() const
void update_cached_msms(const ECCVMOperation &op)
Update cached_active_msm_count or update other row counts and reset cached_active_msm_count.
Stores a table of elliptic curve operations represented in the Ultra format.
size_t get_current_subtable_size() const
void push(const UltraOp &op)
ColumnPolynomials construct_current_ultra_ops_subtable_columns() const
ColumnPolynomials construct_table_columns() const
ColumnPolynomials construct_previous_table_columns() const
void create_new_subtable(size_t size_hint=0)
size_t current_ultra_subtable_size() const
size_t previous_ultra_table_size() const
std::vector< UltraOp > get_reconstructed() const
static constexpr size_t TABLE_WIDTH
size_t ultra_table_size() const
void merge(MergeSettings settings=MergeSettings::PREPEND, std::optional< size_t > offset=std::nullopt)
bb::fq BaseField
Definition bn254.hpp:19
typename Group::affine_element AffineElement
Definition bn254.hpp:22
bb::fr ScalarField
Definition bn254.hpp:18
constexpr uint256_t slice(uint64_t start, uint64_t end) const
constexpr uint64_t get_msb() const
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
MergeSettings
The MergeSettings define whether an current subtable will be added at the beginning (PREPEND) or at t...
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
AffineElement base_point
Defines the opcodes for ECC operations used in both the Ultra and ECCVM formats. There are three opco...
bool return_is_infinity
EccOpCode op_code
BB_INLINE constexpr field to_montgomery_form() const noexcept
static void split_into_endomorphism_scalars(const field &k, field &k1, field &k2)
static field random_element(numeric::RNG *engine=nullptr) noexcept
BB_INLINE constexpr field from_montgomery_form() const noexcept
static constexpr field zero()
void throw_or_abort(std::string const &err)