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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
use std::fmt;

use super::TableColumn;
use crate::plonk::{Column, Selector};
use halo2_middleware::circuit::Any;

/// This is an error that could occur during circuit synthesis.  
///
/// **NOTE**: [`AssignError`] is introduced to provide more debugging info     
/// to developers when assigning witnesses to circuit cells.  
/// Hence, they are used for [`MockProver`] and [`WitnessCollection`].  
/// The [`keygen`] process use the [`NotEnoughRowsAvailable`], since it is just enough.
#[derive(Debug)]
pub enum Error {
    /// This is an error that can occur during synthesis of the circuit, for
    /// example, when the witness is not present.
    Synthesis,
    /// Out of bounds index passed to a backend
    BoundsFailure,
    /// `k` is too small for the given circuit.
    NotEnoughRowsAvailable {
        /// The current value of `k` being used.
        current_k: u32,
    },
    /// Circuit synthesis requires global constants, but circuit configuration did not
    /// call [`ConstraintSystem::enable_constant`] on fixed columns with sufficient space.
    ///
    /// [`ConstraintSystem::enable_constant`]: crate::plonk::ConstraintSystem::enable_constant
    NotEnoughColumnsForConstants,
    /// The instance sets up a copy constraint involving a column that has not been
    /// included in the permutation.
    ColumnNotInPermutation(Column<Any>),
    /// An error relating to a lookup table.
    TableError(TableError),
    /// An error relating to a circuit assignment.
    AssignError(AssignError),
    /// Generic error not covered by previous cases
    Other(String),
}

impl Error {
    /// Constructs an `Error::NotEnoughRowsAvailable`.
    pub fn not_enough_rows_available(current_k: u32) -> Self {
        Error::NotEnoughRowsAvailable { current_k }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Error::Synthesis => write!(f, "General synthesis error"),
            Error::BoundsFailure => write!(f, "An out-of-bounds index was passed to the backend"),
            Error::NotEnoughRowsAvailable { current_k } => write!(
                f,
                "k = {current_k} is too small for the given circuit. Try using a larger value of k",
            ),
            Error::NotEnoughColumnsForConstants => {
                write!(
                    f,
                    "Too few fixed columns are enabled for global constants usage"
                )
            }
            Error::ColumnNotInPermutation(column) => write!(
                f,
                "Column {column:?} must be included in the permutation. Help: try applying `meta.enable_equalty` on the column",
            ),
            Error::TableError(error) => write!(f, "{error}"),
            Error::AssignError(error) => write!(f, "{error}"),
            Error::Other(error) => write!(f, "Other: {error}"),
        }
    }
}

/// This is an error that could occur during table synthesis.
#[derive(Debug)]
pub enum TableError {
    /// A `TableColumn` has not been assigned.
    ColumnNotAssigned(TableColumn),
    /// A Table has columns of uneven lengths.
    UnevenColumnLengths((TableColumn, usize), (TableColumn, usize)),
    /// Attempt to assign a used `TableColumn`
    UsedColumn(TableColumn),
    /// Attempt to overwrite a default value
    OverwriteDefault(TableColumn, String, String),
}

impl fmt::Display for TableError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            TableError::ColumnNotAssigned(col) => {
                write!(
                    f,
                    "{col:?} not fully assigned. Help: assign a value at offset 0.",
                )
            }
            TableError::UnevenColumnLengths((col, col_len), (table, table_len)) => write!(
                f,
                "{col:?} has length {col_len} while {table:?} has length {table_len}",
            ),
            TableError::UsedColumn(col) => {
                write!(f, "{col:?} has already been used")
            }
            TableError::OverwriteDefault(col, default, val) => {
                write!(
                    f,
                    "Attempted to overwrite default value {default} with {val} in {col:?}",
                )
            }
        }
    }
}

/// This is an error that could occur during `assign_advice`, `assign_fixed`, `copy`, etc.
#[derive(Debug)]
pub enum AssignError {
    AssignAdvice {
        desc: String,
        col: Column<Any>,
        row: usize,
        usable_rows: (usize, usize),
        k: u32,
    },
    AssignFixed {
        desc: String,
        col: Column<Any>,
        row: usize,
        usable_rows: (usize, usize),
        k: u32,
    },
    EnableSelector {
        desc: String,
        selector: Selector,
        row: usize,
        usable_rows: (usize, usize),
        k: u32,
    },
    QueryInstance {
        col: Column<Any>,
        row: usize,
        usable_rows: (usize, usize),
        k: u32,
    },
    Copy {
        left_col: Column<Any>,
        left_row: usize,
        right_col: Column<Any>,
        right_row: usize,
        usable_rows: (usize, usize),
        k: u32,
    },
    FillFromRow {
        col: Column<Any>,
        from_row: usize,
        usable_rows: (usize, usize),
        k: u32,
    },
    WitnessMissing {
        func: String,
        desc: String,
    },
}

impl fmt::Display for AssignError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            AssignError::AssignAdvice { desc, col, row, usable_rows:(start, end), k } => write!(
                f,
                "assign_advice `{}` error: column={:?}({}), row={}, usable_rows={}..{}, k={}",
                desc,
                col.column_type(),
                col.index(),
                row,
                start, end,
                k,
            ),
            AssignError::AssignFixed {desc, col, row, usable_rows: (start, end), k } => write!(
                f,
                "assign_fixed `{}` error: column={:?}({}), row={}, usable_rows={}..{}, k={}",
                desc,
                col.column_type(),
                col.index(),
                row,
                start, end,
                k,
            ),
            AssignError::EnableSelector { desc, selector, row, usable_rows: (start, end), k } => write!(
                f,
                "enable_selector `{}` error: column=Selector({:?}), row={}, usable_rows={}..{}, k={}",
                desc,
                selector.index(),
                row,
                start, end,
                k,
            ),
            AssignError::QueryInstance { col, row, usable_rows:(start, end), k } => write!(
                f,
                "query_instance error: column={:?}({}), row={}, usable_rows={}..{}, k={}",
                col.column_type,
                col.index(),
                row,
                start,
                end,
                k,
            ),
            AssignError::Copy { left_col, left_row, right_col, right_row, usable_rows:(start, end), k } => write!(
                f,
                "copy error: left_column={:?}({}), left_row={}, right_column={:?}({}), right_row={}, usable_rows={}..{}, k={}",
                left_col.column_type(),
                left_col.index(),
                left_row,
                right_col.column_type(),
                right_col.index(),
                right_row,
                start, end,
                k,
            ),
            AssignError::FillFromRow { col, from_row, usable_rows:(start, end), k } => write!(
                f,
                "fill_from_row error: column={:?}({}), from_row={}, usable_rows={}..{}, k={}",
                col.column_type(),
                col.index(),
                from_row,
                start, end,
                k,
            ),
            AssignError::WitnessMissing { func, desc } => write!(f, "witness missing/unknown when {} `{}`", func, desc),
        }
    }
}