1use crate::{
5 expressions::{FoldingColumnTrait, FoldingCompatibleExpr, FoldingCompatibleExprInner},
6 instance_witness::Instance,
7 ExpExtension, FoldingConfig, Radix2EvaluationDomain, RelaxedInstance, RelaxedWitness,
8};
9use ark_ec::AffineRepr;
10use ark_ff::{Field, Zero};
11use ark_poly::Evaluations;
12use core::ops::Index;
13use kimchi::circuits::{expr::Variable, gate::CurrOrNext};
14
15#[cfg(not(test))]
16use log::debug;
17#[cfg(test)]
18use std::println as debug;
19
20#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
26pub enum Column {
27 X(usize),
28 Selector(usize),
29}
30
31impl FoldingColumnTrait for Column {
37 fn is_witness(&self) -> bool {
38 match self {
39 Column::X(_) => true,
40 Column::Selector(_) => false,
41 }
42 }
43}
44
45pub struct Provider<C: FoldingConfig> {
50 pub instance: C::Instance,
51 pub witness: C::Witness,
52}
53
54impl<C: FoldingConfig> Provider<C> {
55 pub fn new(instance: C::Instance, witness: C::Witness) -> Self {
56 Self { instance, witness }
57 }
58}
59
60pub struct ExtendedProvider<C: FoldingConfig> {
61 pub inner_provider: Provider<C>,
62 pub instance: RelaxedInstance<<C as FoldingConfig>::Curve, <C as FoldingConfig>::Instance>,
63 pub witness: RelaxedWitness<<C as FoldingConfig>::Curve, <C as FoldingConfig>::Witness>,
64}
65
66impl<C: FoldingConfig> ExtendedProvider<C> {
67 pub fn new(
68 instance: RelaxedInstance<C::Curve, C::Instance>,
69 witness: RelaxedWitness<C::Curve, C::Witness>,
70 ) -> Self {
71 let inner_provider = {
72 let instance = instance.extended_instance.instance.clone();
73 let witness = witness.extended_witness.witness.clone();
74 Provider::new(instance, witness)
75 };
76 Self {
77 inner_provider,
78 instance,
79 witness,
80 }
81 }
82}
83
84pub trait Provide<C: FoldingConfig> {
85 fn resolve(
86 &self,
87 inner: FoldingCompatibleExprInner<C>,
88 domain: Radix2EvaluationDomain<<C::Curve as AffineRepr>::ScalarField>,
89 ) -> Vec<<C::Curve as AffineRepr>::ScalarField>;
90}
91
92impl<C: FoldingConfig> Provide<C> for Provider<C>
93where
94 C::Witness: Index<
95 C::Column,
96 Output = Evaluations<
97 <C::Curve as AffineRepr>::ScalarField,
98 Radix2EvaluationDomain<<C::Curve as AffineRepr>::ScalarField>,
99 >,
100 >,
101 C::Witness: Index<
102 C::Selector,
103 Output = Evaluations<
104 <C::Curve as AffineRepr>::ScalarField,
105 Radix2EvaluationDomain<<C::Curve as AffineRepr>::ScalarField>,
106 >,
107 >,
108 C::Instance: Index<C::Challenge, Output = <C::Curve as AffineRepr>::ScalarField>,
109{
110 fn resolve(
111 &self,
112 inner: FoldingCompatibleExprInner<C>,
113 domain: Radix2EvaluationDomain<<C::Curve as AffineRepr>::ScalarField>,
114 ) -> Vec<<C::Curve as AffineRepr>::ScalarField> {
115 let domain_size = domain.size as usize;
116 match inner {
117 FoldingCompatibleExprInner::Constant(c) => {
118 vec![c; domain_size]
119 }
120 FoldingCompatibleExprInner::Challenge(chal) => {
121 let v = self.instance[chal];
122 vec![v; domain_size]
123 }
124 FoldingCompatibleExprInner::Cell(var) => {
125 let Variable { col, row } = var;
126
127 let col = &self.witness[col].evals;
128
129 let mut col = col.clone();
130 if let CurrOrNext::Next = row {
132 col.rotate_left(1);
133 }
134 col
135 }
136 FoldingCompatibleExprInner::Extensions(_) => {
137 panic!("not handled here");
138 }
139 }
140 }
141}
142
143impl<C: FoldingConfig> Provide<C> for ExtendedProvider<C>
144where
145 C::Witness: Index<
146 C::Column,
147 Output = Evaluations<
148 <C::Curve as AffineRepr>::ScalarField,
149 Radix2EvaluationDomain<<C::Curve as AffineRepr>::ScalarField>,
150 >,
151 >,
152 C::Witness: Index<
153 C::Selector,
154 Output = Evaluations<
155 <C::Curve as AffineRepr>::ScalarField,
156 Radix2EvaluationDomain<<C::Curve as AffineRepr>::ScalarField>,
157 >,
158 >,
159 C::Instance: Index<C::Challenge, Output = <C::Curve as AffineRepr>::ScalarField>,
160{
161 fn resolve(
162 &self,
163 inner: FoldingCompatibleExprInner<C>,
164 domain: Radix2EvaluationDomain<<C::Curve as AffineRepr>::ScalarField>,
165 ) -> Vec<<C::Curve as AffineRepr>::ScalarField> {
166 match inner {
167 FoldingCompatibleExprInner::Extensions(ext) => match ext {
168 ExpExtension::U => {
169 let u = self.instance.u;
170 let domain_size = domain.size as usize;
171 vec![u; domain_size]
172 }
173 ExpExtension::Error => self.witness.error_vec.evals.clone(),
174 ExpExtension::ExtendedWitness(i) => self
175 .witness
176 .extended_witness
177 .extended
178 .get(&i)
179 .unwrap()
180 .evals
181 .clone(),
182 ExpExtension::Alpha(i) => {
183 let alpha = self
184 .instance
185 .extended_instance
186 .instance
187 .get_alphas()
188 .get(i)
189 .unwrap();
190 let domain_size = domain.size as usize;
191 vec![alpha; domain_size]
192 }
193 ExpExtension::Selector(s) => {
194 let col = &self.inner_provider.witness[s].evals;
195 col.clone()
196 }
197 },
198 e => self.inner_provider.resolve(e, domain),
199 }
200 }
201}
202
203pub trait Checker<C: FoldingConfig>: Provide<C> {
204 fn check_rec(
205 &self,
206 exp: FoldingCompatibleExpr<C>,
207 domain: Radix2EvaluationDomain<<C::Curve as AffineRepr>::ScalarField>,
208 ) -> Vec<<C::Curve as AffineRepr>::ScalarField> {
209 let e2 = exp.clone();
210 let res = match exp {
211 FoldingCompatibleExpr::Atom(inner) => self.resolve(inner, domain),
212 FoldingCompatibleExpr::Double(e) => {
213 let v = self.check_rec(*e, domain);
214 v.into_iter().map(|x| x.double()).collect()
215 }
216 FoldingCompatibleExpr::Square(e) => {
217 let v = self.check_rec(*e, domain);
218 v.into_iter().map(|x| x.square()).collect()
219 }
220 FoldingCompatibleExpr::Add(e1, e2) => {
221 let v1 = self.check_rec(*e1, domain);
222 let v2 = self.check_rec(*e2, domain);
223 v1.into_iter().zip(v2).map(|(a, b)| a + b).collect()
224 }
225 FoldingCompatibleExpr::Sub(e1, e2) => {
226 let v1 = self.check_rec(*e1, domain);
227 let v2 = self.check_rec(*e2, domain);
228 v1.into_iter().zip(v2).map(|(a, b)| a - b).collect()
229 }
230 FoldingCompatibleExpr::Mul(e1, e2) => {
231 let v1 = self.check_rec(*e1, domain);
232 let v2 = self.check_rec(*e2, domain);
233 v1.into_iter().zip(v2).map(|(a, b)| a * b).collect()
234 }
235 FoldingCompatibleExpr::Pow(e, exp) => {
236 let v = self.check_rec(*e, domain);
237 v.into_iter().map(|x| x.pow([exp])).collect()
238 }
239 };
240 debug!("exp: {:?}", e2);
241 debug!("res: [\n");
242 for e in res.iter() {
243 debug!("{e}\n");
244 }
245 debug!("]");
246 res
247 }
248
249 fn check(
250 &self,
251 exp: &FoldingCompatibleExpr<C>,
252 domain: Radix2EvaluationDomain<<C::Curve as AffineRepr>::ScalarField>,
253 ) {
254 let res = self.check_rec(exp.clone(), domain);
255 for (i, row) in res.iter().enumerate() {
256 if !row.is_zero() {
257 panic!("check in row {i} failed, {row} != 0");
258 }
259 }
260 }
261}