1use crate::{
275 columns::ExtendedFoldingColumn,
276 quadraticization::{quadraticize, ExtendedWitnessGenerator, Quadraticized},
277 FoldingConfig, ScalarField,
278};
279use ark_ec::AffineRepr;
280use ark_ff::{One, Zero};
281use core::{
282 fmt,
283 fmt::{Display, Formatter},
284};
285use derivative::Derivative;
286use itertools::Itertools;
287use kimchi::circuits::{
288 berkeley_columns::BerkeleyChallengeTerm,
289 expr::{ConstantExprInner, ConstantTerm, ExprInner, Operations, Variable},
290 gate::CurrOrNext,
291};
292
293#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
297pub enum Degree {
298 Zero,
299 One,
300 Two,
301}
302
303impl core::ops::Add for Degree {
304 type Output = Self;
305
306 fn add(self, rhs: Self) -> Self::Output {
307 use Degree::*;
308 match (self, rhs) {
309 (_, Two) | (Two, _) => Two,
310 (_, One) | (One, _) => One,
311 (Zero, Zero) => Zero,
312 }
313 }
314}
315
316impl core::ops::Mul for &Degree {
317 type Output = Degree;
318
319 fn mul(self, rhs: Self) -> Self::Output {
320 use Degree::*;
321 match (self, rhs) {
322 (Zero, other) | (other, Zero) => *other,
323 (One, One) => Two,
324 _ => panic!("The folding library does support only expressions of degree `2` maximum"),
325 }
326 }
327}
328
329pub trait FoldingColumnTrait: Copy + Clone {
330 fn is_witness(&self) -> bool;
331
332 fn degree(&self) -> Degree {
337 match self.is_witness() {
338 true => Degree::One,
339 false => Degree::Zero,
340 }
341 }
342}
343
344#[derive(Derivative)]
346#[derivative(
347 Clone(bound = "C: FoldingConfig"),
348 Debug(bound = "C: FoldingConfig"),
349 PartialEq(bound = "C: FoldingConfig")
350)]
351pub enum ExpExtension<C: FoldingConfig> {
352 U,
354 Error,
356 ExtendedWitness(usize),
358 Alpha(usize),
360 Selector(C::Selector),
362}
363
364#[derive(Derivative)]
367#[derivative(
368 Clone(bound = "C: FoldingConfig"),
369 PartialEq(bound = "C: FoldingConfig"),
370 Debug(bound = "C: FoldingConfig")
371)]
372pub enum FoldingCompatibleExprInner<C: FoldingConfig> {
373 Constant(<C::Curve as AffineRepr>::ScalarField),
374 Challenge(C::Challenge),
375 Cell(Variable<C::Column>),
376 Extensions(ExpExtension<C>),
378}
379
380#[derive(Derivative)]
386#[derivative(
387 Clone(bound = "C: FoldingConfig"),
388 PartialEq(bound = "C: FoldingConfig"),
389 Debug(bound = "C: FoldingConfig")
390)]
391pub enum FoldingCompatibleExpr<C: FoldingConfig> {
392 Atom(FoldingCompatibleExprInner<C>),
393 Pow(Box<Self>, u64),
394 Add(Box<Self>, Box<Self>),
395 Sub(Box<Self>, Box<Self>),
396 Mul(Box<Self>, Box<Self>),
397 Double(Box<Self>),
398 Square(Box<Self>),
399}
400
401impl<C: FoldingConfig> core::ops::Add for FoldingCompatibleExpr<C> {
402 type Output = Self;
403
404 fn add(self, rhs: Self) -> Self {
405 Self::Add(Box::new(self), Box::new(rhs))
406 }
407}
408
409impl<C: FoldingConfig> core::ops::Sub for FoldingCompatibleExpr<C> {
410 type Output = Self;
411
412 fn sub(self, rhs: Self) -> Self {
413 Self::Sub(Box::new(self), Box::new(rhs))
414 }
415}
416
417impl<C: FoldingConfig> core::ops::Mul for FoldingCompatibleExpr<C> {
418 type Output = Self;
419
420 fn mul(self, rhs: Self) -> Self {
421 Self::Mul(Box::new(self), Box::new(rhs))
422 }
423}
424
425impl<C: FoldingConfig> Display for FoldingCompatibleExpr<C> {
427 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
428 match self {
429 FoldingCompatibleExpr::Atom(c) => match c {
430 FoldingCompatibleExprInner::Constant(c) => {
431 if c.is_zero() {
432 write!(f, "0")
433 } else {
434 write!(f, "{}", c)
435 }
436 }
437 FoldingCompatibleExprInner::Challenge(c) => {
438 write!(f, "{:?}", c)
439 }
440 FoldingCompatibleExprInner::Cell(cell) => {
441 let Variable { col, row } = cell;
442 let next = match row {
443 CurrOrNext::Curr => "",
444 CurrOrNext::Next => " * ω",
445 };
446 write!(f, "Col({:?}){}", col, next)
447 }
448 FoldingCompatibleExprInner::Extensions(e) => match e {
449 ExpExtension::U => write!(f, "U"),
450 ExpExtension::Error => write!(f, "E"),
451 ExpExtension::ExtendedWitness(i) => {
452 write!(f, "ExWit({})", i)
453 }
454 ExpExtension::Alpha(i) => write!(f, "α_{i}"),
455 ExpExtension::Selector(s) => write!(f, "Selec({:?})", s),
456 },
457 },
458 FoldingCompatibleExpr::Double(e) => {
459 write!(f, "2 {}", e)
460 }
461 FoldingCompatibleExpr::Square(e) => {
462 write!(f, "{} ^ 2", e)
463 }
464 FoldingCompatibleExpr::Add(e1, e2) => {
465 write!(f, "{} + {}", e1, e2)
466 }
467 FoldingCompatibleExpr::Sub(e1, e2) => {
468 write!(f, "{} - {}", e1, e2)
469 }
470 FoldingCompatibleExpr::Mul(e1, e2) => {
471 write!(f, "({}) ({})", e1, e2)
472 }
473 FoldingCompatibleExpr::Pow(_, _) => todo!(),
474 }
475 }
476}
477
478#[derive(Derivative)]
488#[derivative(
489 Hash(bound = "C:FoldingConfig"),
490 Debug(bound = "C:FoldingConfig"),
491 Clone(bound = "C:FoldingConfig"),
492 PartialEq(bound = "C:FoldingConfig"),
493 Eq(bound = "C:FoldingConfig")
494)]
495pub enum FoldingExp<C: FoldingConfig> {
496 Atom(ExtendedFoldingColumn<C>),
497 Pow(Box<Self>, u64),
498 Add(Box<Self>, Box<Self>),
499 Mul(Box<Self>, Box<Self>),
500 Sub(Box<Self>, Box<Self>),
501 Double(Box<Self>),
502 Square(Box<Self>),
503}
504
505impl<C: FoldingConfig> core::ops::Add for FoldingExp<C> {
506 type Output = Self;
507
508 fn add(self, rhs: Self) -> Self {
509 Self::Add(Box::new(self), Box::new(rhs))
510 }
511}
512
513impl<C: FoldingConfig> core::ops::Sub for FoldingExp<C> {
514 type Output = Self;
515
516 fn sub(self, rhs: Self) -> Self {
517 Self::Sub(Box::new(self), Box::new(rhs))
518 }
519}
520
521impl<C: FoldingConfig> core::ops::Mul for FoldingExp<C> {
522 type Output = Self;
523
524 fn mul(self, rhs: Self) -> Self {
525 Self::Mul(Box::new(self), Box::new(rhs))
526 }
527}
528
529impl<C: FoldingConfig> FoldingExp<C> {
530 pub fn double(self) -> Self {
531 Self::Double(Box::new(self))
532 }
533}
534
535impl<C: FoldingConfig> FoldingCompatibleExpr<C> {
541 pub fn simplify(self) -> FoldingExp<C> {
542 use FoldingExp::*;
543 match self {
544 FoldingCompatibleExpr::Atom(atom) => match atom {
545 FoldingCompatibleExprInner::Constant(c) => Atom(ExtendedFoldingColumn::Constant(c)),
546 FoldingCompatibleExprInner::Challenge(c) => {
547 Atom(ExtendedFoldingColumn::Challenge(c))
548 }
549 FoldingCompatibleExprInner::Cell(col) => Atom(ExtendedFoldingColumn::Inner(col)),
550 FoldingCompatibleExprInner::Extensions(ext) => {
551 match ext {
552 ExpExtension::Selector(s) => Atom(ExtendedFoldingColumn::Selector(s)),
556 _ => {
557 panic!("this should only be created by folding itself")
558 }
559 }
560 }
561 },
562 FoldingCompatibleExpr::Double(exp) => Double(Box::new((*exp).simplify())),
563 FoldingCompatibleExpr::Square(exp) => Square(Box::new((*exp).simplify())),
564 FoldingCompatibleExpr::Add(e1, e2) => {
565 let e1 = Box::new(e1.simplify());
566 let e2 = Box::new(e2.simplify());
567 Add(e1, e2)
568 }
569 FoldingCompatibleExpr::Sub(e1, e2) => {
570 let e1 = Box::new(e1.simplify());
571 let e2 = Box::new(e2.simplify());
572 Sub(e1, e2)
573 }
574 FoldingCompatibleExpr::Mul(e1, e2) => {
575 let e1 = Box::new(e1.simplify());
576 let e2 = Box::new(e2.simplify());
577 Mul(e1, e2)
578 }
579 FoldingCompatibleExpr::Pow(e, p) => Self::pow_to_mul(e.simplify(), p),
580 }
581 }
582
583 fn pow_to_mul(exp: FoldingExp<C>, p: u64) -> FoldingExp<C>
584 where
585 C::Column: Clone,
586 C::Challenge: Clone,
587 {
588 use FoldingExp::*;
589 let e = Box::new(exp);
590 let e_2 = Box::new(Square(e.clone()));
591 match p {
592 2 => *e_2,
593 3 => Mul(e, e_2),
594 4..=8 => {
595 let e_4 = Box::new(Square(e_2.clone()));
596 match p {
597 4 => *e_4,
598 5 => Mul(e, e_4),
599 6 => Mul(e_2, e_4),
600 7 => Mul(e, Box::new(Mul(e_2, e_4))),
601 8 => Square(e_4),
602 _ => unreachable!(),
603 }
604 }
605 _ => panic!("unsupported"),
606 }
607 }
608
609 pub fn map_variable(
613 self,
614 mapper: &(dyn Fn(Variable<C::Column>) -> Variable<C::Column>),
615 ) -> FoldingCompatibleExpr<C> {
616 use FoldingCompatibleExpr::*;
617 match self {
618 FoldingCompatibleExpr::Atom(atom) => match atom {
619 FoldingCompatibleExprInner::Cell(col) => {
620 Atom(FoldingCompatibleExprInner::Cell((mapper)(col)))
621 }
622 atom => Atom(atom),
623 },
624 FoldingCompatibleExpr::Double(exp) => Double(Box::new(exp.map_variable(mapper))),
625 FoldingCompatibleExpr::Square(exp) => Square(Box::new(exp.map_variable(mapper))),
626 FoldingCompatibleExpr::Add(e1, e2) => {
627 let e1 = Box::new(e1.map_variable(mapper));
628 let e2 = Box::new(e2.map_variable(mapper));
629 Add(e1, e2)
630 }
631 FoldingCompatibleExpr::Sub(e1, e2) => {
632 let e1 = Box::new(e1.map_variable(mapper));
633 let e2 = Box::new(e2.map_variable(mapper));
634 Sub(e1, e2)
635 }
636 FoldingCompatibleExpr::Mul(e1, e2) => {
637 let e1 = Box::new(e1.map_variable(mapper));
638 let e2 = Box::new(e2.map_variable(mapper));
639 Mul(e1, e2)
640 }
641 FoldingCompatibleExpr::Pow(e, p) => Pow(Box::new(e.map_variable(mapper)), p),
642 }
643 }
644
645 pub fn flatten_quad_columns(
647 self,
648 mapper: &(dyn Fn(usize) -> Variable<C::Column>),
649 ) -> FoldingCompatibleExpr<C> {
650 use FoldingCompatibleExpr::*;
651 match self {
652 FoldingCompatibleExpr::Atom(atom) => match atom {
653 FoldingCompatibleExprInner::Extensions(ExpExtension::ExtendedWitness(i)) => {
654 Atom(FoldingCompatibleExprInner::Cell((mapper)(i)))
655 }
656 atom => Atom(atom),
657 },
658 FoldingCompatibleExpr::Double(exp) => {
659 Double(Box::new(exp.flatten_quad_columns(mapper)))
660 }
661 FoldingCompatibleExpr::Square(exp) => {
662 Square(Box::new(exp.flatten_quad_columns(mapper)))
663 }
664 FoldingCompatibleExpr::Add(e1, e2) => {
665 let e1 = Box::new(e1.flatten_quad_columns(mapper));
666 let e2 = Box::new(e2.flatten_quad_columns(mapper));
667 Add(e1, e2)
668 }
669 FoldingCompatibleExpr::Sub(e1, e2) => {
670 let e1 = Box::new(e1.flatten_quad_columns(mapper));
671 let e2 = Box::new(e2.flatten_quad_columns(mapper));
672 Sub(e1, e2)
673 }
674 FoldingCompatibleExpr::Mul(e1, e2) => {
675 let e1 = Box::new(e1.flatten_quad_columns(mapper));
676 let e2 = Box::new(e2.flatten_quad_columns(mapper));
677 Mul(e1, e2)
678 }
679 FoldingCompatibleExpr::Pow(e, p) => Pow(Box::new(e.flatten_quad_columns(mapper)), p),
680 }
681 }
682}
683
684impl<C: FoldingConfig> FoldingExp<C> {
685 pub(super) fn folding_degree(&self) -> Degree {
690 use Degree::*;
691 match self {
692 FoldingExp::Atom(ex_col) => match ex_col {
693 ExtendedFoldingColumn::Inner(col) => col.col.degree(),
694 ExtendedFoldingColumn::WitnessExtended(_) => One,
695 ExtendedFoldingColumn::Error => One,
696 ExtendedFoldingColumn::Constant(_) => Zero,
697 ExtendedFoldingColumn::Challenge(_) => One,
698 ExtendedFoldingColumn::Alpha(_) => One,
699 ExtendedFoldingColumn::Selector(_) => One,
700 },
701 FoldingExp::Double(e) => e.folding_degree(),
702 FoldingExp::Square(e) => &e.folding_degree() * &e.folding_degree(),
703 FoldingExp::Mul(e1, e2) => &e1.folding_degree() * &e2.folding_degree(),
704 FoldingExp::Add(e1, e2) | FoldingExp::Sub(e1, e2) => {
705 e1.folding_degree() + e2.folding_degree()
706 }
707 FoldingExp::Pow(_, 0) => Zero,
708 FoldingExp::Pow(e, 1) => e.folding_degree(),
709 FoldingExp::Pow(e, i) => {
710 let degree = e.folding_degree();
711 let mut acc = degree;
712 for _ in 1..*i {
713 acc = &acc * °ree;
714 }
715 acc
716 }
717 }
718 }
719
720 fn into_compatible(self) -> FoldingCompatibleExpr<C> {
722 use FoldingCompatibleExpr::*;
723 use FoldingCompatibleExprInner::*;
724 match self {
725 FoldingExp::Atom(c) => match c {
726 ExtendedFoldingColumn::Inner(col) => Atom(Cell(col)),
727 ExtendedFoldingColumn::WitnessExtended(i) => {
728 Atom(Extensions(ExpExtension::ExtendedWitness(i)))
729 }
730 ExtendedFoldingColumn::Error => Atom(Extensions(ExpExtension::Error)),
731 ExtendedFoldingColumn::Constant(c) => Atom(Constant(c)),
732 ExtendedFoldingColumn::Challenge(c) => Atom(Challenge(c)),
733 ExtendedFoldingColumn::Alpha(i) => Atom(Extensions(ExpExtension::Alpha(i))),
734 ExtendedFoldingColumn::Selector(s) => Atom(Extensions(ExpExtension::Selector(s))),
735 },
736 FoldingExp::Double(exp) => Double(Box::new(exp.into_compatible())),
737 FoldingExp::Square(exp) => Square(Box::new(exp.into_compatible())),
738 FoldingExp::Add(e1, e2) => {
739 let e1 = Box::new(e1.into_compatible());
740 let e2 = Box::new(e2.into_compatible());
741 Add(e1, e2)
742 }
743 FoldingExp::Sub(e1, e2) => {
744 let e1 = Box::new(e1.into_compatible());
745 let e2 = Box::new(e2.into_compatible());
746 Sub(e1, e2)
747 }
748 FoldingExp::Mul(e1, e2) => {
749 let e1 = Box::new(e1.into_compatible());
750 let e2 = Box::new(e2.into_compatible());
751 Mul(e1, e2)
752 }
753 FoldingExp::Pow(_, 0) => Atom(Constant(<C::Curve as AffineRepr>::ScalarField::one())),
755 FoldingExp::Pow(e, 1) => e.into_compatible(),
756 FoldingExp::Pow(e, i) => {
757 let e = e.into_compatible();
758 let mut acc = e.clone();
759 for _ in 1..i {
760 acc = Mul(Box::new(e.clone()), Box::new(acc))
761 }
762 acc
763 }
764 }
765 }
766}
767
768#[derive(Copy, Clone, Debug, PartialEq, Eq)]
771pub enum Sign {
772 Pos,
773 Neg,
774}
775
776impl core::ops::Neg for Sign {
777 type Output = Self;
778
779 fn neg(self) -> Self {
780 match self {
781 Sign::Pos => Sign::Neg,
782 Sign::Neg => Sign::Pos,
783 }
784 }
785}
786
787#[derive(Derivative)]
794#[derivative(Debug, Clone(bound = "C: FoldingConfig"))]
795pub struct Term<C: FoldingConfig> {
796 pub exp: FoldingExp<C>,
797 pub sign: Sign,
798}
799
800impl<C: FoldingConfig> Term<C> {
801 fn double(self) -> Self {
802 let Self { exp, sign } = self;
803 let exp = FoldingExp::Double(Box::new(exp));
804 Self { exp, sign }
805 }
806}
807
808impl<C: FoldingConfig> core::ops::Mul for &Term<C> {
809 type Output = Term<C>;
810
811 fn mul(self, rhs: Self) -> Self::Output {
812 let sign = if self.sign == rhs.sign {
813 Sign::Pos
814 } else {
815 Sign::Neg
816 };
817 let exp = FoldingExp::Mul(Box::new(self.exp.clone()), Box::new(rhs.exp.clone()));
818 Term { exp, sign }
819 }
820}
821
822impl<C: FoldingConfig> core::ops::Neg for Term<C> {
823 type Output = Self;
824
825 fn neg(self) -> Self::Output {
826 Term {
827 sign: -self.sign,
828 ..self
829 }
830 }
831}
832
833#[derive(Derivative)]
838#[derivative(
839 Debug(bound = "C: FoldingConfig"),
840 Clone(bound = "C: FoldingConfig"),
841 Default(bound = "C: FoldingConfig")
842)]
843pub struct IntegratedFoldingExpr<C: FoldingConfig> {
844 pub(super) degree_0: Vec<(FoldingExp<C>, Sign, usize)>,
846 pub(super) degree_1: Vec<(FoldingExp<C>, Sign, usize)>,
847 pub(super) degree_2: Vec<(FoldingExp<C>, Sign, usize)>,
848}
849
850impl<C: FoldingConfig> IntegratedFoldingExpr<C> {
851 pub fn final_expression(self) -> FoldingCompatibleExpr<C> {
853 use FoldingCompatibleExpr::*;
854 use FoldingCompatibleExprInner::*;
856 let Self {
857 degree_0,
858 degree_1,
859 degree_2,
860 } = self;
861 let [d0, d1, d2] = [degree_0, degree_1, degree_2]
862 .map(|exps| {
863 let init =
864 FoldingExp::Atom(ExtendedFoldingColumn::Constant(ScalarField::<C>::zero()));
865 exps.into_iter().fold(init, |acc, (exp, sign, alpha)| {
866 let exp = FoldingExp::Mul(
867 Box::new(exp),
868 Box::new(FoldingExp::Atom(ExtendedFoldingColumn::Alpha(alpha))),
869 );
870 match sign {
871 Sign::Pos => FoldingExp::Add(Box::new(acc), Box::new(exp)),
872 Sign::Neg => FoldingExp::Sub(Box::new(acc), Box::new(exp)),
873 }
874 })
875 })
876 .map(|e| e.into_compatible());
877 let u = || Box::new(Atom(Extensions(ExpExtension::U)));
878 let u2 = || Box::new(Square(u()));
879 let d0 = FoldingCompatibleExpr::Mul(Box::new(d0), u2());
880 let d1 = FoldingCompatibleExpr::Mul(Box::new(d1), u());
881 let d2 = Box::new(d2);
882 let exp = FoldingCompatibleExpr::Add(Box::new(d0), Box::new(d1));
883 let exp = FoldingCompatibleExpr::Add(Box::new(exp), d2);
884 FoldingCompatibleExpr::Add(
885 Box::new(exp),
886 Box::new(Atom(Extensions(ExpExtension::Error))),
887 )
888 }
889}
890
891pub fn extract_terms<C: FoldingConfig>(exp: FoldingExp<C>) -> Box<dyn Iterator<Item = Term<C>>> {
892 use FoldingExp::*;
893 let exps: Box<dyn Iterator<Item = Term<C>>> = match exp {
894 exp @ Atom(_) => Box::new(
895 [Term {
896 exp,
897 sign: Sign::Pos,
898 }]
899 .into_iter(),
900 ),
901 Double(exp) => Box::new(extract_terms(*exp).map(Term::double)),
902 Square(exp) => {
903 let terms = extract_terms(*exp).collect_vec();
904 let mut combinations = Vec::with_capacity(terms.len() ^ 2);
905 for t1 in terms.iter() {
906 for t2 in terms.iter() {
907 combinations.push(t1 * t2)
908 }
909 }
910 Box::new(combinations.into_iter())
911 }
912 Add(e1, e2) => {
913 let e1 = extract_terms(*e1);
914 let e2 = extract_terms(*e2);
915 Box::new(e1.chain(e2))
916 }
917 Sub(e1, e2) => {
918 let e1 = extract_terms(*e1);
919 let e2 = extract_terms(*e2).map(|t| -t);
920 Box::new(e1.chain(e2))
921 }
922 Mul(e1, e2) => {
923 let e1 = extract_terms(*e1).collect_vec();
924 let e2 = extract_terms(*e2).collect_vec();
925 let mut combinations = Vec::with_capacity(e1.len() * e2.len());
926 for t1 in e1.iter() {
927 for t2 in e2.iter() {
928 combinations.push(t1 * t2)
929 }
930 }
931 Box::new(combinations.into_iter())
932 }
933 Pow(_, 0) => Box::new(
934 [Term {
935 exp: FoldingExp::Atom(ExtendedFoldingColumn::Constant(
936 <C::Curve as AffineRepr>::ScalarField::one(),
937 )),
938 sign: Sign::Pos,
939 }]
940 .into_iter(),
941 ),
942 Pow(e, 1) => extract_terms(*e),
943 Pow(e, mut i) => {
944 let e = extract_terms(*e).collect_vec();
945 let mut acc = e.clone();
946 while i > 2 {
948 let mut combinations = Vec::with_capacity(e.len() * acc.len());
949 for t1 in e.iter() {
950 for t2 in acc.iter() {
951 combinations.push(t1 * t2)
952 }
953 }
954 acc = combinations;
955 i -= 1;
956 }
957 Box::new(acc.into_iter())
958 }
959 };
960 exps
961}
962
963pub fn folding_expression<C: FoldingConfig>(
965 exps: Vec<FoldingCompatibleExpr<C>>,
966) -> (IntegratedFoldingExpr<C>, ExtendedWitnessGenerator<C>, usize) {
967 let simplified_expressions = exps.into_iter().map(|exp| exp.simplify()).collect_vec();
968 let (
969 Quadraticized {
970 original_constraints: expressions,
971 extra_constraints: extra_expressions,
972 extended_witness_generator,
973 },
974 added_columns,
975 ) = quadraticize(simplified_expressions);
976 let mut terms = vec![];
977 let mut alpha = 0;
978 for exp in expressions.into_iter() {
984 terms.extend(extract_terms(exp).map(|term| (term, alpha)));
985 alpha += 1;
986 }
987 for exp in extra_expressions.into_iter() {
988 terms.extend(extract_terms(exp).map(|term| (term, alpha)));
989 alpha += 1;
990 }
991 let mut integrated = IntegratedFoldingExpr::default();
992 for (term, alpha) in terms.into_iter() {
993 let Term { exp, sign } = term;
994 let degree = exp.folding_degree();
995 let t = (exp, sign, alpha);
996 match degree {
997 Degree::Zero => integrated.degree_0.push(t),
998 Degree::One => integrated.degree_1.push(t),
999 Degree::Two => integrated.degree_2.push(t),
1000 }
1001 }
1002 (integrated, extended_witness_generator, added_columns)
1003}
1004
1005impl<F, Config: FoldingConfig> From<ConstantExprInner<F, BerkeleyChallengeTerm>>
1008 for FoldingCompatibleExprInner<Config>
1009where
1010 Config::Curve: AffineRepr<ScalarField = F>,
1011 Config::Challenge: From<BerkeleyChallengeTerm>,
1012{
1013 fn from(expr: ConstantExprInner<F, BerkeleyChallengeTerm>) -> Self {
1014 match expr {
1015 ConstantExprInner::Challenge(chal) => {
1016 FoldingCompatibleExprInner::Challenge(chal.into())
1017 }
1018 ConstantExprInner::Constant(c) => match c {
1019 ConstantTerm::Literal(f) => FoldingCompatibleExprInner::Constant(f),
1020 ConstantTerm::EndoCoefficient | ConstantTerm::Mds { row: _, col: _ } => {
1021 panic!("When special constants are involved, don't forget to simplify the expression before.")
1022 }
1023 },
1024 }
1025 }
1026}
1027
1028impl<F, Col, Config: FoldingConfig<Column = Col>>
1029 From<ExprInner<ConstantExprInner<F, BerkeleyChallengeTerm>, Col>>
1030 for FoldingCompatibleExprInner<Config>
1031where
1032 Config::Curve: AffineRepr<ScalarField = F>,
1033 Config::Challenge: From<BerkeleyChallengeTerm>,
1034{
1035 fn from(expr: ExprInner<ConstantExprInner<F, BerkeleyChallengeTerm>, Col>) -> Self {
1037 match expr {
1038 ExprInner::Constant(cexpr) => cexpr.into(),
1039 ExprInner::Cell(col) => FoldingCompatibleExprInner::Cell(col),
1040 ExprInner::UnnormalizedLagrangeBasis(_) => {
1041 panic!("UnnormalizedLagrangeBasis should not be used in folding expressions")
1042 }
1043 ExprInner::VanishesOnZeroKnowledgeAndPreviousRows => {
1044 panic!("VanishesOnZeroKnowledgeAndPreviousRows should not be used in folding expressions")
1045 }
1046 }
1047 }
1048}
1049
1050impl<F, Col, Config: FoldingConfig<Column = Col>>
1051 From<Operations<ExprInner<ConstantExprInner<F, BerkeleyChallengeTerm>, Col>>>
1052 for FoldingCompatibleExpr<Config>
1053where
1054 Config::Curve: AffineRepr<ScalarField = F>,
1055 Config::Challenge: From<BerkeleyChallengeTerm>,
1056{
1057 fn from(expr: Operations<ExprInner<ConstantExprInner<F, BerkeleyChallengeTerm>, Col>>) -> Self {
1058 match expr {
1059 Operations::Atom(inner) => FoldingCompatibleExpr::Atom(inner.into()),
1060 Operations::Add(x, y) => {
1061 FoldingCompatibleExpr::Add(Box::new((*x).into()), Box::new((*y).into()))
1062 }
1063 Operations::Mul(x, y) => {
1064 FoldingCompatibleExpr::Mul(Box::new((*x).into()), Box::new((*y).into()))
1065 }
1066 Operations::Sub(x, y) => {
1067 FoldingCompatibleExpr::Sub(Box::new((*x).into()), Box::new((*y).into()))
1068 }
1069 Operations::Double(x) => FoldingCompatibleExpr::Double(Box::new((*x).into())),
1070 Operations::Square(x) => FoldingCompatibleExpr::Square(Box::new((*x).into())),
1071 Operations::Pow(e, p) => FoldingCompatibleExpr::Pow(Box::new((*e).into()), p),
1072 _ => panic!("Operation not supported in folding expressions"),
1073 }
1074 }
1075}
1076
1077impl<F, Col, Config: FoldingConfig<Column = Col>>
1078 From<Operations<ConstantExprInner<F, BerkeleyChallengeTerm>>> for FoldingCompatibleExpr<Config>
1079where
1080 Config::Curve: AffineRepr<ScalarField = F>,
1081 Config::Challenge: From<BerkeleyChallengeTerm>,
1082{
1083 fn from(expr: Operations<ConstantExprInner<F, BerkeleyChallengeTerm>>) -> Self {
1084 match expr {
1085 Operations::Add(x, y) => {
1086 FoldingCompatibleExpr::Add(Box::new((*x).into()), Box::new((*y).into()))
1087 }
1088 Operations::Mul(x, y) => {
1089 FoldingCompatibleExpr::Mul(Box::new((*x).into()), Box::new((*y).into()))
1090 }
1091 Operations::Sub(x, y) => {
1092 FoldingCompatibleExpr::Sub(Box::new((*x).into()), Box::new((*y).into()))
1093 }
1094 Operations::Double(x) => FoldingCompatibleExpr::Double(Box::new((*x).into())),
1095 Operations::Square(x) => FoldingCompatibleExpr::Square(Box::new((*x).into())),
1096 Operations::Pow(e, p) => FoldingCompatibleExpr::Pow(Box::new((*e).into()), p),
1097 _ => panic!("Operation not supported in folding expressions"),
1098 }
1099 }
1100}
1101
1102impl<F, Col, Config: FoldingConfig<Column = Col>>
1103 From<Operations<ExprInner<Operations<ConstantExprInner<F, BerkeleyChallengeTerm>>, Col>>>
1104 for FoldingCompatibleExpr<Config>
1105where
1106 Config::Curve: AffineRepr<ScalarField = F>,
1107 Config::Challenge: From<BerkeleyChallengeTerm>,
1108{
1109 fn from(
1110 expr: Operations<ExprInner<Operations<ConstantExprInner<F, BerkeleyChallengeTerm>>, Col>>,
1111 ) -> Self {
1112 match expr {
1113 Operations::Atom(inner) => match inner {
1114 ExprInner::Constant(op) => match op {
1115 Operations::Atom(inner) => FoldingCompatibleExpr::Atom(inner.into()),
1118 Operations::Add(x, y) => {
1119 FoldingCompatibleExpr::Add(Box::new((*x).into()), Box::new((*y).into()))
1120 }
1121 Operations::Mul(x, y) => {
1122 FoldingCompatibleExpr::Mul(Box::new((*x).into()), Box::new((*y).into()))
1123 }
1124 Operations::Sub(x, y) => {
1125 FoldingCompatibleExpr::Sub(Box::new((*x).into()), Box::new((*y).into()))
1126 }
1127 Operations::Double(x) => FoldingCompatibleExpr::Double(Box::new((*x).into())),
1128 Operations::Square(x) => FoldingCompatibleExpr::Square(Box::new((*x).into())),
1129 Operations::Pow(e, p) => FoldingCompatibleExpr::Pow(Box::new((*e).into()), p),
1130 _ => panic!("Operation not supported in folding expressions"),
1131 },
1132 ExprInner::Cell(col) => {
1133 FoldingCompatibleExpr::Atom(FoldingCompatibleExprInner::Cell(col))
1134 }
1135 ExprInner::UnnormalizedLagrangeBasis(_) => {
1136 panic!("UnnormalizedLagrangeBasis should not be used in folding expressions")
1137 }
1138 ExprInner::VanishesOnZeroKnowledgeAndPreviousRows => {
1139 panic!("VanishesOnZeroKnowledgeAndPreviousRows should not be used in folding expressions")
1140 }
1141 },
1142 Operations::Add(x, y) => {
1143 FoldingCompatibleExpr::Add(Box::new((*x).into()), Box::new((*y).into()))
1144 }
1145 Operations::Mul(x, y) => {
1146 FoldingCompatibleExpr::Mul(Box::new((*x).into()), Box::new((*y).into()))
1147 }
1148 Operations::Sub(x, y) => {
1149 FoldingCompatibleExpr::Sub(Box::new((*x).into()), Box::new((*y).into()))
1150 }
1151 Operations::Double(x) => FoldingCompatibleExpr::Double(Box::new((*x).into())),
1152 Operations::Square(x) => FoldingCompatibleExpr::Square(Box::new((*x).into())),
1153 Operations::Pow(e, p) => FoldingCompatibleExpr::Pow(Box::new((*e).into()), p),
1154 _ => panic!("Operation not supported in folding expressions"),
1155 }
1156 }
1157}