1use ark_ec::CurveConfig;
2use ark_ff::PrimeField;
3use ark_poly::Evaluations;
4use kimchi::circuits::{domains::EvaluationDomains, gate::CurrOrNext};
5use log::debug;
6use mina_poseidon::constants::SpongeConstants;
7use num_bigint::{BigInt, BigUint};
8use num_integer::Integer;
9use o1_utils::field_helpers::FieldHelpers;
10use poly_commitment::{commitment::CommitmentCurve, ipa::SRS, PolyComm, SRS as _};
11use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
12
13use crate::{
14 challenge::{ChallengeTerm, Challenges},
15 column::Column,
16 curve::{ArrabbiataCurve, PlonkSpongeConstants},
17 interpreter::{Instruction, InterpreterEnv, Side, VERIFIER_STARTING_INSTRUCTION},
18 setup, NUMBER_OF_COLUMNS, NUMBER_OF_VALUES_TO_ABSORB_PUBLIC_IO,
19};
20
21pub struct Program<
23 Fp: PrimeField,
24 Fq: PrimeField,
25 E: ArrabbiataCurve<ScalarField = Fp, BaseField = Fq>,
26> where
27 E::BaseField: PrimeField,
28 <<E as CommitmentCurve>::Params as CurveConfig>::BaseField: PrimeField,
29{
30 pub accumulated_committed_state: Vec<PolyComm<E>>,
34
35 pub previous_committed_state: Vec<PolyComm<E>>,
39
40 pub accumulated_program_state: Vec<Vec<E::ScalarField>>,
49
50 pub accumulated_challenges: Challenges<BigInt>,
52
53 pub previous_challenges: Challenges<BigInt>,
57}
58
59impl<Fp: PrimeField, Fq: PrimeField, E: ArrabbiataCurve<ScalarField = Fp, BaseField = Fq>>
60 Program<Fp, Fq, E>
61where
62 E::BaseField: PrimeField,
63 <<E as CommitmentCurve>::Params as CurveConfig>::BaseField: PrimeField,
64{
65 pub fn new(srs_size: usize, blinder: E) -> Self {
66 let previous_committed_state: Vec<PolyComm<E>> = (0..NUMBER_OF_COLUMNS)
68 .map(|_| PolyComm::new(vec![(blinder + blinder).into()]))
69 .collect();
70
71 let accumulated_committed_state: Vec<PolyComm<E>> = (0..NUMBER_OF_COLUMNS)
73 .map(|_| PolyComm::new(vec![blinder]))
74 .collect();
75
76 let mut accumulated_program_state: Vec<Vec<E::ScalarField>> =
77 Vec::with_capacity(NUMBER_OF_COLUMNS);
78 {
79 let mut vec: Vec<E::ScalarField> = Vec::with_capacity(srs_size);
80 (0..srs_size).for_each(|_| vec.push(E::ScalarField::zero()));
81 (0..NUMBER_OF_COLUMNS).for_each(|_| accumulated_program_state.push(vec.clone()));
82 };
83
84 let accumulated_challenges: Challenges<BigInt> = Challenges::default();
85
86 let previous_challenges: Challenges<BigInt> = Challenges::default();
87
88 Self {
89 accumulated_committed_state,
90 previous_committed_state,
91 accumulated_program_state,
92 accumulated_challenges,
93 previous_challenges,
94 }
95 }
96
97 pub fn commit_state(
103 &mut self,
104 srs: &SRS<E>,
105 domain: EvaluationDomains<E::ScalarField>,
106 witness: &[Vec<BigInt>],
107 ) {
108 let comms: Vec<PolyComm<E>> = witness
109 .par_iter()
110 .map(|evals| {
111 let evals: Vec<E::ScalarField> = evals
112 .par_iter()
113 .map(|x| E::ScalarField::from_biguint(&x.to_biguint().unwrap()).unwrap())
114 .collect();
115 let evals = Evaluations::from_vec_and_domain(evals, domain.d1);
116 srs.commit_evaluations_non_hiding(domain.d1, &evals)
117 })
118 .collect();
119 self.previous_committed_state = comms
120 }
121
122 pub fn absorb_state(&mut self, digest: BigInt) -> Vec<BigInt> {
128 let mut sponge = E::create_new_sponge();
129 let previous_state: E::BaseField =
130 E::BaseField::from_biguint(&digest.to_biguint().unwrap()).unwrap();
131 E::absorb_fq(&mut sponge, previous_state);
132 self.previous_committed_state
133 .iter()
134 .for_each(|comm| E::absorb_curve_points(&mut sponge, &comm.chunks));
135 let state: Vec<BigInt> = sponge
136 .sponge
137 .state
138 .iter()
139 .map(|x| x.to_biguint().into())
140 .collect();
141 state
142 }
143
144 pub fn coin_challenge(&self, sponge_state: Vec<BigInt>) -> (BigInt, Vec<BigInt>) {
166 let mut sponge = E::create_new_sponge();
167 sponge_state.iter().for_each(|x| {
168 E::absorb_fq(
169 &mut sponge,
170 E::BaseField::from_biguint(&x.to_biguint().unwrap()).unwrap(),
171 )
172 });
173 let verifier_answer = E::squeeze_challenge(&mut sponge).to_biguint().into();
174 sponge.sponge.poseidon_block_cipher();
175 let state: Vec<BigInt> = sponge
176 .sponge
177 .state
178 .iter()
179 .map(|x| x.to_biguint().into())
180 .collect();
181 (verifier_answer, state)
182 }
183
184 pub fn accumulate_program_state(&mut self, chal: BigInt, witness: &[Vec<BigInt>]) {
207 let modulus: BigInt = E::ScalarField::modulus_biguint().into();
208 self.accumulated_program_state = self
209 .accumulated_program_state
210 .iter()
211 .zip(witness.iter()) .map(|(evals_accumulator, evals_witness)| {
213 evals_accumulator
214 .iter()
215 .zip(evals_witness.iter()) .map(|(acc, w)| {
217 let rhs: BigInt = (chal.clone() * w).mod_floor(&modulus);
218 let rhs: BigUint = rhs.to_biguint().unwrap();
219 let res = E::ScalarField::from_biguint(&rhs).unwrap();
220 *acc + res
221 })
222 .collect()
223 })
224 .collect();
225 }
226
227 pub fn accumulate_committed_state(&mut self, chal: BigInt) {
246 let chal: BigUint = chal.to_biguint().unwrap();
247 let chal: E::ScalarField = E::ScalarField::from_biguint(&chal).unwrap();
248 self.accumulated_committed_state = self
249 .accumulated_committed_state
250 .iter()
251 .zip(self.previous_committed_state.iter())
252 .map(|(l, r)| l + &r.scale(chal))
253 .collect();
254 }
255}
256
257pub struct Env<
278 Fp: PrimeField,
279 Fq: PrimeField,
280 E1: ArrabbiataCurve<ScalarField = Fp, BaseField = Fq>,
281 E2: ArrabbiataCurve<ScalarField = Fq, BaseField = Fp>,
282> where
283 E1::BaseField: PrimeField,
284 E2::BaseField: PrimeField,
285 <<E1 as CommitmentCurve>::Params as CurveConfig>::BaseField: PrimeField,
286 <<E2 as CommitmentCurve>::Params as CurveConfig>::BaseField: PrimeField,
287{
288 pub indexed_relation: setup::IndexedRelation<Fp, Fq, E1, E2>,
290
291 pub program_e1: Program<Fp, Fq, E1>,
293
294 pub program_e2: Program<Fq, Fp, E2>,
296
297 pub idx_var: usize,
303
304 pub idx_var_next_row: usize,
305
306 pub idx_var_pi: usize,
310
311 pub current_row: usize,
313
314 pub state: [BigInt; NUMBER_OF_COLUMNS],
316
317 pub next_state: [BigInt; NUMBER_OF_COLUMNS],
321
322 pub challenges: Challenges<BigInt>,
327
328 pub current_instruction: Instruction,
332
333 pub sponge_e1: [BigInt; PlonkSpongeConstants::SPONGE_WIDTH],
339 pub sponge_e2: [BigInt; PlonkSpongeConstants::SPONGE_WIDTH],
340
341 pub prover_sponge_state: [BigInt; PlonkSpongeConstants::SPONGE_WIDTH],
348
349 pub verifier_sponge_state: [BigInt; PlonkSpongeConstants::SPONGE_WIDTH],
355
356 pub current_iteration: u64,
358
359 pub last_program_digest_before_execution: BigInt,
366
367 pub last_program_digest_after_execution: BigInt,
373
374 pub r: BigInt,
377
378 pub temporary_accumulators: ((BigInt, BigInt), (BigInt, BigInt)),
393
394 pub idx_values_to_absorb: usize,
396 pub witness: Vec<Vec<BigInt>>,
406
407 pub z0: BigInt,
411
412 pub zi: BigInt,
414 }
416
417impl<
418 Fp: PrimeField,
419 Fq: PrimeField,
420 E1: ArrabbiataCurve<ScalarField = Fp, BaseField = Fq>,
421 E2: ArrabbiataCurve<ScalarField = Fq, BaseField = Fp>,
422 > InterpreterEnv for Env<Fp, Fq, E1, E2>
423where
424 E1::BaseField: PrimeField,
425 E2::BaseField: PrimeField,
426 <<E1 as CommitmentCurve>::Params as CurveConfig>::BaseField: PrimeField,
427 <<E2 as CommitmentCurve>::Params as CurveConfig>::BaseField: PrimeField,
428{
429 type Position = (Column, CurrOrNext);
430
431 type Variable = BigInt;
438
439 fn allocate(&mut self) -> Self::Position {
440 assert!(self.idx_var < NUMBER_OF_COLUMNS, "Maximum number of columns reached ({NUMBER_OF_COLUMNS}), increase the number of columns");
441 let pos = Column::X(self.idx_var);
442 self.idx_var += 1;
443 (pos, CurrOrNext::Curr)
444 }
445
446 fn allocate_next_row(&mut self) -> Self::Position {
447 assert!(self.idx_var_next_row < NUMBER_OF_COLUMNS, "Maximum number of columns reached ({NUMBER_OF_COLUMNS}), increase the number of columns");
448 let pos = Column::X(self.idx_var_next_row);
449 self.idx_var_next_row += 1;
450 (pos, CurrOrNext::Next)
451 }
452
453 fn read_position(&self, pos: Self::Position) -> Self::Variable {
454 let (col, row) = pos;
455 let Column::X(idx) = col else {
456 unimplemented!("Only works for private inputs")
457 };
458 match row {
459 CurrOrNext::Curr => self.state[idx].clone(),
460 CurrOrNext::Next => self.next_state[idx].clone(),
461 }
462 }
463
464 fn write_column(&mut self, pos: Self::Position, v: Self::Variable) -> Self::Variable {
465 let (col, row) = pos;
466 let Column::X(idx) = col else {
467 unimplemented!("Only works for private inputs")
468 };
469 let (modulus, srs_size): (BigInt, usize) =
470 if o1_utils::is_multiple_of(self.current_iteration, 2) {
471 (
472 E1::ScalarField::modulus_biguint().into(),
473 self.indexed_relation.get_srs_size(),
474 )
475 } else {
476 (
477 E2::ScalarField::modulus_biguint().into(),
478 self.indexed_relation.get_srs_size(),
479 )
480 };
481 let v = v.mod_floor(&modulus);
482 match row {
483 CurrOrNext::Curr => {
484 self.state[idx].clone_from(&v);
485 }
486 CurrOrNext::Next => {
487 assert!(self.current_row < srs_size - 1, "The witness builder is writing on the last row. It does not make sense to write on the next row after the last row");
488 self.next_state[idx].clone_from(&v);
489 }
490 }
491 v
492 }
493
494 fn constrain_boolean(&mut self, x: Self::Variable) {
495 let modulus: BigInt = if o1_utils::is_multiple_of(self.current_iteration, 2) {
496 E1::ScalarField::modulus_biguint().into()
497 } else {
498 E2::ScalarField::modulus_biguint().into()
499 };
500 let x = x.mod_floor(&modulus);
501 assert!(x == BigInt::from(0_usize) || x == BigInt::from(1_usize));
502 }
503
504 fn constant(&self, v: BigInt) -> Self::Variable {
505 v
506 }
507
508 fn add_constraint(&mut self, _x: Self::Variable) {
509 unimplemented!("Only when building the constraints")
510 }
511
512 fn assert_zero(&mut self, var: Self::Variable) {
513 assert_eq!(var, BigInt::from(0_usize));
514 }
515
516 fn assert_equal(&mut self, x: Self::Variable, y: Self::Variable) {
517 assert_eq!(x, y);
518 }
519
520 fn square(&mut self, pos: Self::Position, x: Self::Variable) -> Self::Variable {
521 let res = x.clone() * x.clone();
522 self.write_column(pos, res.clone());
523 res
524 }
525
526 unsafe fn bitmask_be(
528 &mut self,
529 x: &Self::Variable,
530 highest_bit: u32,
531 lowest_bit: u32,
532 pos: Self::Position,
533 ) -> Self::Variable {
534 let diff: u32 = highest_bit - lowest_bit;
535 if diff == 0 {
536 self.write_column(pos, BigInt::from(0_usize))
537 } else {
538 assert!(
539 diff > 0,
540 "The difference between the highest and lowest bit should be greater than 0"
541 );
542 let rht = (BigInt::from(1_usize) << diff) - BigInt::from(1_usize);
543 let lft = x >> lowest_bit;
544 let res: BigInt = lft & rht;
545 self.write_column(pos, res)
546 }
547 }
548
549 fn fetch_input(&mut self, pos: Self::Position) -> Self::Variable {
553 let x = BigInt::from(self.current_row as u64);
554 self.write_column(pos, x.clone());
555 x
556 }
557
558 fn reset(&mut self) {
560 self.state.iter().enumerate().for_each(|(i, x)| {
562 self.witness[i][self.current_row].clone_from(x);
563 });
564 self.current_row += 1;
567 self.idx_var = 0;
569 self.idx_var_next_row = 0;
570 self.idx_var_pi = 0;
571 self.state.clone_from(&self.next_state);
573 self.next_state = core::array::from_fn(|_| BigInt::from(0_usize));
575 }
576
577 fn coin_folding_combiner(&mut self, pos: Self::Position) -> Self::Variable {
579 let r = if o1_utils::is_multiple_of(self.current_iteration, 2) {
580 self.sponge_e1[0].clone()
581 } else {
582 self.sponge_e2[0].clone()
583 };
584 let (col, _) = pos;
585 let Column::X(idx) = col else {
586 unimplemented!("Only works for private columns")
587 };
588 self.state[idx].clone_from(&r);
589 self.r.clone_from(&r);
590 r
591 }
592
593 fn load_poseidon_state(&mut self, pos: Self::Position, i: usize) -> Self::Variable {
594 let state = if o1_utils::is_multiple_of(self.current_iteration, 2) {
595 self.sponge_e1[i].clone()
596 } else {
597 self.sponge_e2[i].clone()
598 };
599 self.write_column(pos, state)
600 }
601
602 fn get_poseidon_round_constant(&self, round: usize, i: usize) -> Self::Variable {
603 if o1_utils::is_multiple_of(self.current_iteration, 2) {
604 E1::sponge_params().round_constants[round][i]
605 .to_biguint()
606 .into()
607 } else {
608 E2::sponge_params().round_constants[round][i]
609 .to_biguint()
610 .into()
611 }
612 }
613
614 fn get_poseidon_mds_matrix(&mut self, i: usize, j: usize) -> Self::Variable {
615 if o1_utils::is_multiple_of(self.current_iteration, 2) {
616 E1::sponge_params().mds[i][j].to_biguint().into()
617 } else {
618 E2::sponge_params().mds[i][j].to_biguint().into()
619 }
620 }
621
622 unsafe fn save_poseidon_state(&mut self, x: Self::Variable, i: usize) {
623 if o1_utils::is_multiple_of(self.current_iteration, 2) {
624 let modulus: BigInt = E1::ScalarField::modulus_biguint().into();
625 self.sponge_e1[i] = x.mod_floor(&modulus)
626 } else {
627 let modulus: BigInt = E2::ScalarField::modulus_biguint().into();
628 self.sponge_e2[i] = x.mod_floor(&modulus)
629 }
630 }
631
632 unsafe fn fetch_value_to_absorb(&mut self, pos: Self::Position) -> Self::Variable {
633 let (col, curr_or_next) = pos;
634 let Column::X(_idx) = col else {
636 panic!("Only private inputs can be accepted to load the values to be absorbed")
637 };
638 assert_eq!(
639 curr_or_next,
640 CurrOrNext::Curr,
641 "Only the current row can be used to load the values to be absorbed"
642 );
643 let idx = self.idx_values_to_absorb;
645 let res = if idx < 2 * NUMBER_OF_COLUMNS {
646 let idx_col = idx / 2;
647 debug!("Absorbing the accumulator for the column index {idx_col}. After this, there will still be {} elements to absorb", NUMBER_OF_VALUES_TO_ABSORB_PUBLIC_IO - idx - 1);
648 if o1_utils::is_multiple_of(self.current_iteration, 2) {
649 let (pt_x, pt_y) = self.program_e2.accumulated_committed_state[idx_col]
650 .get_first_chunk()
651 .to_coordinates()
652 .unwrap();
653 if o1_utils::is_multiple_of(idx, 2) {
654 self.write_column(pos, pt_x.to_biguint().into())
655 } else {
656 self.write_column(pos, pt_y.to_biguint().into())
657 }
658 } else {
659 let (pt_x, pt_y) = self.program_e1.accumulated_committed_state[idx_col]
660 .get_first_chunk()
661 .to_coordinates()
662 .unwrap();
663 if o1_utils::is_multiple_of(idx, 2) {
664 self.write_column(pos, pt_x.to_biguint().into())
665 } else {
666 self.write_column(pos, pt_y.to_biguint().into())
667 }
668 }
669 } else {
670 unimplemented!("We only absorb the accumulators for now. Of course, this is not sound.")
671 };
672 self.idx_values_to_absorb += 1;
673 res
674 }
675
676 unsafe fn load_temporary_accumulators(
677 &mut self,
678 pos_x: Self::Position,
679 pos_y: Self::Position,
680 side: Side,
681 ) -> (Self::Variable, Self::Variable) {
682 match self.current_instruction {
683 Instruction::EllipticCurveScaling(i_comm, bit) => {
684 if bit == 0 {
689 if o1_utils::is_multiple_of(self.current_iteration, 2) {
690 match side {
691 Side::Left => {
692 let pt = self.program_e2.previous_committed_state[i_comm].get_first_chunk();
693 let (pt_x, pt_y) = pt.to_coordinates().unwrap();
696 let pt_x = self.write_column(pos_x, pt_x.to_biguint().into());
697 let pt_y = self.write_column(pos_y, pt_y.to_biguint().into());
698 (pt_x, pt_y)
699 }
700 Side::Right => {
708 let pt = self.indexed_relation.srs_e2.h;
709 let (pt_x, pt_y) = pt.to_coordinates().unwrap();
710 let pt_x = self.write_column(pos_x, pt_x.to_biguint().into());
711 let pt_y = self.write_column(pos_y, pt_y.to_biguint().into());
712 (pt_x, pt_y)
713 }
714 }
715 } else {
716 match side {
717 Side::Left => {
718 let pt = self.program_e1.previous_committed_state[i_comm].get_first_chunk();
719 let (pt_x, pt_y) = pt.to_coordinates().unwrap();
722 let pt_x = self.write_column(pos_x, pt_x.to_biguint().into());
723 let pt_y = self.write_column(pos_y, pt_y.to_biguint().into());
724 (pt_x, pt_y)
725 }
726 Side::Right => {
734 let blinder = self.indexed_relation.srs_e1.h;
735 let pt = blinder;
736 let (pt_x, pt_y) = pt.to_coordinates().unwrap();
737 let pt_x = self.write_column(pos_x, pt_x.to_biguint().into());
738 let pt_y = self.write_column(pos_x, pt_y.to_biguint().into());
739 (pt_x, pt_y)
740 }
741 }
742 }
743 } else {
744 panic!("We should not load the temporary accumulators for the bits different than 0 when using the elliptic curve scaling. It has been deactivated since we use the 'next row'");
745 }
746 }
747 Instruction::EllipticCurveAddition(i_comm) => {
748 let (pt_x, pt_y): (BigInt, BigInt) = match side {
750 Side::Left => {
751 if o1_utils::is_multiple_of(self.current_iteration, 2) {
752 let pt = self.program_e2.accumulated_committed_state[i_comm].get_first_chunk();
753 let (x, y) = pt.to_coordinates().unwrap();
754 (x.to_biguint().into(), y.to_biguint().into())
755 } else {
756 let pt = self.program_e1.accumulated_committed_state[i_comm].get_first_chunk();
757 let (x, y) = pt.to_coordinates().unwrap();
758 (x.to_biguint().into(), y.to_biguint().into())
759 }
760 }
761 Side::Right => {
762 if o1_utils::is_multiple_of(self.current_iteration, 2) {
763 let pt = self.program_e2.previous_committed_state[i_comm].get_first_chunk();
764 let (x, y) = pt.to_coordinates().unwrap();
765 (x.to_biguint().into(), y.to_biguint().into())
766 } else {
767 let pt = self.program_e1.previous_committed_state[i_comm].get_first_chunk();
768 let (x, y) = pt.to_coordinates().unwrap();
769 (x.to_biguint().into(), y.to_biguint().into())
770 }
771 }
772 };
773 let pt_x = self.write_column(pos_x, pt_x.clone());
774 let pt_y = self.write_column(pos_y, pt_y.clone());
775 (pt_x, pt_y)
776 }
777 _ => unimplemented!("For now, the accumulators can only be used by the elliptic curve scaling gadget and {:?} is not supported. This should be changed as soon as the gadget is implemented.", self.current_instruction),
778 }
779 }
780
781 unsafe fn save_temporary_accumulators(
782 &mut self,
783 x: Self::Variable,
784 y: Self::Variable,
785 side: Side,
786 ) {
787 match side {
788 Side::Left => {
789 self.temporary_accumulators.0 = (x, y);
790 }
791 Side::Right => {
792 self.temporary_accumulators.1 = (x, y);
793 }
794 }
795 }
796
797 unsafe fn is_same_ec_point(
799 &mut self,
800 pos: Self::Position,
801 x1: Self::Variable,
802 y1: Self::Variable,
803 x2: Self::Variable,
804 y2: Self::Variable,
805 ) -> Self::Variable {
806 let res = if x1 == x2 && y1 == y2 {
807 BigInt::from(1_usize)
808 } else {
809 BigInt::from(0_usize)
810 };
811 self.write_column(pos, res)
812 }
813
814 fn zero(&self) -> Self::Variable {
815 BigInt::from(0_usize)
816 }
817
818 fn one(&self) -> Self::Variable {
819 BigInt::from(1_usize)
820 }
821
822 unsafe fn inverse(&mut self, pos: Self::Position, x: Self::Variable) -> Self::Variable {
828 let res = if o1_utils::is_multiple_of(self.current_iteration, 2) {
829 E1::ScalarField::from_biguint(&x.to_biguint().unwrap())
830 .unwrap()
831 .inverse()
832 .unwrap()
833 .to_biguint()
834 .into()
835 } else {
836 E2::ScalarField::from_biguint(&x.to_biguint().unwrap())
837 .unwrap()
838 .inverse()
839 .unwrap()
840 .to_biguint()
841 .into()
842 };
843 self.write_column(pos, res)
844 }
845
846 fn compute_lambda(
847 &mut self,
848 pos: Self::Position,
849 is_same_point: Self::Variable,
850 x1: Self::Variable,
851 y1: Self::Variable,
852 x2: Self::Variable,
853 y2: Self::Variable,
854 ) -> Self::Variable {
855 let modulus: BigInt = if o1_utils::is_multiple_of(self.current_iteration, 2) {
856 E1::ScalarField::modulus_biguint().into()
857 } else {
858 E2::ScalarField::modulus_biguint().into()
859 };
860 let (num, denom): (BigInt, BigInt) = if is_same_point == BigInt::from(0_usize) {
863 let num: BigInt = y1.clone() - y2.clone();
864 let x1_minus_x2: BigInt = (x1.clone() - x2.clone()).mod_floor(&modulus);
865 let denom = unsafe { self.inverse(pos, x1_minus_x2) };
868 (num, denom)
869 } else {
870 let denom = {
873 let double_y1 = y1.clone() + y1.clone();
874 unsafe { self.inverse(pos, double_y1) }
877 };
878 let num = {
879 let a: BigInt = if o1_utils::is_multiple_of(self.current_iteration, 2) {
880 let a: E2::BaseField = E2::get_curve_params().0;
881 a.to_biguint().into()
882 } else {
883 let a: E1::BaseField = E1::get_curve_params().0;
884 a.to_biguint().into()
885 };
886 let x1_square = x1.clone() * x1.clone();
887 let two_x1_square = x1_square.clone() + x1_square.clone();
888 two_x1_square + x1_square + a
889 };
890 (num, denom)
891 };
892 let res = (num * denom).mod_floor(&modulus);
893 self.write_column(pos, res)
894 }
895
896 fn double_ec_point(
899 &mut self,
900 pos_x: Self::Position,
901 pos_y: Self::Position,
902 x1: Self::Variable,
903 y1: Self::Variable,
904 ) -> (Self::Variable, Self::Variable) {
905 let modulus: BigInt = if o1_utils::is_multiple_of(self.current_iteration, 2) {
906 E1::ScalarField::modulus_biguint().into()
907 } else {
908 E2::ScalarField::modulus_biguint().into()
909 };
910 let lambda_pos = self.allocate();
914 let denom = {
915 let double_y1 = y1.clone() + y1.clone();
916 unsafe { self.inverse(lambda_pos, double_y1) }
919 };
920 let num = {
921 let a: BigInt = if o1_utils::is_multiple_of(self.current_iteration, 2) {
922 let a: E2::BaseField = E2::get_curve_params().0;
923 a.to_biguint().into()
924 } else {
925 let a: E1::BaseField = E1::get_curve_params().0;
926 a.to_biguint().into()
927 };
928 let x1_square = x1.clone() * x1.clone();
929 let two_x1_square = x1_square.clone() + x1_square.clone();
930 two_x1_square + x1_square + a
931 };
932 let lambda = (num * denom).mod_floor(&modulus);
933 self.write_column(lambda_pos, lambda.clone());
934 let x3 = {
936 let double_x1 = x1.clone() + x1.clone();
937 let res = lambda.clone() * lambda.clone() - double_x1.clone();
938 self.write_column(pos_x, res.clone())
939 };
940 let y3 = {
942 let x1_minus_x3 = x1.clone() - x3.clone();
943 let res = lambda.clone() * x1_minus_x3 - y1.clone();
944 self.write_column(pos_y, res.clone())
945 };
946 (x3, y3)
947 }
948}
949
950impl<
951 Fp: PrimeField,
952 Fq: PrimeField,
953 E1: ArrabbiataCurve<ScalarField = Fp, BaseField = Fq>,
954 E2: ArrabbiataCurve<ScalarField = Fq, BaseField = Fp>,
955 > Env<Fp, Fq, E1, E2>
956where
957 E1::BaseField: PrimeField,
958 E2::BaseField: PrimeField,
959 <<E1 as CommitmentCurve>::Params as CurveConfig>::BaseField: PrimeField,
960 <<E2 as CommitmentCurve>::Params as CurveConfig>::BaseField: PrimeField,
961{
962 pub fn new(z0: BigInt, indexed_relation: setup::IndexedRelation<Fp, Fq, E1, E2>) -> Self {
963 let srs_size = indexed_relation.get_srs_size();
964 let (blinder_e1, blinder_e2) = indexed_relation.get_srs_blinders();
965
966 let mut witness: Vec<Vec<BigInt>> = Vec::with_capacity(NUMBER_OF_COLUMNS);
967 {
968 let mut vec: Vec<BigInt> = Vec::with_capacity(srs_size);
969 (0..srs_size).for_each(|_| vec.push(BigInt::from(0_usize)));
970 (0..NUMBER_OF_COLUMNS).for_each(|_| witness.push(vec.clone()));
971 };
972
973 let program_e1 = Program::new(srs_size, blinder_e1);
975 let program_e2 = Program::new(srs_size, blinder_e2);
976
977 let challenges: Challenges<BigInt> = Challenges::default();
979
980 let prover_sponge_state: [BigInt; PlonkSpongeConstants::SPONGE_WIDTH] =
982 core::array::from_fn(|_| BigInt::from(0_u64));
983 let verifier_sponge_state: [BigInt; PlonkSpongeConstants::SPONGE_WIDTH] =
984 core::array::from_fn(|_| BigInt::from(0_u64));
985
986 let sponge_e1 = indexed_relation.initial_sponge.clone();
989 let sponge_e2 = indexed_relation.initial_sponge.clone();
990
991 Self {
992 indexed_relation,
995 program_e1,
998 program_e2,
999 idx_var: 0,
1002 idx_var_next_row: 0,
1003 idx_var_pi: 0,
1004 current_row: 0,
1005 state: core::array::from_fn(|_| BigInt::from(0_usize)),
1006 next_state: core::array::from_fn(|_| BigInt::from(0_usize)),
1007
1008 challenges,
1009
1010 current_instruction: VERIFIER_STARTING_INSTRUCTION,
1011 sponge_e1,
1012 sponge_e2,
1013 prover_sponge_state,
1014 verifier_sponge_state,
1015 current_iteration: 0,
1016 last_program_digest_before_execution: BigInt::from(0_u64),
1018 last_program_digest_after_execution: BigInt::from(0_u64),
1020 r: BigInt::from(0_usize),
1021 temporary_accumulators: (
1023 (BigInt::from(0_u64), BigInt::from(0_u64)),
1024 (BigInt::from(0_u64), BigInt::from(0_u64)),
1025 ),
1026 idx_values_to_absorb: 0,
1027 witness,
1033 z0: z0.clone(),
1036 zi: z0,
1037 }
1038 }
1039
1040 pub fn reset_for_next_iteration(&mut self) {
1042 self.current_row = 0;
1044 self.state = core::array::from_fn(|_| BigInt::from(0_usize));
1045 self.idx_var = 0;
1046 self.current_instruction = VERIFIER_STARTING_INSTRUCTION;
1047 self.idx_values_to_absorb = 0;
1048 }
1049
1050 pub fn accumulate_commitment_blinder(&mut self) {
1055 }
1057
1058 pub fn commit_state(&mut self) {
1064 if o1_utils::is_multiple_of(self.current_iteration, 2) {
1065 assert_eq!(
1066 self.current_row as u64,
1067 self.indexed_relation.domain_fp.d1.size,
1068 "The program has not been fully executed. Missing {} rows",
1069 self.indexed_relation.domain_fp.d1.size - self.current_row as u64,
1070 );
1071 self.program_e1.commit_state(
1073 &self.indexed_relation.srs_e1,
1074 self.indexed_relation.domain_fp,
1075 &self.witness,
1076 )
1077 } else {
1078 assert_eq!(
1079 self.current_row as u64,
1080 self.indexed_relation.domain_fq.d1.size,
1081 "The program has not been fully executed. Missing {} rows",
1082 self.indexed_relation.domain_fq.d1.size - self.current_row as u64,
1083 );
1084 self.program_e2.commit_state(
1086 &self.indexed_relation.srs_e2,
1087 self.indexed_relation.domain_fq,
1088 &self.witness,
1089 )
1090 }
1091 }
1092
1093 pub fn absorb_state(&mut self) {
1099 let state = if o1_utils::is_multiple_of(self.current_iteration, 2) {
1100 let state = self
1102 .program_e1
1103 .absorb_state(self.last_program_digest_after_execution.clone());
1104 state.try_into().unwrap()
1105 } else {
1106 let state = self
1108 .program_e2
1109 .absorb_state(self.last_program_digest_after_execution.clone());
1110 state.try_into().unwrap()
1111 };
1112
1113 self.prover_sponge_state = state;
1114 }
1115
1116 pub fn compute_output(&mut self) {
1120 self.zi = BigInt::from(42_usize)
1121 }
1122
1123 pub fn fetch_instruction(&self) -> Instruction {
1124 self.current_instruction
1125 }
1126
1127 pub fn coin_challenge(&mut self, chal: ChallengeTerm) {
1149 let sponge_state_vec: Vec<BigInt> = self.prover_sponge_state.to_vec();
1150
1151 let (verifier_answer, new_state) = if o1_utils::is_multiple_of(self.current_iteration, 2) {
1152 self.program_e1.coin_challenge(sponge_state_vec)
1153 } else {
1154 self.program_e2.coin_challenge(sponge_state_vec)
1155 };
1156
1157 self.challenges[chal] = verifier_answer;
1158 self.prover_sponge_state = new_state.try_into().unwrap();
1159 }
1160
1161 pub fn accumulate_program_state(&mut self) {
1184 let chal = self.challenges[ChallengeTerm::RelationCombiner].clone();
1185
1186 if o1_utils::is_multiple_of(self.current_iteration, 2) {
1187 self.program_e1
1188 .accumulate_program_state(chal, &self.witness);
1189 } else {
1190 self.program_e2
1191 .accumulate_program_state(chal, &self.witness);
1192 }
1193 }
1194
1195 pub fn accumulate_committed_state(&mut self) {
1214 let chal = self.challenges[ChallengeTerm::RelationCombiner].clone();
1215
1216 if o1_utils::is_multiple_of(self.current_iteration, 2) {
1217 self.program_e2.accumulate_committed_state(chal);
1218 } else {
1219 self.program_e1.accumulate_committed_state(chal);
1220 }
1221 }
1222}