21#include <unordered_map>
22#include <unordered_set>
26template <
typename ExecutionTrace>
54 if (!circuit_finalized) {
56 add_gates_to_ensure_all_polys_are_non_zero();
58 process_non_native_field_multiplications();
60 this->rom_ram_logic.process_ROM_arrays(
this);
61 this->rom_ram_logic.process_RAM_arrays(
this);
62 process_range_lists();
64 populate_public_inputs_block();
65 circuit_finalized =
true;
68 info(
"WARNING: Redundant call to finalize_circuit(). Is this intentional?");
80template <
typename ExecutionTrace>
84 blocks.arithmetic.populate_wires(this->zero_idx(), this->zero_idx(), this->zero_idx(), this->zero_idx());
85 blocks.arithmetic.q_m().emplace_back(1);
86 blocks.arithmetic.q_1().emplace_back(1);
87 blocks.arithmetic.q_2().emplace_back(1);
88 blocks.arithmetic.q_3().emplace_back(1);
89 blocks.arithmetic.q_4().emplace_back(1);
90 blocks.arithmetic.q_c().emplace_back(0);
91 blocks.arithmetic.set_gate_selector(0);
92 check_selector_length_consistency();
96 blocks.delta_range.populate_wires(this->zero_idx(), this->zero_idx(), this->zero_idx(), this->zero_idx());
97 blocks.delta_range.q_m().emplace_back(0);
98 blocks.delta_range.q_1().emplace_back(0);
99 blocks.delta_range.q_2().emplace_back(0);
100 blocks.delta_range.q_3().emplace_back(0);
101 blocks.delta_range.q_4().emplace_back(0);
102 blocks.delta_range.q_c().emplace_back(0);
103 blocks.delta_range.set_gate_selector(1);
105 check_selector_length_consistency();
107 create_unconstrained_gate(
108 blocks.delta_range, this->zero_idx(), this->zero_idx(), this->zero_idx(), this->zero_idx());
111 blocks.elliptic.populate_wires(this->zero_idx(), this->zero_idx(), this->zero_idx(), this->zero_idx());
112 blocks.elliptic.q_m().emplace_back(0);
113 blocks.elliptic.q_1().emplace_back(0);
114 blocks.elliptic.q_2().emplace_back(0);
115 blocks.elliptic.q_3().emplace_back(0);
116 blocks.elliptic.q_4().emplace_back(0);
117 blocks.elliptic.q_c().emplace_back(0);
118 blocks.elliptic.set_gate_selector(1);
119 check_selector_length_consistency();
121 create_unconstrained_gate(blocks.elliptic, this->zero_idx(), this->zero_idx(), this->zero_idx(), this->zero_idx());
124 blocks.memory.populate_wires(this->zero_idx(), this->zero_idx(), this->zero_idx(), this->zero_idx());
125 blocks.memory.q_m().emplace_back(0);
126 blocks.memory.q_1().emplace_back(0);
127 blocks.memory.q_2().emplace_back(0);
128 blocks.memory.q_3().emplace_back(0);
129 blocks.memory.q_4().emplace_back(0);
130 blocks.memory.q_c().emplace_back(0);
131 blocks.memory.set_gate_selector(1);
132 check_selector_length_consistency();
134 create_unconstrained_gate(blocks.memory, this->zero_idx(), this->zero_idx(), this->zero_idx(), this->zero_idx());
137 blocks.nnf.populate_wires(this->zero_idx(), this->zero_idx(), this->zero_idx(), this->zero_idx());
138 blocks.nnf.q_m().emplace_back(0);
139 blocks.nnf.q_1().emplace_back(0);
140 blocks.nnf.q_2().emplace_back(0);
141 blocks.nnf.q_3().emplace_back(0);
142 blocks.nnf.q_4().emplace_back(0);
143 blocks.nnf.q_c().emplace_back(0);
144 blocks.nnf.set_gate_selector(1);
145 check_selector_length_consistency();
147 create_unconstrained_gate(blocks.nnf, this->zero_idx(), this->zero_idx(), this->zero_idx(), this->zero_idx());
150 uint32_t one_idx = put_constant_variable(
FF::one());
151 create_big_add_gate({ this->zero_idx(), this->zero_idx(), this->zero_idx(), one_idx, 0, 0, 0, 1, -1 });
160 uint32_t left_value = 3;
161 uint32_t right_value = 3;
166 uint32_t left_witness_index = this->add_variable(left_witness_value);
167 uint32_t right_witness_index = this->add_variable(right_witness_value);
170 auto read_data = create_gates_from_plookup_accumulators(
173 update_used_witnesses(left_witness_index);
174 update_used_witnesses(right_witness_index);
178 for (
const auto& column : parse_read_data) {
179 update_used_witnesses(column);
180 update_finalize_witnesses(column);
184 blocks.poseidon2_external.populate_wires(this->zero_idx(), this->zero_idx(), this->zero_idx(), this->zero_idx());
185 blocks.poseidon2_external.q_m().emplace_back(0);
186 blocks.poseidon2_external.q_1().emplace_back(0);
187 blocks.poseidon2_external.q_2().emplace_back(0);
188 blocks.poseidon2_external.q_3().emplace_back(0);
189 blocks.poseidon2_external.q_c().emplace_back(0);
190 blocks.poseidon2_external.q_4().emplace_back(0);
191 blocks.poseidon2_external.set_gate_selector(1);
192 check_selector_length_consistency();
196 create_unconstrained_gate(
197 blocks.poseidon2_external, this->zero_idx(), this->zero_idx(), this->zero_idx(), this->zero_idx());
200 blocks.poseidon2_internal.populate_wires(this->zero_idx(), this->zero_idx(), this->zero_idx(), this->zero_idx());
201 blocks.poseidon2_internal.q_m().emplace_back(0);
202 blocks.poseidon2_internal.q_1().emplace_back(0);
203 blocks.poseidon2_internal.q_2().emplace_back(0);
204 blocks.poseidon2_internal.q_3().emplace_back(0);
205 blocks.poseidon2_internal.q_c().emplace_back(0);
206 blocks.poseidon2_internal.q_4().emplace_back(0);
207 blocks.poseidon2_internal.set_gate_selector(1);
208 check_selector_length_consistency();
212 create_unconstrained_gate(
213 blocks.poseidon2_internal, this->zero_idx(), this->zero_idx(), this->zero_idx(), this->zero_idx());
226 this->assert_valid_variables({ in.
a, in.
b, in.
c });
228 blocks.arithmetic.populate_wires(in.
a, in.
b, in.
c, this->zero_idx());
229 blocks.arithmetic.q_m().emplace_back(0);
230 blocks.arithmetic.q_1().emplace_back(in.
a_scaling);
231 blocks.arithmetic.q_2().emplace_back(in.
b_scaling);
232 blocks.arithmetic.q_3().emplace_back(in.
c_scaling);
234 blocks.arithmetic.q_4().emplace_back(0);
235 blocks.arithmetic.set_gate_selector(1);
236 check_selector_length_consistency();
248template <
typename ExecutionTrace>
250 const bool include_next_gate_w_4)
252 this->assert_valid_variables({ in.
a, in.
b, in.
c, in.
d });
253 blocks.arithmetic.populate_wires(in.
a, in.
b, in.
c, in.
d);
255 blocks.arithmetic.q_1().emplace_back(in.
a_scaling);
256 blocks.arithmetic.q_2().emplace_back(in.
b_scaling);
257 blocks.arithmetic.q_3().emplace_back(in.
c_scaling);
259 blocks.arithmetic.q_4().emplace_back(in.
d_scaling);
260 blocks.arithmetic.set_gate_selector(include_next_gate_w_4 ? 2 : 1);
261 check_selector_length_consistency();
273template <
typename ExecutionTrace>
275 const bool include_next_gate_w_4)
277 this->assert_valid_variables({ in.
a, in.
b, in.
c, in.
d });
278 blocks.arithmetic.populate_wires(in.
a, in.
b, in.
c, in.
d);
279 blocks.arithmetic.q_m().emplace_back(0);
280 blocks.arithmetic.q_1().emplace_back(in.
a_scaling);
281 blocks.arithmetic.q_2().emplace_back(in.
b_scaling);
282 blocks.arithmetic.q_3().emplace_back(in.
c_scaling);
284 blocks.arithmetic.q_4().emplace_back(in.
d_scaling);
285 blocks.arithmetic.set_gate_selector(include_next_gate_w_4 ? 2 : 1);
286 check_selector_length_consistency();
295template <
typename ExecutionTrace>
298 this->assert_valid_variables({ in.
a, in.
b, in.
c, in.
d });
300 blocks.arithmetic.populate_wires(in.
a, in.
b, in.
c, in.
d);
302 blocks.arithmetic.q_1().emplace_back(in.
a_scaling);
304 blocks.arithmetic.q_3().emplace_back(in.
c_scaling);
306 blocks.arithmetic.q_4().emplace_back(in.
d_scaling);
307 blocks.arithmetic.set_gate_selector(1);
308 check_selector_length_consistency();
321 this->assert_valid_variables({ in.
a, in.
b, in.
c });
323 blocks.arithmetic.populate_wires(in.
a, in.
b, in.
c, this->zero_idx());
324 blocks.arithmetic.q_m().emplace_back(in.
mul_scaling);
325 blocks.arithmetic.q_1().emplace_back(0);
326 blocks.arithmetic.q_2().emplace_back(0);
327 blocks.arithmetic.q_3().emplace_back(in.
c_scaling);
329 blocks.arithmetic.q_4().emplace_back(0);
330 blocks.arithmetic.set_gate_selector(1);
331 check_selector_length_consistency();
339template <
typename ExecutionTrace>
342 this->assert_valid_variables({ variable_index });
344 blocks.arithmetic.populate_wires(variable_index, variable_index, this->zero_idx(), this->zero_idx());
345 blocks.arithmetic.q_m().emplace_back(1);
346 blocks.arithmetic.q_1().emplace_back(-1);
347 blocks.arithmetic.q_2().emplace_back(0);
348 blocks.arithmetic.q_3().emplace_back(0);
349 blocks.arithmetic.q_c().emplace_back(0);
350 blocks.arithmetic.q_4().emplace_back(0);
351 blocks.arithmetic.set_gate_selector(1);
352 check_selector_length_consistency();
362template <
typename ExecutionTrace>
365 this->assert_valid_variables({ in.
a, in.
b, in.
c });
367 blocks.arithmetic.populate_wires(in.
a, in.
b, in.
c, this->zero_idx());
368 blocks.arithmetic.q_m().emplace_back(in.
q_m);
369 blocks.arithmetic.q_1().emplace_back(in.
q_l);
370 blocks.arithmetic.q_2().emplace_back(in.
q_r);
371 blocks.arithmetic.q_3().emplace_back(in.
q_o);
372 blocks.arithmetic.q_c().emplace_back(in.
q_c);
373 blocks.arithmetic.q_4().emplace_back(0);
374 blocks.arithmetic.set_gate_selector(1);
375 check_selector_length_consistency();
387template <
typename ExecutionTrace>
398 this->assert_valid_variables({ in.
x1, in.
x2, in.
x3, in.
y1, in.
y2, in.
y3 });
400 auto& block = blocks.elliptic;
402 bool previous_elliptic_gate_exists = block.size() > 0;
403 bool can_fuse_into_previous_gate = previous_elliptic_gate_exists;
405 if (can_fuse_into_previous_gate) {
406 can_fuse_into_previous_gate = can_fuse_into_previous_gate && (block.w_r()[block.size() - 1] == in.
x1);
407 can_fuse_into_previous_gate = can_fuse_into_previous_gate && (block.w_o()[block.size() - 1] == in.
y1);
408 can_fuse_into_previous_gate = can_fuse_into_previous_gate && (block.q_3()[block.size() - 1] == 0);
409 can_fuse_into_previous_gate = can_fuse_into_previous_gate && (block.q_4()[block.size() - 1] == 0);
410 can_fuse_into_previous_gate = can_fuse_into_previous_gate && (block.q_1()[block.size() - 1] == 0);
411 can_fuse_into_previous_gate = can_fuse_into_previous_gate && (block.q_arith()[block.size() - 1] == 0);
412 can_fuse_into_previous_gate = can_fuse_into_previous_gate && (block.q_m()[block.size() - 1] == 0);
416 [[maybe_unused]]
bool can_fuse =
418 block.w_r()[block.size() - 1] == in.
x1 &&
419 block.w_o()[block.size() - 1] == in.
y1;
421 if (can_fuse_into_previous_gate) {
423 block.q_elliptic().set(block.size() - 1, 1);
425 block.populate_wires(this->zero_idx(), in.
x1, in.
y1, this->zero_idx());
426 block.q_3().emplace_back(0);
427 block.q_4().emplace_back(0);
430 block.q_2().emplace_back(0);
431 block.q_m().emplace_back(0);
432 block.q_c().emplace_back(0);
433 block.set_gate_selector(1);
434 check_selector_length_consistency();
437 create_unconstrained_gate(block, in.
x2, in.
x3, in.
y3, in.
y2);
445template <
typename ExecutionTrace>
448 auto& block = blocks.elliptic;
458 this->assert_valid_variables({ in.
x1, in.
x3, in.
y1, in.
y3 });
460 bool previous_elliptic_gate_exists = block.size() > 0;
461 bool can_fuse_into_previous_gate = previous_elliptic_gate_exists;
463 if (can_fuse_into_previous_gate) {
464 can_fuse_into_previous_gate = can_fuse_into_previous_gate && (block.w_r()[block.size() - 1] == in.
x1);
465 can_fuse_into_previous_gate = can_fuse_into_previous_gate && (block.w_o()[block.size() - 1] == in.
y1);
466 can_fuse_into_previous_gate = can_fuse_into_previous_gate && (block.q_arith()[block.size() - 1] == 0);
467 can_fuse_into_previous_gate = can_fuse_into_previous_gate && (block.q_lookup_type()[block.size() - 1] == 0);
468 can_fuse_into_previous_gate = can_fuse_into_previous_gate && (block.q_memory()[block.size() - 1] == 0);
469 can_fuse_into_previous_gate = can_fuse_into_previous_gate && (block.q_nnf()[block.size() - 1] == 0);
473 [[maybe_unused]]
bool can_fuse =
475 block.w_r()[block.size() - 1] == in.
x1 &&
476 block.w_o()[block.size() - 1] == in.
y1;
478 if (can_fuse_into_previous_gate) {
479 block.q_elliptic().set(block.size() - 1, 1);
480 block.q_m().set(block.size() - 1, 1);
482 block.populate_wires(this->zero_idx(), in.
x1, in.
y1, this->zero_idx());
483 block.q_m().emplace_back(1);
484 block.q_1().emplace_back(0);
485 block.q_2().emplace_back(0);
486 block.q_3().emplace_back(0);
487 block.q_c().emplace_back(0);
488 block.q_4().emplace_back(0);
489 block.set_gate_selector(1);
490 check_selector_length_consistency();
493 create_unconstrained_gate(block, this->zero_idx(), in.
x3, in.
y3, this->zero_idx());
502template <
typename ExecutionTrace>
505 this->assert_valid_variables({ witness_index });
507 blocks.arithmetic.populate_wires(witness_index, this->zero_idx(), this->zero_idx(), this->zero_idx());
508 blocks.arithmetic.q_m().emplace_back(0);
509 blocks.arithmetic.q_1().emplace_back(1);
510 blocks.arithmetic.q_2().emplace_back(0);
511 blocks.arithmetic.q_3().emplace_back(0);
512 blocks.arithmetic.q_c().emplace_back(-witness_value);
513 blocks.arithmetic.q_4().emplace_back(0);
514 blocks.arithmetic.set_gate_selector(1);
515 check_selector_length_consistency();
519template <
typename ExecutionTrace>
522 if (constant_variable_indices.contains(variable)) {
523 return constant_variable_indices.at(variable);
525 uint32_t variable_index = this->add_variable(variable);
526 fix_witness(variable_index, variable);
527 constant_variable_indices.insert({ variable, variable_index });
528 return variable_index;
540template <
typename ExecutionTrace>
544 if (table.id ==
id) {
550 return lookup_tables.back();
557template <
typename ExecutionTrace>
561 const uint32_t key_a_index,
567 for (
size_t i = 0; i < num_lookups; ++i) {
569 auto& table = get_table(multi_table.basic_table_ids[i]);
573 const auto first_idx = (i == 0) ? key_a_index : this->add_variable(read_values[
plookup::ColumnIdx::C1][i]);
574 const auto second_idx = (i == 0 && (key_b_index.has_value()))
575 ? key_b_index.value()
582 this->assert_valid_variables({ first_idx, second_idx, third_idx });
584 blocks.lookup.q_3().emplace_back(
FF(table.table_index));
585 blocks.lookup.populate_wires(first_idx, second_idx, third_idx, this->zero_idx());
586 blocks.lookup.q_1().emplace_back(0);
587 blocks.lookup.q_2().emplace_back((i == (num_lookups - 1) ? 0 : -multi_table.column_1_step_sizes[i + 1]));
588 blocks.lookup.q_m().emplace_back((i == (num_lookups - 1) ? 0 : -multi_table.column_2_step_sizes[i + 1]));
589 blocks.lookup.q_c().emplace_back((i == (num_lookups - 1) ? 0 : -multi_table.column_3_step_sizes[i + 1]));
590 blocks.lookup.q_4().emplace_back(0);
591 blocks.lookup.set_gate_selector(1);
592 check_selector_length_consistency();
601template <
typename ExecutionTrace>
603 const uint64_t target_range)
606 const auto range_tag = get_new_tag();
607 const auto tau_tag = get_new_tag();
608 create_tag(range_tag, tau_tag);
609 create_tag(tau_tag, range_tag);
614 uint64_t num_multiples_of_three = (target_range / DEFAULT_PLOOKUP_RANGE_STEP_SIZE);
617 for (uint64_t i = 0; i <= num_multiples_of_three; ++i) {
618 const uint32_t index = this->add_variable(i * DEFAULT_PLOOKUP_RANGE_STEP_SIZE);
623 const uint32_t index = this->add_variable(target_range);
635template <
typename ExecutionTrace>
637 const uint32_t variable_index,
const uint64_t num_bits,
const uint64_t target_range_bitnum, std::string
const& msg)
639 this->assert_valid_variables({ variable_index });
646 if (val.
get_msb() >= num_bits && !this->failed()) {
650 const uint64_t sublimb_mask = (1ULL << target_range_bitnum) - 1;
665 std::vector<uint64_t> sublimbs;
666 std::vector<uint32_t> sublimb_indices;
668 const bool has_remainder_bits = (num_bits % target_range_bitnum != 0);
669 const uint64_t num_limbs = (num_bits / target_range_bitnum) + has_remainder_bits;
670 const uint64_t last_limb_size = num_bits - ((num_bits / target_range_bitnum) * target_range_bitnum);
671 const uint64_t last_limb_range = ((uint64_t)1 << last_limb_size) - 1;
674 for (
size_t i = 0; i < num_limbs; ++i) {
675 sublimbs.push_back(accumulator.
data[0] & sublimb_mask);
676 accumulator = accumulator >> target_range_bitnum;
678 for (
size_t i = 0; i < sublimbs.size(); ++i) {
679 const auto limb_idx = this->add_variable(sublimbs[i]);
680 sublimb_indices.emplace_back(limb_idx);
681 if ((i == sublimbs.size() - 1) && has_remainder_bits) {
682 create_new_range_constraint(limb_idx, last_limb_range);
684 create_new_range_constraint(limb_idx, sublimb_mask);
688 const uint64_t num_limb_triples = (num_limbs / 3) + ((num_limbs % 3) != 0);
689 const uint64_t leftovers = (num_limbs % 3) == 0 ? 3 : (num_limbs % 3);
692 uint32_t accumulator_idx = variable_index;
694 for (
size_t i = 0; i < num_limb_triples; ++i) {
695 const bool real_limbs[3]{
696 (i == (num_limb_triples - 1) && (leftovers < 1)) ?
false : true,
697 (i == (num_limb_triples - 1) && (leftovers < 2)) ? false : true,
698 (i == (num_limb_triples - 1) && (leftovers < 3)) ? false : true,
701 const uint64_t round_sublimbs[3]{
702 real_limbs[0] ? sublimbs[3 * i] : 0,
703 real_limbs[1] ? sublimbs[3 * i + 1] : 0,
704 real_limbs[2] ? sublimbs[3 * i + 2] : 0,
706 const uint32_t new_limbs[3]{
707 real_limbs[0] ? sublimb_indices[3 * i] : this->zero_idx(),
708 real_limbs[1] ? sublimb_indices[3 * i + 1] : this->zero_idx(),
709 real_limbs[2] ? sublimb_indices[3 * i + 2] : this->zero_idx(),
711 const uint64_t shifts[3]{
712 target_range_bitnum * (3 * i),
713 target_range_bitnum * (3 * i + 1),
714 target_range_bitnum * (3 * i + 2),
716 uint256_t new_accumulator = accumulator - (
uint256_t(round_sublimbs[0]) << shifts[0]) -
718 (
uint256_t(round_sublimbs[2]) << shifts[2]);
732 ((i == num_limb_triples - 1) ?
false : true));
735 accumulator_idx = this->add_variable(new_accumulator);
736 accumulator = new_accumulator;
738 return sublimb_indices;
750template <
typename ExecutionTrace>
752 const uint64_t target_range,
753 std::string
const msg)
755 const bool is_out_of_range = (
uint256_t(this->get_variable(variable_index)).
data[0] > target_range);
756 if (is_out_of_range && !this->failed()) {
759 if (range_lists.count(target_range) == 0) {
760 range_lists.insert({ target_range, create_range_list(target_range) });
763 const auto existing_tag = this->real_variable_tags[this->real_variable_index[variable_index]];
764 auto& list = range_lists[target_range];
767 if (existing_tag != list.range_tag) {
770 if (existing_tag != DUMMY_TAG) {
771 bool found_tag =
false;
772 for (
const auto& r : range_lists) {
773 if (r.second.range_tag == existing_tag) {
775 if (r.first < target_range) {
782 const uint32_t copied_witness = this->add_variable(this->get_variable(variable_index));
783 create_add_gate({ .a = variable_index,
785 .c = this->zero_idx(),
789 .const_scaling = 0 });
791 create_new_range_constraint(copied_witness, target_range, msg);
798 assign_tag(variable_index, list.range_tag);
799 list.variable_indices.emplace_back(variable_index);
813 x = this->real_variable_index[x];
823 std::vector<uint32_t> sorted_list;
826 const auto& field_element = this->get_variable(variable_index);
827 const uint32_t shrinked_value = (uint32_t)field_element.from_montgomery_form().data[0];
828 sorted_list.emplace_back(shrinked_value);
832 std::sort(sorted_list.begin(), sorted_list.end());
834 std::sort(std::execution::par_unseq, sorted_list.begin(), sorted_list.end());
837 constexpr size_t gate_width = NUM_WIRES;
838 size_t padding = (gate_width - (list.
variable_indices.size() % gate_width)) % gate_width;
840 std::vector<uint32_t> indices;
841 indices.reserve(padding + sorted_list.size());
844 padding += gate_width;
846 for (
size_t i = 0; i < padding; ++i) {
847 indices.emplace_back(this->zero_idx());
849 for (
const auto sorted_value : sorted_list) {
850 const uint32_t index = this->add_variable(sorted_value);
851 assign_tag(index, list.
tau_tag);
852 indices.emplace_back(index);
854 create_sort_constraint_with_edges(indices, 0, list.
target_range);
859 for (
auto& i : range_lists) {
860 process_range_list(i.second);
877template <
typename ExecutionTrace>
880 constexpr size_t gate_width = NUM_WIRES;
882 this->assert_valid_variables(variable_index);
884 for (
size_t i = 0; i < variable_index.size(); i += gate_width) {
885 blocks.delta_range.populate_wires(
886 variable_index[i], variable_index[i + 1], variable_index[i + 2], variable_index[i + 3]);
889 blocks.delta_range.q_m().emplace_back(0);
890 blocks.delta_range.q_1().emplace_back(0);
891 blocks.delta_range.q_2().emplace_back(0);
892 blocks.delta_range.q_3().emplace_back(0);
893 blocks.delta_range.q_c().emplace_back(0);
894 blocks.delta_range.q_4().emplace_back(0);
895 blocks.delta_range.set_gate_selector(1);
896 check_selector_length_consistency();
899 create_unconstrained_gate(blocks.delta_range,
900 variable_index[variable_index.size() - 1],
908template <
typename ExecutionTrace>
911 std::vector<uint32_t> padded_list = variable_index;
912 constexpr size_t gate_width = NUM_WIRES;
913 const uint64_t padding = (gate_width - (padded_list.size() % gate_width)) % gate_width;
914 for (uint64_t i = 0; i < padding; ++i) {
915 padded_list.emplace_back(this->zero_idx());
917 this->assert_valid_variables(variable_index);
918 this->assert_valid_variables(padded_list);
920 for (
size_t i = 0; i < padded_list.size(); i += gate_width) {
921 create_unconstrained_gate(
922 blocks.arithmetic, padded_list[i], padded_list[i + 1], padded_list[i + 2], padded_list[i + 3]);
927template <
typename ExecutionTrace>
929 const std::vector<uint32_t>& variable_index,
const FF& start,
const FF& end)
932 constexpr size_t gate_width = NUM_WIRES;
935 this->assert_valid_variables(variable_index);
937 auto& block = blocks.delta_range;
940 create_add_gate({ variable_index[0], this->zero_idx(), this->zero_idx(), 1, 0, 0, -start });
943 for (
size_t i = 0; i < variable_index.size() - gate_width; i += gate_width) {
945 block.populate_wires(variable_index[i], variable_index[i + 1], variable_index[i + 2], variable_index[i + 3]);
947 block.q_m().emplace_back(0);
948 block.q_1().emplace_back(0);
949 block.q_2().emplace_back(0);
950 block.q_3().emplace_back(0);
951 block.q_c().emplace_back(0);
952 block.q_4().emplace_back(0);
953 block.set_gate_selector(1);
954 check_selector_length_consistency();
957 if (variable_index.size() > gate_width) {
958 block.populate_wires(variable_index[variable_index.size() - 4],
959 variable_index[variable_index.size() - 3],
960 variable_index[variable_index.size() - 2],
961 variable_index[variable_index.size() - 1]);
963 block.q_m().emplace_back(0);
964 block.q_1().emplace_back(0);
965 block.q_2().emplace_back(0);
966 block.q_3().emplace_back(0);
967 block.q_c().emplace_back(0);
968 block.q_4().emplace_back(0);
969 block.set_gate_selector(1);
970 check_selector_length_consistency();
977 create_unconstrained_gate(
978 block, variable_index[variable_index.size() - 1], this->zero_idx(), this->zero_idx(), this->zero_idx());
979 create_add_gate({ variable_index[variable_index.size() - 1], this->zero_idx(), this->zero_idx(), 1, 0, 0, -end });
1004template <
typename ExecutionTrace>
1007 auto& block = blocks.memory;
1008 block.set_gate_selector(type == MEMORY_SELECTORS::MEM_NONE ? 0 : 1);
1010 case MEMORY_SELECTORS::ROM_CONSISTENCY_CHECK: {
1015 block.q_1().emplace_back(1);
1016 block.q_2().emplace_back(1);
1017 block.q_3().emplace_back(0);
1018 block.q_4().emplace_back(0);
1019 block.q_m().emplace_back(0);
1020 block.q_c().emplace_back(0);
1021 check_selector_length_consistency();
1024 case MEMORY_SELECTORS::RAM_CONSISTENCY_CHECK: {
1030 block.q_1().emplace_back(0);
1031 block.q_2().emplace_back(0);
1032 block.q_3().emplace_back(1);
1033 block.q_4().emplace_back(0);
1034 block.q_m().emplace_back(0);
1035 block.q_c().emplace_back(0);
1036 check_selector_length_consistency();
1039 case MEMORY_SELECTORS::RAM_TIMESTAMP_CHECK: {
1042 block.q_1().emplace_back(1);
1043 block.q_2().emplace_back(0);
1044 block.q_3().emplace_back(0);
1045 block.q_4().emplace_back(1);
1046 block.q_m().emplace_back(0);
1047 block.q_c().emplace_back(0);
1048 check_selector_length_consistency();
1051 case MEMORY_SELECTORS::ROM_READ: {
1055 block.q_1().emplace_back(1);
1056 block.q_2().emplace_back(0);
1057 block.q_3().emplace_back(0);
1058 block.q_4().emplace_back(0);
1059 block.q_m().emplace_back(1);
1060 block.q_c().emplace_back(0);
1061 check_selector_length_consistency();
1064 case MEMORY_SELECTORS::RAM_READ: {
1068 block.q_1().emplace_back(1);
1069 block.q_2().emplace_back(0);
1070 block.q_3().emplace_back(0);
1071 block.q_4().emplace_back(0);
1072 block.q_m().emplace_back(1);
1073 block.q_c().emplace_back(0);
1074 check_selector_length_consistency();
1077 case MEMORY_SELECTORS::RAM_WRITE: {
1081 block.q_1().emplace_back(1);
1082 block.q_2().emplace_back(0);
1083 block.q_3().emplace_back(0);
1084 block.q_4().emplace_back(0);
1085 block.q_m().emplace_back(1);
1086 block.q_c().emplace_back(1);
1087 check_selector_length_consistency();
1091 block.q_1().emplace_back(0);
1092 block.q_2().emplace_back(0);
1093 block.q_3().emplace_back(0);
1094 block.q_4().emplace_back(0);
1095 block.q_m().emplace_back(0);
1096 block.q_c().emplace_back(0);
1097 check_selector_length_consistency();
1126template <
typename ExecutionTrace>
1129 auto& block = blocks.nnf;
1130 block.set_gate_selector(type == NNF_SELECTORS::NNF_NONE ? 0 : 1);
1132 case NNF_SELECTORS::LIMB_ACCUMULATE_1: {
1133 block.q_1().emplace_back(0);
1134 block.q_2().emplace_back(0);
1135 block.q_3().emplace_back(1);
1136 block.q_4().emplace_back(1);
1137 block.q_m().emplace_back(0);
1138 block.q_c().emplace_back(0);
1139 check_selector_length_consistency();
1142 case NNF_SELECTORS::LIMB_ACCUMULATE_2: {
1143 block.q_1().emplace_back(0);
1144 block.q_2().emplace_back(0);
1145 block.q_3().emplace_back(1);
1146 block.q_4().emplace_back(0);
1147 block.q_m().emplace_back(1);
1148 block.q_c().emplace_back(0);
1149 check_selector_length_consistency();
1152 case NNF_SELECTORS::NON_NATIVE_FIELD_1: {
1153 block.q_1().emplace_back(0);
1154 block.q_2().emplace_back(1);
1155 block.q_3().emplace_back(1);
1156 block.q_4().emplace_back(0);
1157 block.q_m().emplace_back(0);
1158 block.q_c().emplace_back(0);
1159 check_selector_length_consistency();
1162 case NNF_SELECTORS::NON_NATIVE_FIELD_2: {
1163 block.q_1().emplace_back(0);
1164 block.q_2().emplace_back(1);
1165 block.q_3().emplace_back(0);
1166 block.q_4().emplace_back(1);
1167 block.q_m().emplace_back(0);
1168 block.q_c().emplace_back(0);
1169 check_selector_length_consistency();
1172 case NNF_SELECTORS::NON_NATIVE_FIELD_3: {
1173 block.q_1().emplace_back(0);
1174 block.q_2().emplace_back(1);
1175 block.q_3().emplace_back(0);
1176 block.q_4().emplace_back(0);
1177 block.q_m().emplace_back(1);
1178 block.q_c().emplace_back(0);
1179 check_selector_length_consistency();
1183 block.q_1().emplace_back(0);
1184 block.q_2().emplace_back(0);
1185 block.q_3().emplace_back(0);
1186 block.q_4().emplace_back(0);
1187 block.q_m().emplace_back(0);
1188 block.q_c().emplace_back(0);
1189 check_selector_length_consistency();
1205template <
typename ExecutionTrace>
1207 const uint32_t hi_idx,
1208 const size_t lo_limb_bits,
1209 const size_t hi_limb_bits,
1210 std::string
const& msg)
1218 const bool is_lo_out_of_range = (
uint256_t(this->get_variable_reference(lo_idx)) >= (
uint256_t(1) << lo_limb_bits));
1219 if (is_lo_out_of_range && !this->failed()) {
1220 this->failure(msg +
": lo limb.");
1222 const bool is_hi_out_of_range = (
uint256_t(this->get_variable_reference(hi_idx)) >= (
uint256_t(1) << hi_limb_bits));
1223 if (is_hi_out_of_range && !this->failed()) {
1224 this->failure(msg +
": hi limb.");
1228 const auto get_sublimbs = [&](
const uint32_t& limb_idx,
const std::array<uint64_t, 5>& sublimb_masks) {
1229 const uint256_t limb = this->get_variable(limb_idx);
1235 sublimb_indices[0] = sublimb_masks[0] != 0 ? this->add_variable(limb & MAX_SUBLIMB_MASK) : this->zero_idx();
1236 sublimb_indices[1] =
1237 sublimb_masks[1] != 0 ? this->add_variable((limb >> 14) & MAX_SUBLIMB_MASK) : this->zero_idx();
1238 sublimb_indices[2] =
1239 sublimb_masks[2] != 0 ? this->add_variable((limb >> 28) & MAX_SUBLIMB_MASK) : this->zero_idx();
1240 sublimb_indices[3] =
1241 sublimb_masks[3] != 0 ? this->add_variable((limb >> 42) & MAX_SUBLIMB_MASK) : this->zero_idx();
1242 sublimb_indices[4] =
1243 sublimb_masks[4] != 0 ? this->add_variable((limb >> 56) & MAX_SUBLIMB_MASK) : this->zero_idx();
1244 return sublimb_indices;
1247 const auto get_limb_masks = [](
size_t limb_bits) {
1248 std::array<uint64_t, 5> sublimb_masks;
1249 sublimb_masks[0] = limb_bits >= 14 ? 14 : limb_bits;
1250 sublimb_masks[1] = limb_bits >= 28 ? 14 : (limb_bits > 14 ? limb_bits - 14 : 0);
1251 sublimb_masks[2] = limb_bits >= 42 ? 14 : (limb_bits > 28 ? limb_bits - 28 : 0);
1252 sublimb_masks[3] = limb_bits >= 56 ? 14 : (limb_bits > 42 ? limb_bits - 42 : 0);
1253 sublimb_masks[4] = (limb_bits > 56 ? limb_bits - 56 : 0);
1255 for (
auto& mask : sublimb_masks) {
1256 mask = (1ULL << mask) - 1ULL;
1258 return sublimb_masks;
1261 const auto lo_masks = get_limb_masks(lo_limb_bits);
1262 const auto hi_masks = get_limb_masks(hi_limb_bits);
1266 blocks.nnf.populate_wires(lo_sublimbs[0], lo_sublimbs[1], lo_sublimbs[2], lo_idx);
1267 blocks.nnf.populate_wires(lo_sublimbs[3], lo_sublimbs[4], hi_sublimbs[0], hi_sublimbs[1]);
1268 blocks.nnf.populate_wires(hi_sublimbs[2], hi_sublimbs[3], hi_sublimbs[4], hi_idx);
1270 apply_nnf_selectors(NNF_SELECTORS::LIMB_ACCUMULATE_1);
1271 apply_nnf_selectors(NNF_SELECTORS::LIMB_ACCUMULATE_2);
1272 apply_nnf_selectors(NNF_SELECTORS::NNF_NONE);
1273 this->num_gates += 3;
1275 for (
size_t i = 0; i < 5; i++) {
1276 if (lo_masks[i] != 0) {
1277 create_new_range_constraint(lo_sublimbs[i], lo_masks[i],
"ultra_circuit_builder: sublimb of low too large");
1279 if (hi_masks[i] != 0) {
1280 create_new_range_constraint(hi_sublimbs[i], hi_masks[i],
"ultra_circuit_builder: sublimb of hi too large");
1295template <
typename ExecutionTrace>
1297 const uint32_t limb_idx,
const size_t num_limb_bits)
1300 constexpr FF LIMB_MASK = (
uint256_t(1) << DEFAULT_NON_NATIVE_FIELD_LIMB_BITS) - 1;
1303 const uint256_t hi =
value >> DEFAULT_NON_NATIVE_FIELD_LIMB_BITS;
1306 const uint32_t low_idx = this->add_variable(low);
1307 const uint32_t hi_idx = this->add_variable(hi);
1309 BB_ASSERT_GT(num_limb_bits, DEFAULT_NON_NATIVE_FIELD_LIMB_BITS);
1310 const size_t lo_bits = DEFAULT_NON_NATIVE_FIELD_LIMB_BITS;
1311 const size_t hi_bits = num_limb_bits - DEFAULT_NON_NATIVE_FIELD_LIMB_BITS;
1312 range_constrain_two_limbs(
1313 low_idx, hi_idx, lo_bits, hi_bits,
"decompose_non_native_field_double_width_limb: limbs too large");
1315 return std::array<uint32_t, 2>{ low_idx, hi_idx };
1334template <
typename ExecutionTrace>
1340 this->get_variable(input.
a[0]),
1341 this->get_variable(input.
a[1]),
1342 this->get_variable(input.
a[2]),
1343 this->get_variable(input.
a[3]),
1346 this->get_variable(input.
b[0]),
1347 this->get_variable(input.
b[1]),
1348 this->get_variable(input.
b[2]),
1349 this->get_variable(input.
b[3]),
1352 this->get_variable(input.
q[0]),
1353 this->get_variable(input.
q[1]),
1354 this->get_variable(input.
q[2]),
1355 this->get_variable(input.
q[3]),
1358 this->get_variable(input.
r[0]),
1359 this->get_variable(input.
r[1]),
1360 this->get_variable(input.
r[2]),
1361 this->get_variable(input.
r[3]),
1363 constexpr FF LIMB_SHIFT =
uint256_t(1) << DEFAULT_NON_NATIVE_FIELD_LIMB_BITS;
1364 constexpr FF LIMB_RSHIFT =
FF(1) /
FF(
uint256_t(1) << DEFAULT_NON_NATIVE_FIELD_LIMB_BITS);
1365 constexpr FF LIMB_RSHIFT_2 =
FF(1) /
FF(
uint256_t(1) << (2 * DEFAULT_NON_NATIVE_FIELD_LIMB_BITS));
1367 FF lo_0 =
a[0] *
b[0] - r[0] + (
a[1] *
b[0] +
a[0] *
b[1]) * LIMB_SHIFT;
1372 FF hi_0 =
a[2] *
b[0] +
a[0] *
b[2] + (
a[0] *
b[3] +
a[3] *
b[0] - r[3]) * LIMB_SHIFT;
1373 FF hi_1 = hi_0 +
a[1] *
b[1] - r[2] + (
a[1] *
b[2] +
a[2] *
b[1]) * LIMB_SHIFT;
1380 const uint32_t lo_0_idx = this->add_variable(lo_0);
1381 const uint32_t lo_1_idx = this->add_variable(lo_1);
1382 const uint32_t hi_0_idx = this->add_variable(hi_0);
1383 const uint32_t hi_1_idx = this->add_variable(hi_1);
1384 const uint32_t hi_2_idx = this->add_variable(hi_2);
1385 const uint32_t hi_3_idx = this->add_variable(hi_3);
1392 create_big_add_gate({ input.
q[0],
1402 create_unconstrained_gate(blocks.arithmetic, this->zero_idx(), this->zero_idx(), this->zero_idx(), lo_0_idx);
1418 blocks.nnf.populate_wires(input.
a[1], input.
b[1], input.
r[0], lo_0_idx);
1419 apply_nnf_selectors(NNF_SELECTORS::NON_NATIVE_FIELD_1);
1433 blocks.nnf.populate_wires(input.
a[0], input.
b[0], input.
a[3], input.
b[3]);
1434 apply_nnf_selectors(NNF_SELECTORS::NON_NATIVE_FIELD_2);
1448 blocks.nnf.populate_wires(input.
a[2], input.
b[2], input.
r[3], hi_0_idx);
1449 apply_nnf_selectors(NNF_SELECTORS::NON_NATIVE_FIELD_3);
1455 blocks.nnf.populate_wires(input.
a[1], input.
b[1], input.
r[2], hi_1_idx);
1456 apply_nnf_selectors(NNF_SELECTORS::NNF_NONE);
1465 create_big_add_gate(
1484 create_big_add_gate({
1496 return std::array<uint32_t, 2>{ lo_1_idx, hi_3_idx };
1508 for (
const auto& idx : this->public_inputs()) {
1510 blocks.pub_inputs.populate_wires(idx, idx, this->zero_idx(), this->zero_idx());
1511 for (
auto& selector : this->blocks.pub_inputs.get_selectors()) {
1512 selector.emplace_back(0);
1524 for (
size_t i = 0; i < cached_partial_non_native_field_multiplications.size(); ++i) {
1525 auto& c = cached_partial_non_native_field_multiplications[i];
1526 for (
size_t j = 0; j < c.a.size(); ++j) {
1527 c.a[j] = this->real_variable_index[c.a[j]];
1528 c.b[j] = this->real_variable_index[c.b[j]];
1531 cached_partial_non_native_field_multiplication::deduplicate(cached_partial_non_native_field_multiplications,
this);
1534 for (
const auto& input : cached_partial_non_native_field_multiplications) {
1536 blocks.nnf.populate_wires(input.a[1], input.b[1], this->zero_idx(), input.lo_0);
1537 apply_nnf_selectors(NNF_SELECTORS::NON_NATIVE_FIELD_1);
1540 blocks.nnf.populate_wires(input.a[0], input.b[0], input.a[3], input.b[3]);
1541 apply_nnf_selectors(NNF_SELECTORS::NON_NATIVE_FIELD_2);
1544 blocks.nnf.populate_wires(input.a[2], input.b[2], this->zero_idx(), input.hi_0);
1545 apply_nnf_selectors(NNF_SELECTORS::NON_NATIVE_FIELD_3);
1548 blocks.nnf.populate_wires(input.a[1], input.b[1], this->zero_idx(), input.hi_1);
1549 apply_nnf_selectors(NNF_SELECTORS::NNF_NONE);
1562template <
typename ExecutionTrace>
1568 this->get_variable(input.
a[0]),
1569 this->get_variable(input.
a[1]),
1570 this->get_variable(input.
a[2]),
1571 this->get_variable(input.
a[3]),
1574 this->get_variable(input.
b[0]),
1575 this->get_variable(input.
b[1]),
1576 this->get_variable(input.
b[2]),
1577 this->get_variable(input.
b[3]),
1580 constexpr FF LIMB_SHIFT =
uint256_t(1) << DEFAULT_NON_NATIVE_FIELD_LIMB_BITS;
1582 FF lo_0 =
a[0] *
b[0] + (
a[1] *
b[0] +
a[0] *
b[1]) * LIMB_SHIFT;
1584 FF hi_0 =
a[2] *
b[0] +
a[0] *
b[2] + (
a[0] *
b[3] +
a[3] *
b[0]) * LIMB_SHIFT;
1585 FF hi_1 = hi_0 +
a[1] *
b[1] + (
a[1] *
b[2] +
a[2] *
b[1]) * LIMB_SHIFT;
1587 const uint32_t lo_0_idx = this->add_variable(lo_0);
1588 const uint32_t hi_0_idx = this->add_variable(hi_0);
1589 const uint32_t hi_1_idx = this->add_variable(hi_1);
1600 cached_partial_non_native_field_multiplications.emplace_back(cache_entry);
1601 return std::array<uint32_t, 2>{ lo_0_idx, hi_1_idx };
1609template <
typename ExecutionTrace>
1619 const auto& x_mulconst0 =
std::get<0>(limb0).second;
1620 const auto& x_mulconst1 =
std::get<0>(limb1).second;
1621 const auto& x_mulconst2 =
std::get<0>(limb2).second;
1622 const auto& x_mulconst3 =
std::get<0>(limb3).second;
1630 const auto& y_mulconst0 =
std::get<1>(limb0).second;
1631 const auto& y_mulconst1 =
std::get<1>(limb1).second;
1632 const auto& y_mulconst2 =
std::get<1>(limb2).second;
1633 const auto& y_mulconst3 =
std::get<1>(limb3).second;
1643 const auto z_0value = this->get_variable(x_0) * x_mulconst0 + this->get_variable(y_0) * y_mulconst0 + addconst0;
1644 const auto z_1value = this->get_variable(x_1) * x_mulconst1 + this->get_variable(y_1) * y_mulconst1 + addconst1;
1645 const auto z_2value = this->get_variable(x_2) * x_mulconst2 + this->get_variable(y_2) * y_mulconst2 + addconst2;
1646 const auto z_3value = this->get_variable(x_3) * x_mulconst3 + this->get_variable(y_3) * y_mulconst3 + addconst3;
1647 const auto z_pvalue = this->get_variable(x_p) + this->get_variable(y_p) + addconstp;
1649 const auto z_0 = this->add_variable(z_0value);
1650 const auto z_1 = this->add_variable(z_1value);
1651 const auto z_2 = this->add_variable(z_2value);
1652 const auto z_3 = this->add_variable(z_3value);
1653 const auto z_p = this->add_variable(z_pvalue);
1677 auto& block = blocks.arithmetic;
1678 block.populate_wires(y_p, x_0, y_0, x_p);
1679 block.populate_wires(z_p, x_1, y_1, z_0);
1680 block.populate_wires(x_2, y_2, z_2, z_1);
1681 block.populate_wires(x_3, y_3, z_3, this->zero_idx());
1683 block.q_m().emplace_back(addconstp);
1684 block.q_1().emplace_back(0);
1685 block.q_2().emplace_back(-x_mulconst0 *
1687 block.q_3().emplace_back(-y_mulconst0 * 2);
1688 block.q_4().emplace_back(0);
1689 block.q_c().emplace_back(-addconst0 * 2);
1690 block.set_gate_selector(3);
1692 block.q_m().emplace_back(0);
1693 block.q_1().emplace_back(0);
1694 block.q_2().emplace_back(-x_mulconst1);
1695 block.q_3().emplace_back(-y_mulconst1);
1696 block.q_4().emplace_back(0);
1697 block.q_c().emplace_back(-addconst1);
1698 block.set_gate_selector(2);
1700 block.q_m().emplace_back(0);
1701 block.q_1().emplace_back(-x_mulconst2);
1702 block.q_2().emplace_back(-y_mulconst2);
1703 block.q_3().emplace_back(1);
1704 block.q_4().emplace_back(0);
1705 block.q_c().emplace_back(-addconst2);
1706 block.set_gate_selector(1);
1708 block.q_m().emplace_back(0);
1709 block.q_1().emplace_back(-x_mulconst3);
1710 block.q_2().emplace_back(-y_mulconst3);
1711 block.q_3().emplace_back(1);
1712 block.q_4().emplace_back(0);
1713 block.q_c().emplace_back(-addconst3);
1714 block.set_gate_selector(1);
1716 check_selector_length_consistency();
1718 this->num_gates += 4;
1720 z_0, z_1, z_2, z_3, z_p,
1724template <
typename ExecutionTrace>
1734 const auto& x_mulconst0 =
std::get<0>(limb0).second;
1735 const auto& x_mulconst1 =
std::get<0>(limb1).second;
1736 const auto& x_mulconst2 =
std::get<0>(limb2).second;
1737 const auto& x_mulconst3 =
std::get<0>(limb3).second;
1745 const auto& y_mulconst0 =
std::get<1>(limb0).second;
1746 const auto& y_mulconst1 =
std::get<1>(limb1).second;
1747 const auto& y_mulconst2 =
std::get<1>(limb2).second;
1748 const auto& y_mulconst3 =
std::get<1>(limb3).second;
1758 const auto z_0value = this->get_variable(x_0) * x_mulconst0 - this->get_variable(y_0) * y_mulconst0 + addconst0;
1759 const auto z_1value = this->get_variable(x_1) * x_mulconst1 - this->get_variable(y_1) * y_mulconst1 + addconst1;
1760 const auto z_2value = this->get_variable(x_2) * x_mulconst2 - this->get_variable(y_2) * y_mulconst2 + addconst2;
1761 const auto z_3value = this->get_variable(x_3) * x_mulconst3 - this->get_variable(y_3) * y_mulconst3 + addconst3;
1762 const auto z_pvalue = this->get_variable(x_p) - this->get_variable(y_p) + addconstp;
1764 const auto z_0 = this->add_variable(z_0value);
1765 const auto z_1 = this->add_variable(z_1value);
1766 const auto z_2 = this->add_variable(z_2value);
1767 const auto z_3 = this->add_variable(z_3value);
1768 const auto z_p = this->add_variable(z_pvalue);
1789 auto& block = blocks.arithmetic;
1790 block.populate_wires(y_p, x_0, y_0, z_p);
1791 block.populate_wires(x_p, x_1, y_1, z_0);
1792 block.populate_wires(x_2, y_2, z_2, z_1);
1793 block.populate_wires(x_3, y_3, z_3, this->zero_idx());
1795 block.q_m().emplace_back(-addconstp);
1796 block.q_1().emplace_back(0);
1797 block.q_2().emplace_back(-x_mulconst0 * 2);
1798 block.q_3().emplace_back(y_mulconst0 * 2);
1799 block.q_4().emplace_back(0);
1800 block.q_c().emplace_back(-addconst0 * 2);
1801 block.set_gate_selector(3);
1803 block.q_m().emplace_back(0);
1804 block.q_1().emplace_back(0);
1805 block.q_2().emplace_back(-x_mulconst1);
1806 block.q_3().emplace_back(y_mulconst1);
1807 block.q_4().emplace_back(0);
1808 block.q_c().emplace_back(-addconst1);
1809 block.set_gate_selector(2);
1811 block.q_m().emplace_back(0);
1812 block.q_1().emplace_back(-x_mulconst2);
1813 block.q_2().emplace_back(y_mulconst2);
1814 block.q_3().emplace_back(1);
1815 block.q_4().emplace_back(0);
1816 block.q_c().emplace_back(-addconst2);
1817 block.set_gate_selector(1);
1819 block.q_m().emplace_back(0);
1820 block.q_1().emplace_back(-x_mulconst3);
1821 block.q_2().emplace_back(y_mulconst3);
1822 block.q_3().emplace_back(1);
1823 block.q_4().emplace_back(0);
1824 block.q_c().emplace_back(-addconst3);
1825 block.set_gate_selector(1);
1827 check_selector_length_consistency();
1829 this->num_gates += 4;
1831 z_0, z_1, z_2, z_3, z_p,
1845template <
typename ExecutionTrace>
1848 return this->rom_ram_logic.create_ROM_array(array_size);
1861template <
typename ExecutionTrace>
1864 return this->rom_ram_logic.create_RAM_array(array_size);
1874template <
typename ExecutionTrace>
1876 const size_t index_value,
1877 const uint32_t value_witness)
1879 this->rom_ram_logic.init_RAM_element(
this, ram_id, index_value, value_witness);
1882template <
typename ExecutionTrace>
1885 return this->rom_ram_logic.read_RAM_array(
this, ram_id, index_witness);
1888template <
typename ExecutionTrace>
1890 const uint32_t index_witness,
1891 const uint32_t value_witness)
1893 this->rom_ram_logic.write_RAM_array(
this, ram_id, index_witness, value_witness);
1910template <
typename ExecutionTrace>
1912 const size_t index_value,
1913 const uint32_t value_witness)
1915 this->rom_ram_logic.set_ROM_element(
this, rom_id, index_value, value_witness);
1925template <
typename ExecutionTrace>
1927 const size_t index_value,
1928 const std::array<uint32_t, 2>& value_witnesses)
1930 this->rom_ram_logic.set_ROM_element_pair(
this, rom_id, index_value, value_witnesses);
1940template <
typename ExecutionTrace>
1943 return this->rom_ram_logic.read_ROM_array(
this, rom_id, index_witness);
1953template <
typename ExecutionTrace>
1955 const uint32_t index_witness)
1957 return this->rom_ram_logic.read_ROM_array_pair(
this, rom_id, index_witness);
1963template <
typename FF>
1966 auto& block = this->blocks.poseidon2_external;
1967 block.populate_wires(in.
a, in.
b, in.
c, in.
d);
1968 block.q_m().emplace_back(0);
1972 block.q_c().emplace_back(0);
1974 block.set_gate_selector(1);
1975 this->check_selector_length_consistency();
1982template <
typename FF>
1985 auto& block = this->blocks.poseidon2_internal;
1986 block.populate_wires(in.
a, in.
b, in.
c, in.
d);
1987 block.q_m().emplace_back(0);
1989 block.q_2().emplace_back(0);
1990 block.q_3().emplace_back(0);
1991 block.q_c().emplace_back(0);
1992 block.q_4().emplace_back(0);
1993 block.set_gate_selector(1);
1994 this->check_selector_length_consistency();
2008 auto first_zero_idx = this->get_first_variable_in_class(this->zero_idx());
2009 if (!this->variable_names.contains(first_zero_idx)) {
2010 this->set_variable_name(this->zero_idx(),
"zero");
2012 this->variable_names[first_zero_idx] =
"zero";
2018 FF::Params::modulus_0, FF::Params::modulus_1, FF::Params::modulus_2, FF::Params::modulus_3
2020 std::stringstream
buf;
2022 << modulus[1] <<
std::setw(16) << modulus[0];
2026 for (uint32_t i = 0; i < this->num_public_inputs(); i++) {
2027 cir.
public_inps.push_back(this->real_variable_index[this->public_inputs()[i]]);
2030 for (
auto& tup : base::variable_names) {
2031 cir.
vars_of_interest.insert({ this->real_variable_index[tup.first], tup.second });
2034 for (
const auto& var : this->get_variables()) {
2047 for (
auto& block : blocks.get()) {
2050 for (
size_t idx = 0; idx < block.size(); ++idx) {
2051 std::vector<FF> tmp_sel = { block.q_m()[idx],
2057 block.q_arith()[idx],
2058 block.q_delta_range()[idx],
2059 block.q_elliptic()[idx],
2060 block.q_memory()[idx],
2062 block.q_lookup_type()[idx],
2065 std::vector<uint32_t> tmp_w = {
2066 this->real_variable_index[block.w_l()[idx]],
2067 this->real_variable_index[block.w_r()[idx]],
2068 this->real_variable_index[block.w_o()[idx]],
2069 this->real_variable_index[block.w_4()[idx]],
2072 if (idx < block.size() - 1) {
2073 tmp_w.push_back(block.w_l()[idx + 1]);
2074 tmp_w.push_back(block.w_r()[idx + 1]);
2075 tmp_w.push_back(block.w_o()[idx + 1]);
2076 tmp_w.push_back(block.w_4()[idx + 1]);
2084 block_selectors.push_back(tmp_sel);
2085 block_wires.push_back(tmp_w);
2087 cir.
selectors.push_back(block_selectors);
2088 cir.
wires.push_back(block_wires);
2093 for (
const auto& table : this->lookup_tables) {
2094 const FF table_index(table.table_index);
2095 info(
"Table no: ", table.table_index);
2097 for (
size_t i = 0; i < table.size(); ++i) {
2098 tmp_table.push_back({ table.column_1[i], table.column_2[i], table.column_3[i] });
2105 for (
const auto& list : range_lists) {
2106 cir.
range_tags[list.second.range_tag] = list.first;
2109 for (
auto& rom_table : this->rom_ram_logic.rom_arrays) {
2110 std::sort(rom_table.records.begin(), rom_table.records.end());
2113 table.reserve(rom_table.records.size());
2114 for (
const auto& rom_entry : rom_table.records) {
2116 this->real_variable_index[rom_entry.index_witness],
2117 this->real_variable_index[rom_entry.value_column1_witness],
2118 this->real_variable_index[rom_entry.value_column2_witness],
2125 for (
auto& ram_table : this->rom_ram_logic.ram_arrays) {
2126 std::sort(ram_table.records.begin(), ram_table.records.end());
2129 table.reserve(ram_table.records.size());
2130 for (
const auto& ram_entry : ram_table.records) {
2131 table.push_back({ this->real_variable_index[ram_entry.index_witness],
2132 this->real_variable_index[ram_entry.value_witness],
2133 this->real_variable_index[ram_entry.timestamp_witness],
2134 ram_entry.access_type });
2143 msgpack::pack(
buffer, cir);
#define BB_ASSERT_GT(left, right,...)
#define BB_ASSERT_EQ(actual, expected,...)
#define BB_ASSERT_LTE(left, right,...)
#define BB_ASSERT_LT(left, right,...)
#define ASSERT(expression,...)
#define BB_BENCH_NAME(name)
void create_add_gate(const add_triple_< FF > &in) override
Create an addition gate, where in.a * in.a_scaling + in.b * in.b_scaling + in.c * in....
void fix_witness(const uint32_t witness_index, const FF &witness_value)
Add a gate equating a particular witness to a constant, fixing its value.
void init_RAM_element(const size_t ram_id, const size_t index_value, const uint32_t value_witness)
Initialize a RAM cell to equal value_witness
void create_ecc_dbl_gate(const ecc_dbl_gate_< FF > &in)
Create an elliptic curve doubling gate.
void add_gates_to_ensure_all_polys_are_non_zero()
Ensure all polynomials have at least one non-zero coefficient to avoid commiting to the zero-polynomi...
void process_range_list(RangeList &list)
void create_poseidon2_internal_gate(const poseidon2_internal_gate_< FF > &in)
Poseidon2 internal round gate, activates the q_poseidon2_internal selector and relation.
size_t create_RAM_array(const size_t array_size)
Create a new updatable memory region.
void create_big_mul_gate(const mul_quad_< FF > &in)
Create a basic multiplication gate q_m * a * b + q_1 * a + q_2 * b + q_3 * c + q_4 * d + q_c = 0 (q_a...
void create_big_mul_add_gate(const mul_quad_< FF > &in, const bool use_next_gate_w_4=false)
Create a big multiplication-addition gate, where in.a * in.b * in.mul_scaling + in....
void process_range_lists()
std::vector< uint32_t > decompose_into_default_range(const uint32_t variable_index, const uint64_t num_bits, const uint64_t target_range_bitnum=DEFAULT_PLOOKUP_RANGE_BITNUM, std::string const &msg="decompose_into_default_range")
msgpack::sbuffer export_circuit() override
void create_sort_constraint_with_edges(const std::vector< uint32_t > &variable_index, const FF &, const FF &)
std::tuple< scaled_witness, scaled_witness, FF > add_simple
uint32_t read_RAM_array(const size_t ram_id, const uint32_t index_witness)
void create_unconstrained_gates(const std::vector< uint32_t > &variable_index)
void create_big_add_gate(const add_quad_< FF > &in, const bool use_next_gate_w_4=false)
Create a big addition gate, where in.a * in.a_scaling + in.b * in.b_scaling + in.c * in....
typename ExecutionTrace::FF FF
std::array< uint32_t, 5 > evaluate_non_native_field_addition(add_simple limb0, add_simple limb1, add_simple limb2, add_simple limb3, std::tuple< uint32_t, uint32_t, FF > limbp)
size_t create_ROM_array(const size_t array_size)
Create a new read-only memory region.
plookup::ReadData< uint32_t > create_gates_from_plookup_accumulators(const plookup::MultiTableId &id, const plookup::ReadData< FF > &read_values, const uint32_t key_a_index, std::optional< uint32_t > key_b_index=std::nullopt)
Perform a series of lookups, one for each 'row' in read_values.
std::array< uint32_t, 2 > decompose_non_native_field_double_width_limb(const uint32_t limb_idx, const size_t num_limb_bits=(2 *DEFAULT_NON_NATIVE_FIELD_LIMB_BITS))
Decompose a single witness into two, where the lowest is DEFAULT_NON_NATIVE_FIELD_LIMB_BITS (68) rang...
plookup::BasicTable & get_table(const plookup::BasicTableId id)
Get the basic table with provided ID from the set of tables for the present circuit; create it if it ...
void apply_nnf_selectors(const NNF_SELECTORS type)
Enable the nnf gate of particular type.
void create_bool_gate(const uint32_t a) override
Generate an arithmetic gate equivalent to x^2 - x = 0, which forces x to be 0 or 1.
void create_ecc_add_gate(const ecc_add_gate_< FF > &in)
Create an elliptic curve addition gate.
void finalize_circuit(const bool ensure_nonzero)
void create_sort_constraint(const std::vector< uint32_t > &variable_index)
void create_poly_gate(const poly_triple_< FF > &in) override
A plonk gate with disabled (set to zero) fourth wire. q_m * a * b + q_1 * a + q_2 * b + q_3.
void create_poseidon2_external_gate(const poseidon2_external_gate_< FF > &in)
Poseidon2 external round gate, activates the q_poseidon2_external selector and relation.
std::array< uint32_t, 2 > evaluate_non_native_field_multiplication(const non_native_multiplication_witnesses< FF > &input)
Queue up non-native field multiplication data.
void populate_public_inputs_block()
Copy the public input idx data into the public inputs trace block.
uint32_t read_ROM_array(const size_t rom_id, const uint32_t index_witness)
Read a single element from ROM.
RangeList create_range_list(const uint64_t target_range)
uint32_t put_constant_variable(const FF &variable)
void set_ROM_element(const size_t rom_id, const size_t index_value, const uint32_t value_witness)
Initialize a rom cell to equal value_witness
void create_mul_gate(const mul_triple_< FF > &in) override
Create a multiplication gate with q_m * a * b + q_3 * c + q_const = 0.
void write_RAM_array(const size_t ram_id, const uint32_t index_witness, const uint32_t value_witness)
void set_ROM_element_pair(const size_t rom_id, const size_t index_value, const std::array< uint32_t, 2 > &value_witnesses)
Initialize a ROM array element with a pair of witness values.
std::array< uint32_t, 2 > read_ROM_array_pair(const size_t rom_id, const uint32_t index_witness)
Read a pair of elements from ROM.
void range_constrain_two_limbs(const uint32_t lo_idx, const uint32_t hi_idx, const size_t lo_limb_bits=DEFAULT_NON_NATIVE_FIELD_LIMB_BITS, const size_t hi_limb_bits=DEFAULT_NON_NATIVE_FIELD_LIMB_BITS, std::string const &msg="range_constrain_two_limbs")
std::array< uint32_t, 2 > queue_partial_non_native_field_multiplication(const non_native_partial_multiplication_witnesses< FF > &input)
std::array< uint32_t, 5 > evaluate_non_native_field_subtraction(add_simple limb0, add_simple limb1, add_simple limb2, add_simple limb3, std::tuple< uint32_t, uint32_t, FF > limbp)
void apply_memory_selectors(const MEMORY_SELECTORS type)
Enable the memory gate of particular type.
void process_non_native_field_multiplications()
Called in compute_prover_instance when finalizing circuit. Iterates over the cached_non_native_field_...
void create_new_range_constraint(const uint32_t variable_index, const uint64_t target_range, std::string const msg="create_new_range_constraint")
Constrain a variable to a range.
static constexpr Fq curve_b
constexpr uint64_t get_msb() const
Container type for lookup table reads.
std::vector< BasicTable::LookupEntry > lookup_entries
uint8_t buffer[RANDOM_BUFFER_SIZE]
ReadData< bb::fr > get_lookup_accumulators(const MultiTableId id, const fr &key_a, const fr &key_b, const bool is_2_to_1_lookup)
Given a table ID and the key(s) for a key-value lookup, return the lookup accumulators.
BasicTable create_basic_table(const BasicTableId id, const size_t index)
const MultiTable & get_multitable(const MultiTableId id)
Return the multitable with the provided ID; construct all MultiTables if not constructed already.
Entry point for Barretenberg command-line interface.
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Serialized state of a circuit.
std::vector< std::vector< std::vector< FF > > > selectors
std::vector< uint32_t > real_variable_index
std::unordered_map< uint32_t, uint64_t > range_tags
std::unordered_map< uint32_t, std::string > vars_of_interest
std::vector< std::vector< uint32_t > > ram_states
std::vector< std::vector< std::array< uint32_t, 2 > > > rom_states
std::vector< std::vector< std::vector< uint32_t > > > ram_records
std::vector< std::vector< std::vector< uint32_t > > > rom_records
std::vector< std::vector< std::vector< FF > > > lookup_tables
std::vector< uint32_t > real_variable_tags
std::vector< uint32_t > public_inps
std::vector< FF > variables
std::vector< std::vector< std::vector< uint32_t > > > wires
std::vector< uint32_t > variable_indices
Used to store instructions to create partial_non_native_field_multiplication gates.
std::array< uint32_t, 4 > a
static constexpr std::array< std::array< FF, t >, rounds_f+rounds_p > round_constants
static constexpr field one()
static constexpr uint256_t modulus
BB_INLINE constexpr field to_montgomery_form() const noexcept
std::array< uint32_t, 4 > a
std::array< uint32_t, 4 > q
std::array< uint32_t, 4 > b
std::array< uint32_t, 4 > r
std::array< FF, 4 > neg_modulus
std::array< uint32_t, 4 > b
std::array< uint32_t, 4 > a
A basic table from which we can perform lookups (for example, an xor table)