1use crate::{
2 expr_eval::GenericEvalEnv,
3 plonkish_lang::{PlonkishChallenge, PlonkishWitnessGeneric},
4 prover::Proof,
5};
6use ark_ff::Field;
7use ark_poly::{
8 univariate::DensePolynomial, EvaluationDomain, Evaluations, Polynomial,
9 Radix2EvaluationDomain as R2D,
10};
11use folding::{
12 eval_leaf::EvalLeaf, instance_witness::ExtendedWitness, FoldingCompatibleExpr, FoldingConfig,
13};
14use kimchi::{
15 self, circuits::domains::EvaluationDomains, curve::KimchiCurve, groupmap::GroupMap,
16 plonk_sponge::FrSponge, proof::PointEvaluations,
17};
18use kimchi_msm::columns::Column as GenericColumn;
19use mina_poseidon::{sponge::ScalarChallenge, FqSponge};
20use poly_commitment::{
21 commitment::{
22 absorb_commitment, combined_inner_product, BatchEvaluationProof, CommitmentCurve,
23 Evaluation, PolyComm,
24 },
25 kzg::{KZGProof, PairingSRS},
26 OpenProof, SRS,
27};
28use rand::thread_rng;
29use rayon::iter::{IntoParallelIterator, ParallelIterator};
30
31pub type Pairing = kimchi_msm::BN254;
32pub type G = kimchi_msm::BN254G1Affine;
34pub type Fp = kimchi_msm::Fp;
36pub type Fq = ark_bn254::Fq;
39
40pub fn verify<
41 EFqSponge: Clone + FqSponge<Fq, G, Fp>,
42 EFrSponge: FrSponge<Fp>,
43 FC: FoldingConfig<Column = GenericColumn<usize>, Curve = G, Challenge = PlonkishChallenge>,
44 const N_WIT: usize,
45 const N_REL: usize,
46 const N_DSEL: usize,
47 const N_FSEL: usize,
48 const NPUB: usize,
49>(
50 domain: EvaluationDomains<Fp>,
51 srs: &PairingSRS<Pairing>,
52 combined_expr: &FoldingCompatibleExpr<FC>,
53 fixed_selectors: Box<[Evaluations<Fp, R2D<Fp>>; N_FSEL]>,
54 proof: &Proof<N_WIT, N_REL, N_DSEL, N_FSEL, G, KZGProof<Pairing>>,
55) -> bool {
56 assert!(N_WIT == N_REL + N_DSEL);
57
58 let Proof {
59 proof_comms,
60 proof_evals,
61 opening_proof,
62 ..
63 } = proof;
64
65 let fixed_selectors_evals_d1: Box<[Evaluations<Fp, R2D<Fp>>; N_FSEL]> = fixed_selectors;
70
71 let fixed_selectors_polys: Box<[DensePolynomial<Fp>; N_FSEL]> = {
72 o1_utils::array::vec_to_boxed_array(
73 fixed_selectors_evals_d1
74 .into_par_iter()
75 .map(|evals| evals.interpolate())
76 .collect(),
77 )
78 };
79
80 let fixed_selectors_comms: Box<[PolyComm<G>; N_FSEL]> = {
81 let comm = |poly: &DensePolynomial<Fp>| srs.commit_non_hiding(poly, 1);
82 o1_utils::array::vec_to_boxed_array(
83 fixed_selectors_polys
84 .as_ref()
85 .into_par_iter()
86 .map(comm)
87 .collect(),
88 )
89 };
90
91 let mut fq_sponge = EFqSponge::new(G::other_curve_sponge_params());
96
97 fixed_selectors_comms
98 .as_ref()
99 .iter()
100 .chain(&proof_comms.witness_comms)
101 .for_each(|comm| absorb_commitment(&mut fq_sponge, comm));
102
103 absorb_commitment(&mut fq_sponge, &proof_comms.t_comm);
108
109 let zeta_chal = ScalarChallenge(fq_sponge.challenge());
111 let (_, endo_r) = G::endos();
112 let zeta: Fp = zeta_chal.to_field(endo_r);
113 let omega = domain.d1.group_gen;
114 let zeta_omega = zeta * omega;
115
116 let mut coms_and_evaluations: Vec<Evaluation<_>> = vec![];
117
118 coms_and_evaluations.extend(
119 (&proof_comms.witness_comms)
120 .into_iter()
121 .zip(&proof_evals.witness_evals)
122 .map(|(commitment, point_eval)| Evaluation {
123 commitment: commitment.clone(),
124 evaluations: vec![vec![point_eval.zeta], vec![point_eval.zeta_omega]],
125 }),
126 );
127
128 coms_and_evaluations.extend(
129 (fixed_selectors_comms)
130 .into_iter()
131 .zip(proof_evals.fixed_selectors_evals.iter())
132 .map(|(commitment, point_eval)| Evaluation {
133 commitment,
134 evaluations: vec![vec![point_eval.zeta], vec![point_eval.zeta_omega]],
135 }),
136 );
137
138 let fq_sponge_before_coms_and_evaluations = fq_sponge.clone();
140 let mut fr_sponge = EFrSponge::new(G::sponge_params());
141 fr_sponge.absorb(&fq_sponge.digest());
142
143 for PointEvaluations { zeta, zeta_omega } in (&proof_evals.witness_evals).into_iter() {
144 fr_sponge.absorb(zeta);
145 fr_sponge.absorb(zeta_omega);
146 }
147
148 for PointEvaluations { zeta, zeta_omega } in proof_evals.fixed_selectors_evals.as_ref().iter() {
149 fr_sponge.absorb(zeta);
150 fr_sponge.absorb(zeta_omega);
151 }
152
153 let ft_comm = {
157 let evaluation_point_to_domain_size = zeta.pow([domain.d1.size]);
158 let chunked_t_comm = proof_comms
159 .t_comm
160 .chunk_commitment(evaluation_point_to_domain_size);
161
162 let minus_vanishing_poly_at_zeta: Fp = -domain.d1.vanishing_polynomial().evaluate(&zeta);
164 chunked_t_comm.scale(minus_vanishing_poly_at_zeta)
165 };
166
167 let ft_eval0 = {
168 let witness_evals_vecs = (&proof_evals.witness_evals)
169 .into_iter()
170 .map(|x| vec![x.zeta])
171 .collect::<Vec<_>>()
172 .try_into()
173 .unwrap();
174 let fixed_selectors_evals_vecs = proof_evals
175 .fixed_selectors_evals
176 .into_iter()
177 .map(|x| vec![x.zeta])
178 .collect::<Vec<_>>()
179 .try_into()
180 .unwrap();
181 let error_vec = vec![proof_evals.error_vec.zeta];
182
183 let alphas = proof.alphas.clone();
184 let challenges = proof.challenges;
185 let u = proof.u;
186
187 let eval_env: GenericEvalEnv<G, N_WIT, N_FSEL, Vec<Fp>> = {
188 let ext_witness = ExtendedWitness {
189 witness: PlonkishWitnessGeneric {
190 witness: witness_evals_vecs,
191 fixed_selectors: fixed_selectors_evals_vecs,
192 phantom: core::marker::PhantomData,
193 },
194 extended: Default::default(),
195 };
196
197 GenericEvalEnv {
198 ext_witness,
199 alphas,
200 challenges,
201 error_vec,
202 u,
203 }
204 };
205
206 let eval_res: Vec<_> = match eval_env.eval_naive_fcompat(combined_expr) {
207 EvalLeaf::Result(x) => x,
208 EvalLeaf::Col(x) => x.to_vec(),
209 _ => panic!("eval_leaf is not Result"),
210 };
211
212 -eval_res[0]
214 };
215
216 coms_and_evaluations.push(Evaluation {
217 commitment: ft_comm,
218 evaluations: vec![vec![ft_eval0], vec![proof_evals.ft_eval1]],
219 });
220
221 fr_sponge.absorb(&proof_evals.ft_eval1);
222 let v_chal = fr_sponge.challenge();
225 let v = v_chal.to_field(endo_r);
226 let u_chal = fr_sponge.challenge();
227 let u = u_chal.to_field(endo_r);
228
229 let combined_inner_product = {
230 let es: Vec<_> = coms_and_evaluations
231 .iter()
232 .map(|Evaluation { evaluations, .. }| evaluations.clone())
233 .collect();
234
235 combined_inner_product(&v, &u, es.as_slice())
236 };
237
238 let batch = BatchEvaluationProof {
239 sponge: fq_sponge_before_coms_and_evaluations,
240 evaluations: coms_and_evaluations,
241 evaluation_points: vec![zeta, zeta_omega],
242 polyscale: v,
243 evalscale: u,
244 opening: opening_proof,
245 combined_inner_product,
246 };
247
248 let group_map = <G as CommitmentCurve>::Map::setup();
249 OpenProof::verify(srs, &group_map, &mut [batch], &mut thread_rng())
250}