ivc/
expr_eval.rs

1use crate::plonkish_lang::{CombinableEvals, PlonkishChallenge, PlonkishWitnessGeneric};
2use ark_ec::AffineRepr;
3use ark_ff::Field;
4use ark_poly::{Evaluations, Radix2EvaluationDomain as R2D};
5use core::ops::Index;
6use folding::{
7    columns::ExtendedFoldingColumn,
8    eval_leaf::EvalLeaf,
9    expressions::{ExpExtension, FoldingCompatibleExprInner, FoldingExp},
10    instance_witness::ExtendedWitness,
11    Alphas, FoldingCompatibleExpr, FoldingConfig,
12};
13use kimchi::{
14    self,
15    circuits::{expr::Variable, gate::CurrOrNext},
16    curve::KimchiCurve,
17};
18use kimchi_msm::columns::Column as GenericColumn;
19use strum::EnumCount;
20
21#[derive(Clone)]
22/// Generic structure containing column vectors.
23pub struct GenericVecStructure<G: KimchiCurve>(pub Vec<Vec<G::ScalarField>>);
24
25impl<G: KimchiCurve> Index<GenericColumn<usize>> for GenericVecStructure<G> {
26    type Output = [G::ScalarField];
27
28    fn index(&self, index: GenericColumn<usize>) -> &Self::Output {
29        match index {
30            GenericColumn::FixedSelector(i) => &self.0[i],
31            _ => panic!("should not happen"),
32        }
33    }
34}
35
36/// Minimal environment needed for evaluating constraints.
37pub struct GenericEvalEnv<
38    Curve: KimchiCurve,
39    const N_COL: usize,
40    const N_FSEL: usize,
41    Eval: CombinableEvals<Curve::ScalarField>,
42> {
43    pub ext_witness:
44        ExtendedWitness<Curve, PlonkishWitnessGeneric<N_COL, N_FSEL, Curve::ScalarField, Eval>>,
45    pub alphas: Alphas<Curve::ScalarField>,
46    pub challenges: [Curve::ScalarField; PlonkishChallenge::COUNT],
47    pub error_vec: Eval,
48    /// The scalar `u` that is used to homogenize the polynomials
49    pub u: Curve::ScalarField,
50}
51
52pub type SimpleEvalEnv<Curve, const N_COL: usize, const N_FSEL: usize> = GenericEvalEnv<
53    Curve,
54    N_COL,
55    N_FSEL,
56    Evaluations<<Curve as AffineRepr>::ScalarField, R2D<<Curve as AffineRepr>::ScalarField>>,
57>;
58
59impl<
60        Curve: KimchiCurve,
61        const N_COL: usize,
62        const N_FSEL: usize,
63        Evals: CombinableEvals<Curve::ScalarField>,
64    > GenericEvalEnv<Curve, N_COL, N_FSEL, Evals>
65{
66    fn challenge(&self, challenge: PlonkishChallenge) -> Curve::ScalarField {
67        match challenge {
68            PlonkishChallenge::Beta => self.challenges[0],
69            PlonkishChallenge::Gamma => self.challenges[1],
70            PlonkishChallenge::JointCombiner => self.challenges[2],
71        }
72    }
73
74    pub fn process_extended_folding_column<
75        FC: FoldingConfig<Column = GenericColumn<usize>, Curve = Curve, Challenge = PlonkishChallenge>,
76    >(
77        &self,
78        col: &ExtendedFoldingColumn<FC>,
79    ) -> EvalLeaf<Curve::ScalarField> {
80        use EvalLeaf::Col;
81        use ExtendedFoldingColumn::*;
82        match col {
83                Inner(Variable { col, row }) => {
84                    let wit = match row {
85                        CurrOrNext::Curr => &self.ext_witness.witness,
86                        CurrOrNext::Next => panic!("not implemented"),
87                    };
88                    // The following is possible because Index is implemented for our
89                    // circuit witnesses
90                    Col(&wit[*col])
91                },
92                WitnessExtended(i) => Col(&self.ext_witness.extended.get(i).unwrap().evals),
93                Error => panic!("shouldn't happen"),
94                Constant(c) => EvalLeaf::Const(*c),
95                Challenge(chall) => EvalLeaf::Const(self.challenge(*chall)),
96                Alpha(i) => {
97                    let alpha = self.alphas.get(*i).expect("alpha not present");
98                    EvalLeaf::Const(alpha)
99                }
100                Selector(_s) => unimplemented!("Selector not implemented for FoldingEnvironment. No selectors are supposed to be used when it is Plonkish relations."),
101        }
102    }
103
104    /// Evaluates the expression in the provided side
105    pub fn eval_naive_fexpr<
106        'a,
107        FC: FoldingConfig<Column = GenericColumn<usize>, Curve = Curve, Challenge = PlonkishChallenge>,
108    >(
109        &'a self,
110        exp: &FoldingExp<FC>,
111    ) -> EvalLeaf<'a, Curve::ScalarField> {
112        use FoldingExp::*;
113
114        match exp {
115            Atom(column) => self.process_extended_folding_column(column),
116            Double(e) => {
117                let col = self.eval_naive_fexpr(e);
118                col.map(Field::double, |f| {
119                    Field::double_in_place(f);
120                })
121            }
122            Square(e) => {
123                let col = self.eval_naive_fexpr(e);
124                col.map(Field::square, |f| {
125                    Field::square_in_place(f);
126                })
127            }
128            Add(e1, e2) => self.eval_naive_fexpr(e1) + self.eval_naive_fexpr(e2),
129            Sub(e1, e2) => self.eval_naive_fexpr(e1) - self.eval_naive_fexpr(e2),
130            Mul(e1, e2) => self.eval_naive_fexpr(e1) * self.eval_naive_fexpr(e2),
131            Pow(_e, _i) => panic!("We're not supposed to use this"),
132        }
133    }
134
135    /// For FoldingCompatibleExp
136    pub fn eval_naive_fcompat<
137        'a,
138        FC: FoldingConfig<Column = GenericColumn<usize>, Curve = Curve, Challenge = PlonkishChallenge>,
139    >(
140        &'a self,
141        exp: &FoldingCompatibleExpr<FC>,
142    ) -> EvalLeaf<'a, Curve::ScalarField> where {
143        use FoldingCompatibleExpr::*;
144
145        match exp {
146            Atom(column) => {
147                use FoldingCompatibleExprInner::*;
148                match column {
149                    Cell(Variable { col, row }) => {
150                        let wit = match row {
151                            CurrOrNext::Curr => &self.ext_witness.witness,
152                            CurrOrNext::Next => panic!("not implemented"),
153                        };
154                        // The following is possible because Index is implemented for our
155                        // circuit witnesses
156                        EvalLeaf::Col(&wit[*col])
157                    }
158                    Challenge(chal) => EvalLeaf::Const(self.challenge(*chal)),
159                    Constant(c) => EvalLeaf::Const(*c),
160                    Extensions(ext) => {
161                        use ExpExtension::*;
162                        match ext {
163                            U => EvalLeaf::Const(self.u),
164                            Error => EvalLeaf::Col(self.error_vec.e_as_slice()),
165                            ExtendedWitness(i) => {
166                                EvalLeaf::Col(&self.ext_witness.extended.get(i).unwrap().evals)
167                            }
168                            Alpha(i) => EvalLeaf::Const(self.alphas.get(*i).unwrap()),
169                            Selector(_sel) => panic!("No selectors supported yet"),
170                        }
171                    }
172                }
173            }
174            Double(e) => {
175                let col = self.eval_naive_fcompat(e);
176                col.map(Field::double, |f| {
177                    Field::double_in_place(f);
178                })
179            }
180            Square(e) => {
181                let col = self.eval_naive_fcompat(e);
182                col.map(Field::square, |f| {
183                    Field::square_in_place(f);
184                })
185            }
186            Add(e1, e2) => self.eval_naive_fcompat(e1) + self.eval_naive_fcompat(e2),
187            Sub(e1, e2) => self.eval_naive_fcompat(e1) - self.eval_naive_fcompat(e2),
188            Mul(e1, e2) => self.eval_naive_fcompat(e1) * self.eval_naive_fcompat(e2),
189            Pow(_e, _i) => panic!("We're not supposed to use this"),
190        }
191    }
192}