Skip to main content

kimchi/circuits/
expr.rs

1use crate::{
2    circuits::{
3        berkeley_columns,
4        berkeley_columns::BerkeleyChallengeTerm,
5        constraints::FeatureFlags,
6        domains::Domain,
7        gate::CurrOrNext,
8        lookup::lookups::{LookupPattern, LookupPatterns},
9        polynomials::{
10            foreign_field_common::KimchiForeignElement, permutation::eval_vanishes_on_last_n_rows,
11        },
12    },
13    collections::{HashMap, HashSet},
14    proof::PointEvaluations,
15};
16use alloc::{
17    boxed::Box,
18    format,
19    string::{String, ToString},
20    vec,
21    vec::Vec,
22};
23use ark_ff::{FftField, Field, One, PrimeField, Zero};
24use ark_poly::{
25    univariate::DensePolynomial, EvaluationDomain, Evaluations, Radix2EvaluationDomain as D,
26};
27use core::{
28    cmp::Ordering,
29    fmt,
30    fmt::{Debug, Display},
31    iter::FromIterator,
32    ops::{Add, AddAssign, Index, Mul, MulAssign, Neg, Sub},
33};
34use itertools::Itertools;
35use o1_utils::{field_helpers::pows, foreign_field::ForeignFieldHelpers, FieldHelpers};
36#[cfg(feature = "parallel")]
37use rayon::prelude::*;
38use serde::{Deserialize, Serialize};
39use thiserror::Error;
40use CurrOrNext::{Curr, Next};
41
42use self::constraints::ExprOps;
43
44#[derive(Debug, Error)]
45pub enum ExprError<Column> {
46    #[error("Empty stack")]
47    EmptyStack,
48
49    #[error("Lookup should not have been used")]
50    LookupShouldNotBeUsed,
51
52    #[error("Linearization failed (needed {0:?} evaluated at the {1:?} row")]
53    MissingEvaluation(Column, CurrOrNext),
54
55    #[error("Cannot get index evaluation {0:?} (should have been linearized away)")]
56    MissingIndexEvaluation(Column),
57
58    #[error("Linearization failed (too many unevaluated columns: {0:?}")]
59    FailedLinearization(Vec<Variable<Column>>),
60
61    #[error("runtime table not available")]
62    MissingRuntime,
63}
64
65/// The Challenge term that contains an alpha.
66/// Is used to make a random linear combination of constraints
67pub trait AlphaChallengeTerm<'a>:
68    Copy + Clone + Debug + PartialEq + Eq + Serialize + Deserialize<'a> + Display
69{
70    const ALPHA: Self;
71}
72
73/// The collection of constants required to evaluate an `Expr`.
74#[derive(Clone)]
75pub struct Constants<F: 'static> {
76    /// The endomorphism coefficient
77    pub endo_coefficient: F,
78    /// The MDS matrix
79    pub mds: &'static [[F; 3]; 3],
80    /// The number of zero-knowledge rows
81    pub zk_rows: u64,
82}
83
84pub trait ColumnEnvironment<
85    'a,
86    F: FftField,
87    ChallengeTerm,
88    Challenges: Index<ChallengeTerm, Output = F>,
89>
90{
91    /// The generic type of column the environment can use.
92    /// In other words, with the multi-variate polynomial analogy, it is the
93    /// variables the multi-variate polynomials are defined upon.
94    /// i.e. for a polynomial `P(X, Y, Z)`, the type will represent the variable
95    /// `X`, `Y` and `Z`.
96    type Column;
97
98    /// Return the evaluation of the given column, over the domain.
99    fn get_column(&self, col: &Self::Column) -> Option<&'a Evaluations<F, D<F>>>;
100
101    /// Defines the domain over which the column is evaluated
102    fn column_domain(&self, col: &Self::Column) -> Domain;
103
104    fn get_domain(&self, d: Domain) -> D<F>;
105
106    /// Return the constants parameters that the expression might use.
107    /// For instance, it can be the matrix used by the linear layer in the
108    /// permutation.
109    fn get_constants(&self) -> &Constants<F>;
110
111    /// Return the challenges, coined by the verifier.
112    fn get_challenges(&self) -> &Challenges;
113
114    fn vanishes_on_zero_knowledge_and_previous_rows(&self) -> &'a Evaluations<F, D<F>>;
115
116    /// Return the value `prod_{j != 1} (1 - omega^j)`, used for efficiently
117    /// computing the evaluations of the unnormalized Lagrange basis polynomials.
118    fn l0_1(&self) -> F;
119}
120
121// In this file, we define...
122//
123//     The unnormalized lagrange polynomial
124//
125//         l_i(x) = (x^n - 1) / (x - omega^i) = prod_{j != i} (x - omega^j)
126//
127//     and the normalized lagrange polynomial
128//
129//         L_i(x) = l_i(x) / l_i(omega^i)
130
131/// Computes `prod_{j != n} (1 - omega^j)`
132///     Assure we don't multiply by (1 - omega^n) = (1 - omega^0) = (1 - 1) = 0
133pub fn l0_1<F: FftField>(d: D<F>) -> F {
134    d.elements()
135        .skip(1)
136        .fold(F::one(), |acc, omega_j| acc * (F::one() - omega_j))
137}
138
139// Compute the ith unnormalized lagrange basis
140pub fn unnormalized_lagrange_basis<F: FftField>(domain: &D<F>, i: i32, pt: &F) -> F {
141    let omega_i = if i < 0 {
142        domain.group_gen.pow([-i as u64]).inverse().unwrap()
143    } else {
144        domain.group_gen.pow([i as u64])
145    };
146    domain.evaluate_vanishing_polynomial(*pt) / (*pt - omega_i)
147}
148
149#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
150/// A type representing a variable which can appear in a constraint. It specifies a column
151/// and a relative position (Curr or Next)
152pub struct Variable<Column> {
153    /// The column of this variable
154    pub col: Column,
155    /// The row (Curr of Next) of this variable
156    pub row: CurrOrNext,
157}
158
159/// Define the constant terms an expression can use.
160/// It can be any constant term (`Literal`), a matrix (`Mds` - used by the
161/// permutation used by Poseidon for instance), or endomorphism coefficients
162/// (`EndoCoefficient` - used as an optimisation).
163/// As for `challengeTerm`, it has been used initially to implement the PLONK
164/// IOP, with the custom gate Poseidon. However, the terms have no built-in
165/// semantic in the expression framework.
166/// TODO: we should generalize the expression type over challenges and constants.
167/// See <https://github.com/MinaProtocol/mina/issues/15287>
168#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
169pub enum ConstantTerm<F> {
170    EndoCoefficient,
171    Mds { row: usize, col: usize },
172    Literal(F),
173}
174
175pub trait Literal: Sized + Clone {
176    type F;
177
178    fn literal(x: Self::F) -> Self;
179
180    fn to_literal(self) -> Result<Self::F, Self>;
181
182    fn to_literal_ref(&self) -> Option<&Self::F>;
183
184    /// Obtains the representation of some constants as a literal.
185    /// This is useful before converting Kimchi expressions with constants
186    /// to folding compatible expressions.
187    fn as_literal(&self, constants: &Constants<Self::F>) -> Self;
188}
189
190impl<F: Field> Literal for F {
191    type F = F;
192
193    fn literal(x: Self::F) -> Self {
194        x
195    }
196
197    fn to_literal(self) -> Result<Self::F, Self> {
198        Ok(self)
199    }
200
201    fn to_literal_ref(&self) -> Option<&Self::F> {
202        Some(self)
203    }
204
205    fn as_literal(&self, _constants: &Constants<Self::F>) -> Self {
206        *self
207    }
208}
209
210impl<F: Clone> Literal for ConstantTerm<F> {
211    type F = F;
212    fn literal(x: Self::F) -> Self {
213        ConstantTerm::Literal(x)
214    }
215    fn to_literal(self) -> Result<Self::F, Self> {
216        match self {
217            ConstantTerm::Literal(x) => Ok(x),
218            x => Err(x),
219        }
220    }
221    fn to_literal_ref(&self) -> Option<&Self::F> {
222        match self {
223            ConstantTerm::Literal(x) => Some(x),
224            _ => None,
225        }
226    }
227    fn as_literal(&self, constants: &Constants<Self::F>) -> Self {
228        match self {
229            ConstantTerm::EndoCoefficient => {
230                ConstantTerm::Literal(constants.endo_coefficient.clone())
231            }
232            ConstantTerm::Mds { row, col } => {
233                ConstantTerm::Literal(constants.mds[*row][*col].clone())
234            }
235            ConstantTerm::Literal(_) => self.clone(),
236        }
237    }
238}
239
240#[derive(Clone, Debug, PartialEq)]
241pub enum ConstantExprInner<F, ChallengeTerm> {
242    Challenge(ChallengeTerm),
243    Constant(ConstantTerm<F>),
244}
245
246impl<'a, F: Clone, ChallengeTerm: AlphaChallengeTerm<'a>> Literal
247    for ConstantExprInner<F, ChallengeTerm>
248{
249    type F = F;
250    fn literal(x: Self::F) -> Self {
251        Self::Constant(ConstantTerm::literal(x))
252    }
253    fn to_literal(self) -> Result<Self::F, Self> {
254        match self {
255            Self::Constant(x) => match x.to_literal() {
256                Ok(x) => Ok(x),
257                Err(x) => Err(Self::Constant(x)),
258            },
259            x => Err(x),
260        }
261    }
262    fn to_literal_ref(&self) -> Option<&Self::F> {
263        match self {
264            Self::Constant(x) => x.to_literal_ref(),
265            _ => None,
266        }
267    }
268    fn as_literal(&self, constants: &Constants<Self::F>) -> Self {
269        match self {
270            Self::Constant(x) => Self::Constant(x.as_literal(constants)),
271            Self::Challenge(_) => self.clone(),
272        }
273    }
274}
275
276impl<'a, F, ChallengeTerm: AlphaChallengeTerm<'a>> From<ChallengeTerm>
277    for ConstantExprInner<F, ChallengeTerm>
278{
279    fn from(x: ChallengeTerm) -> Self {
280        ConstantExprInner::Challenge(x)
281    }
282}
283
284impl<F, ChallengeTerm> From<ConstantTerm<F>> for ConstantExprInner<F, ChallengeTerm> {
285    fn from(x: ConstantTerm<F>) -> Self {
286        ConstantExprInner::Constant(x)
287    }
288}
289
290#[derive(Clone, Debug, PartialEq, Eq, Hash)]
291pub enum Operations<T> {
292    Atom(T),
293    Pow(Box<Self>, u64),
294    Add(Box<Self>, Box<Self>),
295    Mul(Box<Self>, Box<Self>),
296    Sub(Box<Self>, Box<Self>),
297    Double(Box<Self>),
298    Square(Box<Self>),
299    Cache(CacheId, Box<Self>),
300    IfFeature(FeatureFlag, Box<Self>, Box<Self>),
301}
302
303impl<T> From<T> for Operations<T> {
304    fn from(x: T) -> Self {
305        Operations::Atom(x)
306    }
307}
308
309impl<T: Literal + Clone> Literal for Operations<T> {
310    type F = T::F;
311
312    fn literal(x: Self::F) -> Self {
313        Self::Atom(T::literal(x))
314    }
315
316    fn to_literal(self) -> Result<Self::F, Self> {
317        match self {
318            Self::Atom(x) => match x.to_literal() {
319                Ok(x) => Ok(x),
320                Err(x) => Err(Self::Atom(x)),
321            },
322            x => Err(x),
323        }
324    }
325
326    fn to_literal_ref(&self) -> Option<&Self::F> {
327        match self {
328            Self::Atom(x) => x.to_literal_ref(),
329            _ => None,
330        }
331    }
332
333    fn as_literal(&self, constants: &Constants<Self::F>) -> Self {
334        match self {
335            Self::Atom(x) => Self::Atom(x.as_literal(constants)),
336            Self::Pow(x, n) => Self::Pow(Box::new(x.as_literal(constants)), *n),
337            Self::Add(x, y) => Self::Add(
338                Box::new(x.as_literal(constants)),
339                Box::new(y.as_literal(constants)),
340            ),
341            Self::Mul(x, y) => Self::Mul(
342                Box::new(x.as_literal(constants)),
343                Box::new(y.as_literal(constants)),
344            ),
345            Self::Sub(x, y) => Self::Sub(
346                Box::new(x.as_literal(constants)),
347                Box::new(y.as_literal(constants)),
348            ),
349            Self::Double(x) => Self::Double(Box::new(x.as_literal(constants))),
350            Self::Square(x) => Self::Square(Box::new(x.as_literal(constants))),
351            Self::Cache(id, x) => Self::Cache(*id, Box::new(x.as_literal(constants))),
352            Self::IfFeature(flag, if_true, if_false) => Self::IfFeature(
353                *flag,
354                Box::new(if_true.as_literal(constants)),
355                Box::new(if_false.as_literal(constants)),
356            ),
357        }
358    }
359}
360
361pub type ConstantExpr<F, ChallengeTerm> = Operations<ConstantExprInner<F, ChallengeTerm>>;
362
363impl<F, ChallengeTerm> From<ConstantTerm<F>> for ConstantExpr<F, ChallengeTerm> {
364    fn from(x: ConstantTerm<F>) -> Self {
365        ConstantExprInner::from(x).into()
366    }
367}
368
369impl<'a, F, ChallengeTerm: AlphaChallengeTerm<'a>> From<ChallengeTerm>
370    for ConstantExpr<F, ChallengeTerm>
371{
372    fn from(x: ChallengeTerm) -> Self {
373        ConstantExprInner::from(x).into()
374    }
375}
376
377impl<F: Copy, ChallengeTerm: Copy> ConstantExprInner<F, ChallengeTerm> {
378    fn to_polish<Column>(
379        &self,
380        _cache: &mut HashMap<CacheId, usize>,
381        res: &mut Vec<PolishToken<F, Column, ChallengeTerm>>,
382    ) {
383        match self {
384            ConstantExprInner::Challenge(chal) => res.push(PolishToken::Challenge(*chal)),
385            ConstantExprInner::Constant(c) => res.push(PolishToken::Constant(*c)),
386        }
387    }
388}
389
390impl<F: Copy, ChallengeTerm: Copy> Operations<ConstantExprInner<F, ChallengeTerm>> {
391    fn to_polish<Column>(
392        &self,
393        cache: &mut HashMap<CacheId, usize>,
394        res: &mut Vec<PolishToken<F, Column, ChallengeTerm>>,
395    ) {
396        match self {
397            Operations::Atom(atom) => atom.to_polish(cache, res),
398            Operations::Add(x, y) => {
399                x.as_ref().to_polish(cache, res);
400                y.as_ref().to_polish(cache, res);
401                res.push(PolishToken::Add)
402            }
403            Operations::Mul(x, y) => {
404                x.as_ref().to_polish(cache, res);
405                y.as_ref().to_polish(cache, res);
406                res.push(PolishToken::Mul)
407            }
408            Operations::Sub(x, y) => {
409                x.as_ref().to_polish(cache, res);
410                y.as_ref().to_polish(cache, res);
411                res.push(PolishToken::Sub)
412            }
413            Operations::Pow(x, n) => {
414                x.to_polish(cache, res);
415                res.push(PolishToken::Pow(*n))
416            }
417            Operations::Double(x) => {
418                x.to_polish(cache, res);
419                res.push(PolishToken::Dup);
420                res.push(PolishToken::Add);
421            }
422            Operations::Square(x) => {
423                x.to_polish(cache, res);
424                res.push(PolishToken::Dup);
425                res.push(PolishToken::Mul);
426            }
427            Operations::Cache(id, x) => {
428                match cache.get(id) {
429                    Some(pos) =>
430                    // Already computed and stored this.
431                    {
432                        res.push(PolishToken::Load(*pos))
433                    }
434                    None => {
435                        // Haven't computed this yet. Compute it, then store it.
436                        x.to_polish(cache, res);
437                        res.push(PolishToken::Store);
438                        cache.insert(*id, cache.len());
439                    }
440                }
441            }
442            Operations::IfFeature(feature, if_true, if_false) => {
443                {
444                    // True branch
445                    let tok = PolishToken::SkipIfNot(*feature, 0);
446                    res.push(tok);
447                    let len_before = res.len();
448                    /* Clone the cache, to make sure we don't try to access cached statements later
449                    when the feature flag is off. */
450                    let mut cache = cache.clone();
451                    if_true.to_polish(&mut cache, res);
452                    let len_after = res.len();
453                    res[len_before - 1] = PolishToken::SkipIfNot(*feature, len_after - len_before);
454                }
455
456                {
457                    // False branch
458                    let tok = PolishToken::SkipIfNot(*feature, 0);
459                    res.push(tok);
460                    let len_before = res.len();
461                    /* Clone the cache, to make sure we don't try to access cached statements later
462                    when the feature flag is on. */
463                    let mut cache = cache.clone();
464                    if_false.to_polish(&mut cache, res);
465                    let len_after = res.len();
466                    res[len_before - 1] = PolishToken::SkipIfNot(*feature, len_after - len_before);
467                }
468            }
469        }
470    }
471}
472
473impl<T: Literal> Operations<T>
474where
475    T::F: Field,
476{
477    /// Exponentiate a constant expression.
478    pub fn pow(self, p: u64) -> Self {
479        if p == 0 {
480            return Self::literal(T::F::one());
481        }
482        match self.to_literal() {
483            Ok(l) => Self::literal(<T::F as Field>::pow(&l, [p])),
484            Err(x) => Self::Pow(Box::new(x), p),
485        }
486    }
487}
488
489impl<F: Field, ChallengeTerm: Copy> ConstantExpr<F, ChallengeTerm> {
490    /// Evaluate the given constant expression to a field element.
491    pub fn value(&self, c: &Constants<F>, chals: &dyn Index<ChallengeTerm, Output = F>) -> F {
492        use ConstantExprInner::*;
493        use Operations::*;
494        match self {
495            Atom(Challenge(challenge_term)) => chals[*challenge_term],
496            Atom(Constant(ConstantTerm::EndoCoefficient)) => c.endo_coefficient,
497            Atom(Constant(ConstantTerm::Mds { row, col })) => c.mds[*row][*col],
498            Atom(Constant(ConstantTerm::Literal(x))) => *x,
499            Pow(x, p) => x.value(c, chals).pow([*p]),
500            Mul(x, y) => x.value(c, chals) * y.value(c, chals),
501            Add(x, y) => x.value(c, chals) + y.value(c, chals),
502            Sub(x, y) => x.value(c, chals) - y.value(c, chals),
503            Double(x) => x.value(c, chals).double(),
504            Square(x) => x.value(c, chals).square(),
505            Cache(_, x) => {
506                // TODO: Use cache ID
507                x.value(c, chals)
508            }
509            IfFeature(_flag, _if_true, _if_false) => todo!(),
510        }
511    }
512}
513
514/// A key for a cached value
515#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
516pub struct CacheId(usize);
517
518/// A cache
519#[derive(Default)]
520pub struct Cache {
521    next_id: usize,
522}
523
524impl CacheId {
525    fn get_from<'b, F: FftField>(
526        &self,
527        cache: &'b HashMap<CacheId, EvalResult<'_, F>>,
528    ) -> Option<EvalResult<'b, F>> {
529        cache.get(self).map(|e| match e {
530            EvalResult::Constant(x) => EvalResult::Constant(*x),
531            EvalResult::SubEvals {
532                domain,
533                shift,
534                evals,
535            } => EvalResult::SubEvals {
536                domain: *domain,
537                shift: *shift,
538                evals,
539            },
540            EvalResult::Evals { domain, evals } => EvalResult::SubEvals {
541                domain: *domain,
542                shift: 0,
543                evals,
544            },
545        })
546    }
547
548    fn var_name(&self) -> String {
549        format!("x_{}", self.0)
550    }
551
552    fn latex_name(&self) -> String {
553        format!("x_{{{}}}", self.0)
554    }
555}
556
557impl Cache {
558    fn next_id(&mut self) -> CacheId {
559        let id = self.next_id;
560        self.next_id += 1;
561        CacheId(id)
562    }
563
564    pub fn cache<F: Field, ChallengeTerm, T: ExprOps<F, ChallengeTerm>>(&mut self, e: T) -> T {
565        e.cache(self)
566    }
567}
568
569/// The feature flags that can be used to enable or disable parts of constraints.
570#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
571#[cfg_attr(
572    feature = "ocaml_types",
573    derive(ocaml::IntoValue, ocaml::FromValue, ocaml_gen::Enum)
574)]
575pub enum FeatureFlag {
576    RangeCheck0,
577    RangeCheck1,
578    ForeignFieldAdd,
579    ForeignFieldMul,
580    Xor,
581    Rot,
582    LookupTables,
583    RuntimeLookupTables,
584    LookupPattern(LookupPattern),
585    /// Enabled if the table width is at least the given number
586    TableWidth(isize), // NB: isize so that we don't need to convert for OCaml :(
587    /// Enabled if the number of lookups per row is at least the given number
588    LookupsPerRow(isize), // NB: isize so that we don't need to convert for OCaml :(
589}
590
591impl FeatureFlag {
592    fn is_enabled(&self) -> bool {
593        todo!("Handle features")
594    }
595}
596
597#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
598pub struct RowOffset {
599    pub zk_rows: bool,
600    pub offset: i32,
601}
602
603#[derive(Clone, Debug, PartialEq)]
604pub enum ExprInner<C, Column> {
605    Constant(C),
606    Cell(Variable<Column>),
607    VanishesOnZeroKnowledgeAndPreviousRows,
608    /// UnnormalizedLagrangeBasis(i) is
609    /// (x^n - 1) / (x - omega^i)
610    UnnormalizedLagrangeBasis(RowOffset),
611}
612
613/// An multi-variate polynomial over the base ring `C` with
614/// variables
615///
616/// - `Cell(v)` for `v : Variable`
617/// - VanishesOnZeroKnowledgeAndPreviousRows
618/// - UnnormalizedLagrangeBasis(i) for `i : i32`
619///
620/// This represents a PLONK "custom constraint", which enforces that
621/// the corresponding combination of the polynomials corresponding to
622/// the above variables should vanish on the PLONK domain.
623pub type Expr<C, Column> = Operations<ExprInner<C, Column>>;
624
625impl<F, Column, ChallengeTerm> From<ConstantExpr<F, ChallengeTerm>>
626    for Expr<ConstantExpr<F, ChallengeTerm>, Column>
627{
628    fn from(x: ConstantExpr<F, ChallengeTerm>) -> Self {
629        Expr::Atom(ExprInner::Constant(x))
630    }
631}
632
633impl<'a, F, Column, ChallengeTerm: AlphaChallengeTerm<'a>> From<ConstantTerm<F>>
634    for Expr<ConstantExpr<F, ChallengeTerm>, Column>
635{
636    fn from(x: ConstantTerm<F>) -> Self {
637        ConstantExpr::from(x).into()
638    }
639}
640
641impl<'a, F, Column, ChallengeTerm: AlphaChallengeTerm<'a>> From<ChallengeTerm>
642    for Expr<ConstantExpr<F, ChallengeTerm>, Column>
643{
644    fn from(x: ChallengeTerm) -> Self {
645        ConstantExpr::from(x).into()
646    }
647}
648
649impl<T: Literal, Column: Clone> Literal for ExprInner<T, Column> {
650    type F = T::F;
651
652    fn literal(x: Self::F) -> Self {
653        ExprInner::Constant(T::literal(x))
654    }
655
656    fn to_literal(self) -> Result<Self::F, Self> {
657        match self {
658            ExprInner::Constant(x) => match x.to_literal() {
659                Ok(x) => Ok(x),
660                Err(x) => Err(ExprInner::Constant(x)),
661            },
662            x => Err(x),
663        }
664    }
665
666    fn to_literal_ref(&self) -> Option<&Self::F> {
667        match self {
668            ExprInner::Constant(x) => x.to_literal_ref(),
669            _ => None,
670        }
671    }
672
673    fn as_literal(&self, constants: &Constants<Self::F>) -> Self {
674        match self {
675            ExprInner::Constant(x) => ExprInner::Constant(x.as_literal(constants)),
676            ExprInner::Cell(_)
677            | ExprInner::VanishesOnZeroKnowledgeAndPreviousRows
678            | ExprInner::UnnormalizedLagrangeBasis(_) => self.clone(),
679        }
680    }
681}
682
683impl<T: Literal + PartialEq> Operations<T>
684where
685    T::F: Field,
686{
687    fn apply_feature_flags_inner(&self, features: &FeatureFlags) -> (Self, bool) {
688        use Operations::*;
689        match self {
690            Atom(_) => (self.clone(), false),
691            Double(c) => {
692                let (c_reduced, reduce_further) = c.apply_feature_flags_inner(features);
693                if reduce_further && c_reduced.is_zero() {
694                    (Self::zero(), true)
695                } else {
696                    (Double(Box::new(c_reduced)), false)
697                }
698            }
699            Square(c) => {
700                let (c_reduced, reduce_further) = c.apply_feature_flags_inner(features);
701                if reduce_further && (c_reduced.is_zero() || c_reduced.is_one()) {
702                    (c_reduced, true)
703                } else {
704                    (Square(Box::new(c_reduced)), false)
705                }
706            }
707            Add(c1, c2) => {
708                let (c1_reduced, reduce_further1) = c1.apply_feature_flags_inner(features);
709                let (c2_reduced, reduce_further2) = c2.apply_feature_flags_inner(features);
710                if reduce_further1 && c1_reduced.is_zero() {
711                    if reduce_further2 && c2_reduced.is_zero() {
712                        (Self::zero(), true)
713                    } else {
714                        (c2_reduced, false)
715                    }
716                } else if reduce_further2 && c2_reduced.is_zero() {
717                    (c1_reduced, false)
718                } else {
719                    (Add(Box::new(c1_reduced), Box::new(c2_reduced)), false)
720                }
721            }
722            Sub(c1, c2) => {
723                let (c1_reduced, reduce_further1) = c1.apply_feature_flags_inner(features);
724                let (c2_reduced, reduce_further2) = c2.apply_feature_flags_inner(features);
725                if reduce_further1 && c1_reduced.is_zero() {
726                    if reduce_further2 && c2_reduced.is_zero() {
727                        (Self::zero(), true)
728                    } else {
729                        (-c2_reduced, false)
730                    }
731                } else if reduce_further2 && c2_reduced.is_zero() {
732                    (c1_reduced, false)
733                } else {
734                    (Sub(Box::new(c1_reduced), Box::new(c2_reduced)), false)
735                }
736            }
737            Mul(c1, c2) => {
738                let (c1_reduced, reduce_further1) = c1.apply_feature_flags_inner(features);
739                let (c2_reduced, reduce_further2) = c2.apply_feature_flags_inner(features);
740                if reduce_further1 && c1_reduced.is_zero()
741                    || reduce_further2 && c2_reduced.is_zero()
742                {
743                    (Self::zero(), true)
744                } else if reduce_further1 && c1_reduced.is_one() {
745                    if reduce_further2 && c2_reduced.is_one() {
746                        (Self::one(), true)
747                    } else {
748                        (c2_reduced, false)
749                    }
750                } else if reduce_further2 && c2_reduced.is_one() {
751                    (c1_reduced, false)
752                } else {
753                    (Mul(Box::new(c1_reduced), Box::new(c2_reduced)), false)
754                }
755            }
756            Pow(c, power) => {
757                let (c_reduced, reduce_further) = c.apply_feature_flags_inner(features);
758                if reduce_further && (c_reduced.is_zero() || c_reduced.is_one()) {
759                    (c_reduced, true)
760                } else {
761                    (Pow(Box::new(c_reduced), *power), false)
762                }
763            }
764            Cache(cache_id, c) => {
765                let (c_reduced, reduce_further) = c.apply_feature_flags_inner(features);
766                if reduce_further {
767                    (c_reduced, true)
768                } else {
769                    (Cache(*cache_id, Box::new(c_reduced)), false)
770                }
771            }
772            IfFeature(feature, c1, c2) => {
773                let is_enabled = {
774                    use FeatureFlag::*;
775                    match feature {
776                        RangeCheck0 => features.range_check0,
777                        RangeCheck1 => features.range_check1,
778                        ForeignFieldAdd => features.foreign_field_add,
779                        ForeignFieldMul => features.foreign_field_mul,
780                        Xor => features.xor,
781                        Rot => features.rot,
782                        LookupTables => {
783                            features.lookup_features.patterns != LookupPatterns::default()
784                        }
785                        RuntimeLookupTables => features.lookup_features.uses_runtime_tables,
786                        LookupPattern(pattern) => features.lookup_features.patterns[*pattern],
787                        TableWidth(width) => features
788                            .lookup_features
789                            .patterns
790                            .into_iter()
791                            .any(|feature| feature.max_joint_size() >= (*width as u32)),
792                        LookupsPerRow(count) => features
793                            .lookup_features
794                            .patterns
795                            .into_iter()
796                            .any(|feature| feature.max_lookups_per_row() >= (*count as usize)),
797                    }
798                };
799                if is_enabled {
800                    let (c1_reduced, _) = c1.apply_feature_flags_inner(features);
801                    (c1_reduced, false)
802                } else {
803                    let (c2_reduced, _) = c2.apply_feature_flags_inner(features);
804                    (c2_reduced, true)
805                }
806            }
807        }
808    }
809    pub fn apply_feature_flags(&self, features: &FeatureFlags) -> Self {
810        let (res, _) = self.apply_feature_flags_inner(features);
811        res
812    }
813}
814
815/// For efficiency of evaluation, we compile expressions to
816/// [reverse Polish notation](https://en.wikipedia.org/wiki/Reverse_Polish_notation)
817/// expressions, which are vectors of the below tokens.
818#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
819pub enum PolishToken<F, Column, ChallengeTerm> {
820    Constant(ConstantTerm<F>),
821    Challenge(ChallengeTerm),
822    Cell(Variable<Column>),
823    Dup,
824    Pow(u64),
825    Add,
826    Mul,
827    Sub,
828    VanishesOnZeroKnowledgeAndPreviousRows,
829    UnnormalizedLagrangeBasis(RowOffset),
830    Store,
831    Load(usize),
832    /// Skip the given number of tokens if the feature is enabled.
833    SkipIf(FeatureFlag, usize),
834    /// Skip the given number of tokens if the feature is disabled.
835    SkipIfNot(FeatureFlag, usize),
836}
837
838pub trait ColumnEvaluations<F> {
839    type Column;
840    fn evaluate(&self, col: Self::Column) -> Result<PointEvaluations<F>, ExprError<Self::Column>>;
841}
842
843impl<Column: Copy> Variable<Column> {
844    fn evaluate<F: Field, Evaluations: ColumnEvaluations<F, Column = Column>>(
845        &self,
846        evals: &Evaluations,
847    ) -> Result<F, ExprError<Column>> {
848        let point_evaluations = evals.evaluate(self.col)?;
849        match self.row {
850            CurrOrNext::Curr => Ok(point_evaluations.zeta),
851            CurrOrNext::Next => Ok(point_evaluations.zeta_omega),
852        }
853    }
854}
855
856impl<F: FftField, Column: Copy, ChallengeTerm: Copy> PolishToken<F, Column, ChallengeTerm> {
857    /// Evaluate an RPN expression to a field element.
858    pub fn evaluate<Evaluations: ColumnEvaluations<F, Column = Column>>(
859        toks: &[PolishToken<F, Column, ChallengeTerm>],
860        d: D<F>,
861        pt: F,
862        evals: &Evaluations,
863        c: &Constants<F>,
864        chals: &dyn Index<ChallengeTerm, Output = F>,
865    ) -> Result<F, ExprError<Column>> {
866        let mut stack = vec![];
867        let mut cache: Vec<F> = vec![];
868
869        let mut skip_count = 0;
870
871        for t in toks.iter() {
872            if skip_count > 0 {
873                skip_count -= 1;
874                continue;
875            }
876
877            use ConstantTerm::*;
878            use PolishToken::*;
879            match t {
880                Challenge(challenge_term) => stack.push(chals[*challenge_term]),
881                Constant(EndoCoefficient) => stack.push(c.endo_coefficient),
882                Constant(Mds { row, col }) => stack.push(c.mds[*row][*col]),
883                VanishesOnZeroKnowledgeAndPreviousRows => {
884                    stack.push(eval_vanishes_on_last_n_rows(d, c.zk_rows + 1, pt))
885                }
886                UnnormalizedLagrangeBasis(i) => {
887                    let offset = if i.zk_rows {
888                        -(c.zk_rows as i32) + i.offset
889                    } else {
890                        i.offset
891                    };
892                    stack.push(unnormalized_lagrange_basis(&d, offset, &pt))
893                }
894                Constant(Literal(x)) => stack.push(*x),
895                Dup => stack.push(stack[stack.len() - 1]),
896                Cell(v) => stack.push(v.evaluate(evals)?),
897                Pow(n) => {
898                    let i = stack.len() - 1;
899                    stack[i] = stack[i].pow([*n]);
900                }
901                Add => {
902                    let y = stack.pop().ok_or(ExprError::EmptyStack)?;
903                    let x = stack.pop().ok_or(ExprError::EmptyStack)?;
904                    stack.push(x + y);
905                }
906                Mul => {
907                    let y = stack.pop().ok_or(ExprError::EmptyStack)?;
908                    let x = stack.pop().ok_or(ExprError::EmptyStack)?;
909                    stack.push(x * y);
910                }
911                Sub => {
912                    let y = stack.pop().ok_or(ExprError::EmptyStack)?;
913                    let x = stack.pop().ok_or(ExprError::EmptyStack)?;
914                    stack.push(x - y);
915                }
916                Store => {
917                    let x = stack[stack.len() - 1];
918                    cache.push(x);
919                }
920                Load(i) => stack.push(cache[*i]),
921                SkipIf(feature, count) => {
922                    if feature.is_enabled() {
923                        skip_count = *count;
924                        stack.push(F::zero());
925                    }
926                }
927                SkipIfNot(feature, count) => {
928                    if !feature.is_enabled() {
929                        skip_count = *count;
930                        stack.push(F::zero());
931                    }
932                }
933            }
934        }
935
936        assert_eq!(stack.len(), 1);
937        Ok(stack[0])
938    }
939}
940
941impl<C, Column> Expr<C, Column> {
942    /// Convenience function for constructing cell variables.
943    pub fn cell(col: Column, row: CurrOrNext) -> Expr<C, Column> {
944        Expr::Atom(ExprInner::Cell(Variable { col, row }))
945    }
946
947    pub fn double(self) -> Self {
948        Expr::Double(Box::new(self))
949    }
950
951    pub fn square(self) -> Self {
952        Expr::Square(Box::new(self))
953    }
954
955    /// Convenience function for constructing constant expressions.
956    pub fn constant(c: C) -> Expr<C, Column> {
957        Expr::Atom(ExprInner::Constant(c))
958    }
959
960    /// Return the degree of the expression.
961    /// The degree of a cell is defined by the first argument `d1_size`, a
962    /// constant being of degree zero. The degree of the expression is defined
963    /// recursively using the definition of the degree of a multivariate
964    /// polynomial. The function can be (and is) used to compute the domain
965    /// size, hence the name of the first argument `d1_size`.
966    /// The second parameter `zk_rows` is used to define the degree of the
967    /// constructor `VanishesOnZeroKnowledgeAndPreviousRows`.
968    pub fn degree(&self, d1_size: u64, zk_rows: u64) -> u64 {
969        use ExprInner::*;
970        use Operations::*;
971        match self {
972            Double(x) => x.degree(d1_size, zk_rows),
973            Atom(Constant(_)) => 0,
974            Atom(VanishesOnZeroKnowledgeAndPreviousRows) => zk_rows + 1,
975            Atom(UnnormalizedLagrangeBasis(_)) => d1_size,
976            Atom(Cell(_)) => d1_size,
977            Square(x) => 2 * x.degree(d1_size, zk_rows),
978            Mul(x, y) => (*x).degree(d1_size, zk_rows) + (*y).degree(d1_size, zk_rows),
979            Add(x, y) | Sub(x, y) => {
980                core::cmp::max((*x).degree(d1_size, zk_rows), (*y).degree(d1_size, zk_rows))
981            }
982            Pow(e, d) => d * e.degree(d1_size, zk_rows),
983            Cache(_, e) => e.degree(d1_size, zk_rows),
984            IfFeature(_, e1, e2) => {
985                core::cmp::max(e1.degree(d1_size, zk_rows), e2.degree(d1_size, zk_rows))
986            }
987        }
988    }
989}
990
991impl<'a, F, Column: FormattedOutput + Debug + Clone, ChallengeTerm> fmt::Display
992    for Expr<ConstantExpr<F, ChallengeTerm>, Column>
993where
994    F: PrimeField,
995    ChallengeTerm: AlphaChallengeTerm<'a>,
996{
997    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
998        let cache = &mut HashMap::new();
999        write!(f, "{}", self.text(cache))
1000    }
1001}
1002
1003#[derive(Clone)]
1004enum EvalResult<'a, F: FftField> {
1005    Constant(F),
1006    Evals {
1007        domain: Domain,
1008        evals: Evaluations<F, D<F>>,
1009    },
1010    /// SubEvals is used to refer to evaluations that can be trivially obtained from a
1011    /// borrowed evaluation. In this case, by taking a subset of the entries
1012    /// (specifically when the borrowed `evals` is over a superset of `domain`)
1013    /// and shifting them
1014    SubEvals {
1015        domain: Domain,
1016        shift: usize,
1017        evals: &'a Evaluations<F, D<F>>,
1018    },
1019}
1020
1021/// Compute the evaluations of the unnormalized lagrange polynomial on
1022/// H_8 or H_4. Taking H_8 as an example, we show how to compute this
1023/// polynomial on the expanded domain.
1024///
1025/// Let H = < omega >, |H| = n.
1026///
1027/// Let l_i(x) be the unnormalized lagrange polynomial,
1028/// (x^n - 1) / (x - omega^i)
1029/// = prod_{j != i} (x - omega^j)
1030///
1031/// For h in H, h != omega^i,
1032/// l_i(h) = 0.
1033/// l_i(omega^i)
1034/// = prod_{j != i} (omega^i - omega^j)
1035/// = omega^{i (n - 1)} * prod_{j != i} (1 - omega^{j - i})
1036/// = omega^{i (n - 1)} * prod_{j != 0} (1 - omega^j)
1037/// = omega^{i (n - 1)} * l_0(1)
1038/// = omega^{i n} * omega^{-i} * l_0(1)
1039/// = omega^{-i} * l_0(1)
1040///
1041/// So it is easy to compute l_i(omega^i) from just l_0(1).
1042///
1043/// Also, consider the expanded domain H_8 generated by
1044/// an 8nth root of unity omega_8 (where H_8^8 = H).
1045///
1046/// Let omega_8^k in H_8. Write k = 8 * q + r with r < 8.
1047/// Then
1048/// omega_8^k = (omega_8^8)^q * omega_8^r = omega^q * omega_8^r
1049///
1050/// l_i(omega_8^k)
1051/// = (omega_8^{k n} - 1) / (omega_8^k - omega^i)
1052/// = (omega^{q n} omega_8^{r n} - 1) / (omega_8^k - omega^i)
1053/// = ((omega_8^n)^r - 1) / (omega_8^k - omega^i)
1054/// = ((omega_8^n)^r - 1) / (omega^q omega_8^r - omega^i)
1055fn unnormalized_lagrange_evals<
1056    'a,
1057    F: FftField,
1058    ChallengeTerm,
1059    Challenge: Index<ChallengeTerm, Output = F>,
1060    Environment: ColumnEnvironment<'a, F, ChallengeTerm, Challenge>,
1061>(
1062    l0_1: F,
1063    i: i32,
1064    res_domain: Domain,
1065    env: &Environment,
1066) -> Evaluations<F, D<F>> {
1067    let k = match res_domain {
1068        Domain::D1 => 1,
1069        Domain::D2 => 2,
1070        Domain::D4 => 4,
1071        Domain::D8 => 8,
1072    };
1073    let res_domain = env.get_domain(res_domain);
1074
1075    let d1 = env.get_domain(Domain::D1);
1076    let n = d1.size;
1077    // Renormalize negative values to wrap around at domain size
1078    let i = if i < 0 {
1079        ((i as isize) + (n as isize)) as usize
1080    } else {
1081        i as usize
1082    };
1083    let ii = i as u64;
1084    assert!(ii < n);
1085    let omega = d1.group_gen;
1086    let omega_i = omega.pow([ii]);
1087    let omega_minus_i = omega.pow([n - ii]);
1088
1089    // Write res_domain = < omega_k > with
1090    // |res_domain| = k * |H|
1091
1092    // omega_k^0, ..., omega_k^k
1093    let omega_k_n_pows = pows(k, res_domain.group_gen.pow([n]));
1094    let omega_k_pows = pows(k, res_domain.group_gen);
1095
1096    let mut evals: Vec<F> = {
1097        let mut v = vec![F::one(); k * (n as usize)];
1098        let mut omega_q = F::one();
1099        for q in 0..(n as usize) {
1100            // omega_q == omega^q
1101            for r in 1..k {
1102                v[k * q + r] = omega_q * omega_k_pows[r] - omega_i;
1103            }
1104            omega_q *= omega;
1105        }
1106        ark_ff::fields::batch_inversion::<F>(&mut v[..]);
1107        v
1108    };
1109    // At this point, in the 0 mod k indices, we have dummy values,
1110    // and in the other indices k*q + r, we have
1111    // 1 / (omega^q omega_k^r - omega^i)
1112
1113    // Set the 0 mod k indices
1114    for q in 0..(n as usize) {
1115        evals[k * q] = F::zero();
1116    }
1117    evals[k * i] = omega_minus_i * l0_1;
1118
1119    // Finish computing the non-zero mod k indices
1120    for q in 0..(n as usize) {
1121        for r in 1..k {
1122            evals[k * q + r] *= omega_k_n_pows[r] - F::one();
1123        }
1124    }
1125
1126    Evaluations::<F, D<F>>::from_vec_and_domain(evals, res_domain)
1127}
1128
1129/// Implement algebraic methods like `add`, `sub`, `mul`, `square`, etc to use
1130/// algebra on the type `EvalResult`.
1131impl<'a, F: FftField> EvalResult<'a, F> {
1132    /// Create an evaluation over the domain `res_domain`.
1133    /// The second parameter, `g`, is a function used to define the
1134    /// evaluations at a given point of the domain.
1135    /// For instance, the second parameter `g` can simply be the identity
1136    /// functions over a set of field elements.
1137    /// It can also be used to define polynomials like `x^2` when we only have the
1138    /// value of `x`. It can be used in particular to evaluate an expression (a
1139    /// multi-variate polynomial) when we only do have access to the evaluations
1140    /// of the individual variables.
1141    fn init_<G: Sync + Send + Fn(usize) -> F>(
1142        res_domain: (Domain, D<F>),
1143        g: G,
1144    ) -> Evaluations<F, D<F>> {
1145        let n = res_domain.1.size();
1146        Evaluations::<F, D<F>>::from_vec_and_domain(
1147            o1_utils::cfg_into_iter!(0..n).map(g).collect(),
1148            res_domain.1,
1149        )
1150    }
1151
1152    /// Call the internal function `init_` and return the computed evaluation as
1153    /// a value `Evals`.
1154    fn init<G: Sync + Send + Fn(usize) -> F>(res_domain: (Domain, D<F>), g: G) -> Self {
1155        Self::Evals {
1156            domain: res_domain.0,
1157            evals: Self::init_(res_domain, g),
1158        }
1159    }
1160
1161    fn add<'c>(self, other: EvalResult<'_, F>, res_domain: (Domain, D<F>)) -> EvalResult<'c, F> {
1162        use EvalResult::*;
1163        match (self, other) {
1164            (Constant(x), Constant(y)) => Constant(x + y),
1165            (Evals { domain, mut evals }, Constant(x))
1166            | (Constant(x), Evals { domain, mut evals }) => {
1167                o1_utils::cfg_iter_mut!(evals.evals).for_each(|e| *e += x);
1168                Evals { domain, evals }
1169            }
1170            (
1171                SubEvals {
1172                    evals,
1173                    domain,
1174                    shift,
1175                },
1176                Constant(x),
1177            )
1178            | (
1179                Constant(x),
1180                SubEvals {
1181                    evals,
1182                    domain,
1183                    shift,
1184                },
1185            ) => {
1186                let n = res_domain.1.size();
1187                let scale = (domain as usize) / (res_domain.0 as usize);
1188                assert!(
1189                    scale != 0,
1190                    "Check that the implementation of
1191                column_domain and the evaluation domain of the
1192                witnesses are the same"
1193                );
1194                let v: Vec<_> = o1_utils::cfg_into_iter!(0..n)
1195                    .map(|i| {
1196                        x + evals.evals[(scale * i + (domain as usize) * shift) % evals.evals.len()]
1197                    })
1198                    .collect();
1199                Evals {
1200                    domain: res_domain.0,
1201                    evals: Evaluations::<F, D<F>>::from_vec_and_domain(v, res_domain.1),
1202                }
1203            }
1204            (
1205                Evals {
1206                    domain: d1,
1207                    evals: mut es1,
1208                },
1209                Evals {
1210                    domain: d2,
1211                    evals: es2,
1212                },
1213            ) => {
1214                assert_eq!(d1, d2);
1215                es1 += &es2;
1216                Evals {
1217                    domain: d1,
1218                    evals: es1,
1219                }
1220            }
1221            (
1222                SubEvals {
1223                    domain: d_sub,
1224                    shift: s,
1225                    evals: es_sub,
1226                },
1227                Evals {
1228                    domain: d,
1229                    mut evals,
1230                },
1231            )
1232            | (
1233                Evals {
1234                    domain: d,
1235                    mut evals,
1236                },
1237                SubEvals {
1238                    domain: d_sub,
1239                    shift: s,
1240                    evals: es_sub,
1241                },
1242            ) => {
1243                let scale = (d_sub as usize) / (d as usize);
1244                assert!(
1245                    scale != 0,
1246                    "Check that the implementation of
1247                column_domain and the evaluation domain of the
1248                witnesses are the same"
1249                );
1250                o1_utils::cfg_iter_mut!(evals.evals)
1251                    .enumerate()
1252                    .for_each(|(i, e)| {
1253                        *e += es_sub.evals[(scale * i + (d_sub as usize) * s) % es_sub.evals.len()];
1254                    });
1255                Evals { evals, domain: d }
1256            }
1257            (
1258                SubEvals {
1259                    domain: d1,
1260                    shift: s1,
1261                    evals: es1,
1262                },
1263                SubEvals {
1264                    domain: d2,
1265                    shift: s2,
1266                    evals: es2,
1267                },
1268            ) => {
1269                let scale1 = (d1 as usize) / (res_domain.0 as usize);
1270                assert!(
1271                    scale1 != 0,
1272                    "Check that the implementation of
1273                column_domain and the evaluation domain of the
1274                witnesses are the same"
1275                );
1276                let scale2 = (d2 as usize) / (res_domain.0 as usize);
1277                assert!(
1278                    scale2 != 0,
1279                    "Check that the implementation of
1280                column_domain and the evaluation domain of the
1281                witnesses are the same"
1282                );
1283                let n = res_domain.1.size();
1284                let v: Vec<_> = o1_utils::cfg_into_iter!(0..n)
1285                    .map(|i| {
1286                        es1.evals[(scale1 * i + (d1 as usize) * s1) % es1.evals.len()]
1287                            + es2.evals[(scale2 * i + (d2 as usize) * s2) % es2.evals.len()]
1288                    })
1289                    .collect();
1290
1291                Evals {
1292                    domain: res_domain.0,
1293                    evals: Evaluations::<F, D<F>>::from_vec_and_domain(v, res_domain.1),
1294                }
1295            }
1296        }
1297    }
1298
1299    fn sub<'c>(self, other: EvalResult<'_, F>, res_domain: (Domain, D<F>)) -> EvalResult<'c, F> {
1300        use EvalResult::*;
1301        match (self, other) {
1302            (Constant(x), Constant(y)) => Constant(x - y),
1303            (Evals { domain, mut evals }, Constant(x)) => {
1304                o1_utils::cfg_iter_mut!(evals.evals).for_each(|e| *e -= x);
1305                Evals { domain, evals }
1306            }
1307            (Constant(x), Evals { domain, mut evals }) => {
1308                o1_utils::cfg_iter_mut!(evals.evals).for_each(|e| *e = x - *e);
1309                Evals { domain, evals }
1310            }
1311            (
1312                SubEvals {
1313                    evals,
1314                    domain: d,
1315                    shift: s,
1316                },
1317                Constant(x),
1318            ) => {
1319                let scale = (d as usize) / (res_domain.0 as usize);
1320                assert!(
1321                    scale != 0,
1322                    "Check that the implementation of
1323                column_domain and the evaluation domain of the
1324                witnesses are the same"
1325                );
1326                EvalResult::init(res_domain, |i| {
1327                    evals.evals[(scale * i + (d as usize) * s) % evals.evals.len()] - x
1328                })
1329            }
1330            (
1331                Constant(x),
1332                SubEvals {
1333                    evals,
1334                    domain: d,
1335                    shift: s,
1336                },
1337            ) => {
1338                let scale = (d as usize) / (res_domain.0 as usize);
1339                assert!(
1340                    scale != 0,
1341                    "Check that the implementation of
1342                column_domain and the evaluation domain of the
1343                witnesses are the same"
1344                );
1345
1346                EvalResult::init(res_domain, |i| {
1347                    x - evals.evals[(scale * i + (d as usize) * s) % evals.evals.len()]
1348                })
1349            }
1350            (
1351                Evals {
1352                    domain: d1,
1353                    evals: mut es1,
1354                },
1355                Evals {
1356                    domain: d2,
1357                    evals: es2,
1358                },
1359            ) => {
1360                assert_eq!(d1, d2);
1361                es1 -= &es2;
1362                Evals {
1363                    domain: d1,
1364                    evals: es1,
1365                }
1366            }
1367            (
1368                SubEvals {
1369                    domain: d_sub,
1370                    shift: s,
1371                    evals: es_sub,
1372                },
1373                Evals {
1374                    domain: d,
1375                    mut evals,
1376                },
1377            ) => {
1378                let scale = (d_sub as usize) / (d as usize);
1379                assert!(
1380                    scale != 0,
1381                    "Check that the implementation of
1382                column_domain and the evaluation domain of the
1383                witnesses are the same"
1384                );
1385
1386                o1_utils::cfg_iter_mut!(evals.evals)
1387                    .enumerate()
1388                    .for_each(|(i, e)| {
1389                        *e = es_sub.evals[(scale * i + (d_sub as usize) * s) % es_sub.evals.len()]
1390                            - *e;
1391                    });
1392                Evals { evals, domain: d }
1393            }
1394            (
1395                Evals {
1396                    domain: d,
1397                    mut evals,
1398                },
1399                SubEvals {
1400                    domain: d_sub,
1401                    shift: s,
1402                    evals: es_sub,
1403                },
1404            ) => {
1405                let scale = (d_sub as usize) / (d as usize);
1406                assert!(
1407                    scale != 0,
1408                    "Check that the implementation of
1409                column_domain and the evaluation domain of the
1410                witnesses are the same"
1411                );
1412                o1_utils::cfg_iter_mut!(evals.evals)
1413                    .enumerate()
1414                    .for_each(|(i, e)| {
1415                        *e -= es_sub.evals[(scale * i + (d_sub as usize) * s) % es_sub.evals.len()];
1416                    });
1417                Evals { evals, domain: d }
1418            }
1419            (
1420                SubEvals {
1421                    domain: d1,
1422                    shift: s1,
1423                    evals: es1,
1424                },
1425                SubEvals {
1426                    domain: d2,
1427                    shift: s2,
1428                    evals: es2,
1429                },
1430            ) => {
1431                let scale1 = (d1 as usize) / (res_domain.0 as usize);
1432                assert!(
1433                    scale1 != 0,
1434                    "Check that the implementation of
1435                column_domain and the evaluation domain of the
1436                witnesses are the same"
1437                );
1438                let scale2 = (d2 as usize) / (res_domain.0 as usize);
1439                assert!(
1440                    scale2 != 0,
1441                    "Check that the implementation of
1442                column_domain and the evaluation domain of the
1443                witnesses are the same"
1444                );
1445
1446                EvalResult::init(res_domain, |i| {
1447                    es1.evals[(scale1 * i + (d1 as usize) * s1) % es1.evals.len()]
1448                        - es2.evals[(scale2 * i + (d2 as usize) * s2) % es2.evals.len()]
1449                })
1450            }
1451        }
1452    }
1453
1454    fn pow<'b>(self, d: u64, res_domain: (Domain, D<F>)) -> EvalResult<'b, F> {
1455        let mut acc = EvalResult::Constant(F::one());
1456        for i in (0..u64::BITS).rev() {
1457            acc = acc.square(res_domain);
1458
1459            if (d >> i) & 1 == 1 {
1460                // TODO: Avoid the unnecessary cloning
1461                acc = acc.mul(self.clone(), res_domain)
1462            }
1463        }
1464        acc
1465    }
1466
1467    fn square<'b>(self, res_domain: (Domain, D<F>)) -> EvalResult<'b, F> {
1468        use EvalResult::*;
1469        match self {
1470            Constant(x) => Constant(x.square()),
1471            Evals { domain, mut evals } => {
1472                o1_utils::cfg_iter_mut!(evals.evals).for_each(|e| {
1473                    e.square_in_place();
1474                });
1475                Evals { domain, evals }
1476            }
1477            SubEvals {
1478                evals,
1479                domain: d,
1480                shift: s,
1481            } => {
1482                let scale = (d as usize) / (res_domain.0 as usize);
1483                assert!(
1484                    scale != 0,
1485                    "Check that the implementation of
1486                column_domain and the evaluation domain of the
1487                witnesses are the same"
1488                );
1489                EvalResult::init(res_domain, |i| {
1490                    evals.evals[(scale * i + (d as usize) * s) % evals.evals.len()].square()
1491                })
1492            }
1493        }
1494    }
1495
1496    fn mul<'c>(self, other: EvalResult<'_, F>, res_domain: (Domain, D<F>)) -> EvalResult<'c, F> {
1497        use EvalResult::*;
1498        match (self, other) {
1499            (Constant(x), Constant(y)) => Constant(x * y),
1500            (Evals { domain, mut evals }, Constant(x))
1501            | (Constant(x), Evals { domain, mut evals }) => {
1502                o1_utils::cfg_iter_mut!(evals.evals).for_each(|e| *e *= x);
1503                Evals { domain, evals }
1504            }
1505            (
1506                SubEvals {
1507                    evals,
1508                    domain: d,
1509                    shift: s,
1510                },
1511                Constant(x),
1512            )
1513            | (
1514                Constant(x),
1515                SubEvals {
1516                    evals,
1517                    domain: d,
1518                    shift: s,
1519                },
1520            ) => {
1521                let scale = (d as usize) / (res_domain.0 as usize);
1522                assert!(
1523                    scale != 0,
1524                    "Check that the implementation of
1525                column_domain and the evaluation domain of the
1526                witnesses are the same"
1527                );
1528                EvalResult::init(res_domain, |i| {
1529                    x * evals.evals[(scale * i + (d as usize) * s) % evals.evals.len()]
1530                })
1531            }
1532            (
1533                Evals {
1534                    domain: d1,
1535                    evals: mut es1,
1536                },
1537                Evals {
1538                    domain: d2,
1539                    evals: es2,
1540                },
1541            ) => {
1542                assert_eq!(d1, d2);
1543                es1 *= &es2;
1544                Evals {
1545                    domain: d1,
1546                    evals: es1,
1547                }
1548            }
1549            (
1550                SubEvals {
1551                    domain: d_sub,
1552                    shift: s,
1553                    evals: es_sub,
1554                },
1555                Evals {
1556                    domain: d,
1557                    mut evals,
1558                },
1559            )
1560            | (
1561                Evals {
1562                    domain: d,
1563                    mut evals,
1564                },
1565                SubEvals {
1566                    domain: d_sub,
1567                    shift: s,
1568                    evals: es_sub,
1569                },
1570            ) => {
1571                let scale = (d_sub as usize) / (d as usize);
1572                assert!(
1573                    scale != 0,
1574                    "Check that the implementation of
1575                column_domainand the evaluation domain of the
1576                witnesses are the same"
1577                );
1578
1579                o1_utils::cfg_iter_mut!(evals.evals)
1580                    .enumerate()
1581                    .for_each(|(i, e)| {
1582                        *e *= es_sub.evals[(scale * i + (d_sub as usize) * s) % es_sub.evals.len()];
1583                    });
1584                Evals { evals, domain: d }
1585            }
1586            (
1587                SubEvals {
1588                    domain: d1,
1589                    shift: s1,
1590                    evals: es1,
1591                },
1592                SubEvals {
1593                    domain: d2,
1594                    shift: s2,
1595                    evals: es2,
1596                },
1597            ) => {
1598                let scale1 = (d1 as usize) / (res_domain.0 as usize);
1599                assert!(
1600                    scale1 != 0,
1601                    "Check that the implementation of
1602                column_domain and the evaluation domain of the
1603                witnesses are the same"
1604                );
1605                let scale2 = (d2 as usize) / (res_domain.0 as usize);
1606
1607                assert!(
1608                    scale2 != 0,
1609                    "Check that the implementation of
1610                column_domain and the evaluation domain of the
1611                witnesses are the same"
1612                );
1613                EvalResult::init(res_domain, |i| {
1614                    es1.evals[(scale1 * i + (d1 as usize) * s1) % es1.evals.len()]
1615                        * es2.evals[(scale2 * i + (d2 as usize) * s2) % es2.evals.len()]
1616                })
1617            }
1618        }
1619    }
1620}
1621
1622impl<'a, F: Field, Column: PartialEq + Copy, ChallengeTerm: AlphaChallengeTerm<'a>>
1623    Expr<ConstantExpr<F, ChallengeTerm>, Column>
1624{
1625    /// Convenience function for constructing expressions from literal
1626    /// field elements.
1627    pub fn literal(x: F) -> Self {
1628        ConstantTerm::Literal(x).into()
1629    }
1630
1631    /// Combines multiple constraints `[c0, ..., cn]` into a single constraint
1632    /// `alpha^alpha0 * c0 + alpha^{alpha0 + 1} * c1 + ... + alpha^{alpha0 + n} * cn`.
1633    pub fn combine_constraints(alphas: impl Iterator<Item = u32>, cs: Vec<Self>) -> Self {
1634        let zero = Expr::<ConstantExpr<F, ChallengeTerm>, Column>::zero();
1635        cs.into_iter()
1636            .zip_eq(alphas)
1637            .map(|(c, i)| Expr::from(ConstantExpr::pow(ChallengeTerm::ALPHA.into(), i as u64)) * c)
1638            .fold(zero, |acc, x| acc + x)
1639    }
1640}
1641
1642impl<F: FftField, Column: Copy, ChallengeTerm: Copy> Expr<ConstantExpr<F, ChallengeTerm>, Column> {
1643    /// Compile an expression to an RPN expression.
1644    pub fn to_polish(&self) -> Vec<PolishToken<F, Column, ChallengeTerm>> {
1645        let mut res = vec![];
1646        let mut cache = HashMap::new();
1647        self.to_polish_(&mut cache, &mut res);
1648        res
1649    }
1650
1651    fn to_polish_(
1652        &self,
1653        cache: &mut HashMap<CacheId, usize>,
1654        res: &mut Vec<PolishToken<F, Column, ChallengeTerm>>,
1655    ) {
1656        match self {
1657            Expr::Double(x) => {
1658                x.to_polish_(cache, res);
1659                res.push(PolishToken::Dup);
1660                res.push(PolishToken::Add);
1661            }
1662            Expr::Square(x) => {
1663                x.to_polish_(cache, res);
1664                res.push(PolishToken::Dup);
1665                res.push(PolishToken::Mul);
1666            }
1667            Expr::Pow(x, d) => {
1668                x.to_polish_(cache, res);
1669                res.push(PolishToken::Pow(*d))
1670            }
1671            Expr::Atom(ExprInner::Constant(c)) => {
1672                c.to_polish(cache, res);
1673            }
1674            Expr::Atom(ExprInner::Cell(v)) => res.push(PolishToken::Cell(*v)),
1675            Expr::Atom(ExprInner::VanishesOnZeroKnowledgeAndPreviousRows) => {
1676                res.push(PolishToken::VanishesOnZeroKnowledgeAndPreviousRows);
1677            }
1678            Expr::Atom(ExprInner::UnnormalizedLagrangeBasis(i)) => {
1679                res.push(PolishToken::UnnormalizedLagrangeBasis(*i));
1680            }
1681            Expr::Add(x, y) => {
1682                x.to_polish_(cache, res);
1683                y.to_polish_(cache, res);
1684                res.push(PolishToken::Add);
1685            }
1686            Expr::Sub(x, y) => {
1687                x.to_polish_(cache, res);
1688                y.to_polish_(cache, res);
1689                res.push(PolishToken::Sub);
1690            }
1691            Expr::Mul(x, y) => {
1692                x.to_polish_(cache, res);
1693                y.to_polish_(cache, res);
1694                res.push(PolishToken::Mul);
1695            }
1696            Expr::Cache(id, e) => {
1697                match cache.get(id) {
1698                    Some(pos) =>
1699                    // Already computed and stored this.
1700                    {
1701                        res.push(PolishToken::Load(*pos))
1702                    }
1703                    None => {
1704                        // Haven't computed this yet. Compute it, then store it.
1705                        e.to_polish_(cache, res);
1706                        res.push(PolishToken::Store);
1707                        cache.insert(*id, cache.len());
1708                    }
1709                }
1710            }
1711            Expr::IfFeature(feature, e1, e2) => {
1712                {
1713                    // True branch
1714                    let tok = PolishToken::SkipIfNot(*feature, 0);
1715                    res.push(tok);
1716                    let len_before = res.len();
1717                    /* Clone the cache, to make sure we don't try to access cached statements later
1718                    when the feature flag is off. */
1719                    let mut cache = cache.clone();
1720                    e1.to_polish_(&mut cache, res);
1721                    let len_after = res.len();
1722                    res[len_before - 1] = PolishToken::SkipIfNot(*feature, len_after - len_before);
1723                }
1724
1725                {
1726                    // False branch
1727                    let tok = PolishToken::SkipIfNot(*feature, 0);
1728                    res.push(tok);
1729                    let len_before = res.len();
1730                    /* Clone the cache, to make sure we don't try to access cached statements later
1731                    when the feature flag is on. */
1732                    let mut cache = cache.clone();
1733                    e2.to_polish_(&mut cache, res);
1734                    let len_after = res.len();
1735                    res[len_before - 1] = PolishToken::SkipIfNot(*feature, len_after - len_before);
1736                }
1737            }
1738        }
1739    }
1740}
1741
1742impl<F: FftField, Column: PartialEq + Copy, ChallengeTerm: Copy>
1743    Expr<ConstantExpr<F, ChallengeTerm>, Column>
1744{
1745    fn evaluate_constants_(
1746        &self,
1747        c: &Constants<F>,
1748        chals: &dyn Index<ChallengeTerm, Output = F>,
1749    ) -> Expr<F, Column> {
1750        use ExprInner::*;
1751        use Operations::*;
1752        // TODO: Use cache
1753        match self {
1754            Double(x) => x.evaluate_constants_(c, chals).double(),
1755            Pow(x, d) => x.evaluate_constants_(c, chals).pow(*d),
1756            Square(x) => x.evaluate_constants_(c, chals).square(),
1757            Atom(Constant(x)) => Atom(Constant(x.value(c, chals))),
1758            Atom(Cell(v)) => Atom(Cell(*v)),
1759            Atom(VanishesOnZeroKnowledgeAndPreviousRows) => {
1760                Atom(VanishesOnZeroKnowledgeAndPreviousRows)
1761            }
1762            Atom(UnnormalizedLagrangeBasis(i)) => Atom(UnnormalizedLagrangeBasis(*i)),
1763            Add(x, y) => x.evaluate_constants_(c, chals) + y.evaluate_constants_(c, chals),
1764            Mul(x, y) => x.evaluate_constants_(c, chals) * y.evaluate_constants_(c, chals),
1765            Sub(x, y) => x.evaluate_constants_(c, chals) - y.evaluate_constants_(c, chals),
1766            Cache(id, e) => Cache(*id, Box::new(e.evaluate_constants_(c, chals))),
1767            IfFeature(feature, e1, e2) => IfFeature(
1768                *feature,
1769                Box::new(e1.evaluate_constants_(c, chals)),
1770                Box::new(e2.evaluate_constants_(c, chals)),
1771            ),
1772        }
1773    }
1774
1775    /// Evaluate an expression as a field element against an environment.
1776    pub fn evaluate<
1777        'a,
1778        Evaluations: ColumnEvaluations<F, Column = Column>,
1779        Challenge: Index<ChallengeTerm, Output = F>,
1780        Environment: ColumnEnvironment<'a, F, ChallengeTerm, Challenge, Column = Column>,
1781    >(
1782        &self,
1783        d: D<F>,
1784        pt: F,
1785        evals: &Evaluations,
1786        env: &Environment,
1787    ) -> Result<F, ExprError<Column>> {
1788        self.evaluate_(d, pt, evals, env.get_constants(), env.get_challenges())
1789    }
1790
1791    /// Evaluate an expression as a field element against the constants.
1792    pub fn evaluate_<Evaluations: ColumnEvaluations<F, Column = Column>>(
1793        &self,
1794        d: D<F>,
1795        pt: F,
1796        evals: &Evaluations,
1797        c: &Constants<F>,
1798        chals: &dyn Index<ChallengeTerm, Output = F>,
1799    ) -> Result<F, ExprError<Column>> {
1800        use ExprInner::*;
1801        use Operations::*;
1802        match self {
1803            Double(x) => x.evaluate_(d, pt, evals, c, chals).map(|x| x.double()),
1804            Atom(Constant(x)) => Ok(x.value(c, chals)),
1805            Pow(x, p) => Ok(x.evaluate_(d, pt, evals, c, chals)?.pow([*p])),
1806            Mul(x, y) => {
1807                let x = (*x).evaluate_(d, pt, evals, c, chals)?;
1808                let y = (*y).evaluate_(d, pt, evals, c, chals)?;
1809                Ok(x * y)
1810            }
1811            Square(x) => Ok(x.evaluate_(d, pt, evals, c, chals)?.square()),
1812            Add(x, y) => {
1813                let x = (*x).evaluate_(d, pt, evals, c, chals)?;
1814                let y = (*y).evaluate_(d, pt, evals, c, chals)?;
1815                Ok(x + y)
1816            }
1817            Sub(x, y) => {
1818                let x = (*x).evaluate_(d, pt, evals, c, chals)?;
1819                let y = (*y).evaluate_(d, pt, evals, c, chals)?;
1820                Ok(x - y)
1821            }
1822            Atom(VanishesOnZeroKnowledgeAndPreviousRows) => {
1823                Ok(eval_vanishes_on_last_n_rows(d, c.zk_rows + 1, pt))
1824            }
1825            Atom(UnnormalizedLagrangeBasis(i)) => {
1826                let offset = if i.zk_rows {
1827                    -(c.zk_rows as i32) + i.offset
1828                } else {
1829                    i.offset
1830                };
1831                Ok(unnormalized_lagrange_basis(&d, offset, &pt))
1832            }
1833            Atom(Cell(v)) => v.evaluate(evals),
1834            Cache(_, e) => e.evaluate_(d, pt, evals, c, chals),
1835            IfFeature(feature, e1, e2) => {
1836                if feature.is_enabled() {
1837                    e1.evaluate_(d, pt, evals, c, chals)
1838                } else {
1839                    e2.evaluate_(d, pt, evals, c, chals)
1840                }
1841            }
1842        }
1843    }
1844
1845    /// Evaluate the constant expressions in this expression down into field elements.
1846    pub fn evaluate_constants<
1847        'a,
1848        Challenge: Index<ChallengeTerm, Output = F>,
1849        Environment: ColumnEnvironment<'a, F, ChallengeTerm, Challenge, Column = Column>,
1850    >(
1851        &self,
1852        env: &Environment,
1853    ) -> Expr<F, Column> {
1854        self.evaluate_constants_(env.get_constants(), env.get_challenges())
1855    }
1856
1857    /// Compute the polynomial corresponding to this expression, in evaluation form.
1858    /// The routine will first replace the constants (verifier challenges and
1859    /// constants like the matrix used by `Poseidon`) in the expression with their
1860    /// respective values using `evaluate_constants` and will after evaluate the
1861    /// monomials with the corresponding column values using the method
1862    /// `evaluations`.
1863    pub fn evaluations<
1864        'a,
1865        Challenge: Index<ChallengeTerm, Output = F>,
1866        Environment: ColumnEnvironment<'a, F, ChallengeTerm, Challenge, Column = Column>,
1867    >(
1868        &self,
1869        env: &Environment,
1870    ) -> Evaluations<F, D<F>> {
1871        self.evaluate_constants(env).evaluations(env)
1872    }
1873}
1874
1875/// Use as a result of the expression evaluations routine.
1876/// For now, the left branch is the result of an evaluation and the right branch
1877/// is the ID of an element in the cache
1878enum Either<A, B> {
1879    Left(A),
1880    Right(B),
1881}
1882
1883impl<F: FftField, Column: Copy> Expr<F, Column> {
1884    /// Evaluate an expression into a field element.
1885    pub fn evaluate<Evaluations: ColumnEvaluations<F, Column = Column>>(
1886        &self,
1887        d: D<F>,
1888        pt: F,
1889        zk_rows: u64,
1890        evals: &Evaluations,
1891    ) -> Result<F, ExprError<Column>> {
1892        use ExprInner::*;
1893        use Operations::*;
1894        match self {
1895            Atom(Constant(x)) => Ok(*x),
1896            Pow(x, p) => Ok(x.evaluate(d, pt, zk_rows, evals)?.pow([*p])),
1897            Double(x) => x.evaluate(d, pt, zk_rows, evals).map(|x| x.double()),
1898            Square(x) => x.evaluate(d, pt, zk_rows, evals).map(|x| x.square()),
1899            Mul(x, y) => {
1900                let x = (*x).evaluate(d, pt, zk_rows, evals)?;
1901                let y = (*y).evaluate(d, pt, zk_rows, evals)?;
1902                Ok(x * y)
1903            }
1904            Add(x, y) => {
1905                let x = (*x).evaluate(d, pt, zk_rows, evals)?;
1906                let y = (*y).evaluate(d, pt, zk_rows, evals)?;
1907                Ok(x + y)
1908            }
1909            Sub(x, y) => {
1910                let x = (*x).evaluate(d, pt, zk_rows, evals)?;
1911                let y = (*y).evaluate(d, pt, zk_rows, evals)?;
1912                Ok(x - y)
1913            }
1914            Atom(VanishesOnZeroKnowledgeAndPreviousRows) => {
1915                Ok(eval_vanishes_on_last_n_rows(d, zk_rows + 1, pt))
1916            }
1917            Atom(UnnormalizedLagrangeBasis(i)) => {
1918                let offset = if i.zk_rows {
1919                    -(zk_rows as i32) + i.offset
1920                } else {
1921                    i.offset
1922                };
1923                Ok(unnormalized_lagrange_basis(&d, offset, &pt))
1924            }
1925            Atom(Cell(v)) => v.evaluate(evals),
1926            Cache(_, e) => e.evaluate(d, pt, zk_rows, evals),
1927            IfFeature(feature, e1, e2) => {
1928                if feature.is_enabled() {
1929                    e1.evaluate(d, pt, zk_rows, evals)
1930                } else {
1931                    e2.evaluate(d, pt, zk_rows, evals)
1932                }
1933            }
1934        }
1935    }
1936
1937    /// Compute the polynomial corresponding to this expression, in evaluation form.
1938    pub fn evaluations<
1939        'a,
1940        ChallengeTerm,
1941        Challenge: Index<ChallengeTerm, Output = F>,
1942        Environment: ColumnEnvironment<'a, F, ChallengeTerm, Challenge, Column = Column>,
1943    >(
1944        &self,
1945        env: &Environment,
1946    ) -> Evaluations<F, D<F>> {
1947        let d1_size = env.get_domain(Domain::D1).size;
1948        let deg = self.degree(d1_size, env.get_constants().zk_rows);
1949        let d = if deg <= d1_size {
1950            Domain::D1
1951        } else if deg <= 4 * d1_size {
1952            Domain::D4
1953        } else if deg <= 8 * d1_size {
1954            Domain::D8
1955        } else {
1956            panic!("constraint had degree {deg} > d8 ({})", 8 * d1_size);
1957        };
1958
1959        let mut cache = HashMap::new();
1960
1961        let evals = match self.evaluations_helper(&mut cache, d, env) {
1962            Either::Left(x) => x,
1963            Either::Right(id) => cache.get(&id).unwrap().clone(),
1964        };
1965
1966        match evals {
1967            EvalResult::Evals { evals, domain } => {
1968                assert_eq!(domain, d);
1969                evals
1970            }
1971            EvalResult::Constant(x) => EvalResult::init_((d, env.get_domain(d)), |_| x),
1972            EvalResult::SubEvals {
1973                evals,
1974                domain: d_sub,
1975                shift: s,
1976            } => {
1977                let res_domain = env.get_domain(d);
1978                let scale = (d_sub as usize) / (d as usize);
1979                assert!(
1980                    scale != 0,
1981                    "Check that the implementation of
1982                column_domain and the evaluation domain of the
1983                witnesses are the same"
1984                );
1985                EvalResult::init_((d, res_domain), |i| {
1986                    evals.evals[(scale * i + (d_sub as usize) * s) % evals.evals.len()]
1987                })
1988            }
1989        }
1990    }
1991
1992    fn evaluations_helper<
1993        'a,
1994        'b,
1995        ChallengeTerm,
1996        Challenge: Index<ChallengeTerm, Output = F>,
1997        Environment: ColumnEnvironment<'a, F, ChallengeTerm, Challenge, Column = Column>,
1998    >(
1999        &self,
2000        cache: &'b mut HashMap<CacheId, EvalResult<'a, F>>,
2001        d: Domain,
2002        env: &Environment,
2003    ) -> Either<EvalResult<'a, F>, CacheId>
2004    where
2005        'a: 'b,
2006    {
2007        let dom = (d, env.get_domain(d));
2008
2009        let res: EvalResult<'a, F> = match self {
2010            Expr::Square(x) => match x.evaluations_helper(cache, d, env) {
2011                Either::Left(x) => x.square(dom),
2012                Either::Right(id) => id.get_from(cache).unwrap().square(dom),
2013            },
2014            Expr::Double(x) => {
2015                let x = x.evaluations_helper(cache, d, env);
2016                let res = match x {
2017                    Either::Left(x) => {
2018                        let x = match x {
2019                            EvalResult::Evals { domain, mut evals } => {
2020                                o1_utils::cfg_iter_mut!(evals.evals).for_each(|x| {
2021                                    x.double_in_place();
2022                                });
2023                                return Either::Left(EvalResult::Evals { domain, evals });
2024                            }
2025                            x => x,
2026                        };
2027                        let xx = || match &x {
2028                            EvalResult::Constant(x) => EvalResult::Constant(*x),
2029                            EvalResult::SubEvals {
2030                                domain,
2031                                shift,
2032                                evals,
2033                            } => EvalResult::SubEvals {
2034                                domain: *domain,
2035                                shift: *shift,
2036                                evals,
2037                            },
2038                            EvalResult::Evals { domain, evals } => EvalResult::SubEvals {
2039                                domain: *domain,
2040                                shift: 0,
2041                                evals,
2042                            },
2043                        };
2044                        xx().add(xx(), dom)
2045                    }
2046                    Either::Right(id) => {
2047                        let x1 = id.get_from(cache).unwrap();
2048                        let x2 = id.get_from(cache).unwrap();
2049                        x1.add(x2, dom)
2050                    }
2051                };
2052                return Either::Left(res);
2053            }
2054            Expr::Cache(id, e) => match cache.get(id) {
2055                Some(_) => return Either::Right(*id),
2056                None => {
2057                    match e.evaluations_helper(cache, d, env) {
2058                        Either::Left(es) => {
2059                            cache.insert(*id, es);
2060                        }
2061                        Either::Right(_) => {}
2062                    };
2063                    return Either::Right(*id);
2064                }
2065            },
2066            Expr::Pow(x, p) => {
2067                let x = x.evaluations_helper(cache, d, env);
2068                match x {
2069                    Either::Left(x) => x.pow(*p, (d, env.get_domain(d))),
2070                    Either::Right(id) => {
2071                        id.get_from(cache).unwrap().pow(*p, (d, env.get_domain(d)))
2072                    }
2073                }
2074            }
2075            Expr::Atom(ExprInner::VanishesOnZeroKnowledgeAndPreviousRows) => EvalResult::SubEvals {
2076                domain: Domain::D8,
2077                shift: 0,
2078                evals: env.vanishes_on_zero_knowledge_and_previous_rows(),
2079            },
2080            Expr::Atom(ExprInner::Constant(x)) => EvalResult::Constant(*x),
2081            Expr::Atom(ExprInner::UnnormalizedLagrangeBasis(i)) => {
2082                let offset = if i.zk_rows {
2083                    -(env.get_constants().zk_rows as i32) + i.offset
2084                } else {
2085                    i.offset
2086                };
2087                EvalResult::Evals {
2088                    domain: d,
2089                    evals: unnormalized_lagrange_evals(env.l0_1(), offset, d, env),
2090                }
2091            }
2092            Expr::Atom(ExprInner::Cell(Variable { col, row })) => {
2093                let evals: &'a Evaluations<F, D<F>> = {
2094                    match env.get_column(col) {
2095                        None => return Either::Left(EvalResult::Constant(F::zero())),
2096                        Some(e) => e,
2097                    }
2098                };
2099                EvalResult::SubEvals {
2100                    domain: env.column_domain(col),
2101                    shift: row.shift(),
2102                    evals,
2103                }
2104            }
2105            Expr::Add(e1, e2) => {
2106                let dom = (d, env.get_domain(d));
2107                let f = |x: EvalResult<F>, y: EvalResult<F>| x.add(y, dom);
2108                let e1 = e1.evaluations_helper(cache, d, env);
2109                let e2 = e2.evaluations_helper(cache, d, env);
2110                use Either::*;
2111                match (e1, e2) {
2112                    (Left(e1), Left(e2)) => f(e1, e2),
2113                    (Right(id1), Left(e2)) => f(id1.get_from(cache).unwrap(), e2),
2114                    (Left(e1), Right(id2)) => f(e1, id2.get_from(cache).unwrap()),
2115                    (Right(id1), Right(id2)) => {
2116                        f(id1.get_from(cache).unwrap(), id2.get_from(cache).unwrap())
2117                    }
2118                }
2119            }
2120            Expr::Sub(e1, e2) => {
2121                let dom = (d, env.get_domain(d));
2122                let f = |x: EvalResult<F>, y: EvalResult<F>| x.sub(y, dom);
2123                let e1 = e1.evaluations_helper(cache, d, env);
2124                let e2 = e2.evaluations_helper(cache, d, env);
2125                use Either::*;
2126                match (e1, e2) {
2127                    (Left(e1), Left(e2)) => f(e1, e2),
2128                    (Right(id1), Left(e2)) => f(id1.get_from(cache).unwrap(), e2),
2129                    (Left(e1), Right(id2)) => f(e1, id2.get_from(cache).unwrap()),
2130                    (Right(id1), Right(id2)) => {
2131                        f(id1.get_from(cache).unwrap(), id2.get_from(cache).unwrap())
2132                    }
2133                }
2134            }
2135            Expr::Mul(e1, e2) => {
2136                let dom = (d, env.get_domain(d));
2137                let f = |x: EvalResult<F>, y: EvalResult<F>| x.mul(y, dom);
2138                let e1 = e1.evaluations_helper(cache, d, env);
2139                let e2 = e2.evaluations_helper(cache, d, env);
2140                use Either::*;
2141                match (e1, e2) {
2142                    (Left(e1), Left(e2)) => f(e1, e2),
2143                    (Right(id1), Left(e2)) => f(id1.get_from(cache).unwrap(), e2),
2144                    (Left(e1), Right(id2)) => f(e1, id2.get_from(cache).unwrap()),
2145                    (Right(id1), Right(id2)) => {
2146                        f(id1.get_from(cache).unwrap(), id2.get_from(cache).unwrap())
2147                    }
2148                }
2149            }
2150            Expr::IfFeature(feature, e1, e2) => {
2151                /* Clone the cache, to make sure we don't try to access cached statements later
2152                when the feature flag is off. */
2153                let mut cache = cache.clone();
2154                if feature.is_enabled() {
2155                    return e1.evaluations_helper(&mut cache, d, env);
2156                } else {
2157                    return e2.evaluations_helper(&mut cache, d, env);
2158                }
2159            }
2160        };
2161        Either::Left(res)
2162    }
2163}
2164
2165#[derive(Clone, Debug, Serialize, Deserialize)]
2166/// A "linearization", which is linear combination with `E` coefficients of
2167/// columns.
2168pub struct Linearization<E, Column> {
2169    pub constant_term: E,
2170    pub index_terms: Vec<(Column, E)>,
2171}
2172
2173impl<E: Default, Column> Default for Linearization<E, Column> {
2174    fn default() -> Self {
2175        Linearization {
2176            constant_term: E::default(),
2177            index_terms: vec![],
2178        }
2179    }
2180}
2181
2182impl<A, Column: Copy> Linearization<A, Column> {
2183    /// Apply a function to all the coefficients in the linearization.
2184    pub fn map<B, F: Fn(&A) -> B>(&self, f: F) -> Linearization<B, Column> {
2185        Linearization {
2186            constant_term: f(&self.constant_term),
2187            index_terms: self.index_terms.iter().map(|(c, x)| (*c, f(x))).collect(),
2188        }
2189    }
2190}
2191
2192impl<F: FftField, Column: PartialEq + Copy, ChallengeTerm: Copy>
2193    Linearization<Expr<ConstantExpr<F, ChallengeTerm>, Column>, Column>
2194{
2195    /// Evaluate the constants in a linearization with `ConstantExpr<F>` coefficients down
2196    /// to literal field elements.
2197    pub fn evaluate_constants<
2198        'a,
2199        Challenge: Index<ChallengeTerm, Output = F>,
2200        Environment: ColumnEnvironment<'a, F, ChallengeTerm, Challenge, Column = Column>,
2201    >(
2202        &self,
2203        env: &Environment,
2204    ) -> Linearization<Expr<F, Column>, Column> {
2205        self.map(|e| e.evaluate_constants(env))
2206    }
2207}
2208
2209impl<F: FftField, Column: Copy + Debug, ChallengeTerm: Copy>
2210    Linearization<Vec<PolishToken<F, Column, ChallengeTerm>>, Column>
2211{
2212    /// Given a linearization and an environment, compute the polynomial corresponding to the
2213    /// linearization, in evaluation form.
2214    pub fn to_polynomial<
2215        'a,
2216        Challenge: Index<ChallengeTerm, Output = F>,
2217        ColEvaluations: ColumnEvaluations<F, Column = Column>,
2218        Environment: ColumnEnvironment<'a, F, ChallengeTerm, Challenge, Column = Column>,
2219    >(
2220        &self,
2221        env: &Environment,
2222        pt: F,
2223        evals: &ColEvaluations,
2224    ) -> (F, Evaluations<F, D<F>>) {
2225        let cs = env.get_constants();
2226        let chals = env.get_challenges();
2227        let d1 = env.get_domain(Domain::D1);
2228        let n = d1.size();
2229        let mut res = vec![F::zero(); n];
2230        self.index_terms.iter().for_each(|(idx, c)| {
2231            let c = PolishToken::evaluate(c, d1, pt, evals, cs, chals).unwrap();
2232            let e = env
2233                .get_column(idx)
2234                .unwrap_or_else(|| panic!("Index polynomial {idx:?} not found"));
2235            let scale = e.evals.len() / n;
2236            o1_utils::cfg_iter_mut!(res)
2237                .enumerate()
2238                .for_each(|(i, r)| *r += c * e.evals[scale * i]);
2239        });
2240        let p = Evaluations::<F, D<F>>::from_vec_and_domain(res, d1);
2241        (
2242            PolishToken::evaluate(&self.constant_term, d1, pt, evals, cs, chals).unwrap(),
2243            p,
2244        )
2245    }
2246}
2247
2248impl<F: FftField, Column: Debug + PartialEq + Copy, ChallengeTerm: Copy>
2249    Linearization<Expr<ConstantExpr<F, ChallengeTerm>, Column>, Column>
2250{
2251    /// Given a linearization and an environment, compute the polynomial corresponding to the
2252    /// linearization, in evaluation form.
2253    pub fn to_polynomial<
2254        'a,
2255        Challenge: Index<ChallengeTerm, Output = F>,
2256        ColEvaluations: ColumnEvaluations<F, Column = Column>,
2257        Environment: ColumnEnvironment<'a, F, ChallengeTerm, Challenge, Column = Column>,
2258    >(
2259        &self,
2260        env: &Environment,
2261        pt: F,
2262        evals: &ColEvaluations,
2263    ) -> (F, DensePolynomial<F>) {
2264        let cs = env.get_constants();
2265        let chals = env.get_challenges();
2266        let d1 = env.get_domain(Domain::D1);
2267        let n = d1.size();
2268        let mut res = vec![F::zero(); n];
2269        self.index_terms.iter().for_each(|(idx, c)| {
2270            let c = c.evaluate_(d1, pt, evals, cs, chals).unwrap();
2271            let e = env
2272                .get_column(idx)
2273                .unwrap_or_else(|| panic!("Index polynomial {idx:?} not found"));
2274            let scale = e.evals.len() / n;
2275            o1_utils::cfg_iter_mut!(res)
2276                .enumerate()
2277                .for_each(|(i, r)| *r += c * e.evals[scale * i])
2278        });
2279        let p = Evaluations::<F, D<F>>::from_vec_and_domain(res, d1).interpolate();
2280        (
2281            self.constant_term
2282                .evaluate_(d1, pt, evals, cs, chals)
2283                .unwrap(),
2284            p,
2285        )
2286    }
2287}
2288
2289type Monomials<F, Column> = HashMap<Vec<Variable<Column>>, Expr<F, Column>>;
2290
2291fn mul_monomials<
2292    F: Neg<Output = F> + Clone + One + Zero + PartialEq,
2293    Column: Ord + Copy + core::hash::Hash,
2294>(
2295    e1: &Monomials<F, Column>,
2296    e2: &Monomials<F, Column>,
2297) -> Monomials<F, Column>
2298where
2299    ExprInner<F, Column>: Literal,
2300    <ExprInner<F, Column> as Literal>::F: Field,
2301{
2302    let mut res: HashMap<_, Expr<F, Column>> = HashMap::new();
2303    for (m1, c1) in e1.iter() {
2304        for (m2, c2) in e2.iter() {
2305            let mut m = m1.clone();
2306            m.extend(m2);
2307            m.sort();
2308            let c1c2 = c1.clone() * c2.clone();
2309            let v = res.entry(m).or_insert_with(Expr::<F, Column>::zero);
2310            *v = v.clone() + c1c2;
2311        }
2312    }
2313    res
2314}
2315
2316impl<
2317        F: Neg<Output = F> + Clone + One + Zero + PartialEq,
2318        Column: Ord + Copy + core::hash::Hash,
2319    > Expr<F, Column>
2320where
2321    ExprInner<F, Column>: Literal,
2322    <ExprInner<F, Column> as Literal>::F: Field,
2323{
2324    // TODO: This function (which takes linear time)
2325    // is called repeatedly in monomials, yielding quadratic behavior for
2326    // that function. It's ok for now as we only call that function once on
2327    // a small input when producing the verification key.
2328    fn is_constant(&self, evaluated: &HashSet<Column>) -> bool {
2329        use ExprInner::*;
2330        use Operations::*;
2331        match self {
2332            Pow(x, _) => x.is_constant(evaluated),
2333            Square(x) => x.is_constant(evaluated),
2334            Atom(Constant(_)) => true,
2335            Atom(Cell(v)) => evaluated.contains(&v.col),
2336            Double(x) => x.is_constant(evaluated),
2337            Add(x, y) | Sub(x, y) | Mul(x, y) => {
2338                x.is_constant(evaluated) && y.is_constant(evaluated)
2339            }
2340            Atom(VanishesOnZeroKnowledgeAndPreviousRows) => true,
2341            Atom(UnnormalizedLagrangeBasis(_)) => true,
2342            Cache(_, x) => x.is_constant(evaluated),
2343            IfFeature(_, e1, e2) => e1.is_constant(evaluated) && e2.is_constant(evaluated),
2344        }
2345    }
2346
2347    fn monomials(&self, ev: &HashSet<Column>) -> HashMap<Vec<Variable<Column>>, Expr<F, Column>> {
2348        let sing = |v: Vec<Variable<Column>>, c: Expr<F, Column>| {
2349            let mut h = HashMap::new();
2350            h.insert(v, c);
2351            h
2352        };
2353        let constant = |e: Expr<F, Column>| sing(vec![], e);
2354        use ExprInner::*;
2355        use Operations::*;
2356
2357        if self.is_constant(ev) {
2358            return constant(self.clone());
2359        }
2360
2361        match self {
2362            Pow(x, d) => {
2363                // Run the multiplication logic with square and multiply
2364                let mut acc = sing(vec![], Expr::<F, Column>::one());
2365                let mut acc_is_one = true;
2366                let x = x.monomials(ev);
2367
2368                for i in (0..u64::BITS).rev() {
2369                    if !acc_is_one {
2370                        let acc2 = mul_monomials(&acc, &acc);
2371                        acc = acc2;
2372                    }
2373
2374                    if (d >> i) & 1 == 1 {
2375                        let res = mul_monomials(&acc, &x);
2376                        acc = res;
2377                        acc_is_one = false;
2378                    }
2379                }
2380                acc
2381            }
2382            Double(e) => {
2383                HashMap::from_iter(e.monomials(ev).into_iter().map(|(m, c)| (m, c.double())))
2384            }
2385            Cache(_, e) => e.monomials(ev),
2386            Atom(UnnormalizedLagrangeBasis(i)) => constant(Atom(UnnormalizedLagrangeBasis(*i))),
2387            Atom(VanishesOnZeroKnowledgeAndPreviousRows) => {
2388                constant(Atom(VanishesOnZeroKnowledgeAndPreviousRows))
2389            }
2390            Atom(Constant(c)) => constant(Atom(Constant(c.clone()))),
2391            Atom(Cell(var)) => sing(vec![*var], Atom(Constant(F::one()))),
2392            Add(e1, e2) => {
2393                let mut res = e1.monomials(ev);
2394                for (m, c) in e2.monomials(ev) {
2395                    let v = match res.remove(&m) {
2396                        None => c,
2397                        Some(v) => v + c,
2398                    };
2399                    res.insert(m, v);
2400                }
2401                res
2402            }
2403            Sub(e1, e2) => {
2404                let mut res = e1.monomials(ev);
2405                for (m, c) in e2.monomials(ev) {
2406                    let v = match res.remove(&m) {
2407                        None => -c, // Expr::constant(F::one()) * c,
2408                        Some(v) => v - c,
2409                    };
2410                    res.insert(m, v);
2411                }
2412                res
2413            }
2414            Mul(e1, e2) => {
2415                let e1 = e1.monomials(ev);
2416                let e2 = e2.monomials(ev);
2417                mul_monomials(&e1, &e2)
2418            }
2419            Square(x) => {
2420                let x = x.monomials(ev);
2421                mul_monomials(&x, &x)
2422            }
2423            IfFeature(feature, e1, e2) => {
2424                let mut res = HashMap::new();
2425                let e1_monomials = e1.monomials(ev);
2426                let mut e2_monomials = e2.monomials(ev);
2427                for (m, c) in e1_monomials.into_iter() {
2428                    let else_branch = match e2_monomials.remove(&m) {
2429                        None => Expr::zero(),
2430                        Some(c) => c,
2431                    };
2432                    let expr = Expr::IfFeature(*feature, Box::new(c), Box::new(else_branch));
2433                    res.insert(m, expr);
2434                }
2435                for (m, c) in e2_monomials.into_iter() {
2436                    let expr = Expr::IfFeature(*feature, Box::new(Expr::zero()), Box::new(c));
2437                    res.insert(m, expr);
2438                }
2439                res
2440            }
2441        }
2442    }
2443
2444    /// There is an optimization in PLONK called "linearization" in which a certain
2445    /// polynomial is expressed as a linear combination of other polynomials in order
2446    /// to reduce the number of evaluations needed in the IOP (by relying on the homomorphic
2447    /// property of the polynomial commitments used.)
2448    ///
2449    /// The function performs this "linearization", which we now describe in some detail.
2450    ///
2451    /// In mathematical language, an expression `e: Expr<F>`
2452    /// is an element of the polynomial ring `F[V]`, where `V` is a set of variables.
2453    ///
2454    /// Given a subset `V_0` of `V` (and letting `V_1 = V \setminus V_0`), there is a map
2455    /// `factor_{V_0}: F[V] -> (F[V_1])[V_0]`. That is, polynomials with `F` coefficients in the variables `V = V_0 \cup V_1`
2456    /// are the same thing as polynomials with `F[V_1]` coefficients in variables `V_0`.
2457    ///
2458    /// There is also a function
2459    /// `lin_or_err : (F[V_1])[V_0] -> Result<Vec<(V_0, F[V_1])>, &str>`
2460    ///
2461    /// which checks if the given input is in fact a degree 1 polynomial in the variables `V_0`
2462    /// (i.e., a linear combination of `V_0` elements with `F[V_1]` coefficients)
2463    /// returning this linear combination if so.
2464    ///
2465    /// Given an expression `e` and set of columns `C_0`, letting
2466    /// `V_0 = { Variable { col: c, row: r } | c in C_0, r in { Curr, Next } }`,
2467    /// this function computes `lin_or_err(factor_{V_0}(e))`, although it does not
2468    /// compute it in that way. Instead, it computes it by reducing the expression into
2469    /// a sum of monomials with `F` coefficients, and then factors the monomials.
2470    pub fn linearize(
2471        &self,
2472        evaluated: HashSet<Column>,
2473    ) -> Result<Linearization<Expr<F, Column>, Column>, ExprError<Column>> {
2474        let mut res: HashMap<Column, Expr<F, Column>> = HashMap::new();
2475        let mut constant_term: Expr<F, Column> = Self::zero();
2476        let monomials = self.monomials(&evaluated);
2477
2478        for (m, c) in monomials {
2479            let (evaluated, mut unevaluated): (Vec<_>, _) =
2480                m.into_iter().partition(|v| evaluated.contains(&v.col));
2481            let c = evaluated
2482                .into_iter()
2483                .fold(c, |acc, v| acc * Expr::Atom(ExprInner::Cell(v)));
2484            if unevaluated.is_empty() {
2485                constant_term += c;
2486            } else if unevaluated.len() == 1 {
2487                let var = unevaluated.remove(0);
2488                match var.row {
2489                    Next => {
2490                        return Err(ExprError::MissingEvaluation(var.col, var.row));
2491                    }
2492                    Curr => {
2493                        let e = match res.remove(&var.col) {
2494                            Some(v) => v + c,
2495                            None => c,
2496                        };
2497                        res.insert(var.col, e);
2498                        // This code used to be
2499                        //
2500                        // let v = res.entry(var.col).or_insert(0.into());
2501                        // *v = v.clone() + c
2502                        //
2503                        // but calling clone made it extremely slow, so I replaced it
2504                        // with the above that moves v out of the map with .remove and
2505                        // into v + c.
2506                        //
2507                        // I'm not sure if there's a way to do it with the HashMap API
2508                        // without calling remove.
2509                    }
2510                }
2511            } else {
2512                return Err(ExprError::FailedLinearization(unevaluated));
2513            }
2514        }
2515        Ok(Linearization {
2516            constant_term,
2517            index_terms: res.into_iter().collect(),
2518        })
2519    }
2520}
2521
2522// Trait implementations
2523
2524impl<T: Literal> Zero for Operations<T>
2525where
2526    T::F: Field,
2527{
2528    fn zero() -> Self {
2529        Self::literal(T::F::zero())
2530    }
2531
2532    fn is_zero(&self) -> bool {
2533        if let Some(x) = self.to_literal_ref() {
2534            x.is_zero()
2535        } else {
2536            false
2537        }
2538    }
2539}
2540
2541impl<T: Literal + PartialEq> One for Operations<T>
2542where
2543    T::F: Field,
2544{
2545    fn one() -> Self {
2546        Self::literal(T::F::one())
2547    }
2548
2549    fn is_one(&self) -> bool {
2550        if let Some(x) = self.to_literal_ref() {
2551            x.is_one()
2552        } else {
2553            false
2554        }
2555    }
2556}
2557
2558impl<T: Literal> Neg for Operations<T>
2559where
2560    T::F: One + Neg<Output = T::F> + Copy,
2561{
2562    type Output = Self;
2563
2564    fn neg(self) -> Self {
2565        match self.to_literal() {
2566            Ok(x) => Self::literal(x.neg()),
2567            Err(x) => Operations::Mul(Box::new(Self::literal(T::F::one().neg())), Box::new(x)),
2568        }
2569    }
2570}
2571
2572impl<T: Literal> Add<Self> for Operations<T>
2573where
2574    T::F: Field,
2575{
2576    type Output = Self;
2577    fn add(self, other: Self) -> Self {
2578        if self.is_zero() {
2579            return other;
2580        }
2581        if other.is_zero() {
2582            return self;
2583        }
2584        let (x, y) = {
2585            match (self.to_literal(), other.to_literal()) {
2586                (Ok(x), Ok(y)) => return Self::literal(x + y),
2587                (Ok(x), Err(y)) => (Self::literal(x), y),
2588                (Err(x), Ok(y)) => (x, Self::literal(y)),
2589                (Err(x), Err(y)) => (x, y),
2590            }
2591        };
2592        Operations::Add(Box::new(x), Box::new(y))
2593    }
2594}
2595
2596impl<T: Literal> Sub<Self> for Operations<T>
2597where
2598    T::F: Field,
2599{
2600    type Output = Self;
2601    fn sub(self, other: Self) -> Self {
2602        if other.is_zero() {
2603            return self;
2604        }
2605        let (x, y) = {
2606            match (self.to_literal(), other.to_literal()) {
2607                (Ok(x), Ok(y)) => return Self::literal(x - y),
2608                (Ok(x), Err(y)) => (Self::literal(x), y),
2609                (Err(x), Ok(y)) => (x, Self::literal(y)),
2610                (Err(x), Err(y)) => (x, y),
2611            }
2612        };
2613        Operations::Sub(Box::new(x), Box::new(y))
2614    }
2615}
2616
2617impl<T: Literal + PartialEq> Mul<Self> for Operations<T>
2618where
2619    T::F: Field,
2620{
2621    type Output = Self;
2622    fn mul(self, other: Self) -> Self {
2623        if self.is_zero() || other.is_zero() {
2624            return Self::zero();
2625        }
2626
2627        if self.is_one() {
2628            return other;
2629        }
2630        if other.is_one() {
2631            return self;
2632        }
2633        let (x, y) = {
2634            match (self.to_literal(), other.to_literal()) {
2635                (Ok(x), Ok(y)) => return Self::literal(x * y),
2636                (Ok(x), Err(y)) => (Self::literal(x), y),
2637                (Err(x), Ok(y)) => (x, Self::literal(y)),
2638                (Err(x), Err(y)) => (x, y),
2639            }
2640        };
2641        Operations::Mul(Box::new(x), Box::new(y))
2642    }
2643}
2644
2645impl<F: Zero + Clone, Column: Clone> AddAssign<Expr<F, Column>> for Expr<F, Column>
2646where
2647    ExprInner<F, Column>: Literal,
2648    <ExprInner<F, Column> as Literal>::F: Field,
2649{
2650    fn add_assign(&mut self, other: Self) {
2651        if self.is_zero() {
2652            *self = other;
2653        } else if !other.is_zero() {
2654            *self = Expr::Add(Box::new(self.clone()), Box::new(other));
2655        }
2656    }
2657}
2658
2659impl<F, Column> MulAssign<Expr<F, Column>> for Expr<F, Column>
2660where
2661    F: Zero + One + PartialEq + Clone,
2662    Column: PartialEq + Clone,
2663    ExprInner<F, Column>: Literal,
2664    <ExprInner<F, Column> as Literal>::F: Field,
2665{
2666    fn mul_assign(&mut self, other: Self) {
2667        if self.is_zero() || other.is_zero() {
2668            *self = Self::zero();
2669        } else if self.is_one() {
2670            *self = other;
2671        } else if !other.is_one() {
2672            *self = Expr::Mul(Box::new(self.clone()), Box::new(other));
2673        }
2674    }
2675}
2676
2677impl<F: Field, Column> From<u64> for Expr<F, Column> {
2678    fn from(x: u64) -> Self {
2679        Expr::Atom(ExprInner::Constant(F::from(x)))
2680    }
2681}
2682
2683impl<'a, F: Field, Column, ChallengeTerm: AlphaChallengeTerm<'a>> From<u64>
2684    for Expr<ConstantExpr<F, ChallengeTerm>, Column>
2685{
2686    fn from(x: u64) -> Self {
2687        ConstantTerm::Literal(F::from(x)).into()
2688    }
2689}
2690
2691impl<F: Field, ChallengeTerm> From<u64> for ConstantExpr<F, ChallengeTerm> {
2692    fn from(x: u64) -> Self {
2693        ConstantTerm::Literal(F::from(x)).into()
2694    }
2695}
2696
2697impl<'a, F: Field, Column: PartialEq + Copy, ChallengeTerm: AlphaChallengeTerm<'a>> Mul<F>
2698    for Expr<ConstantExpr<F, ChallengeTerm>, Column>
2699{
2700    type Output = Expr<ConstantExpr<F, ChallengeTerm>, Column>;
2701
2702    fn mul(self, y: F) -> Self::Output {
2703        Expr::from(ConstantTerm::Literal(y)) * self
2704    }
2705}
2706
2707//
2708// Display
2709//
2710
2711pub trait FormattedOutput: Sized {
2712    fn is_alpha(&self) -> bool;
2713    fn ocaml(&self, cache: &mut HashMap<CacheId, Self>) -> String;
2714    fn latex(&self, cache: &mut HashMap<CacheId, Self>) -> String;
2715    fn text(&self, cache: &mut HashMap<CacheId, Self>) -> String;
2716}
2717
2718impl<'a, ChallengeTerm> FormattedOutput for ChallengeTerm
2719where
2720    ChallengeTerm: AlphaChallengeTerm<'a>,
2721{
2722    fn is_alpha(&self) -> bool {
2723        self.eq(&ChallengeTerm::ALPHA)
2724    }
2725    fn ocaml(&self, _cache: &mut HashMap<CacheId, Self>) -> String {
2726        self.to_string()
2727    }
2728
2729    fn latex(&self, _cache: &mut HashMap<CacheId, Self>) -> String {
2730        "\\".to_string() + &self.to_string()
2731    }
2732
2733    fn text(&self, _cache: &mut HashMap<CacheId, Self>) -> String {
2734        self.to_string()
2735    }
2736}
2737
2738impl<F: PrimeField> FormattedOutput for ConstantTerm<F> {
2739    fn is_alpha(&self) -> bool {
2740        false
2741    }
2742    fn ocaml(&self, _cache: &mut HashMap<CacheId, Self>) -> String {
2743        use ConstantTerm::*;
2744        match self {
2745            EndoCoefficient => "endo_coefficient".to_string(),
2746            Mds { row, col } => format!("mds({row}, {col})"),
2747            Literal(x) => format!(
2748                "field(\"{:#066X}\")",
2749                Into::<num_bigint::BigUint>::into(x.into_bigint())
2750            ),
2751        }
2752    }
2753
2754    fn latex(&self, _cache: &mut HashMap<CacheId, Self>) -> String {
2755        use ConstantTerm::*;
2756        match self {
2757            EndoCoefficient => "endo\\_coefficient".to_string(),
2758            Mds { row, col } => format!("mds({row}, {col})"),
2759            Literal(x) => format!("\\mathbb{{F}}({})", x.into_bigint().into()),
2760        }
2761    }
2762
2763    fn text(&self, _cache: &mut HashMap<CacheId, Self>) -> String {
2764        use ConstantTerm::*;
2765        match self {
2766            EndoCoefficient => "endo_coefficient".to_string(),
2767            Mds { row, col } => format!("mds({row}, {col})"),
2768            Literal(x) => format!("0x{}", x.to_hex()),
2769        }
2770    }
2771}
2772
2773impl<'a, F: PrimeField, ChallengeTerm> FormattedOutput for ConstantExprInner<F, ChallengeTerm>
2774where
2775    ChallengeTerm: AlphaChallengeTerm<'a>,
2776{
2777    fn is_alpha(&self) -> bool {
2778        use ConstantExprInner::*;
2779        match self {
2780            Challenge(x) => x.is_alpha(),
2781            Constant(x) => x.is_alpha(),
2782        }
2783    }
2784    fn ocaml(&self, cache: &mut HashMap<CacheId, Self>) -> String {
2785        use ConstantExprInner::*;
2786        match self {
2787            Challenge(x) => {
2788                let mut inner_cache = HashMap::new();
2789                let res = x.ocaml(&mut inner_cache);
2790                inner_cache.into_iter().for_each(|(k, v)| {
2791                    let _ = cache.insert(k, Challenge(v));
2792                });
2793                res
2794            }
2795            Constant(x) => {
2796                let mut inner_cache = HashMap::new();
2797                let res = x.ocaml(&mut inner_cache);
2798                inner_cache.into_iter().for_each(|(k, v)| {
2799                    let _ = cache.insert(k, Constant(v));
2800                });
2801                res
2802            }
2803        }
2804    }
2805    fn latex(&self, cache: &mut HashMap<CacheId, Self>) -> String {
2806        use ConstantExprInner::*;
2807        match self {
2808            Challenge(x) => {
2809                let mut inner_cache = HashMap::new();
2810                let res = x.latex(&mut inner_cache);
2811                inner_cache.into_iter().for_each(|(k, v)| {
2812                    let _ = cache.insert(k, Challenge(v));
2813                });
2814                res
2815            }
2816            Constant(x) => {
2817                let mut inner_cache = HashMap::new();
2818                let res = x.latex(&mut inner_cache);
2819                inner_cache.into_iter().for_each(|(k, v)| {
2820                    let _ = cache.insert(k, Constant(v));
2821                });
2822                res
2823            }
2824        }
2825    }
2826    fn text(&self, cache: &mut HashMap<CacheId, Self>) -> String {
2827        use ConstantExprInner::*;
2828        match self {
2829            Challenge(x) => {
2830                let mut inner_cache = HashMap::new();
2831                let res = x.text(&mut inner_cache);
2832                inner_cache.into_iter().for_each(|(k, v)| {
2833                    let _ = cache.insert(k, Challenge(v));
2834                });
2835                res
2836            }
2837            Constant(x) => {
2838                let mut inner_cache = HashMap::new();
2839                let res = x.text(&mut inner_cache);
2840                inner_cache.into_iter().for_each(|(k, v)| {
2841                    let _ = cache.insert(k, Constant(v));
2842                });
2843                res
2844            }
2845        }
2846    }
2847}
2848
2849impl<Column: FormattedOutput + Debug> FormattedOutput for Variable<Column> {
2850    fn is_alpha(&self) -> bool {
2851        false
2852    }
2853
2854    fn ocaml(&self, _cache: &mut HashMap<CacheId, Self>) -> String {
2855        format!("var({:?}, {:?})", self.col, self.row)
2856    }
2857
2858    fn latex(&self, _cache: &mut HashMap<CacheId, Self>) -> String {
2859        let col = self.col.latex(&mut HashMap::new());
2860        match self.row {
2861            Curr => col,
2862            Next => format!("\\tilde{{{col}}}"),
2863        }
2864    }
2865
2866    fn text(&self, _cache: &mut HashMap<CacheId, Self>) -> String {
2867        let col = self.col.text(&mut HashMap::new());
2868        match self.row {
2869            Curr => format!("Curr({col})"),
2870            Next => format!("Next({col})"),
2871        }
2872    }
2873}
2874
2875impl<T: FormattedOutput + Clone> FormattedOutput for Operations<T> {
2876    fn is_alpha(&self) -> bool {
2877        match self {
2878            Operations::Atom(x) => x.is_alpha(),
2879            _ => false,
2880        }
2881    }
2882    fn ocaml(&self, cache: &mut HashMap<CacheId, Self>) -> String {
2883        use Operations::*;
2884        match self {
2885            Atom(x) => {
2886                let mut inner_cache = HashMap::new();
2887                let res = x.ocaml(&mut inner_cache);
2888                inner_cache.into_iter().for_each(|(k, v)| {
2889                    let _ = cache.insert(k, Atom(v));
2890                });
2891                res
2892            }
2893            Pow(x, n) => {
2894                if x.is_alpha() {
2895                    format!("alpha_pow({n})")
2896                } else {
2897                    format!("pow({}, {n})", x.ocaml(cache))
2898                }
2899            }
2900            Add(x, y) => format!("({} + {})", x.ocaml(cache), y.ocaml(cache)),
2901            Mul(x, y) => format!("({} * {})", x.ocaml(cache), y.ocaml(cache)),
2902            Sub(x, y) => format!("({} - {})", x.ocaml(cache), y.ocaml(cache)),
2903            Double(x) => format!("double({})", x.ocaml(cache)),
2904            Square(x) => format!("square({})", x.ocaml(cache)),
2905            Cache(id, e) => {
2906                cache.insert(*id, e.as_ref().clone());
2907                id.var_name()
2908            }
2909            IfFeature(feature, e1, e2) => {
2910                format!(
2911                    "if_feature({:?}, (fun () -> {}), (fun () -> {}))",
2912                    feature,
2913                    e1.ocaml(cache),
2914                    e2.ocaml(cache)
2915                )
2916            }
2917        }
2918    }
2919
2920    fn latex(&self, cache: &mut HashMap<CacheId, Self>) -> String {
2921        use Operations::*;
2922        match self {
2923            Atom(x) => {
2924                let mut inner_cache = HashMap::new();
2925                let res = x.latex(&mut inner_cache);
2926                inner_cache.into_iter().for_each(|(k, v)| {
2927                    let _ = cache.insert(k, Atom(v));
2928                });
2929                res
2930            }
2931            Pow(x, n) => format!("{}^{{{n}}}", x.latex(cache)),
2932            Add(x, y) => format!("({} + {})", x.latex(cache), y.latex(cache)),
2933            Mul(x, y) => format!("({} \\cdot {})", x.latex(cache), y.latex(cache)),
2934            Sub(x, y) => format!("({} - {})", x.latex(cache), y.latex(cache)),
2935            Double(x) => format!("2 ({})", x.latex(cache)),
2936            Square(x) => format!("({})^2", x.latex(cache)),
2937            Cache(id, e) => {
2938                cache.insert(*id, e.as_ref().clone());
2939                id.var_name()
2940            }
2941            IfFeature(feature, _, _) => format!("{feature:?}"),
2942        }
2943    }
2944
2945    fn text(&self, cache: &mut HashMap<CacheId, Self>) -> String {
2946        use Operations::*;
2947        match self {
2948            Atom(x) => {
2949                let mut inner_cache = HashMap::new();
2950                let res = x.text(&mut inner_cache);
2951                inner_cache.into_iter().for_each(|(k, v)| {
2952                    let _ = cache.insert(k, Atom(v));
2953                });
2954                res
2955            }
2956            Pow(x, n) => format!("{}^{n}", x.text(cache)),
2957            Add(x, y) => format!("({} + {})", x.text(cache), y.text(cache)),
2958            Mul(x, y) => format!("({} * {})", x.text(cache), y.text(cache)),
2959            Sub(x, y) => format!("({} - {})", x.text(cache), y.text(cache)),
2960            Double(x) => format!("double({})", x.text(cache)),
2961            Square(x) => format!("square({})", x.text(cache)),
2962            Cache(id, e) => {
2963                cache.insert(*id, e.as_ref().clone());
2964                id.var_name()
2965            }
2966            IfFeature(feature, _, _) => format!("{feature:?}"),
2967        }
2968    }
2969}
2970
2971impl<'a, F, Column: FormattedOutput + Debug + Clone, ChallengeTerm> FormattedOutput
2972    for Expr<ConstantExpr<F, ChallengeTerm>, Column>
2973where
2974    F: PrimeField,
2975    ChallengeTerm: AlphaChallengeTerm<'a>,
2976{
2977    fn is_alpha(&self) -> bool {
2978        use ExprInner::*;
2979        use Operations::*;
2980        match self {
2981            Atom(Constant(x)) => x.is_alpha(),
2982            _ => false,
2983        }
2984    }
2985    /// Converts the expression in OCaml code
2986    /// Recursively print the expression,
2987    /// except for the cached expression that are stored in the `cache`.
2988    fn ocaml(
2989        &self,
2990        cache: &mut HashMap<CacheId, Expr<ConstantExpr<F, ChallengeTerm>, Column>>,
2991    ) -> String {
2992        use ExprInner::*;
2993        use Operations::*;
2994        match self {
2995            Double(x) => format!("double({})", x.ocaml(cache)),
2996            Atom(Constant(x)) => {
2997                let mut inner_cache = HashMap::new();
2998                let res = x.ocaml(&mut inner_cache);
2999                inner_cache.into_iter().for_each(|(k, v)| {
3000                    let _ = cache.insert(k, Atom(Constant(v)));
3001                });
3002                res
3003            }
3004            Atom(Cell(v)) => format!("cell({})", v.ocaml(&mut HashMap::new())),
3005            Atom(UnnormalizedLagrangeBasis(i)) => {
3006                format!("unnormalized_lagrange_basis({}, {})", i.zk_rows, i.offset)
3007            }
3008            Atom(VanishesOnZeroKnowledgeAndPreviousRows) => {
3009                "vanishes_on_zero_knowledge_and_previous_rows".to_string()
3010            }
3011            Add(x, y) => format!("({} + {})", x.ocaml(cache), y.ocaml(cache)),
3012            Mul(x, y) => format!("({} * {})", x.ocaml(cache), y.ocaml(cache)),
3013            Sub(x, y) => format!("({} - {})", x.ocaml(cache), y.ocaml(cache)),
3014            Pow(x, d) => format!("pow({}, {d})", x.ocaml(cache)),
3015            Square(x) => format!("square({})", x.ocaml(cache)),
3016            Cache(id, e) => {
3017                cache.insert(*id, e.as_ref().clone());
3018                id.var_name()
3019            }
3020            IfFeature(feature, e1, e2) => {
3021                format!(
3022                    "if_feature({:?}, (fun () -> {}), (fun () -> {}))",
3023                    feature,
3024                    e1.ocaml(cache),
3025                    e2.ocaml(cache)
3026                )
3027            }
3028        }
3029    }
3030
3031    fn latex(
3032        &self,
3033        cache: &mut HashMap<CacheId, Expr<ConstantExpr<F, ChallengeTerm>, Column>>,
3034    ) -> String {
3035        use ExprInner::*;
3036        use Operations::*;
3037        match self {
3038            Double(x) => format!("2 ({})", x.latex(cache)),
3039            Atom(Constant(x)) => {
3040                let mut inner_cache = HashMap::new();
3041                let res = x.latex(&mut inner_cache);
3042                inner_cache.into_iter().for_each(|(k, v)| {
3043                    let _ = cache.insert(k, Atom(Constant(v)));
3044                });
3045                res
3046            }
3047            Atom(Cell(v)) => v.latex(&mut HashMap::new()),
3048            Atom(UnnormalizedLagrangeBasis(RowOffset {
3049                zk_rows: true,
3050                offset: i,
3051            })) => {
3052                format!("unnormalized\\_lagrange\\_basis(zk\\_rows + {})", *i)
3053            }
3054            Atom(UnnormalizedLagrangeBasis(RowOffset {
3055                zk_rows: false,
3056                offset: i,
3057            })) => {
3058                format!("unnormalized\\_lagrange\\_basis({})", *i)
3059            }
3060            Atom(VanishesOnZeroKnowledgeAndPreviousRows) => {
3061                "vanishes\\_on\\_zero\\_knowledge\\_and\\_previous\\_row".to_string()
3062            }
3063            Add(x, y) => format!("({} + {})", x.latex(cache), y.latex(cache)),
3064            Mul(x, y) => format!("({} \\cdot {})", x.latex(cache), y.latex(cache)),
3065            Sub(x, y) => format!("({} - {})", x.latex(cache), y.latex(cache)),
3066            Pow(x, d) => format!("{}^{{{d}}}", x.latex(cache)),
3067            Square(x) => format!("({})^2", x.latex(cache)),
3068            Cache(id, e) => {
3069                cache.insert(*id, e.as_ref().clone());
3070                id.latex_name()
3071            }
3072            IfFeature(feature, _, _) => format!("{feature:?}"),
3073        }
3074    }
3075
3076    /// Recursively print the expression,
3077    /// except for the cached expression that are stored in the `cache`.
3078    fn text(
3079        &self,
3080        cache: &mut HashMap<CacheId, Expr<ConstantExpr<F, ChallengeTerm>, Column>>,
3081    ) -> String {
3082        use ExprInner::*;
3083        use Operations::*;
3084        match self {
3085            Double(x) => format!("double({})", x.text(cache)),
3086            Atom(Constant(x)) => {
3087                let mut inner_cache = HashMap::new();
3088                let res = x.text(&mut inner_cache);
3089                inner_cache.into_iter().for_each(|(k, v)| {
3090                    let _ = cache.insert(k, Atom(Constant(v)));
3091                });
3092                res
3093            }
3094            Atom(Cell(v)) => v.text(&mut HashMap::new()),
3095            Atom(UnnormalizedLagrangeBasis(RowOffset {
3096                zk_rows: true,
3097                offset: i,
3098            })) => match i.cmp(&0) {
3099                Ordering::Greater => format!("unnormalized_lagrange_basis(zk_rows + {})", *i),
3100                Ordering::Equal => "unnormalized_lagrange_basis(zk_rows)".to_string(),
3101                Ordering::Less => format!("unnormalized_lagrange_basis(zk_rows - {})", (-*i)),
3102            },
3103            Atom(UnnormalizedLagrangeBasis(RowOffset {
3104                zk_rows: false,
3105                offset: i,
3106            })) => {
3107                format!("unnormalized_lagrange_basis({})", *i)
3108            }
3109            Atom(VanishesOnZeroKnowledgeAndPreviousRows) => {
3110                "vanishes_on_zero_knowledge_and_previous_rows".to_string()
3111            }
3112            Add(x, y) => format!("({} + {})", x.text(cache), y.text(cache)),
3113            Mul(x, y) => format!("({} * {})", x.text(cache), y.text(cache)),
3114            Sub(x, y) => format!("({} - {})", x.text(cache), y.text(cache)),
3115            Pow(x, d) => format!("pow({}, {d})", x.text(cache)),
3116            Square(x) => format!("square({})", x.text(cache)),
3117            Cache(id, e) => {
3118                cache.insert(*id, e.as_ref().clone());
3119                id.var_name()
3120            }
3121            IfFeature(feature, _, _) => format!("{feature:?}"),
3122        }
3123    }
3124}
3125
3126impl<'a, F, Column: FormattedOutput + Debug + Clone, ChallengeTerm>
3127    Expr<ConstantExpr<F, ChallengeTerm>, Column>
3128where
3129    F: PrimeField,
3130    ChallengeTerm: AlphaChallengeTerm<'a>,
3131{
3132    /// Converts the expression in LaTeX
3133    // It is only used by visual tooling like kimchi-visu
3134    pub fn latex_str(&self) -> Vec<String> {
3135        let mut env = HashMap::new();
3136        let e = self.latex(&mut env);
3137
3138        let mut env: Vec<_> = env.into_iter().collect();
3139        // HashMap deliberately uses an unstable order; here we sort to ensure
3140        // that the output is consistent when printing.
3141        env.sort_by_key(|(x, _)| *x);
3142
3143        let mut res = vec![];
3144        for (k, v) in env {
3145            let mut rhs = v.latex_str();
3146            let last = rhs.pop().expect("returned an empty expression");
3147            res.push(format!("{} = {last}", k.latex_name()));
3148            res.extend(rhs);
3149        }
3150        res.push(e);
3151        res
3152    }
3153
3154    /// Converts the expression in OCaml code
3155    pub fn ocaml_str(&self) -> String {
3156        let mut env = HashMap::new();
3157        let e = self.ocaml(&mut env);
3158
3159        let mut env: Vec<_> = env.into_iter().collect();
3160        // HashMap deliberately uses an unstable order; here we sort to ensure
3161        // that the output is consistent when printing.
3162        env.sort_by_key(|(x, _)| *x);
3163
3164        let mut res = String::new();
3165        for (k, v) in env {
3166            let rhs = v.ocaml_str();
3167            let cached = format!("let {} = {rhs} in ", k.var_name());
3168            res.push_str(&cached);
3169        }
3170
3171        res.push_str(&e);
3172        res
3173    }
3174}
3175
3176//
3177// Constraints
3178//
3179
3180/// A number of useful constraints
3181pub mod constraints {
3182    use o1_utils::Two;
3183
3184    use crate::circuits::argument::ArgumentData;
3185    use core::fmt;
3186
3187    use super::*;
3188    use crate::circuits::berkeley_columns::{coeff, witness};
3189
3190    /// This trait defines a common arithmetic operations interface
3191    /// that can be used by constraints.  It allows us to reuse
3192    /// constraint code for witness computation.
3193    pub trait ExprOps<F, ChallengeTerm>:
3194        Add<Output = Self>
3195        + Sub<Output = Self>
3196        + Neg<Output = Self>
3197        + Mul<Output = Self>
3198        + AddAssign<Self>
3199        + MulAssign<Self>
3200        + Clone
3201        + Zero
3202        + One
3203        + From<u64>
3204        + fmt::Debug
3205        + fmt::Display
3206    // Add more as necessary
3207    where
3208        Self: core::marker::Sized,
3209    {
3210        /// 2^pow
3211        fn two_pow(pow: u64) -> Self;
3212
3213        /// 2^{LIMB_BITS}
3214        fn two_to_limb() -> Self;
3215
3216        /// 2^{2 * LIMB_BITS}
3217        fn two_to_2limb() -> Self;
3218
3219        /// 2^{3 * LIMB_BITS}
3220        fn two_to_3limb() -> Self;
3221
3222        /// Double the value
3223        fn double(&self) -> Self;
3224
3225        /// Compute the square of this value
3226        fn square(&self) -> Self;
3227
3228        /// Raise the value to the given power
3229        fn pow(&self, p: u64) -> Self;
3230
3231        /// Constrain to boolean
3232        fn boolean(&self) -> Self;
3233
3234        /// Constrain to crumb (i.e. two bits)
3235        fn crumb(&self) -> Self;
3236
3237        /// Create a literal
3238        fn literal(x: F) -> Self;
3239
3240        // Witness variable
3241        fn witness(row: CurrOrNext, col: usize, env: Option<&ArgumentData<F>>) -> Self;
3242
3243        /// Coefficient
3244        fn coeff(col: usize, env: Option<&ArgumentData<F>>) -> Self;
3245
3246        /// Create a constant
3247        fn constant(expr: ConstantExpr<F, ChallengeTerm>, env: Option<&ArgumentData<F>>) -> Self;
3248
3249        /// Cache item
3250        fn cache(&self, cache: &mut Cache) -> Self;
3251    }
3252    // TODO generalize with generic Column/challengeterm
3253    // We need to create a trait for berkeley_columns::Environment
3254    impl<F> ExprOps<F, BerkeleyChallengeTerm>
3255        for Expr<ConstantExpr<F, BerkeleyChallengeTerm>, berkeley_columns::Column>
3256    where
3257        F: PrimeField,
3258        // TODO remove
3259        Expr<ConstantExpr<F, BerkeleyChallengeTerm>, berkeley_columns::Column>: core::fmt::Display,
3260    {
3261        fn two_pow(pow: u64) -> Self {
3262            Expr::<ConstantExpr<F, BerkeleyChallengeTerm>, berkeley_columns::Column>::literal(
3263                <F as Two<F>>::two_pow(pow),
3264            )
3265        }
3266
3267        fn two_to_limb() -> Self {
3268            Expr::<ConstantExpr<F, BerkeleyChallengeTerm>, berkeley_columns::Column>::literal(
3269                KimchiForeignElement::<F>::two_to_limb(),
3270            )
3271        }
3272
3273        fn two_to_2limb() -> Self {
3274            Expr::<ConstantExpr<F, BerkeleyChallengeTerm>, berkeley_columns::Column>::literal(
3275                KimchiForeignElement::<F>::two_to_2limb(),
3276            )
3277        }
3278
3279        fn two_to_3limb() -> Self {
3280            Expr::<ConstantExpr<F, BerkeleyChallengeTerm>, berkeley_columns::Column>::literal(
3281                KimchiForeignElement::<F>::two_to_3limb(),
3282            )
3283        }
3284
3285        fn double(&self) -> Self {
3286            Expr::double(self.clone())
3287        }
3288
3289        fn square(&self) -> Self {
3290            Expr::square(self.clone())
3291        }
3292
3293        fn pow(&self, p: u64) -> Self {
3294            Expr::pow(self.clone(), p)
3295        }
3296
3297        fn boolean(&self) -> Self {
3298            constraints::boolean(self)
3299        }
3300
3301        fn crumb(&self) -> Self {
3302            constraints::crumb(self)
3303        }
3304
3305        fn literal(x: F) -> Self {
3306            ConstantTerm::Literal(x).into()
3307        }
3308
3309        fn witness(row: CurrOrNext, col: usize, _: Option<&ArgumentData<F>>) -> Self {
3310            witness(col, row)
3311        }
3312
3313        fn coeff(col: usize, _: Option<&ArgumentData<F>>) -> Self {
3314            coeff(col)
3315        }
3316
3317        fn constant(
3318            expr: ConstantExpr<F, BerkeleyChallengeTerm>,
3319            _: Option<&ArgumentData<F>>,
3320        ) -> Self {
3321            Expr::from(expr)
3322        }
3323
3324        fn cache(&self, cache: &mut Cache) -> Self {
3325            Expr::Cache(cache.next_id(), Box::new(self.clone()))
3326        }
3327    }
3328    // TODO generalize with generic Column/challengeterm
3329    // We need to generalize argument.rs
3330    impl<F: Field> ExprOps<F, BerkeleyChallengeTerm> for F {
3331        fn two_pow(pow: u64) -> Self {
3332            <F as Two<F>>::two_pow(pow)
3333        }
3334
3335        fn two_to_limb() -> Self {
3336            KimchiForeignElement::<F>::two_to_limb()
3337        }
3338
3339        fn two_to_2limb() -> Self {
3340            KimchiForeignElement::<F>::two_to_2limb()
3341        }
3342
3343        fn two_to_3limb() -> Self {
3344            KimchiForeignElement::<F>::two_to_3limb()
3345        }
3346
3347        fn double(&self) -> Self {
3348            *self * F::from(2u64)
3349        }
3350
3351        fn square(&self) -> Self {
3352            *self * *self
3353        }
3354
3355        fn pow(&self, p: u64) -> Self {
3356            self.pow([p])
3357        }
3358
3359        fn boolean(&self) -> Self {
3360            constraints::boolean(self)
3361        }
3362
3363        fn crumb(&self) -> Self {
3364            constraints::crumb(self)
3365        }
3366
3367        fn literal(x: F) -> Self {
3368            x
3369        }
3370
3371        fn witness(row: CurrOrNext, col: usize, env: Option<&ArgumentData<F>>) -> Self {
3372            match env {
3373                Some(data) => data.witness[(row, col)],
3374                None => panic!("Missing witness"),
3375            }
3376        }
3377
3378        fn coeff(col: usize, env: Option<&ArgumentData<F>>) -> Self {
3379            match env {
3380                Some(data) => data.coeffs[col],
3381                None => panic!("Missing coefficients"),
3382            }
3383        }
3384
3385        fn constant(
3386            expr: ConstantExpr<F, BerkeleyChallengeTerm>,
3387            env: Option<&ArgumentData<F>>,
3388        ) -> Self {
3389            match env {
3390                Some(data) => expr.value(&data.constants, &data.challenges),
3391                None => panic!("Missing constants"),
3392            }
3393        }
3394
3395        fn cache(&self, _: &mut Cache) -> Self {
3396            *self
3397        }
3398    }
3399
3400    /// Creates a constraint to enforce that b is either 0 or 1.
3401    pub fn boolean<F: Field, ChallengeTerm, T: ExprOps<F, ChallengeTerm>>(b: &T) -> T {
3402        b.square() - b.clone()
3403    }
3404
3405    /// Crumb constraint for 2-bit value x
3406    pub fn crumb<F: Field, ChallengeTerm, T: ExprOps<F, ChallengeTerm>>(x: &T) -> T {
3407        // Assert x \in [0,3] i.e. assert x*(x - 1)*(x - 2)*(x - 3) == 0
3408        x.clone()
3409            * (x.clone() - 1u64.into())
3410            * (x.clone() - 2u64.into())
3411            * (x.clone() - 3u64.into())
3412    }
3413
3414    /// lo + mi * 2^{LIMB_BITS}
3415    pub fn compact_limb<F: Field, ChallengeTerm, T: ExprOps<F, ChallengeTerm>>(
3416        lo: &T,
3417        mi: &T,
3418    ) -> T {
3419        lo.clone() + mi.clone() * T::two_to_limb()
3420    }
3421}
3422
3423/// Auto clone macro - Helps make constraints more readable
3424/// by eliminating requirement to .clone() all the time
3425#[macro_export]
3426macro_rules! auto_clone {
3427    ($var:ident, $expr:expr) => {
3428        let $var = $expr;
3429        let $var = || $var.clone();
3430    };
3431    ($var:ident) => {
3432        let $var = || $var.clone();
3433    };
3434}
3435#[macro_export]
3436macro_rules! auto_clone_array {
3437    ($var:ident, $expr:expr) => {
3438        let $var = $expr;
3439        let $var = |i: usize| $var[i].clone();
3440    };
3441    ($var:ident) => {
3442        let $var = |i: usize| $var[i].clone();
3443    };
3444}
3445
3446pub use auto_clone;
3447pub use auto_clone_array;
3448
3449/// You can import this module like `use kimchi::circuits::expr::prologue::*` to obtain a number of handy aliases and helpers
3450pub mod prologue {
3451    pub use super::{
3452        berkeley_columns::{coeff, constant, index, witness, witness_curr, witness_next, E},
3453        FeatureFlag,
3454    };
3455}