Skip to main content

haloumi_core/
table.rs

1//! Types and traits related to PLONK tables.
2//!
3//! Some types try to replicate the API of their namesakes in Halo2.
4
5use std::ops::Deref;
6
7use ff::Field;
8use thiserror::Error;
9
10use crate::{
11    expressions::ExprBuilder,
12    info_traits::CreateQuery,
13    query::{Advice, Fixed, Instance},
14};
15
16/// Column type
17pub trait ColumnType: std::fmt::Debug + Copy + Clone + PartialEq + Eq + std::hash::Hash {
18    /// Constructs a polynomial representing a query to the cell.
19    fn query_cell<F: Field, E: ExprBuilder<F>>(&self, index: usize, at: Rotation) -> E;
20}
21
22/// Erased column type.
23#[derive(Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
24pub enum Any {
25    /// Fixed type.
26    Fixed,
27    /// Advice type.
28    Advice,
29    /// Instance type.
30    Instance,
31}
32
33impl std::fmt::Debug for Any {
34    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35        match self {
36            Self::Fixed => write!(f, "Fix"),
37            Self::Advice => write!(f, "Adv"),
38            Self::Instance => write!(f, "Ins"),
39        }
40    }
41}
42
43impl ColumnType for Any {
44    fn query_cell<F: Field, E: ExprBuilder<F>>(&self, index: usize, at: Rotation) -> E {
45        match self {
46            Any::Fixed => Fixed.query_cell(index, at),
47            Any::Advice => Advice.query_cell(index, at),
48            Any::Instance => Instance.query_cell(index, at),
49        }
50    }
51}
52
53impl ColumnType for Fixed {
54    fn query_cell<F: Field, E: ExprBuilder<F>>(&self, index: usize, at: Rotation) -> E {
55        E::FixedQuery::query_expr(index, at)
56    }
57}
58
59impl ColumnType for Advice {
60    fn query_cell<F: Field, E: ExprBuilder<F>>(&self, index: usize, at: Rotation) -> E {
61        E::AdviceQuery::query_expr(index, at)
62    }
63}
64
65impl ColumnType for Instance {
66    fn query_cell<F: Field, E: ExprBuilder<F>>(&self, index: usize, at: Rotation) -> E {
67        E::InstanceQuery::query_expr(index, at)
68    }
69}
70
71/// A column with a type.
72#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
73pub struct Column<C: ColumnType> {
74    index: usize,
75    column_type: C,
76}
77
78impl<C: ColumnType + std::fmt::Debug> std::fmt::Debug for Column<C> {
79    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
80        write!(f, "{:?}:{}", self.column_type, self.index)
81    }
82}
83
84impl<C: ColumnType> Column<C> {
85    /// Creates a new column.
86    pub fn new(index: usize, column_type: C) -> Self {
87        Self { index, column_type }
88    }
89
90    /// Returns the index of a column.
91    pub fn index(&self) -> usize {
92        self.index
93    }
94
95    /// Returns the column type.
96    pub fn column_type(&self) -> &C {
97        &self.column_type
98    }
99
100    /// Creates an expression representing a query to a cell in this column.
101    pub fn query_cell<F: Field, E: ExprBuilder<F>>(&self, at: Rotation) -> E {
102        self.column_type.query_cell(self.index, at)
103    }
104}
105
106impl From<Column<Fixed>> for Column<Any> {
107    fn from(value: Column<Fixed>) -> Self {
108        Self {
109            index: value.index,
110            column_type: Any::Fixed,
111        }
112    }
113}
114
115impl TryFrom<Column<Any>> for Column<Fixed> {
116    type Error = TableError;
117
118    fn try_from(value: Column<Any>) -> Result<Self, Self::Error> {
119        match value.column_type {
120            Any::Fixed => Ok(Self {
121                index: value.index,
122                column_type: Fixed,
123            }),
124            c => Err(TableError::ExpectedFixed(c)),
125        }
126    }
127}
128
129impl From<Column<Advice>> for Column<Any> {
130    fn from(value: Column<Advice>) -> Self {
131        Self {
132            index: value.index,
133            column_type: Any::Advice,
134        }
135    }
136}
137
138impl TryFrom<Column<Any>> for Column<Advice> {
139    type Error = TableError;
140
141    fn try_from(value: Column<Any>) -> Result<Self, Self::Error> {
142        match value.column_type {
143            Any::Advice => Ok(Self {
144                index: value.index,
145                column_type: Advice,
146            }),
147            c => Err(TableError::ExpectedAdvice(c)),
148        }
149    }
150}
151
152impl From<Column<Instance>> for Column<Any> {
153    fn from(value: Column<Instance>) -> Self {
154        Self {
155            index: value.index,
156            column_type: Any::Instance,
157        }
158    }
159}
160
161impl TryFrom<Column<Any>> for Column<Instance> {
162    type Error = TableError;
163
164    fn try_from(value: Column<Any>) -> Result<Self, Self::Error> {
165        match value.column_type {
166            Any::Instance => Ok(Self {
167                index: value.index,
168                column_type: Instance,
169            }),
170            c => Err(TableError::ExpectedInstance(c)),
171        }
172    }
173}
174
175/// Represents a cell in the table.
176#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
177pub struct Cell {
178    /// The index of the region this cell belongs to.
179    pub region_index: RegionIndex,
180    /// Offset relative to the region of the cell's row.
181    pub row_offset: usize,
182    /// The cell's column.
183    pub column: Column<Any>,
184}
185
186/// Replacement type for Halo2's `Rotation` type.
187pub type Rotation = i32;
188
189/// Extension methods for [`Rotation`].
190pub trait RotationExt {
191    /// Returns the current row.
192    fn cur() -> Self;
193
194    /// Returns the next row.
195    fn next() -> Self;
196
197    /// Returns the previous row.
198    fn prev() -> Self;
199}
200
201impl RotationExt for Rotation {
202    fn cur() -> Self {
203        0
204    }
205
206    fn next() -> Self {
207        1
208    }
209
210    fn prev() -> Self {
211        -1
212    }
213}
214
215/// Replacement for Halo2's `RegionIndex` type.
216#[derive(Eq, Hash, PartialEq, Debug, Copy, Clone)]
217pub struct RegionIndex(usize);
218
219impl Deref for RegionIndex {
220    type Target = usize;
221
222    fn deref(&self) -> &Self::Target {
223        &self.0
224    }
225}
226
227impl From<usize> for RegionIndex {
228    fn from(value: usize) -> Self {
229        Self(value)
230    }
231}
232
233/// Replacement for Halo2's `RegionStart` type.
234#[derive(Eq, Hash, PartialEq, Debug, Copy, Clone)]
235pub struct RegionStart(usize);
236
237impl Deref for RegionStart {
238    type Target = usize;
239
240    fn deref(&self) -> &Self::Target {
241        &self.0
242    }
243}
244
245impl From<usize> for RegionStart {
246    fn from(value: usize) -> Self {
247        Self(value)
248    }
249}
250
251/// Errors related to the PLONK table.
252#[derive(Error, Copy, Clone, Debug)]
253pub enum TableError {
254    /// Unexpected column type when Fixed was expected.
255    #[error("Expected Any::Fixed. Got {0:?}")]
256    ExpectedFixed(Any),
257    /// Unexpected column type when Advice was expected.
258    #[error("Expected Any::Advice. Got {0:?}")]
259    ExpectedAdvice(Any),
260    /// Unexpected column type when Instance was expected.
261    #[error("Expected Any::Instance. Got {0:?}")]
262    ExpectedInstance(Any),
263}