1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
//! Implementation of permutation argument.

use crate::plonk::{Column, Error};
use halo2_middleware::circuit::{Any, Cell};

/// A permutation argument.
#[derive(Default, Debug, Clone)]
pub struct Argument {
    /// A sequence of columns involved in the argument.
    pub(crate) columns: Vec<Column<Any>>,
}

impl Argument {
    /// Returns the minimum circuit degree required by the permutation argument.
    /// The argument may use larger degree gates depending on the actual
    /// circuit's degree and how many columns are involved in the permutation.
    pub(crate) fn required_degree(&self) -> usize {
        // degree 2:
        // l_0(X) * (1 - z(X)) = 0
        //
        // We will fit as many polynomials p_i(X) as possible
        // into the required degree of the circuit, so the
        // following will not affect the required degree of
        // this middleware.
        //
        // (1 - (l_last(X) + l_blind(X))) * (
        //   z(\omega X) \prod (p(X) + \beta s_i(X) + \gamma)
        // - z(X) \prod (p(X) + \delta^i \beta X + \gamma)
        // )
        //
        // On the first sets of columns, except the first
        // set, we will do
        //
        // l_0(X) * (z(X) - z'(\omega^(last) X)) = 0
        //
        // where z'(X) is the permutation for the previous set
        // of columns.
        //
        // On the final set of columns, we will do
        //
        // degree 3:
        // l_last(X) * (z'(X)^2 - z'(X)) = 0
        //
        // which will allow the last value to be zero to
        // ensure the argument is perfectly complete.

        // There are constraints of degree 3 regardless of the
        // number of columns involved.
        3
    }

    pub(crate) fn add_column(&mut self, column: Column<Any>) {
        if !self.columns.contains(&column) {
            self.columns.push(column);
        }
    }

    /// Returns columns that participate on the permutation argument.
    pub fn get_columns(&self) -> Vec<Column<Any>> {
        self.columns.clone()
    }
}

#[derive(Clone, Debug)]
pub(crate) struct Assembly {
    pub(crate) n: usize,
    pub(crate) columns: Vec<Column<Any>>,
    pub(crate) copies: Vec<(Cell, Cell)>,
}

impl Assembly {
    pub(crate) fn new(n: usize, p: &Argument) -> Self {
        Self {
            n,
            columns: p.columns.clone(),
            copies: Vec::new(),
        }
    }

    pub(crate) fn copy(
        &mut self,
        left_column: Column<Any>,
        left_row: usize,
        right_column: Column<Any>,
        right_row: usize,
    ) -> Result<(), Error> {
        if !self.columns.contains(&left_column) {
            return Err(Error::ColumnNotInPermutation(left_column));
        }
        if !self.columns.contains(&right_column) {
            return Err(Error::ColumnNotInPermutation(right_column));
        }
        // Check bounds
        if left_row >= self.n || right_row >= self.n {
            return Err(Error::BoundsFailure);
        }
        self.copies.push((
            Cell {
                column: left_column.into(),
                row: left_row,
            },
            Cell {
                column: right_column.into(),
                row: right_row,
            },
        ));
        Ok(())
    }
}