barretenberg
Loading...
Searching...
No Matches
generalized_permutation.hpp
1#pragma once
2#include "barretenberg/numeric/bitop/get_msb.hpp"
3#include "barretenberg/polynomials/iterate_over_domain.hpp"
4#include "barretenberg/polynomials/polynomial.hpp"
5
6namespace proof_system::plonk {
7template <typename program_settings>
8inline void compute_gen_permutation_lagrange_base_single(barretenberg::polynomial& output,
9 const std::vector<uint32_t>& permutation,
10 const barretenberg::evaluation_domain& small_domain)
11{
12 if (output.size() < permutation.size()) {
13 throw_or_abort("Permutation polynomial size is insufficient to store permutations.");
14 }
15 // permutation encoding:
16 // low 28 bits defines the location in witness polynomial
17 // upper 2 bits defines the witness polynomial:
18 // 0 = left
19 // 1 = right
20 // 2 = output
21 const barretenberg::fr* roots = small_domain.get_round_roots()[small_domain.log2_size - 2];
22 const size_t root_size = small_domain.size >> 1UL;
23 const size_t log2_root_size = static_cast<size_t>(numeric::get_msb(root_size));
24
25 ITERATE_OVER_DOMAIN_START(small_domain);
26 // permutation[i] will specify the 'index' that this wire value will map to
27 // here, 'index' refers to an element of our subgroup H
28 // we can almost use permutation[i] to directly index our `roots` array, which contains our subgroup elements
29 // we first have to mask off the 2 high bits, which describe which wire polynomial our permutation maps to (we'll
30 // deal with that in a bit) we then have to accommodate for the fact that, `roots` only contains *half* of our
31 // subgroup elements. this is because w^{n/2} = -w and we don't want to perform redundant work computing roots of
32 // unity
33
34 // Step 1: mask the high bits and get the permutation index
35 const size_t raw_idx = static_cast<size_t>(permutation[i] & ~program_settings::permutation_mask);
36
37 // Step 2: is `raw_idx` >= (n / 2)? if so, we will need to index `-roots[raw_idx - subgroup_size / 2]` instead of
38 // `roots[raw_idx]`
39 const bool negative_idx = raw_idx >= root_size;
40
41 // Step 3: compute the index of the subgroup element we'll be accessing.
42 // To avoid a conditional branch, we can subtract `negative_idx << log2_root_size` from `raw_idx`
43 // here, `log2_root_size = numeric::get_msb(subgroup_size / 2)` (we know our subgroup size will be a power of 2, so
44 // we lose no precision here)
45 const size_t idx = raw_idx - (static_cast<size_t>(negative_idx) << log2_root_size);
46
47 // call `conditionally_subtract_double_modulus`, using `negative_idx` as our predicate.
48 // Our roots of unity table is partially 'overloaded' - we either store the root `w`, or `modulus + w`
49 // So to ensure we correctly compute `modulus - w`, we need to compute `2 * modulus - w`
50 // The output will similarly be overloaded (containing either 2 * modulus - w, or modulus - w)
51 output[i] = roots[idx].conditionally_subtract_from_double_modulus(static_cast<uint64_t>(negative_idx));
52
53 // finally, if our permutation maps to an index in either the right wire vector, or the output wire vector, we need
54 // to multiply our result by one of two quadratic non-residues.
55 // (this ensure that mapping into the left wires gives unique values that are not repeated in the right or output
56 // wire permutations) (ditto for right wire and output wire mappings)
57
58 // isolate the highest 2 bits of `permutation[i]` and shunt them down into the 2 least significant bits
59 const uint32_t column_index =
60 ((permutation[i] & program_settings::permutation_mask) >> program_settings::permutation_shift);
61 if (column_index > 0) {
62 output[i] *= barretenberg::fr::coset_generator(column_index - 1);
63 }
64 ITERATE_OVER_DOMAIN_END;
65}
66} // namespace proof_system::plonk
Definition: widget.bench.cpp:13