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;
8
9use crate::{
10    error::Error,
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(Debug, 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 ColumnType for Any {
34    fn query_cell<F: Field, E: ExprBuilder<F>>(&self, index: usize, at: Rotation) -> E {
35        match self {
36            Any::Fixed => Fixed.query_cell(index, at),
37            Any::Advice => Advice.query_cell(index, at),
38            Any::Instance => Instance.query_cell(index, at),
39        }
40    }
41}
42
43impl ColumnType for Fixed {
44    fn query_cell<F: Field, E: ExprBuilder<F>>(&self, index: usize, at: Rotation) -> E {
45        E::FixedQuery::query_expr(index, at)
46    }
47}
48
49impl ColumnType for Advice {
50    fn query_cell<F: Field, E: ExprBuilder<F>>(&self, index: usize, at: Rotation) -> E {
51        E::AdviceQuery::query_expr(index, at)
52    }
53}
54
55impl ColumnType for Instance {
56    fn query_cell<F: Field, E: ExprBuilder<F>>(&self, index: usize, at: Rotation) -> E {
57        E::InstanceQuery::query_expr(index, at)
58    }
59}
60
61/// A column with a type.
62#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
63pub struct Column<C: ColumnType> {
64    index: usize,
65    column_type: C,
66}
67
68impl<C: ColumnType> Column<C> {
69    /// Creates a new column.
70    pub fn new(index: usize, column_type: C) -> Self {
71        Self { index, column_type }
72    }
73
74    /// Returns the index of a column.
75    pub fn index(&self) -> usize {
76        self.index
77    }
78
79    /// Returns the column type.
80    pub fn column_type(&self) -> &C {
81        &self.column_type
82    }
83
84    /// Creates an expression representing a query to a cell in this column.
85    pub fn query_cell<F: Field, E: ExprBuilder<F>>(&self, at: Rotation) -> E {
86        self.column_type.query_cell(self.index, at)
87    }
88}
89
90impl From<Column<Fixed>> for Column<Any> {
91    fn from(value: Column<Fixed>) -> Self {
92        Self {
93            index: value.index,
94            column_type: Any::Fixed,
95        }
96    }
97}
98
99impl TryFrom<Column<Any>> for Column<Fixed> {
100    type Error = Error;
101
102    fn try_from(value: Column<Any>) -> Result<Self, Self::Error> {
103        match value.column_type {
104            Any::Fixed => Ok(Self {
105                index: value.index,
106                column_type: Fixed,
107            }),
108            c => Err(Error::ExpectedFixed(c)),
109        }
110    }
111}
112
113impl From<Column<Advice>> for Column<Any> {
114    fn from(value: Column<Advice>) -> Self {
115        Self {
116            index: value.index,
117            column_type: Any::Advice,
118        }
119    }
120}
121
122impl TryFrom<Column<Any>> for Column<Advice> {
123    type Error = Error;
124
125    fn try_from(value: Column<Any>) -> Result<Self, Self::Error> {
126        match value.column_type {
127            Any::Advice => Ok(Self {
128                index: value.index,
129                column_type: Advice,
130            }),
131            c => Err(Error::ExpectedAdvice(c)),
132        }
133    }
134}
135
136impl From<Column<Instance>> for Column<Any> {
137    fn from(value: Column<Instance>) -> Self {
138        Self {
139            index: value.index,
140            column_type: Any::Instance,
141        }
142    }
143}
144
145impl TryFrom<Column<Any>> for Column<Instance> {
146    type Error = Error;
147
148    fn try_from(value: Column<Any>) -> Result<Self, Self::Error> {
149        match value.column_type {
150            Any::Instance => Ok(Self {
151                index: value.index,
152                column_type: Instance,
153            }),
154            c => Err(Error::ExpectedInstance(c)),
155        }
156    }
157}
158
159/// Represents a cell in the table.
160#[derive(Debug, PartialEq, Eq, Copy, Clone)]
161pub struct Cell {
162    /// The index of the region this cell belongs to.
163    pub region_index: RegionIndex,
164    /// Offset relative to the region of the cell's row.
165    pub row_offset: usize,
166    /// The cell's column.
167    pub column: Column<Any>,
168}
169
170/// Replacement type for Halo2's `Rotation` type.
171pub type Rotation = i32;
172
173/// Extension methods for [`Rotation`].
174pub trait RotationExt {
175    /// Returns the current row.
176    fn cur() -> Self;
177
178    /// Returns the next row.
179    fn next() -> Self;
180
181    /// Returns the previous row.
182    fn prev() -> Self;
183}
184
185impl RotationExt for Rotation {
186    fn cur() -> Self {
187        0
188    }
189
190    fn next() -> Self {
191        1
192    }
193
194    fn prev() -> Self {
195        -1
196    }
197}
198
199/// Replacement for Halo2's `RegionIndex` type.
200#[derive(Eq, Hash, PartialEq, Debug, Copy, Clone)]
201pub struct RegionIndex(usize);
202
203impl Deref for RegionIndex {
204    type Target = usize;
205
206    fn deref(&self) -> &Self::Target {
207        &self.0
208    }
209}
210
211impl From<usize> for RegionIndex {
212    fn from(value: usize) -> Self {
213        Self(value)
214    }
215}