Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
translator_proving_key.cpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Planned, auditors: [], commit: }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
9
10#include <algorithm>
11
12namespace bb {
24{
25 // The vector of groups of polynomials to be concatenated
26 auto groups = proving_key->polynomials.get_groups_to_be_concatenated();
27 // Resulting concatenated polynomials
28 auto targets = proving_key->polynomials.get_concatenated();
29
30 const size_t num_polys_in_group = groups[0].size();
32
33 const size_t MINI_CIRCUIT_SIZE = Flavor::MINI_CIRCUIT_SIZE;
34
35 auto ordering_function = [&](size_t index) {
36 // Get the index of the concatenated polynomial (group index)
37 size_t i = index / num_polys_in_group;
38 // Get the index of the polynomial within the group
39 size_t j = index % num_polys_in_group;
40 auto& group = groups[i];
41 auto& current_target = targets[i];
42
43 // Copy into appropriate position in the concatenated polynomial: j * MINI + k
44 // Note: null padding slots in group 4 are zero-sized polynomials, so this loop is a no-op for them.
45 for (size_t k = group[j].start_index(); k < group[j].end_index(); k++) {
46 current_target.at(j * MINI_CIRCUIT_SIZE + k) = group[j][k];
47 }
48 };
49 parallel_for(groups.size() * num_polys_in_group, ordering_function);
50}
51
76{
77 RefArray ordered_constraint_polynomials{ proving_key->polynomials.ordered_range_constraints_0,
78 proving_key->polynomials.ordered_range_constraints_1,
79 proving_key->polynomials.ordered_range_constraints_2,
80 proving_key->polynomials.ordered_range_constraints_3 };
81 std::vector<size_t> extra_denominator_uint(dyadic_circuit_size_without_masking);
82
83 const auto sorted_elements = get_sorted_steps();
84 auto to_be_concatenated_groups = proving_key->polynomials.get_groups_to_be_concatenated();
85 const size_t circuit_size = proving_key->polynomials.get_polynomial_size();
86
87 // Given the polynomials in group_i, transfer their elements, sorted in non-descending order, into the corresponding
88 // ordered_range_constraint_i up to the given capacity and the remaining elements to the last range constraint.
89 // Sorting is done by converting the elements to uint for efficiency.
90 auto ordering_function = [&](size_t i) {
91 const auto& group = to_be_concatenated_groups[i];
92 std::vector<uint32_t> ordered_vectors_uint(dyadic_circuit_size_without_masking);
93
94 // Calculate how much space there is for values from the group polynomials given we also need to append the
95 // additional steps
96 auto free_space_before_runway = dyadic_circuit_size_without_masking - sorted_elements.size();
97
98 // Calculate the starting index of this group's overflowing elements in the extra denominator polynomial
99 size_t extra_denominator_offset = i * sorted_elements.size();
100
101 // Number of real values per lane: MINI_CIRCUIT_SIZE positions minus the virtual zero at index 0
102 // minus NUM_MASKED_ROWS_END masking rows at the end of each block
103 static constexpr size_t values_per_lane = Flavor::MINI_CIRCUIT_SIZE - 1 - Flavor::NUM_MASKED_ROWS_END;
104
105 // Go through each polynomial in the concatenated group
106 for (size_t j = 0; j < Flavor::CONCATENATION_GROUP_SIZE; j++) {
107
108 // Dense offset: avoid phantom zeros by packing values tightly
109 auto current_offset = j * values_per_lane;
110
111 // For each element in the polynomial (excluding masking rows at the end)
112 for (size_t k = group[j].start_index(); k < group[j].end_index() - Flavor::NUM_MASKED_ROWS_END; k++) {
113
114 auto vec_idx = current_offset + (k - group[j].start_index());
115
116 // Put it in the target polynomial
117 if (vec_idx < free_space_before_runway) {
118 ordered_vectors_uint[vec_idx] = static_cast<uint32_t>(uint256_t(group[j][k]).data[0]);
119
120 // Or in the extra one if there is no space left
121 } else {
122 extra_denominator_uint[extra_denominator_offset] =
123 static_cast<uint32_t>(uint256_t(group[j][k]).data[0]);
124 extra_denominator_offset++;
125 }
126 }
127 }
128
129 // Verify that overflow entries didn't exceed the reserved space (SORTED_STEPS_COUNT per group)
130 BB_ASSERT(extra_denominator_offset <= (i + 1) * Flavor::SORTED_STEPS_COUNT,
131 "Translator: overflow entries exceed reserved space in ordered polynomial");
132
133 // Advance the iterator past the last written element in the range constraint polynomial and complete it with
134 // sorted steps
135 auto ordered_vector_it = ordered_vectors_uint.begin();
136 std::advance(ordered_vector_it, free_space_before_runway);
137 std::copy(sorted_elements.cbegin(), sorted_elements.cend(), ordered_vector_it);
138
139 // Sort the polynomial in nondescending order. We sort using the uint32_t vector for 2 reasons:
140 // 1. It is faster to sort integers
141 // 2. Comparison operators for finite fields are operating on internal form, so we'd have to convert them
142 // from Montgomery
143 std::sort(ordered_vectors_uint.begin(), ordered_vectors_uint.end());
144 BB_ASSERT_EQ(ordered_vectors_uint.size(), dyadic_circuit_size_without_masking);
145
146 // All polynomials reserve the same amount of space at the end (max across all polynomials)
147 // so that lagrange_real_last marks the same position for all polynomials
148 // Place sorted values contiguously from position 1 to circuit_size - MAX_RANDOM_VALUES_PER_ORDERED
149 // Position 0 remains 0 (virtual zero). Last MAX_RANDOM_VALUES_PER_ORDERED positions reserved for random values.
150 size_t sorted_idx = 1; // Skip vec[0] (virtual zero at position 0)
151 for (size_t pos = 1; pos < circuit_size - Flavor::MAX_RANDOM_VALUES_PER_ORDERED; pos++) {
152 ordered_constraint_polynomials[i].at(pos) = FF(ordered_vectors_uint[sorted_idx]);
153 sorted_idx++;
154 }
155 };
156
157 // Construct the first NUM_CONCATENATED_POLYS - 1 polynomials (range constraint groups only)
158 constexpr size_t NUM_RANGE_CONSTRAINT_GROUPS = Flavor::NUM_CONCATENATED_POLYS - 1;
159 parallel_for(NUM_RANGE_CONSTRAINT_GROUPS, ordering_function);
160
161 // Advance the iterator into the extra range constraint past the last written element
162 auto extra_denominator_it = extra_denominator_uint.begin();
163 std::advance(extra_denominator_it, NUM_RANGE_CONSTRAINT_GROUPS * sorted_elements.size());
164
165 // Add steps to the extra denominator polynomial to fill it
166 std::copy(sorted_elements.cbegin(), sorted_elements.cend(), extra_denominator_it);
167 // Sort it
168#ifdef NO_PAR_ALGOS
169 std::sort(extra_denominator_uint.begin(), extra_denominator_uint.end());
170#else
171 std::sort(std::execution::par_unseq, extra_denominator_uint.begin(), extra_denominator_uint.end());
172#endif
173
174 // Place sorted values for the 5th polynomial
175 // All polynomials reserve the same amount of space at the end
176 {
177 size_t sorted_idx = 1; // Skip vec[0] (virtual zero at position 0)
178 for (size_t pos = 1; pos < circuit_size - Flavor::MAX_RANDOM_VALUES_PER_ORDERED; pos++) {
179 proving_key->polynomials.ordered_range_constraints_4.at(pos) = FF(extra_denominator_uint[sorted_idx]);
180 sorted_idx++;
181 }
182 }
183
184 // Transfer randomness from concatenated to ordered polynomials such that the commitments and evaluations of all
185 // ordered polynomials and their shifts are hidden
187}
188
199{
200 auto concatenated = proving_key->polynomials.get_concatenated();
201 auto ordered = proving_key->polynomials.get_ordered_range_constraints();
202 const size_t num_ordered_polynomials = ordered.size();
203 const size_t MINI = Flavor::MINI_CIRCUIT_SIZE;
204
205 // Collect all random values from masking positions in concatenated range constraint polynomials
206 // NOTE: Only extract from the first NUM_CONCATENATED_POLYS - 1 concatenated polys
207 // (concatenated_range_constraints_0..3) which appear in the permutation numerator.
208 // The last (concatenated_non_range) is not in the numerator.
209 // Masking positions are at the end of each block: [j*MINI + (MINI - NUM_MASKED_ROWS_END), j*MINI + MINI)
210 constexpr size_t NUM_RANGE_CONSTRAINT_GROUPS = Flavor::NUM_CONCATENATED_POLYS - 1;
211 const size_t num_random_values_per_concat = Flavor::NUM_MASKED_ROWS_END * Flavor::CONCATENATION_GROUP_SIZE;
212 const size_t total_num_random_values = num_random_values_per_concat * NUM_RANGE_CONSTRAINT_GROUPS;
213 const size_t num_random_values_per_ordered = total_num_random_values / num_ordered_polynomials;
214 const size_t remaining_random_values = total_num_random_values % num_ordered_polynomials;
215
216 std::vector<FF> random_values(total_num_random_values);
217
218 // Extract random values from scattered masking positions in the first NUM_RANGE_CONSTRAINT_GROUPS concatenated
219 // polynomials. Each thread handles one concatenated polynomial, writing to a disjoint slice of random_values.
220 parallel_for(NUM_RANGE_CONSTRAINT_GROUPS, [&](size_t i) {
221 const auto& current_concat = concatenated[i];
222 size_t idx = i * num_random_values_per_concat;
223 for (size_t j = 0; j < Flavor::CONCATENATION_GROUP_SIZE; j++) {
224 size_t block_masking_start = j * MINI + (MINI - Flavor::NUM_MASKED_ROWS_END);
225 for (size_t k = 0; k < Flavor::NUM_MASKED_ROWS_END; k++) {
226 random_values[idx] = current_concat[block_masking_start + k];
227 idx++;
228 }
229 }
230 });
231
232 // Distribute random values to ordered polynomials at the END (contiguous).
233 // Each ordered polynomial gets values at the last positions.
234 const size_t circuit_size = proving_key->polynomials.get_polynomial_size();
235 parallel_for(num_ordered_polynomials, [&](size_t i) {
236 auto& current_ordered = ordered[i];
237 size_t values_for_this_poly = num_random_values_per_ordered + (i < remaining_random_values ? 1 : 0);
238 // Compute offset into random_values for this ordered polynomial
239 size_t random_idx = i * num_random_values_per_ordered + std::min(i, remaining_random_values);
240 // Place random values at the END: [circuit_size - values_for_this_poly, circuit_size)
241 for (size_t k = 0; k < values_for_this_poly; k++) {
242 current_ordered.at(circuit_size - values_for_this_poly + k) = random_values[random_idx];
243 random_idx++;
244 }
245 });
246}
247
285{
286 const size_t MINI = Flavor::MINI_CIRCUIT_SIZE;
287 const size_t circuit_size = proving_key->polynomials.get_polynomial_size();
288
289 proving_key->polynomials.lagrange_first.at(0) = 1;
290 // lagrange_real_last marks the last position with sorted values in ordered polynomials
291 // (where we check maximum value = 2^14 - 1)
292 proving_key->polynomials.lagrange_real_last.at(circuit_size - Flavor::MAX_RANDOM_VALUES_PER_ORDERED - 1) = 1;
293 proving_key->polynomials.lagrange_last.at(circuit_size - 1) = 1;
294
295 // Scattered masking: last NUM_MASKED_ROWS_END rows of each of the 16 blocks
296 for (size_t j = 0; j < Flavor::CONCATENATION_GROUP_SIZE; j++) {
297 for (size_t k = MINI - Flavor::NUM_MASKED_ROWS_END; k < MINI; k++) {
298 proving_key->polynomials.lagrange_masking.at(j * MINI + k) = 1;
299 }
300 }
301
302 // lagrange_ordered_masking: marks the last MAX_RANDOM_VALUES_PER_ORDERED positions (contiguous at end)
303 // where random values are placed in ordered polynomials
304 for (size_t i = circuit_size - Flavor::MAX_RANDOM_VALUES_PER_ORDERED; i < circuit_size; i++) {
305 proving_key->polynomials.lagrange_ordered_masking.at(i) = 1;
306 }
307
308 for (size_t i = Flavor::RANDOMNESS_START; i < Flavor::RESULT_ROW; i++) {
309 proving_key->polynomials.lagrange_mini_masking.at(i) = 1;
310 }
311
312 // Location of randomness for wires defined within the mini circuit
314 proving_key->polynomials.lagrange_mini_masking.at(i) = 1;
315 }
316
317 // Translator VM processes two rows of its execution trace at a time, establishing different relations between
318 // polynomials at even and odd indices
320 proving_key->polynomials.lagrange_even_in_minicircuit.at(i) = 1;
321 proving_key->polynomials.lagrange_odd_in_minicircuit.at(i + 1) = 1;
322 }
323
324 // Position of evaluation result
325 proving_key->polynomials.lagrange_result_row.at(Flavor::RESULT_ROW) = 1;
326 proving_key->polynomials.lagrange_last_in_minicircuit.at(dyadic_mini_circuit_size_without_masking - 1) = 1;
327}
328
344{
345
346 const auto sorted_elements = get_sorted_steps();
347 // The numerator has NUM_CONCATENATED_POLYS factors: (NUM_CONCATENATED_POLYS - 1) concatenated range constraint
348 // polynomials + 1 extra_numerator, matching NUM_CONCATENATED_POLYS ordered polynomials in the denominator.
349 // Each sorted element appears NUM_CONCATENATED_POLYS times.
350 constexpr size_t NUM_FACTORS_IN_NUMERATOR = Flavor::NUM_CONCATENATED_POLYS;
351 auto fill_with_shift = [&](size_t shift) {
352 for (size_t i = 0; i < sorted_elements.size(); i++) {
353 proving_key->polynomials.ordered_extra_range_constraints_numerator.at(
354 shift + i * NUM_FACTORS_IN_NUMERATOR) = sorted_elements[i];
355 }
356 };
357 // Fill polynomials with a sequence, where each element is repeated NUM_FACTORS_IN_NUMERATOR times
358 parallel_for(NUM_FACTORS_IN_NUMERATOR, fill_with_shift);
359}
360
361} // namespace bb
#define BB_ASSERT(expression,...)
Definition assert.hpp:70
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:83
A template class for a reference array. Behaves as if std::array<T&, N> was possible.
Definition ref_array.hpp:22
static constexpr size_t MINI_CIRCUIT_SIZE
static constexpr size_t MAX_RANDOM_VALUES_PER_ORDERED
static constexpr size_t NUM_CONCATENATED_POLYS
static constexpr size_t RANDOMNESS_START
static constexpr size_t CONCATENATION_GROUP_SIZE
static constexpr size_t RESULT_ROW
static constexpr size_t NUM_MASKED_ROWS_END
static constexpr size_t SORTED_STEPS_COUNT
void split_concatenated_random_coefficients_to_ordered()
Distribute the randomness from the 4 concatenated range constraint polynomials to the 5 ordered range...
void compute_concatenated_polynomials()
Construct a set of polynomials that are the result of concatenating a group of polynomials into one....
static std::array< size_t, Flavor::SORTED_STEPS_COUNT > get_sorted_steps()
Create the array of steps inserted in each ordered range constraint to ensure they respect the approp...
static constexpr size_t mini_circuit_dyadic_size
void compute_extra_range_constraint_numerator()
Compute the extra numerator for the grand product polynomial.
static constexpr size_t dyadic_circuit_size_without_masking
void compute_translator_range_constraint_ordered_polynomials()
Compute denominator polynomials for Translator's range constraint permutation.
std::shared_ptr< ProvingKey > proving_key
static constexpr size_t dyadic_mini_circuit_size_without_masking
void compute_lagrange_polynomials()
Constructs all Lagrange precomputed polynomials required for Translator relations....
group class. Represents an elliptic curve group element. Group is parametrised by Fq and Fr
Definition group.hpp:38
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
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