halo2_proofs/plonk/permutation/
keygen.rs

1use ff::Field;
2use group::Curve;
3
4use super::{Argument, ProvingKey, VerifyingKey};
5use crate::{
6    arithmetic::{CurveAffine, FieldExt},
7    plonk::{Any, Column, Error},
8    poly::{
9        commitment::{Blind, Params},
10        EvaluationDomain,
11    },
12};
13
14#[derive(Debug)]
15pub(crate) struct Assembly {
16    columns: Vec<Column<Any>>,
17    pub(crate) mapping: Vec<Vec<(usize, usize)>>,
18    aux: Vec<Vec<(usize, usize)>>,
19    sizes: Vec<Vec<usize>>,
20}
21
22impl Assembly {
23    pub(crate) fn new(n: usize, p: &Argument) -> Self {
24        // Initialize the copy vector to keep track of copy constraints in all
25        // the permutation arguments.
26        let mut columns = vec![];
27        for i in 0..p.columns.len() {
28            // Computes [(i, 0), (i, 1), ..., (i, n - 1)]
29            columns.push((0..n).map(|j| (i, j)).collect());
30        }
31
32        // Before any equality constraints are applied, every cell in the permutation is
33        // in a 1-cycle; therefore mapping and aux are identical, because every cell is
34        // its own distinguished element.
35        Assembly {
36            columns: p.columns.clone(),
37            mapping: columns.clone(),
38            aux: columns,
39            sizes: vec![vec![1usize; n]; p.columns.len()],
40        }
41    }
42
43    pub(crate) fn copy(
44        &mut self,
45        left_column: Column<Any>,
46        left_row: usize,
47        right_column: Column<Any>,
48        right_row: usize,
49    ) -> Result<(), Error> {
50        let left_column = self
51            .columns
52            .iter()
53            .position(|c| c == &left_column)
54            .ok_or(Error::ColumnNotInPermutation(left_column))?;
55        let right_column = self
56            .columns
57            .iter()
58            .position(|c| c == &right_column)
59            .ok_or(Error::ColumnNotInPermutation(right_column))?;
60
61        // Check bounds
62        if left_row >= self.mapping[left_column].len()
63            || right_row >= self.mapping[right_column].len()
64        {
65            return Err(Error::BoundsFailure);
66        }
67
68        // See book/src/design/permutation.md for a description of this algorithm.
69
70        let mut left_cycle = self.aux[left_column][left_row];
71        let mut right_cycle = self.aux[right_column][right_row];
72
73        // If left and right are in the same cycle, do nothing.
74        if left_cycle == right_cycle {
75            return Ok(());
76        }
77
78        if self.sizes[left_cycle.0][left_cycle.1] < self.sizes[right_cycle.0][right_cycle.1] {
79            std::mem::swap(&mut left_cycle, &mut right_cycle);
80        }
81
82        // Merge the right cycle into the left one.
83        self.sizes[left_cycle.0][left_cycle.1] += self.sizes[right_cycle.0][right_cycle.1];
84        let mut i = right_cycle;
85        loop {
86            self.aux[i.0][i.1] = left_cycle;
87            i = self.mapping[i.0][i.1];
88            if i == right_cycle {
89                break;
90            }
91        }
92
93        let tmp = self.mapping[left_column][left_row];
94        self.mapping[left_column][left_row] = self.mapping[right_column][right_row];
95        self.mapping[right_column][right_row] = tmp;
96
97        Ok(())
98    }
99
100    pub(crate) fn build_vk<C: CurveAffine>(
101        self,
102        params: &Params<C>,
103        domain: &EvaluationDomain<C::Scalar>,
104        p: &Argument,
105    ) -> VerifyingKey<C> {
106        // Compute [omega^0, omega^1, ..., omega^{params.n - 1}]
107        let mut omega_powers = Vec::with_capacity(params.n as usize);
108        {
109            let mut cur = C::Scalar::one();
110            for _ in 0..params.n {
111                omega_powers.push(cur);
112                cur *= &domain.get_omega();
113            }
114        }
115
116        // Compute [omega_powers * \delta^0, omega_powers * \delta^1, ..., omega_powers * \delta^m]
117        let mut deltaomega = Vec::with_capacity(p.columns.len());
118        {
119            let mut cur = C::Scalar::one();
120            for _ in 0..p.columns.len() {
121                let mut omega_powers = omega_powers.clone();
122                for o in &mut omega_powers {
123                    *o *= &cur;
124                }
125
126                deltaomega.push(omega_powers);
127
128                cur *= &C::Scalar::DELTA;
129            }
130        }
131
132        // Pre-compute commitments for the URS.
133        let mut commitments = vec![];
134        for i in 0..p.columns.len() {
135            // Computes the permutation polynomial based on the permutation
136            // description in the assembly.
137            let mut permutation_poly = domain.empty_lagrange();
138            for (j, p) in permutation_poly.iter_mut().enumerate() {
139                let (permuted_i, permuted_j) = self.mapping[i][j];
140                *p = deltaomega[permuted_i][permuted_j];
141            }
142
143            // Compute commitment to permutation polynomial
144            commitments.push(
145                params
146                    .commit_lagrange(&permutation_poly, Blind::default())
147                    .to_affine(),
148            );
149        }
150        VerifyingKey { commitments }
151    }
152
153    pub(crate) fn build_pk<C: CurveAffine>(
154        self,
155        params: &Params<C>,
156        domain: &EvaluationDomain<C::Scalar>,
157        p: &Argument,
158    ) -> ProvingKey<C> {
159        // Compute [omega^0, omega^1, ..., omega^{params.n - 1}]
160        let mut omega_powers = Vec::with_capacity(params.n as usize);
161        {
162            let mut cur = C::Scalar::one();
163            for _ in 0..params.n {
164                omega_powers.push(cur);
165                cur *= &domain.get_omega();
166            }
167        }
168
169        // Compute [omega_powers * \delta^0, omega_powers * \delta^1, ..., omega_powers * \delta^m]
170        let mut deltaomega = Vec::with_capacity(p.columns.len());
171        {
172            let mut cur = C::Scalar::one();
173            for _ in 0..p.columns.len() {
174                let mut omega_powers = omega_powers.clone();
175                for o in &mut omega_powers {
176                    *o *= &cur;
177                }
178
179                deltaomega.push(omega_powers);
180
181                cur *= &C::Scalar::DELTA;
182            }
183        }
184
185        // Compute permutation polynomials, convert to coset form.
186        let mut permutations = vec![];
187        let mut polys = vec![];
188        let mut cosets = vec![];
189        for i in 0..p.columns.len() {
190            // Computes the permutation polynomial based on the permutation
191            // description in the assembly.
192            let mut permutation_poly = domain.empty_lagrange();
193            for (j, p) in permutation_poly.iter_mut().enumerate() {
194                let (permuted_i, permuted_j) = self.mapping[i][j];
195                *p = deltaomega[permuted_i][permuted_j];
196            }
197
198            // Store permutation polynomial and precompute its coset evaluation
199            permutations.push(permutation_poly.clone());
200            let poly = domain.lagrange_to_coeff(permutation_poly);
201            polys.push(poly.clone());
202            cosets.push(domain.coeff_to_extended(poly));
203        }
204        ProvingKey {
205            permutations,
206            polys,
207            cosets,
208        }
209    }
210}