Skip to main content

haloumi_core/
slot.rs

1//! Types related to inputs, outputs, and other locations in the circuit.
2
3use std::fmt;
4
5use crate::{
6    eqv::{EqvRelation, SymbolicEqv},
7    slot::{arg::ArgNo, cell::CellRef, output::OutputId},
8};
9
10pub mod arg;
11pub mod cell;
12pub mod output;
13
14/// A slot represents storage locations in a circuit.
15///
16/// A slot can represent IO (Arg, Output, Challenge, ...) or cells in the PLONK table
17/// (Advice, Fixed, TableLookup).
18#[derive(Clone, Copy, Hash, Eq, PartialEq, PartialOrd, Ord)]
19pub enum Slot {
20    /// Points to the n-th input argument
21    Arg(ArgNo),
22    /// Points to the n-th output.
23    Output(OutputId),
24    /// Points to an advice cell.
25    Advice(CellRef),
26    /// Points to a fixed cell.
27    Fixed(CellRef),
28    /// lookup id, column, row, idx, region_idx
29    TableLookup(u64, usize, usize, usize, usize),
30    /// call output: (call #, output #)
31    CallOutput(usize, usize),
32    /// Temporary value
33    Temp(usize),
34    /// Challenge argument (index, phase, n-th arg)
35    Challenge(usize, u8, ArgNo),
36}
37
38impl Slot {
39    /// Creates the [`Slot::Advice`] case using absolute coordinates.
40    ///
41    /// See [`CellRef::absolute`] for more details.
42    pub fn advice_abs(col: usize, row: usize) -> Self {
43        Self::Advice(CellRef::absolute(col, row))
44    }
45
46    /// Creates the [`Slot::Advice`] case using relative coordinates.
47    ///
48    /// See [`CellRef::relative`] for more details.
49    pub fn advice_rel(col: usize, base: usize, offset: usize) -> Self {
50        Self::Advice(CellRef::relative(col, base, offset))
51    }
52
53    /// Creates the [`Slot::Fixed`] case using absolute coordinates.
54    ///
55    /// See [`CellRef::absolute`] for more details.
56    pub fn fixed_abs(col: usize, row: usize) -> Self {
57        Self::Fixed(CellRef::absolute(col, row))
58    }
59
60    /// Creates the [`Slot::Fixed`] case using relative coordinates.
61    ///
62    /// See [`CellRef::relative`] for more details.
63    pub fn fixed_rel(col: usize, base: usize, offset: usize) -> Self {
64        Self::Fixed(CellRef::relative(col, base, offset))
65    }
66}
67
68impl EqvRelation<Slot> for SymbolicEqv {
69    /// Two Slots are symbolically equivalent if they refer to the same data regardless of how is
70    /// pointed to.
71    ///
72    /// Arguments and fields:  equivalent if they refer to the same offset.
73    /// Advice and fixed cells: equivalent if they point to the same cell relative to their base.
74    /// Table lookups: equivalent if they point to the same column and row.
75    /// Call outputs: equivalent if they have the same output number.
76    fn equivalent(lhs: &Slot, rhs: &Slot) -> bool {
77        match (lhs, rhs) {
78            (Slot::Arg(lhs), Slot::Arg(rhs)) => lhs == rhs,
79            (Slot::Output(lhs), Slot::Output(rhs)) => lhs == rhs,
80            (Slot::Advice(lhs), Slot::Advice(rhs)) => Self::equivalent(lhs, rhs),
81            (Slot::Fixed(lhs), Slot::Fixed(rhs)) => Self::equivalent(lhs, rhs),
82            (Slot::TableLookup(_, col0, row0, _, _), Slot::TableLookup(_, col1, row1, _, _)) => {
83                col0 == col1 && row0 == row1
84            }
85            (Slot::CallOutput(_, o0), Slot::CallOutput(_, o1)) => o0 == o1,
86            (Slot::Temp(lhs), Slot::Temp(rhs)) => lhs == rhs,
87            (
88                Slot::Challenge(lhs_index, lhs_phase, _),
89                Slot::Challenge(rhs_index, rhs_phase, _),
90            ) => lhs_index == rhs_index && lhs_phase == rhs_phase,
91            _ => false,
92        }
93    }
94}
95
96impl std::fmt::Debug for Slot {
97    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
98        match self {
99            Self::Arg(arg) => write!(f, "{arg:?}"),
100            Self::Output(field) => write!(f, "{field:?}"),
101            Self::Advice(c) => write!(f, "adv{c:?}"),
102            Self::Fixed(c) => write!(f, "fix{c:?}"),
103            Self::TableLookup(id, col, row, idx, region_idx) => {
104                write!(f, "lookup{id}[{col},{row}]@({idx},{region_idx})")
105            }
106            Self::CallOutput(call, out) => write!(f, "call{call}->{out}"),
107            Self::Temp(id) => write!(f, "t{}", *id),
108            Self::Challenge(index, phase, _) => write!(f, "challenge{index}@{phase}"),
109        }
110    }
111}
112
113impl std::fmt::Display for Slot {
114    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115        match self {
116            Self::Arg(arg) => write!(f, "{arg}"),
117            Self::Output(field) => write!(f, "{field}"),
118            Self::Advice(c) => write!(f, "adv{c}"),
119            Self::Fixed(c) => write!(f, "fix{c}"),
120            Self::TableLookup(id, col, row, idx, region_idx) => {
121                write!(f, "lookup{id}[{col},{row}]@({idx},{region_idx})")
122            }
123            Self::CallOutput(call, out) => write!(f, "call{call}->{out}"),
124            Self::Temp(id) => write!(f, "t{}", *id),
125            Self::Challenge(index, phase, _) => write!(f, "challenge{index}@{phase}"),
126        }
127    }
128}
129
130impl From<ArgNo> for Slot {
131    fn from(value: ArgNo) -> Self {
132        Self::Arg(value)
133    }
134}
135
136impl From<OutputId> for Slot {
137    fn from(value: OutputId) -> Self {
138        Self::Output(value)
139    }
140}