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}