10#include "barretenberg/common/ref_vector.hpp"
11#include "barretenberg/ecc/curves/bn254/fr.hpp"
13#include "barretenberg/plonk/proof_system/proving_key/proving_key.hpp"
14#include "barretenberg/polynomials/iterate_over_domain.hpp"
15#include "barretenberg/polynomials/polynomial.hpp"
20#include <initializer_list>
27namespace proof_system {
48 uint32_t row_index = 0;
49 uint8_t column_index = 0;
50 bool is_public_input =
false;
55 using Mapping = std::array<std::vector<permutation_subgroup_element>, NUM_WIRES>;
60using CyclicPermutation = std::vector<cycle_node>;
73template <
typename Flavor>
74std::vector<CyclicPermutation> compute_wire_copy_cycles(
const typename Flavor::CircuitBuilder& circuit_constructor)
77 const size_t num_gates = circuit_constructor.num_gates;
78 std::span<const uint32_t> public_inputs = circuit_constructor.public_inputs;
79 const size_t num_public_inputs = public_inputs.size();
82 const size_t number_of_cycles = circuit_constructor.variables.size();
83 std::vector<CyclicPermutation> copy_cycles(number_of_cycles);
84 copy_cycles.reserve(num_gates * 3);
87 std::span<const uint32_t> real_variable_index = circuit_constructor.real_variable_index;
91 if constexpr (Flavor::has_zero_row) {
92 for (
size_t wire_idx = 0; wire_idx < Flavor::NUM_WIRES; ++wire_idx) {
93 const auto wire_index =
static_cast<uint32_t
>(wire_idx);
94 const uint32_t gate_index = 0;
95 const uint32_t zero_idx = circuit_constructor.zero_idx;
96 copy_cycles[zero_idx].emplace_back(
cycle_node{ wire_index, gate_index });
101 const size_t num_zero_rows = Flavor::has_zero_row ? 1 : 0;
102 size_t pub_inputs_offset = num_zero_rows;
103 size_t gates_offset = num_public_inputs + num_zero_rows;
106 if constexpr (IsGoblinFlavor<Flavor>) {
108 const size_t op_gates_offset = num_zero_rows;
109 const size_t num_ecc_op_gates = circuit_constructor.num_ecc_op_gates;
110 pub_inputs_offset += num_ecc_op_gates;
111 gates_offset += num_ecc_op_gates;
113 const auto& op_wires = circuit_constructor.ecc_op_wires;
115 for (
size_t i = 0; i < num_ecc_op_gates; ++i) {
116 for (
size_t op_wire_idx = 0; op_wire_idx < Flavor::NUM_WIRES; ++op_wire_idx) {
117 const uint32_t var_index = circuit_constructor.real_variable_index[op_wires[op_wire_idx][i]];
118 const auto wire_index =
static_cast<uint32_t
>(op_wire_idx);
119 const auto gate_idx =
static_cast<uint32_t
>(i + op_gates_offset);
120 copy_cycles[var_index].emplace_back(cycle_node{ wire_index, gate_idx });
137 for (
size_t i = 0; i < num_public_inputs; ++i) {
138 const uint32_t public_input_index = real_variable_index[public_inputs[i]];
139 const auto gate_index =
static_cast<uint32_t
>(i + pub_inputs_offset);
141 copy_cycles[public_input_index].emplace_back(cycle_node{ 0, gate_index });
142 copy_cycles[public_input_index].emplace_back(cycle_node{ 1, gate_index });
146 for (
size_t i = 0; i < num_gates; ++i) {
148 for (
auto& wire : circuit_constructor.wires) {
154 const uint32_t var_index = circuit_constructor.real_variable_index[wire[i]];
155 const auto wire_index =
static_cast<uint32_t
>(wire_idx);
156 const auto gate_idx =
static_cast<uint32_t
>(i + gates_offset);
157 copy_cycles[var_index].emplace_back(cycle_node{ wire_index, gate_idx });
177template <
typename Flavor,
bool generalized>
178PermutationMapping<Flavor::NUM_WIRES> compute_permutation_mapping(
179 const typename Flavor::CircuitBuilder& circuit_constructor,
typename Flavor::ProvingKey* proving_key)
182 auto wire_copy_cycles = compute_wire_copy_cycles<Flavor>(circuit_constructor);
184 PermutationMapping<Flavor::NUM_WIRES> mapping;
188 for (
size_t i = 0; i < Flavor::NUM_WIRES; ++i) {
189 mapping.sigmas[i].reserve(proving_key->circuit_size);
190 if constexpr (generalized) {
191 mapping.ids[i].reserve(proving_key->circuit_size);
194 for (
size_t j = 0; j < proving_key->circuit_size; ++j) {
195 mapping.sigmas[i].emplace_back(permutation_subgroup_element{ .row_index =
static_cast<uint32_t
>(j),
196 .column_index =
static_cast<uint8_t
>(i),
197 .is_public_input =
false,
199 if constexpr (generalized) {
200 mapping.ids[i].emplace_back(permutation_subgroup_element{ .row_index =
static_cast<uint32_t
>(j),
201 .column_index =
static_cast<uint8_t
>(i),
202 .is_public_input =
false,
209 std::span<const uint32_t> real_variable_tags = circuit_constructor.real_variable_tags;
212 size_t cycle_index = 0;
213 for (
auto& copy_cycle : wire_copy_cycles) {
214 for (
size_t node_idx = 0; node_idx < copy_cycle.size(); ++node_idx) {
216 cycle_node current_cycle_node = copy_cycle[node_idx];
218 size_t next_cycle_node_index = (node_idx == copy_cycle.size() - 1 ? 0 : node_idx + 1);
219 cycle_node next_cycle_node = copy_cycle[next_cycle_node_index];
220 const auto current_row = current_cycle_node.gate_index;
221 const auto next_row = next_cycle_node.gate_index;
223 const auto current_column = current_cycle_node.wire_index;
224 const auto next_column =
static_cast<uint8_t
>(next_cycle_node.wire_index);
226 mapping.sigmas[current_column][current_row] = {
227 .row_index = next_row, .column_index = next_column, .is_public_input =
false, .is_tag =
false
230 if constexpr (generalized) {
231 bool first_node = (node_idx == 0);
232 bool last_node = (next_cycle_node_index == 0);
235 mapping.ids[current_column][current_row].is_tag =
true;
236 mapping.ids[current_column][current_row].row_index = (real_variable_tags[cycle_index]);
239 mapping.sigmas[current_column][current_row].is_tag =
true;
242 mapping.sigmas[current_column][current_row].row_index =
243 circuit_constructor.tau.at(real_variable_tags[cycle_index]);
251 const auto num_public_inputs =
static_cast<uint32_t
>(circuit_constructor.public_inputs.size());
254 const size_t num_zero_rows = Flavor::has_zero_row ? 1 : 0;
255 size_t pub_input_offset = num_zero_rows;
257 if constexpr (IsGoblinFlavor<Flavor>) {
258 pub_input_offset += circuit_constructor.num_ecc_op_gates;
260 for (
size_t i = 0; i < num_public_inputs; ++i) {
261 size_t idx = i + pub_input_offset;
262 mapping.sigmas[0][idx].row_index =
static_cast<uint32_t
>(idx);
263 mapping.sigmas[0][idx].column_index = 0;
264 mapping.sigmas[0][idx].is_public_input =
true;
265 if (mapping.sigmas[0][idx].is_tag) {
266 std::cerr <<
"MAPPING IS BOTH A TAG AND A PUBLIC INPUT" << std::endl;
282template <
typename Flavor>
283void compute_honk_style_permutation_lagrange_polynomials_from_mapping(
285 std::array<std::vector<permutation_subgroup_element>, Flavor::NUM_WIRES>& permutation_mappings,
288 using FF =
typename Flavor::FF;
289 const size_t num_gates = proving_key->circuit_size;
291 size_t wire_index = 0;
292 for (
auto& current_permutation_poly : permutation_polynomials) {
293 ITERATE_OVER_DOMAIN_START(proving_key->evaluation_domain);
294 const auto& current_mapping = permutation_mappings[wire_index][i];
295 if (current_mapping.is_public_input) {
304 current_permutation_poly[i] = -
FF(current_mapping.row_index + 1 + num_gates * current_mapping.column_index);
305 }
else if (current_mapping.is_tag) {
307 current_permutation_poly[i] = num_gates * Flavor::NUM_WIRES + current_mapping.row_index;
311 current_permutation_poly[i] =
FF(current_mapping.row_index + num_gates * current_mapping.column_index);
313 ITERATE_OVER_DOMAIN_END;
328 const std::vector<permutation_subgroup_element>& permutation,
331 if (output.size() < permutation.size()) {
332 throw_or_abort(
"Permutation polynomial size is insufficient to store permutations.");
340 ASSERT(small_domain.log2_size > 1);
341 const barretenberg::fr* roots = small_domain.get_round_roots()[small_domain.log2_size - 2];
342 const size_t root_size = small_domain.size >> 1UL;
343 const size_t log2_root_size =
static_cast<size_t>(numeric::get_msb(root_size));
345 ITERATE_OVER_DOMAIN_START(small_domain);
353 size_t raw_idx = permutation[i].row_index;
357 const bool negative_idx = raw_idx >= root_size;
363 const size_t idx = raw_idx - (
static_cast<size_t>(negative_idx) << log2_root_size);
369 output[i] = roots[idx].conditionally_subtract_from_double_modulus(
static_cast<uint64_t
>(negative_idx));
376 if (permutation[i].is_public_input) {
380 output[i] *= barretenberg::fr::external_coset_generator();
381 }
else if (permutation[i].is_tag) {
382 output[i] *= barretenberg::fr::tag_coset_generator();
385 const uint32_t column_index = permutation[i].column_index;
386 if (column_index > 0) {
387 output[i] *= barretenberg::fr::coset_generator(column_index - 1);
391 ITERATE_OVER_DOMAIN_END;
402template <
size_t program_w
idth>
405 std::array<std::vector<permutation_subgroup_element>, program_width>& mappings,
408 for (
size_t i = 0; i < program_width; i++) {
409 std::string index = std::to_string(i + 1);
412 key->polynomial_store.put(label +
"_" + index +
"_lagrange", polynomial_lagrange.
share());
425template <
size_t program_w
idth>
428 for (
size_t i = 0; i < program_width; ++i) {
429 std::string index = std::to_string(i + 1);
430 std::string prefix = label +
"_" + index;
433 auto sigma_polynomial_lagrange = key->polynomial_store.get(prefix +
"_lagrange");
436 barretenberg::polynomial_arithmetic::ifft(
437 (
barretenberg::fr*)&sigma_polynomial_lagrange[0], &sigma_polynomial[0], key->small_domain);
441 sigma_fft.coset_fft(key->large_domain);
443 key->polynomial_store.put(prefix, sigma_polynomial.
share());
444 key->polynomial_store.put(prefix +
"_fft", sigma_fft.
share());
456template <
typename Flavor>
461 auto mapping = compute_permutation_mapping<
Flavor,
false>(circuit_constructor, key);
465 compute_monomial_and_coset_fft_polynomials_from_lagrange<Flavor::NUM_WIRES>(
"sigma", key);
475 const size_t n = proving_key->circuit_size;
478 lagrange_polynomial_0[0] = 1;
479 proving_key->lagrange_first = lagrange_polynomial_0.
share();
481 lagrange_polynomial_n_min_1[n - 1] = 1;
482 proving_key->lagrange_last = lagrange_polynomial_n_min_1.
share();
494template <
typename Flavor>
498 auto mapping = compute_permutation_mapping<
Flavor,
true>(circuit_constructor, key);
504 compute_monomial_and_coset_fft_polynomials_from_lagrange<Flavor::NUM_WIRES>(
"sigma", key);
505 compute_monomial_and_coset_fft_polynomials_from_lagrange<Flavor::NUM_WIRES>(
"id", key);
517template <
typename Flavor>
521 auto mapping = compute_permutation_mapping<Flavor, true>(circuit_constructor, proving_key);
524 compute_honk_style_permutation_lagrange_polynomials_from_mapping<Flavor>(
525 proving_key->get_sigma_polynomials(), mapping.sigmas, proving_key);
526 compute_honk_style_permutation_lagrange_polynomials_from_mapping<Flavor>(
527 proving_key->get_id_polynomials(), mapping.ids, proving_key);
A template class for a reference vector. Behaves as if std::vector<T&> was possible.
Definition: ref_vector.hpp:20
Polynomial share() const
Definition: polynomial.cpp:141
Definition: AvmMini_flavor.hpp:231
Definition: AvmMini_flavor.hpp:21
Base class templates for structures that contain data parameterized by the fundamental polynomials of...
void compute_monomial_and_coset_fft_polynomials_from_lagrange(std::string label, plonk::proving_key *key)
Compute the monomial and coset-fft version of each lagrange polynomial of the given label.
Definition: permutation_lib.hpp:426
void compute_standard_plonk_lagrange_polynomial(barretenberg::polynomial &output, const std::vector< permutation_subgroup_element > &permutation, const barretenberg::evaluation_domain &small_domain)
Definition: permutation_lib.hpp:327
void compute_honk_generalized_sigma_permutations(const typename Flavor::CircuitBuilder &circuit_constructor, typename Flavor::ProvingKey *proving_key)
Compute generalized permutation sigmas and ids for ultra plonk.
Definition: permutation_lib.hpp:518
void compute_standard_plonk_sigma_permutations(const typename Flavor::CircuitBuilder &circuit_constructor, typename Flavor::ProvingKey *key)
Compute sigma permutation polynomials for standard plonk and put them in the polynomial cache.
Definition: permutation_lib.hpp:457
void compute_plonk_generalized_sigma_permutations(const typename Flavor::CircuitBuilder &circuit_constructor, typename Flavor::ProvingKey *key)
Compute generalized permutation sigmas and ids for ultra plonk.
Definition: permutation_lib.hpp:495
void compute_first_and_last_lagrange_polynomials(const auto &proving_key)
Compute Lagrange Polynomials L_0 and L_{n-1} and put them in the polynomial cache.
Definition: permutation_lib.hpp:473
void compute_plonk_permutation_lagrange_polynomials_from_mapping(std::string label, std::array< std::vector< permutation_subgroup_element >, program_width > &mappings, plonk::proving_key *key)
Compute lagrange polynomial from mapping (used for sigmas or ids)
Definition: permutation_lib.hpp:403
Definition: permutation_lib.hpp:54
cycle_node represents the index of a value of the circuit. It will belong to a CyclicPermutation,...
Definition: permutation_lib.hpp:36
Permutations subgroup element structure is used to hold data necessary to construct permutation polyn...
Definition: permutation_lib.hpp:47
Definition: proving_key.hpp:38