kimchi_msm/circuit_design/
capabilities.rs

1/// Provides generic environment traits that allow manipulating columns and
2/// requesting lookups.
3///
4/// Every trait implies two categories of implementations:
5/// constraint ones (that operate over expressions, building a
6/// circuit), and witness ones (that operate over values, building
7/// values for the circuit).
8use crate::{columns::ColumnIndexer, logup::LookupTableID};
9use ark_ff::PrimeField;
10
11/// Environment capability for accessing and reading columns. This is necessary for
12/// building constraints.
13pub trait ColAccessCap<F: PrimeField, CIx: ColumnIndexer<usize>> {
14    // NB: 'static here means that `Variable` does not contain any
15    // references with a lifetime less than 'static. Which is true in
16    // our case. Necessary for `set_assert_mapper`
17    type Variable: Clone
18        + std::ops::Add<Self::Variable, Output = Self::Variable>
19        + std::ops::Sub<Self::Variable, Output = Self::Variable>
20        + std::ops::Mul<Self::Variable, Output = Self::Variable>
21        + std::ops::Neg<Output = Self::Variable>
22        + From<u64>
23        + std::fmt::Debug
24        + 'static;
25
26    /// Asserts that the value is zero.
27    fn assert_zero(&mut self, cst: Self::Variable);
28
29    /// Sets an assert predicate `f(X)` such that when assert_zero is
30    /// called on x, it will actually perform `assert_zero(f(x))`.
31    fn set_assert_mapper(&mut self, mapper: Box<dyn Fn(Self::Variable) -> Self::Variable>);
32
33    /// Reads value from a column position.
34    fn read_column(&self, col: CIx) -> Self::Variable;
35
36    /// Turns a constant value into a variable.
37    fn constant(value: F) -> Self::Variable;
38}
39
40/// Environment capability similar to `ColAccessCap` but for /also
41/// writing/ columns. Used on the witness side.
42pub trait ColWriteCap<F: PrimeField, CIx: ColumnIndexer<usize>>
43where
44    Self: ColAccessCap<F, CIx>,
45{
46    fn write_column(&mut self, col: CIx, value: &Self::Variable);
47}
48
49/// Capability for invoking table lookups.
50pub trait LookupCap<F: PrimeField, CIx: ColumnIndexer<usize>, LT: LookupTableID>
51where
52    Self: ColAccessCap<F, CIx>,
53{
54    /// Look up (read) value from a lookup table.
55    fn lookup(&mut self, lookup_id: LT, value: Vec<Self::Variable>);
56
57    /// Write a value into a runtime table. Panics if called on a fixed table.
58    fn lookup_runtime_write(&mut self, lookup_id: LT, value: Vec<Self::Variable>);
59}
60
61/// Capability for reading and moving forward in a multirow fashion.
62/// Holds a "current" row that can be moved forward with `next_row`.
63/// The `ColWriteCap` and `ColAccessCap` reason in terms of current
64/// row. The two other methods can be used to read/write previous.
65pub trait MultiRowReadCap<F: PrimeField, CIx: ColumnIndexer<usize>>
66where
67    Self: ColWriteCap<F, CIx>,
68{
69    /// Read value from a (row,column) position.
70    fn read_row_column(&mut self, row: usize, col: CIx) -> Self::Variable;
71
72    /// Progresses to the next row.
73    fn next_row(&mut self);
74
75    /// Returns the current row.
76    fn curr_row(&self) -> usize;
77}
78
79// TODO this trait is very powerful. It basically abstract
80// WitnessBuilderEnv (and other, similar environments). Nothing
81// similar can be implemented for constraint building envs.
82//
83// Where possible, do your computation over Variable or directly via
84// F-typed inputs to a function.
85/// A direct field access capability modelling an abstract witness
86/// builder. Not for constraint building.
87pub trait DirectWitnessCap<F: PrimeField, CIx: ColumnIndexer<usize>>
88where
89    Self: MultiRowReadCap<F, CIx>,
90{
91    /// Convert an abstract variable to a field element! Inverse of Env::constant().
92    fn variable_to_field(value: Self::Variable) -> F;
93}
94
95////////////////////////////////////////////////////////////////////////////
96// Hybrid capabilities
97////////////////////////////////////////////////////////////////////////////
98
99/// Capability for computing arithmetic functions and enforcing
100/// constraints simultaneously.
101///
102/// The "hybrid" in the name of the trait (and other traits here)
103/// means "maybe".
104///
105/// That is, it allows computations which /might be/ no-ops (even
106/// partially) in the constraint builder case. For example, "hcopy",
107/// despite its name, does not do any "write", so hcopy !=>
108/// write_column.
109pub trait HybridCopyCap<F: PrimeField, CIx: ColumnIndexer<usize>>
110where
111    Self: ColAccessCap<F, CIx>,
112{
113    /// Given variable `x` and position `ix`, it (hybrid) writes `x`
114    /// into `ix`, and returns the value.
115    fn hcopy(&mut self, x: &Self::Variable, ix: CIx) -> Self::Variable;
116}
117
118////////////////////////////////////////////////////////////////////////////
119// Helpers
120////////////////////////////////////////////////////////////////////////////
121
122/// Write an array of values simultaneously.
123pub fn read_column_array<F, Env, const ARR_N: usize, CIx: ColumnIndexer<usize>, ColMap>(
124    env: &mut Env,
125    column_map: ColMap,
126) -> [Env::Variable; ARR_N]
127where
128    F: PrimeField,
129    Env: ColAccessCap<F, CIx>,
130    ColMap: Fn(usize) -> CIx,
131{
132    core::array::from_fn(|i| env.read_column(column_map(i)))
133}
134
135/// Write a field element directly as a constant.
136pub fn write_column_const<F, Env, CIx: ColumnIndexer<usize>>(env: &mut Env, col: CIx, var: &F)
137where
138    F: PrimeField,
139    Env: ColWriteCap<F, CIx>,
140{
141    env.write_column(col, &Env::constant(*var));
142}
143
144/// Write an array of values simultaneously.
145pub fn write_column_array<F, Env, const ARR_N: usize, CIx: ColumnIndexer<usize>, ColMap>(
146    env: &mut Env,
147    input: [Env::Variable; ARR_N],
148    column_map: ColMap,
149) where
150    F: PrimeField,
151    Env: ColWriteCap<F, CIx>,
152    ColMap: Fn(usize) -> CIx,
153{
154    input.iter().enumerate().for_each(|(i, var)| {
155        env.write_column(column_map(i), var);
156    })
157}
158
159/// Write an array of /field/ values simultaneously.
160pub fn write_column_array_const<F, Env, const ARR_N: usize, CIx: ColumnIndexer<usize>, ColMap>(
161    env: &mut Env,
162    input: &[F; ARR_N],
163    column_map: ColMap,
164) where
165    F: PrimeField,
166    Env: ColWriteCap<F, CIx>,
167    ColMap: Fn(usize) -> CIx,
168{
169    input.iter().enumerate().for_each(|(i, var)| {
170        env.write_column(column_map(i), &Env::constant(*var));
171    })
172}