Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
permutation_lib.hpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Complete, auditors: [Raju], commit: 21a7e3670e6 }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
14#pragma once
15
22
23#include <cstddef>
24#include <cstdint>
25#include <vector>
26
27namespace bb {
28
35struct cycle_node {
36 uint32_t wire_idx;
37 uint32_t gate_idx;
38};
39
41
69template <typename Flavor>
71 typename Flavor::ProverPolynomials& polynomials,
72 const std::vector<CyclicPermutation>& copy_cycles)
73{
74 using FF = typename Flavor::FF;
75 constexpr size_t NUM_WIRES = Flavor::NUM_WIRES;
76 constexpr size_t SEPARATOR = PERMUTATION_ARGUMENT_VALUE_SEPARATOR;
77
78 auto sigmas = polynomials.get_sigmas();
79 auto ids = polynomials.get_ids();
80
81 // SEPARATOR ensures that the identity values for `id_i`/`sigma_i` and `id_j`/`sigma_j` (i != j) are disjoint, and
82 // that tag values (at `SEPARATOR * NUM_WIRES + ...`) cannot collide with identity values.
83 BB_ASSERT_LT(sigmas[0].size(), SEPARATOR);
84
85 // Phase 1: identity init across the active range of every sigma/id polynomial in parallel.
86 {
87 BB_BENCH_NAME("permutation_polys_identity_init");
88 const size_t domain_size = sigmas[0].size();
89 const MultithreadData thread_data = calculate_thread_data(domain_size);
90 for (size_t wire_idx = 0; wire_idx < NUM_WIRES; ++wire_idx) {
91 auto& sigma = sigmas[wire_idx];
92 auto& id = ids[wire_idx];
93 const size_t base = SEPARATOR * wire_idx;
94 parallel_for(thread_data.num_threads, [&](size_t j) {
95 BB_BENCH_TRACY_NAME("Permutation::identity_init");
96 const size_t start = thread_data.start[j];
97 const size_t end = thread_data.end[j];
98 for (size_t i = start; i < end; ++i) {
99 const size_t poly_idx = i + sigma.start_index();
100 const FF v = FF(poly_idx + base);
101 sigma.at(poly_idx) = v;
102 id.at(poly_idx) = v;
103 }
104 });
105 }
106 }
107
108 // Phase 2: apply cycle linkages and tag values directly to sigma/id polys.
109 {
110 BB_BENCH_NAME("permutation_polys_cycle_linkages");
111
112 // Cycles are disjoint by construction of the generalized permutation argument: every
113 // (gate_idx, wire_idx) position belongs to exactly one variable, hence to exactly one cycle.
114 // Per-(col, row) writes from different cycles never alias, so parallelising across cycle_idx is
115 // safe without per-thread staging or merge.
116 std::span<const uint32_t> real_variable_tags = circuit.real_variable_tags;
117 const auto& tau = circuit.tau();
118
120 copy_cycles.size(),
121 [&](size_t cycle_idx) {
122 const CyclicPermutation& cycle = copy_cycles[cycle_idx];
123 const auto cycle_size = cycle.size();
124 if (cycle_size == 0) {
125 return;
126 }
127
128 // sigma at every non-last node points to the next node in the cycle.
129 for (size_t node_idx = 0; node_idx + 1 < cycle_size; ++node_idx) {
130 const cycle_node& current = cycle[node_idx];
131 const cycle_node& next = cycle[node_idx + 1];
132 sigmas[current.wire_idx].at(current.gate_idx) = FF(next.gate_idx + (SEPARATOR * next.wire_idx));
133 }
134
135 const uint32_t var_tag = real_variable_tags[cycle_idx];
136
137 // sigma at the last node is tagged and points to tau(var_tag) instead of wrapping to first.
138 const cycle_node& last_node = cycle[cycle_size - 1];
139 sigmas[last_node.wire_idx].at(last_node.gate_idx) = FF((SEPARATOR * NUM_WIRES) + tau.at(var_tag));
140
141 // id at the first node is tagged with the cycle's variable tag (this follows the
142 // generalized permutation argument: per cycle, exactly one element per permutation
143 // polynomial is a tag).
144 const cycle_node& first_node = cycle[0];
145 ids[first_node.wire_idx].at(first_node.gate_idx) = FF((SEPARATOR * NUM_WIRES) + var_tag);
146 },
147 /*heuristic_cost=*/thread_heuristics::FF_COPY_COST * 8);
148 }
149
150 // Phase 3: public input override on sigma_0.
151 //
152 // We intentionally want to break the cycles of the public input variables as an optimization.
153 // During the witness generation, both the left and right wire polynomials (w_l and w_r
154 // respectively) at row idx i contain the i-th public input. Let n = SEPARATOR. The initial
155 // CyclicPermutation created for these variables copy-constrained to the ith public input
156 // therefore always starts with (i) -> (n+i), followed by the indices of the variables in the
157 // "real" gates (i.e., the gates not merely present to set-up inputs).
158 //
159 // We change this and make i point to -(i+1). This choice "unbalances" the grand product
160 // argument, so that the final result of the grand product is _not_ 1. These indices are chosen
161 // so they can easily be computed by the verifier (just knowing the public inputs), and this
162 // algorithm constitutes a specification of the "permutation argument with public inputs"
163 // optimization due to Gabizon and Williamson. The verifier can expect the final product to be
164 // equal to the "public input delta" that is computed in <honk/library/grand_product_delta.hpp>.
165 {
166 BB_BENCH_NAME("permutation_polys_public_input_overrides");
167 const auto num_public_inputs = static_cast<uint32_t>(circuit.num_public_inputs());
168 const auto pub_inputs_offset = circuit.blocks.pub_inputs.trace_offset();
169 for (size_t i = 0; i < num_public_inputs; ++i) {
170 const uint32_t idx = static_cast<uint32_t>(i + pub_inputs_offset);
171 sigmas[0].at(idx) = -FF(idx + 1);
172 }
173 }
174}
175
176} // namespace bb
#define BB_ASSERT_LT(left, right,...)
Definition assert.hpp:143
bb::field< bb::Bn254FrParams > FF
Definition field.cpp:24
#define BB_BENCH_NAME(name)
Definition bb_bench.hpp:264
A container for the prover polynomials.
typename Curve::ScalarField FF
static constexpr size_t NUM_WIRES
Base class templates shared across Honk flavors.
constexpr size_t FF_COPY_COST
Definition thread.hpp:144
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
MultithreadData calculate_thread_data(size_t num_iterations, size_t min_iterations_per_thread)
Calculates number of threads and index bounds for each thread.
Definition thread.cpp:207
void parallel_for_heuristic(size_t num_points, const std::function< void(size_t, size_t, size_t)> &func, size_t heuristic_cost)
Split a loop into several loops running in parallel based on operations in 1 iteration.
Definition thread.cpp:171
void compute_permutation_argument_polynomials(const typename Flavor::CircuitBuilder &circuit, typename Flavor::ProverPolynomials &polynomials, const std::vector< CyclicPermutation > &copy_cycles)
Compute Honk-style permutation sigma/id polynomials and add to prover_instance.
constexpr uint32_t PERMUTATION_ARGUMENT_VALUE_SEPARATOR
Definition constants.hpp:10
std::vector< cycle_node > CyclicPermutation
void parallel_for(size_t num_iterations, const std::function< void(size_t)> &func)
Definition thread.cpp:111
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
cycle_node represents the idx of a value of the circuit. It will belong to a CyclicPermutation,...