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) => match v.evaluate(evals) {
897                    Ok(x) => stack.push(x),
898                    Err(e) => return Err(e),
899                },
900                Pow(n) => {
901                    let i = stack.len() - 1;
902                    stack[i] = stack[i].pow([*n]);
903                }
904                Add => {
905                    let y = stack.pop().ok_or(ExprError::EmptyStack)?;
906                    let x = stack.pop().ok_or(ExprError::EmptyStack)?;
907                    stack.push(x + y);
908                }
909                Mul => {
910                    let y = stack.pop().ok_or(ExprError::EmptyStack)?;
911                    let x = stack.pop().ok_or(ExprError::EmptyStack)?;
912                    stack.push(x * y);
913                }
914                Sub => {
915                    let y = stack.pop().ok_or(ExprError::EmptyStack)?;
916                    let x = stack.pop().ok_or(ExprError::EmptyStack)?;
917                    stack.push(x - y);
918                }
919                Store => {
920                    let x = stack[stack.len() - 1];
921                    cache.push(x);
922                }
923                Load(i) => stack.push(cache[*i]),
924                SkipIf(feature, count) => {
925                    if feature.is_enabled() {
926                        skip_count = *count;
927                        stack.push(F::zero());
928                    }
929                }
930                SkipIfNot(feature, count) => {
931                    if !feature.is_enabled() {
932                        skip_count = *count;
933                        stack.push(F::zero());
934                    }
935                }
936            }
937        }
938
939        assert_eq!(stack.len(), 1);
940        Ok(stack[0])
941    }
942}
943
944impl<C, Column> Expr<C, Column> {
945    /// Convenience function for constructing cell variables.
946    pub fn cell(col: Column, row: CurrOrNext) -> Expr<C, Column> {
947        Expr::Atom(ExprInner::Cell(Variable { col, row }))
948    }
949
950    pub fn double(self) -> Self {
951        Expr::Double(Box::new(self))
952    }
953
954    pub fn square(self) -> Self {
955        Expr::Square(Box::new(self))
956    }
957
958    /// Convenience function for constructing constant expressions.
959    pub fn constant(c: C) -> Expr<C, Column> {
960        Expr::Atom(ExprInner::Constant(c))
961    }
962
963    /// Return the degree of the expression.
964    /// The degree of a cell is defined by the first argument `d1_size`, a
965    /// constant being of degree zero. The degree of the expression is defined
966    /// recursively using the definition of the degree of a multivariate
967    /// polynomial. The function can be (and is) used to compute the domain
968    /// size, hence the name of the first argument `d1_size`.
969    /// The second parameter `zk_rows` is used to define the degree of the
970    /// constructor `VanishesOnZeroKnowledgeAndPreviousRows`.
971    pub fn degree(&self, d1_size: u64, zk_rows: u64) -> u64 {
972        use ExprInner::*;
973        use Operations::*;
974        match self {
975            Double(x) => x.degree(d1_size, zk_rows),
976            Atom(Constant(_)) => 0,
977            Atom(VanishesOnZeroKnowledgeAndPreviousRows) => zk_rows + 1,
978            Atom(UnnormalizedLagrangeBasis(_)) => d1_size,
979            Atom(Cell(_)) => d1_size,
980            Square(x) => 2 * x.degree(d1_size, zk_rows),
981            Mul(x, y) => (*x).degree(d1_size, zk_rows) + (*y).degree(d1_size, zk_rows),
982            Add(x, y) | Sub(x, y) => {
983                core::cmp::max((*x).degree(d1_size, zk_rows), (*y).degree(d1_size, zk_rows))
984            }
985            Pow(e, d) => d * e.degree(d1_size, zk_rows),
986            Cache(_, e) => e.degree(d1_size, zk_rows),
987            IfFeature(_, e1, e2) => {
988                core::cmp::max(e1.degree(d1_size, zk_rows), e2.degree(d1_size, zk_rows))
989            }
990        }
991    }
992}
993
994impl<'a, F, Column: FormattedOutput + Debug + Clone, ChallengeTerm> fmt::Display
995    for Expr<ConstantExpr<F, ChallengeTerm>, Column>
996where
997    F: PrimeField,
998    ChallengeTerm: AlphaChallengeTerm<'a>,
999{
1000    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1001        let cache = &mut HashMap::new();
1002        write!(f, "{}", self.text(cache))
1003    }
1004}
1005
1006#[derive(Clone)]
1007enum EvalResult<'a, F: FftField> {
1008    Constant(F),
1009    Evals {
1010        domain: Domain,
1011        evals: Evaluations<F, D<F>>,
1012    },
1013    /// SubEvals is used to refer to evaluations that can be trivially obtained from a
1014    /// borrowed evaluation. In this case, by taking a subset of the entries
1015    /// (specifically when the borrowed `evals` is over a superset of `domain`)
1016    /// and shifting them
1017    SubEvals {
1018        domain: Domain,
1019        shift: usize,
1020        evals: &'a Evaluations<F, D<F>>,
1021    },
1022}
1023
1024/// Compute the evaluations of the unnormalized lagrange polynomial on
1025/// H_8 or H_4. Taking H_8 as an example, we show how to compute this
1026/// polynomial on the expanded domain.
1027///
1028/// Let H = < omega >, |H| = n.
1029///
1030/// Let l_i(x) be the unnormalized lagrange polynomial,
1031/// (x^n - 1) / (x - omega^i)
1032/// = prod_{j != i} (x - omega^j)
1033///
1034/// For h in H, h != omega^i,
1035/// l_i(h) = 0.
1036/// l_i(omega^i)
1037/// = prod_{j != i} (omega^i - omega^j)
1038/// = omega^{i (n - 1)} * prod_{j != i} (1 - omega^{j - i})
1039/// = omega^{i (n - 1)} * prod_{j != 0} (1 - omega^j)
1040/// = omega^{i (n - 1)} * l_0(1)
1041/// = omega^{i n} * omega^{-i} * l_0(1)
1042/// = omega^{-i} * l_0(1)
1043///
1044/// So it is easy to compute l_i(omega^i) from just l_0(1).
1045///
1046/// Also, consider the expanded domain H_8 generated by
1047/// an 8nth root of unity omega_8 (where H_8^8 = H).
1048///
1049/// Let omega_8^k in H_8. Write k = 8 * q + r with r < 8.
1050/// Then
1051/// omega_8^k = (omega_8^8)^q * omega_8^r = omega^q * omega_8^r
1052///
1053/// l_i(omega_8^k)
1054/// = (omega_8^{k n} - 1) / (omega_8^k - omega^i)
1055/// = (omega^{q n} omega_8^{r n} - 1) / (omega_8^k - omega^i)
1056/// = ((omega_8^n)^r - 1) / (omega_8^k - omega^i)
1057/// = ((omega_8^n)^r - 1) / (omega^q omega_8^r - omega^i)
1058fn unnormalized_lagrange_evals<
1059    'a,
1060    F: FftField,
1061    ChallengeTerm,
1062    Challenge: Index<ChallengeTerm, Output = F>,
1063    Environment: ColumnEnvironment<'a, F, ChallengeTerm, Challenge>,
1064>(
1065    l0_1: F,
1066    i: i32,
1067    res_domain: Domain,
1068    env: &Environment,
1069) -> Evaluations<F, D<F>> {
1070    let k = match res_domain {
1071        Domain::D1 => 1,
1072        Domain::D2 => 2,
1073        Domain::D4 => 4,
1074        Domain::D8 => 8,
1075    };
1076    let res_domain = env.get_domain(res_domain);
1077
1078    let d1 = env.get_domain(Domain::D1);
1079    let n = d1.size;
1080    // Renormalize negative values to wrap around at domain size
1081    let i = if i < 0 {
1082        ((i as isize) + (n as isize)) as usize
1083    } else {
1084        i as usize
1085    };
1086    let ii = i as u64;
1087    assert!(ii < n);
1088    let omega = d1.group_gen;
1089    let omega_i = omega.pow([ii]);
1090    let omega_minus_i = omega.pow([n - ii]);
1091
1092    // Write res_domain = < omega_k > with
1093    // |res_domain| = k * |H|
1094
1095    // omega_k^0, ..., omega_k^k
1096    let omega_k_n_pows = pows(k, res_domain.group_gen.pow([n]));
1097    let omega_k_pows = pows(k, res_domain.group_gen);
1098
1099    let mut evals: Vec<F> = {
1100        let mut v = vec![F::one(); k * (n as usize)];
1101        let mut omega_q = F::one();
1102        for q in 0..(n as usize) {
1103            // omega_q == omega^q
1104            for r in 1..k {
1105                v[k * q + r] = omega_q * omega_k_pows[r] - omega_i;
1106            }
1107            omega_q *= omega;
1108        }
1109        ark_ff::fields::batch_inversion::<F>(&mut v[..]);
1110        v
1111    };
1112    // At this point, in the 0 mod k indices, we have dummy values,
1113    // and in the other indices k*q + r, we have
1114    // 1 / (omega^q omega_k^r - omega^i)
1115
1116    // Set the 0 mod k indices
1117    for q in 0..(n as usize) {
1118        evals[k * q] = F::zero();
1119    }
1120    evals[k * i] = omega_minus_i * l0_1;
1121
1122    // Finish computing the non-zero mod k indices
1123    for q in 0..(n as usize) {
1124        for r in 1..k {
1125            evals[k * q + r] *= omega_k_n_pows[r] - F::one();
1126        }
1127    }
1128
1129    Evaluations::<F, D<F>>::from_vec_and_domain(evals, res_domain)
1130}
1131
1132/// Implement algebraic methods like `add`, `sub`, `mul`, `square`, etc to use
1133/// algebra on the type `EvalResult`.
1134impl<'a, F: FftField> EvalResult<'a, F> {
1135    /// Create an evaluation over the domain `res_domain`.
1136    /// The second parameter, `g`, is a function used to define the
1137    /// evaluations at a given point of the domain.
1138    /// For instance, the second parameter `g` can simply be the identity
1139    /// functions over a set of field elements.
1140    /// It can also be used to define polynomials like `x^2` when we only have the
1141    /// value of `x`. It can be used in particular to evaluate an expression (a
1142    /// multi-variate polynomial) when we only do have access to the evaluations
1143    /// of the individual variables.
1144    fn init_<G: Sync + Send + Fn(usize) -> F>(
1145        res_domain: (Domain, D<F>),
1146        g: G,
1147    ) -> Evaluations<F, D<F>> {
1148        let n = res_domain.1.size();
1149        Evaluations::<F, D<F>>::from_vec_and_domain(
1150            o1_utils::cfg_into_iter!(0..n).map(g).collect(),
1151            res_domain.1,
1152        )
1153    }
1154
1155    /// Call the internal function `init_` and return the computed evaluation as
1156    /// a value `Evals`.
1157    fn init<G: Sync + Send + Fn(usize) -> F>(res_domain: (Domain, D<F>), g: G) -> Self {
1158        Self::Evals {
1159            domain: res_domain.0,
1160            evals: Self::init_(res_domain, g),
1161        }
1162    }
1163
1164    fn add<'c>(self, other: EvalResult<'_, F>, res_domain: (Domain, D<F>)) -> EvalResult<'c, F> {
1165        use EvalResult::*;
1166        match (self, other) {
1167            (Constant(x), Constant(y)) => Constant(x + y),
1168            (Evals { domain, mut evals }, Constant(x))
1169            | (Constant(x), Evals { domain, mut evals }) => {
1170                o1_utils::cfg_iter_mut!(evals.evals).for_each(|e| *e += x);
1171                Evals { domain, evals }
1172            }
1173            (
1174                SubEvals {
1175                    evals,
1176                    domain,
1177                    shift,
1178                },
1179                Constant(x),
1180            )
1181            | (
1182                Constant(x),
1183                SubEvals {
1184                    evals,
1185                    domain,
1186                    shift,
1187                },
1188            ) => {
1189                let n = res_domain.1.size();
1190                let scale = (domain as usize) / (res_domain.0 as usize);
1191                assert!(
1192                    scale != 0,
1193                    "Check that the implementation of
1194                column_domain and the evaluation domain of the
1195                witnesses are the same"
1196                );
1197                let v: Vec<_> = o1_utils::cfg_into_iter!(0..n)
1198                    .map(|i| {
1199                        x + evals.evals[(scale * i + (domain as usize) * shift) % evals.evals.len()]
1200                    })
1201                    .collect();
1202                Evals {
1203                    domain: res_domain.0,
1204                    evals: Evaluations::<F, D<F>>::from_vec_and_domain(v, res_domain.1),
1205                }
1206            }
1207            (
1208                Evals {
1209                    domain: d1,
1210                    evals: mut es1,
1211                },
1212                Evals {
1213                    domain: d2,
1214                    evals: es2,
1215                },
1216            ) => {
1217                assert_eq!(d1, d2);
1218                es1 += &es2;
1219                Evals {
1220                    domain: d1,
1221                    evals: es1,
1222                }
1223            }
1224            (
1225                SubEvals {
1226                    domain: d_sub,
1227                    shift: s,
1228                    evals: es_sub,
1229                },
1230                Evals {
1231                    domain: d,
1232                    mut evals,
1233                },
1234            )
1235            | (
1236                Evals {
1237                    domain: d,
1238                    mut evals,
1239                },
1240                SubEvals {
1241                    domain: d_sub,
1242                    shift: s,
1243                    evals: es_sub,
1244                },
1245            ) => {
1246                let scale = (d_sub as usize) / (d as usize);
1247                assert!(
1248                    scale != 0,
1249                    "Check that the implementation of
1250                column_domain and the evaluation domain of the
1251                witnesses are the same"
1252                );
1253                o1_utils::cfg_iter_mut!(evals.evals)
1254                    .enumerate()
1255                    .for_each(|(i, e)| {
1256                        *e += es_sub.evals[(scale * i + (d_sub as usize) * s) % es_sub.evals.len()];
1257                    });
1258                Evals { evals, domain: d }
1259            }
1260            (
1261                SubEvals {
1262                    domain: d1,
1263                    shift: s1,
1264                    evals: es1,
1265                },
1266                SubEvals {
1267                    domain: d2,
1268                    shift: s2,
1269                    evals: es2,
1270                },
1271            ) => {
1272                let scale1 = (d1 as usize) / (res_domain.0 as usize);
1273                assert!(
1274                    scale1 != 0,
1275                    "Check that the implementation of
1276                column_domain and the evaluation domain of the
1277                witnesses are the same"
1278                );
1279                let scale2 = (d2 as usize) / (res_domain.0 as usize);
1280                assert!(
1281                    scale2 != 0,
1282                    "Check that the implementation of
1283                column_domain and the evaluation domain of the
1284                witnesses are the same"
1285                );
1286                let n = res_domain.1.size();
1287                let v: Vec<_> = o1_utils::cfg_into_iter!(0..n)
1288                    .map(|i| {
1289                        es1.evals[(scale1 * i + (d1 as usize) * s1) % es1.evals.len()]
1290                            + es2.evals[(scale2 * i + (d2 as usize) * s2) % es2.evals.len()]
1291                    })
1292                    .collect();
1293
1294                Evals {
1295                    domain: res_domain.0,
1296                    evals: Evaluations::<F, D<F>>::from_vec_and_domain(v, res_domain.1),
1297                }
1298            }
1299        }
1300    }
1301
1302    fn sub<'c>(self, other: EvalResult<'_, F>, res_domain: (Domain, D<F>)) -> EvalResult<'c, F> {
1303        use EvalResult::*;
1304        match (self, other) {
1305            (Constant(x), Constant(y)) => Constant(x - y),
1306            (Evals { domain, mut evals }, Constant(x)) => {
1307                o1_utils::cfg_iter_mut!(evals.evals).for_each(|e| *e -= x);
1308                Evals { domain, evals }
1309            }
1310            (Constant(x), Evals { domain, mut evals }) => {
1311                o1_utils::cfg_iter_mut!(evals.evals).for_each(|e| *e = x - *e);
1312                Evals { domain, evals }
1313            }
1314            (
1315                SubEvals {
1316                    evals,
1317                    domain: d,
1318                    shift: s,
1319                },
1320                Constant(x),
1321            ) => {
1322                let scale = (d as usize) / (res_domain.0 as usize);
1323                assert!(
1324                    scale != 0,
1325                    "Check that the implementation of
1326                column_domain and the evaluation domain of the
1327                witnesses are the same"
1328                );
1329                EvalResult::init(res_domain, |i| {
1330                    evals.evals[(scale * i + (d as usize) * s) % evals.evals.len()] - x
1331                })
1332            }
1333            (
1334                Constant(x),
1335                SubEvals {
1336                    evals,
1337                    domain: d,
1338                    shift: s,
1339                },
1340            ) => {
1341                let scale = (d as usize) / (res_domain.0 as usize);
1342                assert!(
1343                    scale != 0,
1344                    "Check that the implementation of
1345                column_domain and the evaluation domain of the
1346                witnesses are the same"
1347                );
1348
1349                EvalResult::init(res_domain, |i| {
1350                    x - evals.evals[(scale * i + (d as usize) * s) % evals.evals.len()]
1351                })
1352            }
1353            (
1354                Evals {
1355                    domain: d1,
1356                    evals: mut es1,
1357                },
1358                Evals {
1359                    domain: d2,
1360                    evals: es2,
1361                },
1362            ) => {
1363                assert_eq!(d1, d2);
1364                es1 -= &es2;
1365                Evals {
1366                    domain: d1,
1367                    evals: es1,
1368                }
1369            }
1370            (
1371                SubEvals {
1372                    domain: d_sub,
1373                    shift: s,
1374                    evals: es_sub,
1375                },
1376                Evals {
1377                    domain: d,
1378                    mut evals,
1379                },
1380            ) => {
1381                let scale = (d_sub as usize) / (d as usize);
1382                assert!(
1383                    scale != 0,
1384                    "Check that the implementation of
1385                column_domain and the evaluation domain of the
1386                witnesses are the same"
1387                );
1388
1389                o1_utils::cfg_iter_mut!(evals.evals)
1390                    .enumerate()
1391                    .for_each(|(i, e)| {
1392                        *e = es_sub.evals[(scale * i + (d_sub as usize) * s) % es_sub.evals.len()]
1393                            - *e;
1394                    });
1395                Evals { evals, domain: d }
1396            }
1397            (
1398                Evals {
1399                    domain: d,
1400                    mut evals,
1401                },
1402                SubEvals {
1403                    domain: d_sub,
1404                    shift: s,
1405                    evals: es_sub,
1406                },
1407            ) => {
1408                let scale = (d_sub as usize) / (d as usize);
1409                assert!(
1410                    scale != 0,
1411                    "Check that the implementation of
1412                column_domain and the evaluation domain of the
1413                witnesses are the same"
1414                );
1415                o1_utils::cfg_iter_mut!(evals.evals)
1416                    .enumerate()
1417                    .for_each(|(i, e)| {
1418                        *e -= es_sub.evals[(scale * i + (d_sub as usize) * s) % es_sub.evals.len()];
1419                    });
1420                Evals { evals, domain: d }
1421            }
1422            (
1423                SubEvals {
1424                    domain: d1,
1425                    shift: s1,
1426                    evals: es1,
1427                },
1428                SubEvals {
1429                    domain: d2,
1430                    shift: s2,
1431                    evals: es2,
1432                },
1433            ) => {
1434                let scale1 = (d1 as usize) / (res_domain.0 as usize);
1435                assert!(
1436                    scale1 != 0,
1437                    "Check that the implementation of
1438                column_domain and the evaluation domain of the
1439                witnesses are the same"
1440                );
1441                let scale2 = (d2 as usize) / (res_domain.0 as usize);
1442                assert!(
1443                    scale2 != 0,
1444                    "Check that the implementation of
1445                column_domain and the evaluation domain of the
1446                witnesses are the same"
1447                );
1448
1449                EvalResult::init(res_domain, |i| {
1450                    es1.evals[(scale1 * i + (d1 as usize) * s1) % es1.evals.len()]
1451                        - es2.evals[(scale2 * i + (d2 as usize) * s2) % es2.evals.len()]
1452                })
1453            }
1454        }
1455    }
1456
1457    fn pow<'b>(self, d: u64, res_domain: (Domain, D<F>)) -> EvalResult<'b, F> {
1458        let mut acc = EvalResult::Constant(F::one());
1459        for i in (0..u64::BITS).rev() {
1460            acc = acc.square(res_domain);
1461
1462            if (d >> i) & 1 == 1 {
1463                // TODO: Avoid the unnecessary cloning
1464                acc = acc.mul(self.clone(), res_domain)
1465            }
1466        }
1467        acc
1468    }
1469
1470    fn square<'b>(self, res_domain: (Domain, D<F>)) -> EvalResult<'b, F> {
1471        use EvalResult::*;
1472        match self {
1473            Constant(x) => Constant(x.square()),
1474            Evals { domain, mut evals } => {
1475                o1_utils::cfg_iter_mut!(evals.evals).for_each(|e| {
1476                    e.square_in_place();
1477                });
1478                Evals { domain, evals }
1479            }
1480            SubEvals {
1481                evals,
1482                domain: d,
1483                shift: s,
1484            } => {
1485                let scale = (d as usize) / (res_domain.0 as usize);
1486                assert!(
1487                    scale != 0,
1488                    "Check that the implementation of
1489                column_domain and the evaluation domain of the
1490                witnesses are the same"
1491                );
1492                EvalResult::init(res_domain, |i| {
1493                    evals.evals[(scale * i + (d as usize) * s) % evals.evals.len()].square()
1494                })
1495            }
1496        }
1497    }
1498
1499    fn mul<'c>(self, other: EvalResult<'_, F>, res_domain: (Domain, D<F>)) -> EvalResult<'c, F> {
1500        use EvalResult::*;
1501        match (self, other) {
1502            (Constant(x), Constant(y)) => Constant(x * y),
1503            (Evals { domain, mut evals }, Constant(x))
1504            | (Constant(x), Evals { domain, mut evals }) => {
1505                o1_utils::cfg_iter_mut!(evals.evals).for_each(|e| *e *= x);
1506                Evals { domain, evals }
1507            }
1508            (
1509                SubEvals {
1510                    evals,
1511                    domain: d,
1512                    shift: s,
1513                },
1514                Constant(x),
1515            )
1516            | (
1517                Constant(x),
1518                SubEvals {
1519                    evals,
1520                    domain: d,
1521                    shift: s,
1522                },
1523            ) => {
1524                let scale = (d as usize) / (res_domain.0 as usize);
1525                assert!(
1526                    scale != 0,
1527                    "Check that the implementation of
1528                column_domain and the evaluation domain of the
1529                witnesses are the same"
1530                );
1531                EvalResult::init(res_domain, |i| {
1532                    x * evals.evals[(scale * i + (d as usize) * s) % evals.evals.len()]
1533                })
1534            }
1535            (
1536                Evals {
1537                    domain: d1,
1538                    evals: mut es1,
1539                },
1540                Evals {
1541                    domain: d2,
1542                    evals: es2,
1543                },
1544            ) => {
1545                assert_eq!(d1, d2);
1546                es1 *= &es2;
1547                Evals {
1548                    domain: d1,
1549                    evals: es1,
1550                }
1551            }
1552            (
1553                SubEvals {
1554                    domain: d_sub,
1555                    shift: s,
1556                    evals: es_sub,
1557                },
1558                Evals {
1559                    domain: d,
1560                    mut evals,
1561                },
1562            )
1563            | (
1564                Evals {
1565                    domain: d,
1566                    mut evals,
1567                },
1568                SubEvals {
1569                    domain: d_sub,
1570                    shift: s,
1571                    evals: es_sub,
1572                },
1573            ) => {
1574                let scale = (d_sub as usize) / (d as usize);
1575                assert!(
1576                    scale != 0,
1577                    "Check that the implementation of
1578                column_domainand the evaluation domain of the
1579                witnesses are the same"
1580                );
1581
1582                o1_utils::cfg_iter_mut!(evals.evals)
1583                    .enumerate()
1584                    .for_each(|(i, e)| {
1585                        *e *= es_sub.evals[(scale * i + (d_sub as usize) * s) % es_sub.evals.len()];
1586                    });
1587                Evals { evals, domain: d }
1588            }
1589            (
1590                SubEvals {
1591                    domain: d1,
1592                    shift: s1,
1593                    evals: es1,
1594                },
1595                SubEvals {
1596                    domain: d2,
1597                    shift: s2,
1598                    evals: es2,
1599                },
1600            ) => {
1601                let scale1 = (d1 as usize) / (res_domain.0 as usize);
1602                assert!(
1603                    scale1 != 0,
1604                    "Check that the implementation of
1605                column_domain and the evaluation domain of the
1606                witnesses are the same"
1607                );
1608                let scale2 = (d2 as usize) / (res_domain.0 as usize);
1609
1610                assert!(
1611                    scale2 != 0,
1612                    "Check that the implementation of
1613                column_domain and the evaluation domain of the
1614                witnesses are the same"
1615                );
1616                EvalResult::init(res_domain, |i| {
1617                    es1.evals[(scale1 * i + (d1 as usize) * s1) % es1.evals.len()]
1618                        * es2.evals[(scale2 * i + (d2 as usize) * s2) % es2.evals.len()]
1619                })
1620            }
1621        }
1622    }
1623}
1624
1625impl<'a, F: Field, Column: PartialEq + Copy, ChallengeTerm: AlphaChallengeTerm<'a>>
1626    Expr<ConstantExpr<F, ChallengeTerm>, Column>
1627{
1628    /// Convenience function for constructing expressions from literal
1629    /// field elements.
1630    pub fn literal(x: F) -> Self {
1631        ConstantTerm::Literal(x).into()
1632    }
1633
1634    /// Combines multiple constraints `[c0, ..., cn]` into a single constraint
1635    /// `alpha^alpha0 * c0 + alpha^{alpha0 + 1} * c1 + ... + alpha^{alpha0 + n} * cn`.
1636    pub fn combine_constraints(alphas: impl Iterator<Item = u32>, cs: Vec<Self>) -> Self {
1637        let zero = Expr::<ConstantExpr<F, ChallengeTerm>, Column>::zero();
1638        cs.into_iter()
1639            .zip_eq(alphas)
1640            .map(|(c, i)| Expr::from(ConstantExpr::pow(ChallengeTerm::ALPHA.into(), i as u64)) * c)
1641            .fold(zero, |acc, x| acc + x)
1642    }
1643}
1644
1645impl<F: FftField, Column: Copy, ChallengeTerm: Copy> Expr<ConstantExpr<F, ChallengeTerm>, Column> {
1646    /// Compile an expression to an RPN expression.
1647    pub fn to_polish(&self) -> Vec<PolishToken<F, Column, ChallengeTerm>> {
1648        let mut res = vec![];
1649        let mut cache = HashMap::new();
1650        self.to_polish_(&mut cache, &mut res);
1651        res
1652    }
1653
1654    fn to_polish_(
1655        &self,
1656        cache: &mut HashMap<CacheId, usize>,
1657        res: &mut Vec<PolishToken<F, Column, ChallengeTerm>>,
1658    ) {
1659        match self {
1660            Expr::Double(x) => {
1661                x.to_polish_(cache, res);
1662                res.push(PolishToken::Dup);
1663                res.push(PolishToken::Add);
1664            }
1665            Expr::Square(x) => {
1666                x.to_polish_(cache, res);
1667                res.push(PolishToken::Dup);
1668                res.push(PolishToken::Mul);
1669            }
1670            Expr::Pow(x, d) => {
1671                x.to_polish_(cache, res);
1672                res.push(PolishToken::Pow(*d))
1673            }
1674            Expr::Atom(ExprInner::Constant(c)) => {
1675                c.to_polish(cache, res);
1676            }
1677            Expr::Atom(ExprInner::Cell(v)) => res.push(PolishToken::Cell(*v)),
1678            Expr::Atom(ExprInner::VanishesOnZeroKnowledgeAndPreviousRows) => {
1679                res.push(PolishToken::VanishesOnZeroKnowledgeAndPreviousRows);
1680            }
1681            Expr::Atom(ExprInner::UnnormalizedLagrangeBasis(i)) => {
1682                res.push(PolishToken::UnnormalizedLagrangeBasis(*i));
1683            }
1684            Expr::Add(x, y) => {
1685                x.to_polish_(cache, res);
1686                y.to_polish_(cache, res);
1687                res.push(PolishToken::Add);
1688            }
1689            Expr::Sub(x, y) => {
1690                x.to_polish_(cache, res);
1691                y.to_polish_(cache, res);
1692                res.push(PolishToken::Sub);
1693            }
1694            Expr::Mul(x, y) => {
1695                x.to_polish_(cache, res);
1696                y.to_polish_(cache, res);
1697                res.push(PolishToken::Mul);
1698            }
1699            Expr::Cache(id, e) => {
1700                match cache.get(id) {
1701                    Some(pos) =>
1702                    // Already computed and stored this.
1703                    {
1704                        res.push(PolishToken::Load(*pos))
1705                    }
1706                    None => {
1707                        // Haven't computed this yet. Compute it, then store it.
1708                        e.to_polish_(cache, res);
1709                        res.push(PolishToken::Store);
1710                        cache.insert(*id, cache.len());
1711                    }
1712                }
1713            }
1714            Expr::IfFeature(feature, e1, e2) => {
1715                {
1716                    // True branch
1717                    let tok = PolishToken::SkipIfNot(*feature, 0);
1718                    res.push(tok);
1719                    let len_before = res.len();
1720                    /* Clone the cache, to make sure we don't try to access cached statements later
1721                    when the feature flag is off. */
1722                    let mut cache = cache.clone();
1723                    e1.to_polish_(&mut cache, res);
1724                    let len_after = res.len();
1725                    res[len_before - 1] = PolishToken::SkipIfNot(*feature, len_after - len_before);
1726                }
1727
1728                {
1729                    // False branch
1730                    let tok = PolishToken::SkipIfNot(*feature, 0);
1731                    res.push(tok);
1732                    let len_before = res.len();
1733                    /* Clone the cache, to make sure we don't try to access cached statements later
1734                    when the feature flag is on. */
1735                    let mut cache = cache.clone();
1736                    e2.to_polish_(&mut cache, res);
1737                    let len_after = res.len();
1738                    res[len_before - 1] = PolishToken::SkipIfNot(*feature, len_after - len_before);
1739                }
1740            }
1741        }
1742    }
1743}
1744
1745impl<F: FftField, Column: PartialEq + Copy, ChallengeTerm: Copy>
1746    Expr<ConstantExpr<F, ChallengeTerm>, Column>
1747{
1748    fn evaluate_constants_(
1749        &self,
1750        c: &Constants<F>,
1751        chals: &dyn Index<ChallengeTerm, Output = F>,
1752    ) -> Expr<F, Column> {
1753        use ExprInner::*;
1754        use Operations::*;
1755        // TODO: Use cache
1756        match self {
1757            Double(x) => x.evaluate_constants_(c, chals).double(),
1758            Pow(x, d) => x.evaluate_constants_(c, chals).pow(*d),
1759            Square(x) => x.evaluate_constants_(c, chals).square(),
1760            Atom(Constant(x)) => Atom(Constant(x.value(c, chals))),
1761            Atom(Cell(v)) => Atom(Cell(*v)),
1762            Atom(VanishesOnZeroKnowledgeAndPreviousRows) => {
1763                Atom(VanishesOnZeroKnowledgeAndPreviousRows)
1764            }
1765            Atom(UnnormalizedLagrangeBasis(i)) => Atom(UnnormalizedLagrangeBasis(*i)),
1766            Add(x, y) => x.evaluate_constants_(c, chals) + y.evaluate_constants_(c, chals),
1767            Mul(x, y) => x.evaluate_constants_(c, chals) * y.evaluate_constants_(c, chals),
1768            Sub(x, y) => x.evaluate_constants_(c, chals) - y.evaluate_constants_(c, chals),
1769            Cache(id, e) => Cache(*id, Box::new(e.evaluate_constants_(c, chals))),
1770            IfFeature(feature, e1, e2) => IfFeature(
1771                *feature,
1772                Box::new(e1.evaluate_constants_(c, chals)),
1773                Box::new(e2.evaluate_constants_(c, chals)),
1774            ),
1775        }
1776    }
1777
1778    /// Evaluate an expression as a field element against an environment.
1779    pub fn evaluate<
1780        'a,
1781        Evaluations: ColumnEvaluations<F, Column = Column>,
1782        Challenge: Index<ChallengeTerm, Output = F>,
1783        Environment: ColumnEnvironment<'a, F, ChallengeTerm, Challenge, Column = Column>,
1784    >(
1785        &self,
1786        d: D<F>,
1787        pt: F,
1788        evals: &Evaluations,
1789        env: &Environment,
1790    ) -> Result<F, ExprError<Column>> {
1791        self.evaluate_(d, pt, evals, env.get_constants(), env.get_challenges())
1792    }
1793
1794    /// Evaluate an expression as a field element against the constants.
1795    pub fn evaluate_<Evaluations: ColumnEvaluations<F, Column = Column>>(
1796        &self,
1797        d: D<F>,
1798        pt: F,
1799        evals: &Evaluations,
1800        c: &Constants<F>,
1801        chals: &dyn Index<ChallengeTerm, Output = F>,
1802    ) -> Result<F, ExprError<Column>> {
1803        use ExprInner::*;
1804        use Operations::*;
1805        match self {
1806            Double(x) => x.evaluate_(d, pt, evals, c, chals).map(|x| x.double()),
1807            Atom(Constant(x)) => Ok(x.value(c, chals)),
1808            Pow(x, p) => Ok(x.evaluate_(d, pt, evals, c, chals)?.pow([*p])),
1809            Mul(x, y) => {
1810                let x = (*x).evaluate_(d, pt, evals, c, chals)?;
1811                let y = (*y).evaluate_(d, pt, evals, c, chals)?;
1812                Ok(x * y)
1813            }
1814            Square(x) => Ok(x.evaluate_(d, pt, evals, c, chals)?.square()),
1815            Add(x, y) => {
1816                let x = (*x).evaluate_(d, pt, evals, c, chals)?;
1817                let y = (*y).evaluate_(d, pt, evals, c, chals)?;
1818                Ok(x + y)
1819            }
1820            Sub(x, y) => {
1821                let x = (*x).evaluate_(d, pt, evals, c, chals)?;
1822                let y = (*y).evaluate_(d, pt, evals, c, chals)?;
1823                Ok(x - y)
1824            }
1825            Atom(VanishesOnZeroKnowledgeAndPreviousRows) => {
1826                Ok(eval_vanishes_on_last_n_rows(d, c.zk_rows + 1, pt))
1827            }
1828            Atom(UnnormalizedLagrangeBasis(i)) => {
1829                let offset = if i.zk_rows {
1830                    -(c.zk_rows as i32) + i.offset
1831                } else {
1832                    i.offset
1833                };
1834                Ok(unnormalized_lagrange_basis(&d, offset, &pt))
1835            }
1836            Atom(Cell(v)) => v.evaluate(evals),
1837            Cache(_, e) => e.evaluate_(d, pt, evals, c, chals),
1838            IfFeature(feature, e1, e2) => {
1839                if feature.is_enabled() {
1840                    e1.evaluate_(d, pt, evals, c, chals)
1841                } else {
1842                    e2.evaluate_(d, pt, evals, c, chals)
1843                }
1844            }
1845        }
1846    }
1847
1848    /// Evaluate the constant expressions in this expression down into field elements.
1849    pub fn evaluate_constants<
1850        'a,
1851        Challenge: Index<ChallengeTerm, Output = F>,
1852        Environment: ColumnEnvironment<'a, F, ChallengeTerm, Challenge, Column = Column>,
1853    >(
1854        &self,
1855        env: &Environment,
1856    ) -> Expr<F, Column> {
1857        self.evaluate_constants_(env.get_constants(), env.get_challenges())
1858    }
1859
1860    /// Compute the polynomial corresponding to this expression, in evaluation form.
1861    /// The routine will first replace the constants (verifier challenges and
1862    /// constants like the matrix used by `Poseidon`) in the expression with their
1863    /// respective values using `evaluate_constants` and will after evaluate the
1864    /// monomials with the corresponding column values using the method
1865    /// `evaluations`.
1866    pub fn evaluations<
1867        'a,
1868        Challenge: Index<ChallengeTerm, Output = F>,
1869        Environment: ColumnEnvironment<'a, F, ChallengeTerm, Challenge, Column = Column>,
1870    >(
1871        &self,
1872        env: &Environment,
1873    ) -> Evaluations<F, D<F>> {
1874        self.evaluate_constants(env).evaluations(env)
1875    }
1876}
1877
1878/// Use as a result of the expression evaluations routine.
1879/// For now, the left branch is the result of an evaluation and the right branch
1880/// is the ID of an element in the cache
1881enum Either<A, B> {
1882    Left(A),
1883    Right(B),
1884}
1885
1886impl<F: FftField, Column: Copy> Expr<F, Column> {
1887    /// Evaluate an expression into a field element.
1888    pub fn evaluate<Evaluations: ColumnEvaluations<F, Column = Column>>(
1889        &self,
1890        d: D<F>,
1891        pt: F,
1892        zk_rows: u64,
1893        evals: &Evaluations,
1894    ) -> Result<F, ExprError<Column>> {
1895        use ExprInner::*;
1896        use Operations::*;
1897        match self {
1898            Atom(Constant(x)) => Ok(*x),
1899            Pow(x, p) => Ok(x.evaluate(d, pt, zk_rows, evals)?.pow([*p])),
1900            Double(x) => x.evaluate(d, pt, zk_rows, evals).map(|x| x.double()),
1901            Square(x) => x.evaluate(d, pt, zk_rows, evals).map(|x| x.square()),
1902            Mul(x, y) => {
1903                let x = (*x).evaluate(d, pt, zk_rows, evals)?;
1904                let y = (*y).evaluate(d, pt, zk_rows, evals)?;
1905                Ok(x * y)
1906            }
1907            Add(x, y) => {
1908                let x = (*x).evaluate(d, pt, zk_rows, evals)?;
1909                let y = (*y).evaluate(d, pt, zk_rows, evals)?;
1910                Ok(x + y)
1911            }
1912            Sub(x, y) => {
1913                let x = (*x).evaluate(d, pt, zk_rows, evals)?;
1914                let y = (*y).evaluate(d, pt, zk_rows, evals)?;
1915                Ok(x - y)
1916            }
1917            Atom(VanishesOnZeroKnowledgeAndPreviousRows) => {
1918                Ok(eval_vanishes_on_last_n_rows(d, zk_rows + 1, pt))
1919            }
1920            Atom(UnnormalizedLagrangeBasis(i)) => {
1921                let offset = if i.zk_rows {
1922                    -(zk_rows as i32) + i.offset
1923                } else {
1924                    i.offset
1925                };
1926                Ok(unnormalized_lagrange_basis(&d, offset, &pt))
1927            }
1928            Atom(Cell(v)) => v.evaluate(evals),
1929            Cache(_, e) => e.evaluate(d, pt, zk_rows, evals),
1930            IfFeature(feature, e1, e2) => {
1931                if feature.is_enabled() {
1932                    e1.evaluate(d, pt, zk_rows, evals)
1933                } else {
1934                    e2.evaluate(d, pt, zk_rows, evals)
1935                }
1936            }
1937        }
1938    }
1939
1940    /// Compute the polynomial corresponding to this expression, in evaluation form.
1941    pub fn evaluations<
1942        'a,
1943        ChallengeTerm,
1944        Challenge: Index<ChallengeTerm, Output = F>,
1945        Environment: ColumnEnvironment<'a, F, ChallengeTerm, Challenge, Column = Column>,
1946    >(
1947        &self,
1948        env: &Environment,
1949    ) -> Evaluations<F, D<F>> {
1950        let d1_size = env.get_domain(Domain::D1).size;
1951        let deg = self.degree(d1_size, env.get_constants().zk_rows);
1952        let d = if deg <= d1_size {
1953            Domain::D1
1954        } else if deg <= 4 * d1_size {
1955            Domain::D4
1956        } else if deg <= 8 * d1_size {
1957            Domain::D8
1958        } else {
1959            panic!("constraint had degree {deg} > d8 ({})", 8 * d1_size);
1960        };
1961
1962        let mut cache = HashMap::new();
1963
1964        let evals = match self.evaluations_helper(&mut cache, d, env) {
1965            Either::Left(x) => x,
1966            Either::Right(id) => cache.get(&id).unwrap().clone(),
1967        };
1968
1969        match evals {
1970            EvalResult::Evals { evals, domain } => {
1971                assert_eq!(domain, d);
1972                evals
1973            }
1974            EvalResult::Constant(x) => EvalResult::init_((d, env.get_domain(d)), |_| x),
1975            EvalResult::SubEvals {
1976                evals,
1977                domain: d_sub,
1978                shift: s,
1979            } => {
1980                let res_domain = env.get_domain(d);
1981                let scale = (d_sub as usize) / (d as usize);
1982                assert!(
1983                    scale != 0,
1984                    "Check that the implementation of
1985                column_domain and the evaluation domain of the
1986                witnesses are the same"
1987                );
1988                EvalResult::init_((d, res_domain), |i| {
1989                    evals.evals[(scale * i + (d_sub as usize) * s) % evals.evals.len()]
1990                })
1991            }
1992        }
1993    }
1994
1995    fn evaluations_helper<
1996        'a,
1997        'b,
1998        ChallengeTerm,
1999        Challenge: Index<ChallengeTerm, Output = F>,
2000        Environment: ColumnEnvironment<'a, F, ChallengeTerm, Challenge, Column = Column>,
2001    >(
2002        &self,
2003        cache: &'b mut HashMap<CacheId, EvalResult<'a, F>>,
2004        d: Domain,
2005        env: &Environment,
2006    ) -> Either<EvalResult<'a, F>, CacheId>
2007    where
2008        'a: 'b,
2009    {
2010        let dom = (d, env.get_domain(d));
2011
2012        let res: EvalResult<'a, F> = match self {
2013            Expr::Square(x) => match x.evaluations_helper(cache, d, env) {
2014                Either::Left(x) => x.square(dom),
2015                Either::Right(id) => id.get_from(cache).unwrap().square(dom),
2016            },
2017            Expr::Double(x) => {
2018                let x = x.evaluations_helper(cache, d, env);
2019                let res = match x {
2020                    Either::Left(x) => {
2021                        let x = match x {
2022                            EvalResult::Evals { domain, mut evals } => {
2023                                o1_utils::cfg_iter_mut!(evals.evals).for_each(|x| {
2024                                    x.double_in_place();
2025                                });
2026                                return Either::Left(EvalResult::Evals { domain, evals });
2027                            }
2028                            x => x,
2029                        };
2030                        let xx = || match &x {
2031                            EvalResult::Constant(x) => EvalResult::Constant(*x),
2032                            EvalResult::SubEvals {
2033                                domain,
2034                                shift,
2035                                evals,
2036                            } => EvalResult::SubEvals {
2037                                domain: *domain,
2038                                shift: *shift,
2039                                evals,
2040                            },
2041                            EvalResult::Evals { domain, evals } => EvalResult::SubEvals {
2042                                domain: *domain,
2043                                shift: 0,
2044                                evals,
2045                            },
2046                        };
2047                        xx().add(xx(), dom)
2048                    }
2049                    Either::Right(id) => {
2050                        let x1 = id.get_from(cache).unwrap();
2051                        let x2 = id.get_from(cache).unwrap();
2052                        x1.add(x2, dom)
2053                    }
2054                };
2055                return Either::Left(res);
2056            }
2057            Expr::Cache(id, e) => match cache.get(id) {
2058                Some(_) => return Either::Right(*id),
2059                None => {
2060                    match e.evaluations_helper(cache, d, env) {
2061                        Either::Left(es) => {
2062                            cache.insert(*id, es);
2063                        }
2064                        Either::Right(_) => {}
2065                    };
2066                    return Either::Right(*id);
2067                }
2068            },
2069            Expr::Pow(x, p) => {
2070                let x = x.evaluations_helper(cache, d, env);
2071                match x {
2072                    Either::Left(x) => x.pow(*p, (d, env.get_domain(d))),
2073                    Either::Right(id) => {
2074                        id.get_from(cache).unwrap().pow(*p, (d, env.get_domain(d)))
2075                    }
2076                }
2077            }
2078            Expr::Atom(ExprInner::VanishesOnZeroKnowledgeAndPreviousRows) => EvalResult::SubEvals {
2079                domain: Domain::D8,
2080                shift: 0,
2081                evals: env.vanishes_on_zero_knowledge_and_previous_rows(),
2082            },
2083            Expr::Atom(ExprInner::Constant(x)) => EvalResult::Constant(*x),
2084            Expr::Atom(ExprInner::UnnormalizedLagrangeBasis(i)) => {
2085                let offset = if i.zk_rows {
2086                    -(env.get_constants().zk_rows as i32) + i.offset
2087                } else {
2088                    i.offset
2089                };
2090                EvalResult::Evals {
2091                    domain: d,
2092                    evals: unnormalized_lagrange_evals(env.l0_1(), offset, d, env),
2093                }
2094            }
2095            Expr::Atom(ExprInner::Cell(Variable { col, row })) => {
2096                let evals: &'a Evaluations<F, D<F>> = {
2097                    match env.get_column(col) {
2098                        None => return Either::Left(EvalResult::Constant(F::zero())),
2099                        Some(e) => e,
2100                    }
2101                };
2102                EvalResult::SubEvals {
2103                    domain: env.column_domain(col),
2104                    shift: row.shift(),
2105                    evals,
2106                }
2107            }
2108            Expr::Add(e1, e2) => {
2109                let dom = (d, env.get_domain(d));
2110                let f = |x: EvalResult<F>, y: EvalResult<F>| x.add(y, dom);
2111                let e1 = e1.evaluations_helper(cache, d, env);
2112                let e2 = e2.evaluations_helper(cache, d, env);
2113                use Either::*;
2114                match (e1, e2) {
2115                    (Left(e1), Left(e2)) => f(e1, e2),
2116                    (Right(id1), Left(e2)) => f(id1.get_from(cache).unwrap(), e2),
2117                    (Left(e1), Right(id2)) => f(e1, id2.get_from(cache).unwrap()),
2118                    (Right(id1), Right(id2)) => {
2119                        f(id1.get_from(cache).unwrap(), id2.get_from(cache).unwrap())
2120                    }
2121                }
2122            }
2123            Expr::Sub(e1, e2) => {
2124                let dom = (d, env.get_domain(d));
2125                let f = |x: EvalResult<F>, y: EvalResult<F>| x.sub(y, dom);
2126                let e1 = e1.evaluations_helper(cache, d, env);
2127                let e2 = e2.evaluations_helper(cache, d, env);
2128                use Either::*;
2129                match (e1, e2) {
2130                    (Left(e1), Left(e2)) => f(e1, e2),
2131                    (Right(id1), Left(e2)) => f(id1.get_from(cache).unwrap(), e2),
2132                    (Left(e1), Right(id2)) => f(e1, id2.get_from(cache).unwrap()),
2133                    (Right(id1), Right(id2)) => {
2134                        f(id1.get_from(cache).unwrap(), id2.get_from(cache).unwrap())
2135                    }
2136                }
2137            }
2138            Expr::Mul(e1, e2) => {
2139                let dom = (d, env.get_domain(d));
2140                let f = |x: EvalResult<F>, y: EvalResult<F>| x.mul(y, dom);
2141                let e1 = e1.evaluations_helper(cache, d, env);
2142                let e2 = e2.evaluations_helper(cache, d, env);
2143                use Either::*;
2144                match (e1, e2) {
2145                    (Left(e1), Left(e2)) => f(e1, e2),
2146                    (Right(id1), Left(e2)) => f(id1.get_from(cache).unwrap(), e2),
2147                    (Left(e1), Right(id2)) => f(e1, id2.get_from(cache).unwrap()),
2148                    (Right(id1), Right(id2)) => {
2149                        f(id1.get_from(cache).unwrap(), id2.get_from(cache).unwrap())
2150                    }
2151                }
2152            }
2153            Expr::IfFeature(feature, e1, e2) => {
2154                /* Clone the cache, to make sure we don't try to access cached statements later
2155                when the feature flag is off. */
2156                let mut cache = cache.clone();
2157                if feature.is_enabled() {
2158                    return e1.evaluations_helper(&mut cache, d, env);
2159                } else {
2160                    return e2.evaluations_helper(&mut cache, d, env);
2161                }
2162            }
2163        };
2164        Either::Left(res)
2165    }
2166}
2167
2168#[derive(Clone, Debug, Serialize, Deserialize)]
2169/// A "linearization", which is linear combination with `E` coefficients of
2170/// columns.
2171pub struct Linearization<E, Column> {
2172    pub constant_term: E,
2173    pub index_terms: Vec<(Column, E)>,
2174}
2175
2176impl<E: Default, Column> Default for Linearization<E, Column> {
2177    fn default() -> Self {
2178        Linearization {
2179            constant_term: E::default(),
2180            index_terms: vec![],
2181        }
2182    }
2183}
2184
2185impl<A, Column: Copy> Linearization<A, Column> {
2186    /// Apply a function to all the coefficients in the linearization.
2187    pub fn map<B, F: Fn(&A) -> B>(&self, f: F) -> Linearization<B, Column> {
2188        Linearization {
2189            constant_term: f(&self.constant_term),
2190            index_terms: self.index_terms.iter().map(|(c, x)| (*c, f(x))).collect(),
2191        }
2192    }
2193}
2194
2195impl<F: FftField, Column: PartialEq + Copy, ChallengeTerm: Copy>
2196    Linearization<Expr<ConstantExpr<F, ChallengeTerm>, Column>, Column>
2197{
2198    /// Evaluate the constants in a linearization with `ConstantExpr<F>` coefficients down
2199    /// to literal field elements.
2200    pub fn evaluate_constants<
2201        'a,
2202        Challenge: Index<ChallengeTerm, Output = F>,
2203        Environment: ColumnEnvironment<'a, F, ChallengeTerm, Challenge, Column = Column>,
2204    >(
2205        &self,
2206        env: &Environment,
2207    ) -> Linearization<Expr<F, Column>, Column> {
2208        self.map(|e| e.evaluate_constants(env))
2209    }
2210}
2211
2212impl<F: FftField, Column: Copy + Debug, ChallengeTerm: Copy>
2213    Linearization<Vec<PolishToken<F, Column, ChallengeTerm>>, Column>
2214{
2215    /// Given a linearization and an environment, compute the polynomial corresponding to the
2216    /// linearization, in evaluation form.
2217    pub fn to_polynomial<
2218        'a,
2219        Challenge: Index<ChallengeTerm, Output = F>,
2220        ColEvaluations: ColumnEvaluations<F, Column = Column>,
2221        Environment: ColumnEnvironment<'a, F, ChallengeTerm, Challenge, Column = Column>,
2222    >(
2223        &self,
2224        env: &Environment,
2225        pt: F,
2226        evals: &ColEvaluations,
2227    ) -> (F, Evaluations<F, D<F>>) {
2228        let cs = env.get_constants();
2229        let chals = env.get_challenges();
2230        let d1 = env.get_domain(Domain::D1);
2231        let n = d1.size();
2232        let mut res = vec![F::zero(); n];
2233        self.index_terms.iter().for_each(|(idx, c)| {
2234            let c = PolishToken::evaluate(c, d1, pt, evals, cs, chals).unwrap();
2235            let e = env
2236                .get_column(idx)
2237                .unwrap_or_else(|| panic!("Index polynomial {idx:?} not found"));
2238            let scale = e.evals.len() / n;
2239            o1_utils::cfg_iter_mut!(res)
2240                .enumerate()
2241                .for_each(|(i, r)| *r += c * e.evals[scale * i]);
2242        });
2243        let p = Evaluations::<F, D<F>>::from_vec_and_domain(res, d1);
2244        (
2245            PolishToken::evaluate(&self.constant_term, d1, pt, evals, cs, chals).unwrap(),
2246            p,
2247        )
2248    }
2249}
2250
2251impl<F: FftField, Column: Debug + PartialEq + Copy, ChallengeTerm: Copy>
2252    Linearization<Expr<ConstantExpr<F, ChallengeTerm>, Column>, Column>
2253{
2254    /// Given a linearization and an environment, compute the polynomial corresponding to the
2255    /// linearization, in evaluation form.
2256    pub fn to_polynomial<
2257        'a,
2258        Challenge: Index<ChallengeTerm, Output = F>,
2259        ColEvaluations: ColumnEvaluations<F, Column = Column>,
2260        Environment: ColumnEnvironment<'a, F, ChallengeTerm, Challenge, Column = Column>,
2261    >(
2262        &self,
2263        env: &Environment,
2264        pt: F,
2265        evals: &ColEvaluations,
2266    ) -> (F, DensePolynomial<F>) {
2267        let cs = env.get_constants();
2268        let chals = env.get_challenges();
2269        let d1 = env.get_domain(Domain::D1);
2270        let n = d1.size();
2271        let mut res = vec![F::zero(); n];
2272        self.index_terms.iter().for_each(|(idx, c)| {
2273            let c = c.evaluate_(d1, pt, evals, cs, chals).unwrap();
2274            let e = env
2275                .get_column(idx)
2276                .unwrap_or_else(|| panic!("Index polynomial {idx:?} not found"));
2277            let scale = e.evals.len() / n;
2278            o1_utils::cfg_iter_mut!(res)
2279                .enumerate()
2280                .for_each(|(i, r)| *r += c * e.evals[scale * i])
2281        });
2282        let p = Evaluations::<F, D<F>>::from_vec_and_domain(res, d1).interpolate();
2283        (
2284            self.constant_term
2285                .evaluate_(d1, pt, evals, cs, chals)
2286                .unwrap(),
2287            p,
2288        )
2289    }
2290}
2291
2292type Monomials<F, Column> = HashMap<Vec<Variable<Column>>, Expr<F, Column>>;
2293
2294fn mul_monomials<
2295    F: Neg<Output = F> + Clone + One + Zero + PartialEq,
2296    Column: Ord + Copy + core::hash::Hash,
2297>(
2298    e1: &Monomials<F, Column>,
2299    e2: &Monomials<F, Column>,
2300) -> Monomials<F, Column>
2301where
2302    ExprInner<F, Column>: Literal,
2303    <ExprInner<F, Column> as Literal>::F: Field,
2304{
2305    let mut res: HashMap<_, Expr<F, Column>> = HashMap::new();
2306    for (m1, c1) in e1.iter() {
2307        for (m2, c2) in e2.iter() {
2308            let mut m = m1.clone();
2309            m.extend(m2);
2310            m.sort();
2311            let c1c2 = c1.clone() * c2.clone();
2312            let v = res.entry(m).or_insert_with(Expr::<F, Column>::zero);
2313            *v = v.clone() + c1c2;
2314        }
2315    }
2316    res
2317}
2318
2319impl<
2320        F: Neg<Output = F> + Clone + One + Zero + PartialEq,
2321        Column: Ord + Copy + core::hash::Hash,
2322    > Expr<F, Column>
2323where
2324    ExprInner<F, Column>: Literal,
2325    <ExprInner<F, Column> as Literal>::F: Field,
2326{
2327    // TODO: This function (which takes linear time)
2328    // is called repeatedly in monomials, yielding quadratic behavior for
2329    // that function. It's ok for now as we only call that function once on
2330    // a small input when producing the verification key.
2331    fn is_constant(&self, evaluated: &HashSet<Column>) -> bool {
2332        use ExprInner::*;
2333        use Operations::*;
2334        match self {
2335            Pow(x, _) => x.is_constant(evaluated),
2336            Square(x) => x.is_constant(evaluated),
2337            Atom(Constant(_)) => true,
2338            Atom(Cell(v)) => evaluated.contains(&v.col),
2339            Double(x) => x.is_constant(evaluated),
2340            Add(x, y) | Sub(x, y) | Mul(x, y) => {
2341                x.is_constant(evaluated) && y.is_constant(evaluated)
2342            }
2343            Atom(VanishesOnZeroKnowledgeAndPreviousRows) => true,
2344            Atom(UnnormalizedLagrangeBasis(_)) => true,
2345            Cache(_, x) => x.is_constant(evaluated),
2346            IfFeature(_, e1, e2) => e1.is_constant(evaluated) && e2.is_constant(evaluated),
2347        }
2348    }
2349
2350    fn monomials(&self, ev: &HashSet<Column>) -> HashMap<Vec<Variable<Column>>, Expr<F, Column>> {
2351        let sing = |v: Vec<Variable<Column>>, c: Expr<F, Column>| {
2352            let mut h = HashMap::new();
2353            h.insert(v, c);
2354            h
2355        };
2356        let constant = |e: Expr<F, Column>| sing(vec![], e);
2357        use ExprInner::*;
2358        use Operations::*;
2359
2360        if self.is_constant(ev) {
2361            return constant(self.clone());
2362        }
2363
2364        match self {
2365            Pow(x, d) => {
2366                // Run the multiplication logic with square and multiply
2367                let mut acc = sing(vec![], Expr::<F, Column>::one());
2368                let mut acc_is_one = true;
2369                let x = x.monomials(ev);
2370
2371                for i in (0..u64::BITS).rev() {
2372                    if !acc_is_one {
2373                        let acc2 = mul_monomials(&acc, &acc);
2374                        acc = acc2;
2375                    }
2376
2377                    if (d >> i) & 1 == 1 {
2378                        let res = mul_monomials(&acc, &x);
2379                        acc = res;
2380                        acc_is_one = false;
2381                    }
2382                }
2383                acc
2384            }
2385            Double(e) => {
2386                HashMap::from_iter(e.monomials(ev).into_iter().map(|(m, c)| (m, c.double())))
2387            }
2388            Cache(_, e) => e.monomials(ev),
2389            Atom(UnnormalizedLagrangeBasis(i)) => constant(Atom(UnnormalizedLagrangeBasis(*i))),
2390            Atom(VanishesOnZeroKnowledgeAndPreviousRows) => {
2391                constant(Atom(VanishesOnZeroKnowledgeAndPreviousRows))
2392            }
2393            Atom(Constant(c)) => constant(Atom(Constant(c.clone()))),
2394            Atom(Cell(var)) => sing(vec![*var], Atom(Constant(F::one()))),
2395            Add(e1, e2) => {
2396                let mut res = e1.monomials(ev);
2397                for (m, c) in e2.monomials(ev) {
2398                    let v = match res.remove(&m) {
2399                        None => c,
2400                        Some(v) => v + c,
2401                    };
2402                    res.insert(m, v);
2403                }
2404                res
2405            }
2406            Sub(e1, e2) => {
2407                let mut res = e1.monomials(ev);
2408                for (m, c) in e2.monomials(ev) {
2409                    let v = match res.remove(&m) {
2410                        None => -c, // Expr::constant(F::one()) * c,
2411                        Some(v) => v - c,
2412                    };
2413                    res.insert(m, v);
2414                }
2415                res
2416            }
2417            Mul(e1, e2) => {
2418                let e1 = e1.monomials(ev);
2419                let e2 = e2.monomials(ev);
2420                mul_monomials(&e1, &e2)
2421            }
2422            Square(x) => {
2423                let x = x.monomials(ev);
2424                mul_monomials(&x, &x)
2425            }
2426            IfFeature(feature, e1, e2) => {
2427                let mut res = HashMap::new();
2428                let e1_monomials = e1.monomials(ev);
2429                let mut e2_monomials = e2.monomials(ev);
2430                for (m, c) in e1_monomials.into_iter() {
2431                    let else_branch = match e2_monomials.remove(&m) {
2432                        None => Expr::zero(),
2433                        Some(c) => c,
2434                    };
2435                    let expr = Expr::IfFeature(*feature, Box::new(c), Box::new(else_branch));
2436                    res.insert(m, expr);
2437                }
2438                for (m, c) in e2_monomials.into_iter() {
2439                    let expr = Expr::IfFeature(*feature, Box::new(Expr::zero()), Box::new(c));
2440                    res.insert(m, expr);
2441                }
2442                res
2443            }
2444        }
2445    }
2446
2447    /// There is an optimization in PLONK called "linearization" in which a certain
2448    /// polynomial is expressed as a linear combination of other polynomials in order
2449    /// to reduce the number of evaluations needed in the IOP (by relying on the homomorphic
2450    /// property of the polynomial commitments used.)
2451    ///
2452    /// The function performs this "linearization", which we now describe in some detail.
2453    ///
2454    /// In mathematical language, an expression `e: Expr<F>`
2455    /// is an element of the polynomial ring `F[V]`, where `V` is a set of variables.
2456    ///
2457    /// Given a subset `V_0` of `V` (and letting `V_1 = V \setminus V_0`), there is a map
2458    /// `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`
2459    /// are the same thing as polynomials with `F[V_1]` coefficients in variables `V_0`.
2460    ///
2461    /// There is also a function
2462    /// `lin_or_err : (F[V_1])[V_0] -> Result<Vec<(V_0, F[V_1])>, &str>`
2463    ///
2464    /// which checks if the given input is in fact a degree 1 polynomial in the variables `V_0`
2465    /// (i.e., a linear combination of `V_0` elements with `F[V_1]` coefficients)
2466    /// returning this linear combination if so.
2467    ///
2468    /// Given an expression `e` and set of columns `C_0`, letting
2469    /// `V_0 = { Variable { col: c, row: r } | c in C_0, r in { Curr, Next } }`,
2470    /// this function computes `lin_or_err(factor_{V_0}(e))`, although it does not
2471    /// compute it in that way. Instead, it computes it by reducing the expression into
2472    /// a sum of monomials with `F` coefficients, and then factors the monomials.
2473    pub fn linearize(
2474        &self,
2475        evaluated: HashSet<Column>,
2476    ) -> Result<Linearization<Expr<F, Column>, Column>, ExprError<Column>> {
2477        let mut res: HashMap<Column, Expr<F, Column>> = HashMap::new();
2478        let mut constant_term: Expr<F, Column> = Self::zero();
2479        let monomials = self.monomials(&evaluated);
2480
2481        for (m, c) in monomials {
2482            let (evaluated, mut unevaluated): (Vec<_>, _) =
2483                m.into_iter().partition(|v| evaluated.contains(&v.col));
2484            let c = evaluated
2485                .into_iter()
2486                .fold(c, |acc, v| acc * Expr::Atom(ExprInner::Cell(v)));
2487            if unevaluated.is_empty() {
2488                constant_term += c;
2489            } else if unevaluated.len() == 1 {
2490                let var = unevaluated.remove(0);
2491                match var.row {
2492                    Next => {
2493                        return Err(ExprError::MissingEvaluation(var.col, var.row));
2494                    }
2495                    Curr => {
2496                        let e = match res.remove(&var.col) {
2497                            Some(v) => v + c,
2498                            None => c,
2499                        };
2500                        res.insert(var.col, e);
2501                        // This code used to be
2502                        //
2503                        // let v = res.entry(var.col).or_insert(0.into());
2504                        // *v = v.clone() + c
2505                        //
2506                        // but calling clone made it extremely slow, so I replaced it
2507                        // with the above that moves v out of the map with .remove and
2508                        // into v + c.
2509                        //
2510                        // I'm not sure if there's a way to do it with the HashMap API
2511                        // without calling remove.
2512                    }
2513                }
2514            } else {
2515                return Err(ExprError::FailedLinearization(unevaluated));
2516            }
2517        }
2518        Ok(Linearization {
2519            constant_term,
2520            index_terms: res.into_iter().collect(),
2521        })
2522    }
2523}
2524
2525// Trait implementations
2526
2527impl<T: Literal> Zero for Operations<T>
2528where
2529    T::F: Field,
2530{
2531    fn zero() -> Self {
2532        Self::literal(T::F::zero())
2533    }
2534
2535    fn is_zero(&self) -> bool {
2536        if let Some(x) = self.to_literal_ref() {
2537            x.is_zero()
2538        } else {
2539            false
2540        }
2541    }
2542}
2543
2544impl<T: Literal + PartialEq> One for Operations<T>
2545where
2546    T::F: Field,
2547{
2548    fn one() -> Self {
2549        Self::literal(T::F::one())
2550    }
2551
2552    fn is_one(&self) -> bool {
2553        if let Some(x) = self.to_literal_ref() {
2554            x.is_one()
2555        } else {
2556            false
2557        }
2558    }
2559}
2560
2561impl<T: Literal> Neg for Operations<T>
2562where
2563    T::F: One + Neg<Output = T::F> + Copy,
2564{
2565    type Output = Self;
2566
2567    fn neg(self) -> Self {
2568        match self.to_literal() {
2569            Ok(x) => Self::literal(x.neg()),
2570            Err(x) => Operations::Mul(Box::new(Self::literal(T::F::one().neg())), Box::new(x)),
2571        }
2572    }
2573}
2574
2575impl<T: Literal> Add<Self> for Operations<T>
2576where
2577    T::F: Field,
2578{
2579    type Output = Self;
2580    fn add(self, other: Self) -> Self {
2581        if self.is_zero() {
2582            return other;
2583        }
2584        if other.is_zero() {
2585            return self;
2586        }
2587        let (x, y) = {
2588            match (self.to_literal(), other.to_literal()) {
2589                (Ok(x), Ok(y)) => return Self::literal(x + y),
2590                (Ok(x), Err(y)) => (Self::literal(x), y),
2591                (Err(x), Ok(y)) => (x, Self::literal(y)),
2592                (Err(x), Err(y)) => (x, y),
2593            }
2594        };
2595        Operations::Add(Box::new(x), Box::new(y))
2596    }
2597}
2598
2599impl<T: Literal> Sub<Self> for Operations<T>
2600where
2601    T::F: Field,
2602{
2603    type Output = Self;
2604    fn sub(self, other: Self) -> Self {
2605        if other.is_zero() {
2606            return self;
2607        }
2608        let (x, y) = {
2609            match (self.to_literal(), other.to_literal()) {
2610                (Ok(x), Ok(y)) => return Self::literal(x - y),
2611                (Ok(x), Err(y)) => (Self::literal(x), y),
2612                (Err(x), Ok(y)) => (x, Self::literal(y)),
2613                (Err(x), Err(y)) => (x, y),
2614            }
2615        };
2616        Operations::Sub(Box::new(x), Box::new(y))
2617    }
2618}
2619
2620impl<T: Literal + PartialEq> Mul<Self> for Operations<T>
2621where
2622    T::F: Field,
2623{
2624    type Output = Self;
2625    fn mul(self, other: Self) -> Self {
2626        if self.is_zero() || other.is_zero() {
2627            return Self::zero();
2628        }
2629
2630        if self.is_one() {
2631            return other;
2632        }
2633        if other.is_one() {
2634            return self;
2635        }
2636        let (x, y) = {
2637            match (self.to_literal(), other.to_literal()) {
2638                (Ok(x), Ok(y)) => return Self::literal(x * y),
2639                (Ok(x), Err(y)) => (Self::literal(x), y),
2640                (Err(x), Ok(y)) => (x, Self::literal(y)),
2641                (Err(x), Err(y)) => (x, y),
2642            }
2643        };
2644        Operations::Mul(Box::new(x), Box::new(y))
2645    }
2646}
2647
2648impl<F: Zero + Clone, Column: Clone> AddAssign<Expr<F, Column>> for Expr<F, Column>
2649where
2650    ExprInner<F, Column>: Literal,
2651    <ExprInner<F, Column> as Literal>::F: Field,
2652{
2653    fn add_assign(&mut self, other: Self) {
2654        if self.is_zero() {
2655            *self = other;
2656        } else if !other.is_zero() {
2657            *self = Expr::Add(Box::new(self.clone()), Box::new(other));
2658        }
2659    }
2660}
2661
2662impl<F, Column> MulAssign<Expr<F, Column>> for Expr<F, Column>
2663where
2664    F: Zero + One + PartialEq + Clone,
2665    Column: PartialEq + Clone,
2666    ExprInner<F, Column>: Literal,
2667    <ExprInner<F, Column> as Literal>::F: Field,
2668{
2669    fn mul_assign(&mut self, other: Self) {
2670        if self.is_zero() || other.is_zero() {
2671            *self = Self::zero();
2672        } else if self.is_one() {
2673            *self = other;
2674        } else if !other.is_one() {
2675            *self = Expr::Mul(Box::new(self.clone()), Box::new(other));
2676        }
2677    }
2678}
2679
2680impl<F: Field, Column> From<u64> for Expr<F, Column> {
2681    fn from(x: u64) -> Self {
2682        Expr::Atom(ExprInner::Constant(F::from(x)))
2683    }
2684}
2685
2686impl<'a, F: Field, Column, ChallengeTerm: AlphaChallengeTerm<'a>> From<u64>
2687    for Expr<ConstantExpr<F, ChallengeTerm>, Column>
2688{
2689    fn from(x: u64) -> Self {
2690        ConstantTerm::Literal(F::from(x)).into()
2691    }
2692}
2693
2694impl<F: Field, ChallengeTerm> From<u64> for ConstantExpr<F, ChallengeTerm> {
2695    fn from(x: u64) -> Self {
2696        ConstantTerm::Literal(F::from(x)).into()
2697    }
2698}
2699
2700impl<'a, F: Field, Column: PartialEq + Copy, ChallengeTerm: AlphaChallengeTerm<'a>> Mul<F>
2701    for Expr<ConstantExpr<F, ChallengeTerm>, Column>
2702{
2703    type Output = Expr<ConstantExpr<F, ChallengeTerm>, Column>;
2704
2705    fn mul(self, y: F) -> Self::Output {
2706        Expr::from(ConstantTerm::Literal(y)) * self
2707    }
2708}
2709
2710//
2711// Display
2712//
2713
2714pub trait FormattedOutput: Sized {
2715    fn is_alpha(&self) -> bool;
2716    fn ocaml(&self, cache: &mut HashMap<CacheId, Self>) -> String;
2717    fn latex(&self, cache: &mut HashMap<CacheId, Self>) -> String;
2718    fn text(&self, cache: &mut HashMap<CacheId, Self>) -> String;
2719}
2720
2721impl<'a, ChallengeTerm> FormattedOutput for ChallengeTerm
2722where
2723    ChallengeTerm: AlphaChallengeTerm<'a>,
2724{
2725    fn is_alpha(&self) -> bool {
2726        self.eq(&ChallengeTerm::ALPHA)
2727    }
2728    fn ocaml(&self, _cache: &mut HashMap<CacheId, Self>) -> String {
2729        self.to_string()
2730    }
2731
2732    fn latex(&self, _cache: &mut HashMap<CacheId, Self>) -> String {
2733        "\\".to_string() + &self.to_string()
2734    }
2735
2736    fn text(&self, _cache: &mut HashMap<CacheId, Self>) -> String {
2737        self.to_string()
2738    }
2739}
2740
2741impl<F: PrimeField> FormattedOutput for ConstantTerm<F> {
2742    fn is_alpha(&self) -> bool {
2743        false
2744    }
2745    fn ocaml(&self, _cache: &mut HashMap<CacheId, Self>) -> String {
2746        use ConstantTerm::*;
2747        match self {
2748            EndoCoefficient => "endo_coefficient".to_string(),
2749            Mds { row, col } => format!("mds({row}, {col})"),
2750            Literal(x) => format!(
2751                "field(\"{:#066X}\")",
2752                Into::<num_bigint::BigUint>::into(x.into_bigint())
2753            ),
2754        }
2755    }
2756
2757    fn latex(&self, _cache: &mut HashMap<CacheId, Self>) -> String {
2758        use ConstantTerm::*;
2759        match self {
2760            EndoCoefficient => "endo\\_coefficient".to_string(),
2761            Mds { row, col } => format!("mds({row}, {col})"),
2762            Literal(x) => format!("\\mathbb{{F}}({})", x.into_bigint().into()),
2763        }
2764    }
2765
2766    fn text(&self, _cache: &mut HashMap<CacheId, Self>) -> String {
2767        use ConstantTerm::*;
2768        match self {
2769            EndoCoefficient => "endo_coefficient".to_string(),
2770            Mds { row, col } => format!("mds({row}, {col})"),
2771            Literal(x) => format!("0x{}", x.to_hex()),
2772        }
2773    }
2774}
2775
2776impl<'a, F: PrimeField, ChallengeTerm> FormattedOutput for ConstantExprInner<F, ChallengeTerm>
2777where
2778    ChallengeTerm: AlphaChallengeTerm<'a>,
2779{
2780    fn is_alpha(&self) -> bool {
2781        use ConstantExprInner::*;
2782        match self {
2783            Challenge(x) => x.is_alpha(),
2784            Constant(x) => x.is_alpha(),
2785        }
2786    }
2787    fn ocaml(&self, cache: &mut HashMap<CacheId, Self>) -> String {
2788        use ConstantExprInner::*;
2789        match self {
2790            Challenge(x) => {
2791                let mut inner_cache = HashMap::new();
2792                let res = x.ocaml(&mut inner_cache);
2793                inner_cache.into_iter().for_each(|(k, v)| {
2794                    let _ = cache.insert(k, Challenge(v));
2795                });
2796                res
2797            }
2798            Constant(x) => {
2799                let mut inner_cache = HashMap::new();
2800                let res = x.ocaml(&mut inner_cache);
2801                inner_cache.into_iter().for_each(|(k, v)| {
2802                    let _ = cache.insert(k, Constant(v));
2803                });
2804                res
2805            }
2806        }
2807    }
2808    fn latex(&self, cache: &mut HashMap<CacheId, Self>) -> String {
2809        use ConstantExprInner::*;
2810        match self {
2811            Challenge(x) => {
2812                let mut inner_cache = HashMap::new();
2813                let res = x.latex(&mut inner_cache);
2814                inner_cache.into_iter().for_each(|(k, v)| {
2815                    let _ = cache.insert(k, Challenge(v));
2816                });
2817                res
2818            }
2819            Constant(x) => {
2820                let mut inner_cache = HashMap::new();
2821                let res = x.latex(&mut inner_cache);
2822                inner_cache.into_iter().for_each(|(k, v)| {
2823                    let _ = cache.insert(k, Constant(v));
2824                });
2825                res
2826            }
2827        }
2828    }
2829    fn text(&self, cache: &mut HashMap<CacheId, Self>) -> String {
2830        use ConstantExprInner::*;
2831        match self {
2832            Challenge(x) => {
2833                let mut inner_cache = HashMap::new();
2834                let res = x.text(&mut inner_cache);
2835                inner_cache.into_iter().for_each(|(k, v)| {
2836                    let _ = cache.insert(k, Challenge(v));
2837                });
2838                res
2839            }
2840            Constant(x) => {
2841                let mut inner_cache = HashMap::new();
2842                let res = x.text(&mut inner_cache);
2843                inner_cache.into_iter().for_each(|(k, v)| {
2844                    let _ = cache.insert(k, Constant(v));
2845                });
2846                res
2847            }
2848        }
2849    }
2850}
2851
2852impl<Column: FormattedOutput + Debug> FormattedOutput for Variable<Column> {
2853    fn is_alpha(&self) -> bool {
2854        false
2855    }
2856
2857    fn ocaml(&self, _cache: &mut HashMap<CacheId, Self>) -> String {
2858        format!("var({:?}, {:?})", self.col, self.row)
2859    }
2860
2861    fn latex(&self, _cache: &mut HashMap<CacheId, Self>) -> String {
2862        let col = self.col.latex(&mut HashMap::new());
2863        match self.row {
2864            Curr => col,
2865            Next => format!("\\tilde{{{col}}}"),
2866        }
2867    }
2868
2869    fn text(&self, _cache: &mut HashMap<CacheId, Self>) -> String {
2870        let col = self.col.text(&mut HashMap::new());
2871        match self.row {
2872            Curr => format!("Curr({col})"),
2873            Next => format!("Next({col})"),
2874        }
2875    }
2876}
2877
2878impl<T: FormattedOutput + Clone> FormattedOutput for Operations<T> {
2879    fn is_alpha(&self) -> bool {
2880        match self {
2881            Operations::Atom(x) => x.is_alpha(),
2882            _ => false,
2883        }
2884    }
2885    fn ocaml(&self, cache: &mut HashMap<CacheId, Self>) -> String {
2886        use Operations::*;
2887        match self {
2888            Atom(x) => {
2889                let mut inner_cache = HashMap::new();
2890                let res = x.ocaml(&mut inner_cache);
2891                inner_cache.into_iter().for_each(|(k, v)| {
2892                    let _ = cache.insert(k, Atom(v));
2893                });
2894                res
2895            }
2896            Pow(x, n) => {
2897                if x.is_alpha() {
2898                    format!("alpha_pow({n})")
2899                } else {
2900                    format!("pow({}, {n})", x.ocaml(cache))
2901                }
2902            }
2903            Add(x, y) => format!("({} + {})", x.ocaml(cache), y.ocaml(cache)),
2904            Mul(x, y) => format!("({} * {})", x.ocaml(cache), y.ocaml(cache)),
2905            Sub(x, y) => format!("({} - {})", x.ocaml(cache), y.ocaml(cache)),
2906            Double(x) => format!("double({})", x.ocaml(cache)),
2907            Square(x) => format!("square({})", x.ocaml(cache)),
2908            Cache(id, e) => {
2909                cache.insert(*id, e.as_ref().clone());
2910                id.var_name()
2911            }
2912            IfFeature(feature, e1, e2) => {
2913                format!(
2914                    "if_feature({:?}, (fun () -> {}), (fun () -> {}))",
2915                    feature,
2916                    e1.ocaml(cache),
2917                    e2.ocaml(cache)
2918                )
2919            }
2920        }
2921    }
2922
2923    fn latex(&self, cache: &mut HashMap<CacheId, Self>) -> String {
2924        use Operations::*;
2925        match self {
2926            Atom(x) => {
2927                let mut inner_cache = HashMap::new();
2928                let res = x.latex(&mut inner_cache);
2929                inner_cache.into_iter().for_each(|(k, v)| {
2930                    let _ = cache.insert(k, Atom(v));
2931                });
2932                res
2933            }
2934            Pow(x, n) => format!("{}^{{{n}}}", x.latex(cache)),
2935            Add(x, y) => format!("({} + {})", x.latex(cache), y.latex(cache)),
2936            Mul(x, y) => format!("({} \\cdot {})", x.latex(cache), y.latex(cache)),
2937            Sub(x, y) => format!("({} - {})", x.latex(cache), y.latex(cache)),
2938            Double(x) => format!("2 ({})", x.latex(cache)),
2939            Square(x) => format!("({})^2", x.latex(cache)),
2940            Cache(id, e) => {
2941                cache.insert(*id, e.as_ref().clone());
2942                id.var_name()
2943            }
2944            IfFeature(feature, _, _) => format!("{feature:?}"),
2945        }
2946    }
2947
2948    fn text(&self, cache: &mut HashMap<CacheId, Self>) -> String {
2949        use Operations::*;
2950        match self {
2951            Atom(x) => {
2952                let mut inner_cache = HashMap::new();
2953                let res = x.text(&mut inner_cache);
2954                inner_cache.into_iter().for_each(|(k, v)| {
2955                    let _ = cache.insert(k, Atom(v));
2956                });
2957                res
2958            }
2959            Pow(x, n) => format!("{}^{n}", x.text(cache)),
2960            Add(x, y) => format!("({} + {})", x.text(cache), y.text(cache)),
2961            Mul(x, y) => format!("({} * {})", x.text(cache), y.text(cache)),
2962            Sub(x, y) => format!("({} - {})", x.text(cache), y.text(cache)),
2963            Double(x) => format!("double({})", x.text(cache)),
2964            Square(x) => format!("square({})", x.text(cache)),
2965            Cache(id, e) => {
2966                cache.insert(*id, e.as_ref().clone());
2967                id.var_name()
2968            }
2969            IfFeature(feature, _, _) => format!("{feature:?}"),
2970        }
2971    }
2972}
2973
2974impl<'a, F, Column: FormattedOutput + Debug + Clone, ChallengeTerm> FormattedOutput
2975    for Expr<ConstantExpr<F, ChallengeTerm>, Column>
2976where
2977    F: PrimeField,
2978    ChallengeTerm: AlphaChallengeTerm<'a>,
2979{
2980    fn is_alpha(&self) -> bool {
2981        use ExprInner::*;
2982        use Operations::*;
2983        match self {
2984            Atom(Constant(x)) => x.is_alpha(),
2985            _ => false,
2986        }
2987    }
2988    /// Converts the expression in OCaml code
2989    /// Recursively print the expression,
2990    /// except for the cached expression that are stored in the `cache`.
2991    fn ocaml(
2992        &self,
2993        cache: &mut HashMap<CacheId, Expr<ConstantExpr<F, ChallengeTerm>, Column>>,
2994    ) -> String {
2995        use ExprInner::*;
2996        use Operations::*;
2997        match self {
2998            Double(x) => format!("double({})", x.ocaml(cache)),
2999            Atom(Constant(x)) => {
3000                let mut inner_cache = HashMap::new();
3001                let res = x.ocaml(&mut inner_cache);
3002                inner_cache.into_iter().for_each(|(k, v)| {
3003                    let _ = cache.insert(k, Atom(Constant(v)));
3004                });
3005                res
3006            }
3007            Atom(Cell(v)) => format!("cell({})", v.ocaml(&mut HashMap::new())),
3008            Atom(UnnormalizedLagrangeBasis(i)) => {
3009                format!("unnormalized_lagrange_basis({}, {})", i.zk_rows, i.offset)
3010            }
3011            Atom(VanishesOnZeroKnowledgeAndPreviousRows) => {
3012                "vanishes_on_zero_knowledge_and_previous_rows".to_string()
3013            }
3014            Add(x, y) => format!("({} + {})", x.ocaml(cache), y.ocaml(cache)),
3015            Mul(x, y) => format!("({} * {})", x.ocaml(cache), y.ocaml(cache)),
3016            Sub(x, y) => format!("({} - {})", x.ocaml(cache), y.ocaml(cache)),
3017            Pow(x, d) => format!("pow({}, {d})", x.ocaml(cache)),
3018            Square(x) => format!("square({})", x.ocaml(cache)),
3019            Cache(id, e) => {
3020                cache.insert(*id, e.as_ref().clone());
3021                id.var_name()
3022            }
3023            IfFeature(feature, e1, e2) => {
3024                format!(
3025                    "if_feature({:?}, (fun () -> {}), (fun () -> {}))",
3026                    feature,
3027                    e1.ocaml(cache),
3028                    e2.ocaml(cache)
3029                )
3030            }
3031        }
3032    }
3033
3034    fn latex(
3035        &self,
3036        cache: &mut HashMap<CacheId, Expr<ConstantExpr<F, ChallengeTerm>, Column>>,
3037    ) -> String {
3038        use ExprInner::*;
3039        use Operations::*;
3040        match self {
3041            Double(x) => format!("2 ({})", x.latex(cache)),
3042            Atom(Constant(x)) => {
3043                let mut inner_cache = HashMap::new();
3044                let res = x.latex(&mut inner_cache);
3045                inner_cache.into_iter().for_each(|(k, v)| {
3046                    let _ = cache.insert(k, Atom(Constant(v)));
3047                });
3048                res
3049            }
3050            Atom(Cell(v)) => v.latex(&mut HashMap::new()),
3051            Atom(UnnormalizedLagrangeBasis(RowOffset {
3052                zk_rows: true,
3053                offset: i,
3054            })) => {
3055                format!("unnormalized\\_lagrange\\_basis(zk\\_rows + {})", *i)
3056            }
3057            Atom(UnnormalizedLagrangeBasis(RowOffset {
3058                zk_rows: false,
3059                offset: i,
3060            })) => {
3061                format!("unnormalized\\_lagrange\\_basis({})", *i)
3062            }
3063            Atom(VanishesOnZeroKnowledgeAndPreviousRows) => {
3064                "vanishes\\_on\\_zero\\_knowledge\\_and\\_previous\\_row".to_string()
3065            }
3066            Add(x, y) => format!("({} + {})", x.latex(cache), y.latex(cache)),
3067            Mul(x, y) => format!("({} \\cdot {})", x.latex(cache), y.latex(cache)),
3068            Sub(x, y) => format!("({} - {})", x.latex(cache), y.latex(cache)),
3069            Pow(x, d) => format!("{}^{{{d}}}", x.latex(cache)),
3070            Square(x) => format!("({})^2", x.latex(cache)),
3071            Cache(id, e) => {
3072                cache.insert(*id, e.as_ref().clone());
3073                id.latex_name()
3074            }
3075            IfFeature(feature, _, _) => format!("{feature:?}"),
3076        }
3077    }
3078
3079    /// Recursively print the expression,
3080    /// except for the cached expression that are stored in the `cache`.
3081    fn text(
3082        &self,
3083        cache: &mut HashMap<CacheId, Expr<ConstantExpr<F, ChallengeTerm>, Column>>,
3084    ) -> String {
3085        use ExprInner::*;
3086        use Operations::*;
3087        match self {
3088            Double(x) => format!("double({})", x.text(cache)),
3089            Atom(Constant(x)) => {
3090                let mut inner_cache = HashMap::new();
3091                let res = x.text(&mut inner_cache);
3092                inner_cache.into_iter().for_each(|(k, v)| {
3093                    let _ = cache.insert(k, Atom(Constant(v)));
3094                });
3095                res
3096            }
3097            Atom(Cell(v)) => v.text(&mut HashMap::new()),
3098            Atom(UnnormalizedLagrangeBasis(RowOffset {
3099                zk_rows: true,
3100                offset: i,
3101            })) => match i.cmp(&0) {
3102                Ordering::Greater => format!("unnormalized_lagrange_basis(zk_rows + {})", *i),
3103                Ordering::Equal => "unnormalized_lagrange_basis(zk_rows)".to_string(),
3104                Ordering::Less => format!("unnormalized_lagrange_basis(zk_rows - {})", (-*i)),
3105            },
3106            Atom(UnnormalizedLagrangeBasis(RowOffset {
3107                zk_rows: false,
3108                offset: i,
3109            })) => {
3110                format!("unnormalized_lagrange_basis({})", *i)
3111            }
3112            Atom(VanishesOnZeroKnowledgeAndPreviousRows) => {
3113                "vanishes_on_zero_knowledge_and_previous_rows".to_string()
3114            }
3115            Add(x, y) => format!("({} + {})", x.text(cache), y.text(cache)),
3116            Mul(x, y) => format!("({} * {})", x.text(cache), y.text(cache)),
3117            Sub(x, y) => format!("({} - {})", x.text(cache), y.text(cache)),
3118            Pow(x, d) => format!("pow({}, {d})", x.text(cache)),
3119            Square(x) => format!("square({})", x.text(cache)),
3120            Cache(id, e) => {
3121                cache.insert(*id, e.as_ref().clone());
3122                id.var_name()
3123            }
3124            IfFeature(feature, _, _) => format!("{feature:?}"),
3125        }
3126    }
3127}
3128
3129impl<'a, F, Column: FormattedOutput + Debug + Clone, ChallengeTerm>
3130    Expr<ConstantExpr<F, ChallengeTerm>, Column>
3131where
3132    F: PrimeField,
3133    ChallengeTerm: AlphaChallengeTerm<'a>,
3134{
3135    /// Converts the expression in LaTeX
3136    // It is only used by visual tooling like kimchi-visu
3137    pub fn latex_str(&self) -> Vec<String> {
3138        let mut env = HashMap::new();
3139        let e = self.latex(&mut env);
3140
3141        let mut env: Vec<_> = env.into_iter().collect();
3142        // HashMap deliberately uses an unstable order; here we sort to ensure
3143        // that the output is consistent when printing.
3144        env.sort_by_key(|(x, _)| *x);
3145
3146        let mut res = vec![];
3147        for (k, v) in env {
3148            let mut rhs = v.latex_str();
3149            let last = rhs.pop().expect("returned an empty expression");
3150            res.push(format!("{} = {last}", k.latex_name()));
3151            res.extend(rhs);
3152        }
3153        res.push(e);
3154        res
3155    }
3156
3157    /// Converts the expression in OCaml code
3158    pub fn ocaml_str(&self) -> String {
3159        let mut env = HashMap::new();
3160        let e = self.ocaml(&mut env);
3161
3162        let mut env: Vec<_> = env.into_iter().collect();
3163        // HashMap deliberately uses an unstable order; here we sort to ensure
3164        // that the output is consistent when printing.
3165        env.sort_by_key(|(x, _)| *x);
3166
3167        let mut res = String::new();
3168        for (k, v) in env {
3169            let rhs = v.ocaml_str();
3170            let cached = format!("let {} = {rhs} in ", k.var_name());
3171            res.push_str(&cached);
3172        }
3173
3174        res.push_str(&e);
3175        res
3176    }
3177}
3178
3179//
3180// Constraints
3181//
3182
3183/// A number of useful constraints
3184pub mod constraints {
3185    use o1_utils::Two;
3186
3187    use crate::circuits::argument::ArgumentData;
3188    use core::fmt;
3189
3190    use super::*;
3191    use crate::circuits::berkeley_columns::{coeff, witness};
3192
3193    /// This trait defines a common arithmetic operations interface
3194    /// that can be used by constraints.  It allows us to reuse
3195    /// constraint code for witness computation.
3196    pub trait ExprOps<F, ChallengeTerm>:
3197        Add<Output = Self>
3198        + Sub<Output = Self>
3199        + Neg<Output = Self>
3200        + Mul<Output = Self>
3201        + AddAssign<Self>
3202        + MulAssign<Self>
3203        + Clone
3204        + Zero
3205        + One
3206        + From<u64>
3207        + fmt::Debug
3208        + fmt::Display
3209    // Add more as necessary
3210    where
3211        Self: core::marker::Sized,
3212    {
3213        /// 2^pow
3214        fn two_pow(pow: u64) -> Self;
3215
3216        /// 2^{LIMB_BITS}
3217        fn two_to_limb() -> Self;
3218
3219        /// 2^{2 * LIMB_BITS}
3220        fn two_to_2limb() -> Self;
3221
3222        /// 2^{3 * LIMB_BITS}
3223        fn two_to_3limb() -> Self;
3224
3225        /// Double the value
3226        fn double(&self) -> Self;
3227
3228        /// Compute the square of this value
3229        fn square(&self) -> Self;
3230
3231        /// Raise the value to the given power
3232        fn pow(&self, p: u64) -> Self;
3233
3234        /// Constrain to boolean
3235        fn boolean(&self) -> Self;
3236
3237        /// Constrain to crumb (i.e. two bits)
3238        fn crumb(&self) -> Self;
3239
3240        /// Create a literal
3241        fn literal(x: F) -> Self;
3242
3243        // Witness variable
3244        fn witness(row: CurrOrNext, col: usize, env: Option<&ArgumentData<F>>) -> Self;
3245
3246        /// Coefficient
3247        fn coeff(col: usize, env: Option<&ArgumentData<F>>) -> Self;
3248
3249        /// Create a constant
3250        fn constant(expr: ConstantExpr<F, ChallengeTerm>, env: Option<&ArgumentData<F>>) -> Self;
3251
3252        /// Cache item
3253        fn cache(&self, cache: &mut Cache) -> Self;
3254    }
3255    // TODO generalize with generic Column/challengeterm
3256    // We need to create a trait for berkeley_columns::Environment
3257    impl<F> ExprOps<F, BerkeleyChallengeTerm>
3258        for Expr<ConstantExpr<F, BerkeleyChallengeTerm>, berkeley_columns::Column>
3259    where
3260        F: PrimeField,
3261        // TODO remove
3262        Expr<ConstantExpr<F, BerkeleyChallengeTerm>, berkeley_columns::Column>: core::fmt::Display,
3263    {
3264        fn two_pow(pow: u64) -> Self {
3265            Expr::<ConstantExpr<F, BerkeleyChallengeTerm>, berkeley_columns::Column>::literal(
3266                <F as Two<F>>::two_pow(pow),
3267            )
3268        }
3269
3270        fn two_to_limb() -> Self {
3271            Expr::<ConstantExpr<F, BerkeleyChallengeTerm>, berkeley_columns::Column>::literal(
3272                KimchiForeignElement::<F>::two_to_limb(),
3273            )
3274        }
3275
3276        fn two_to_2limb() -> Self {
3277            Expr::<ConstantExpr<F, BerkeleyChallengeTerm>, berkeley_columns::Column>::literal(
3278                KimchiForeignElement::<F>::two_to_2limb(),
3279            )
3280        }
3281
3282        fn two_to_3limb() -> Self {
3283            Expr::<ConstantExpr<F, BerkeleyChallengeTerm>, berkeley_columns::Column>::literal(
3284                KimchiForeignElement::<F>::two_to_3limb(),
3285            )
3286        }
3287
3288        fn double(&self) -> Self {
3289            Expr::double(self.clone())
3290        }
3291
3292        fn square(&self) -> Self {
3293            Expr::square(self.clone())
3294        }
3295
3296        fn pow(&self, p: u64) -> Self {
3297            Expr::pow(self.clone(), p)
3298        }
3299
3300        fn boolean(&self) -> Self {
3301            constraints::boolean(self)
3302        }
3303
3304        fn crumb(&self) -> Self {
3305            constraints::crumb(self)
3306        }
3307
3308        fn literal(x: F) -> Self {
3309            ConstantTerm::Literal(x).into()
3310        }
3311
3312        fn witness(row: CurrOrNext, col: usize, _: Option<&ArgumentData<F>>) -> Self {
3313            witness(col, row)
3314        }
3315
3316        fn coeff(col: usize, _: Option<&ArgumentData<F>>) -> Self {
3317            coeff(col)
3318        }
3319
3320        fn constant(
3321            expr: ConstantExpr<F, BerkeleyChallengeTerm>,
3322            _: Option<&ArgumentData<F>>,
3323        ) -> Self {
3324            Expr::from(expr)
3325        }
3326
3327        fn cache(&self, cache: &mut Cache) -> Self {
3328            Expr::Cache(cache.next_id(), Box::new(self.clone()))
3329        }
3330    }
3331    // TODO generalize with generic Column/challengeterm
3332    // We need to generalize argument.rs
3333    impl<F: Field> ExprOps<F, BerkeleyChallengeTerm> for F {
3334        fn two_pow(pow: u64) -> Self {
3335            <F as Two<F>>::two_pow(pow)
3336        }
3337
3338        fn two_to_limb() -> Self {
3339            KimchiForeignElement::<F>::two_to_limb()
3340        }
3341
3342        fn two_to_2limb() -> Self {
3343            KimchiForeignElement::<F>::two_to_2limb()
3344        }
3345
3346        fn two_to_3limb() -> Self {
3347            KimchiForeignElement::<F>::two_to_3limb()
3348        }
3349
3350        fn double(&self) -> Self {
3351            *self * F::from(2u64)
3352        }
3353
3354        fn square(&self) -> Self {
3355            *self * *self
3356        }
3357
3358        fn pow(&self, p: u64) -> Self {
3359            self.pow([p])
3360        }
3361
3362        fn boolean(&self) -> Self {
3363            constraints::boolean(self)
3364        }
3365
3366        fn crumb(&self) -> Self {
3367            constraints::crumb(self)
3368        }
3369
3370        fn literal(x: F) -> Self {
3371            x
3372        }
3373
3374        fn witness(row: CurrOrNext, col: usize, env: Option<&ArgumentData<F>>) -> Self {
3375            match env {
3376                Some(data) => data.witness[(row, col)],
3377                None => panic!("Missing witness"),
3378            }
3379        }
3380
3381        fn coeff(col: usize, env: Option<&ArgumentData<F>>) -> Self {
3382            match env {
3383                Some(data) => data.coeffs[col],
3384                None => panic!("Missing coefficients"),
3385            }
3386        }
3387
3388        fn constant(
3389            expr: ConstantExpr<F, BerkeleyChallengeTerm>,
3390            env: Option<&ArgumentData<F>>,
3391        ) -> Self {
3392            match env {
3393                Some(data) => expr.value(&data.constants, &data.challenges),
3394                None => panic!("Missing constants"),
3395            }
3396        }
3397
3398        fn cache(&self, _: &mut Cache) -> Self {
3399            *self
3400        }
3401    }
3402
3403    /// Creates a constraint to enforce that b is either 0 or 1.
3404    pub fn boolean<F: Field, ChallengeTerm, T: ExprOps<F, ChallengeTerm>>(b: &T) -> T {
3405        b.square() - b.clone()
3406    }
3407
3408    /// Crumb constraint for 2-bit value x
3409    pub fn crumb<F: Field, ChallengeTerm, T: ExprOps<F, ChallengeTerm>>(x: &T) -> T {
3410        // Assert x \in [0,3] i.e. assert x*(x - 1)*(x - 2)*(x - 3) == 0
3411        x.clone()
3412            * (x.clone() - 1u64.into())
3413            * (x.clone() - 2u64.into())
3414            * (x.clone() - 3u64.into())
3415    }
3416
3417    /// lo + mi * 2^{LIMB_BITS}
3418    pub fn compact_limb<F: Field, ChallengeTerm, T: ExprOps<F, ChallengeTerm>>(
3419        lo: &T,
3420        mi: &T,
3421    ) -> T {
3422        lo.clone() + mi.clone() * T::two_to_limb()
3423    }
3424}
3425
3426/// Auto clone macro - Helps make constraints more readable
3427/// by eliminating requirement to .clone() all the time
3428#[macro_export]
3429macro_rules! auto_clone {
3430    ($var:ident, $expr:expr) => {
3431        let $var = $expr;
3432        let $var = || $var.clone();
3433    };
3434    ($var:ident) => {
3435        let $var = || $var.clone();
3436    };
3437}
3438#[macro_export]
3439macro_rules! auto_clone_array {
3440    ($var:ident, $expr:expr) => {
3441        let $var = $expr;
3442        let $var = |i: usize| $var[i].clone();
3443    };
3444    ($var:ident) => {
3445        let $var = |i: usize| $var[i].clone();
3446    };
3447}
3448
3449pub use auto_clone;
3450pub use auto_clone_array;
3451
3452/// You can import this module like `use kimchi::circuits::expr::prologue::*` to obtain a number of handy aliases and helpers
3453pub mod prologue {
3454    pub use super::{
3455        berkeley_columns::{coeff, constant, index, witness, witness_curr, witness_next, E},
3456        FeatureFlag,
3457    };
3458}