1use super::*;
2use crypto_primitives::{ConstIntSemiring, FromPrimitiveWithConfig, FromWithConfig};
3use itertools::Itertools;
4use num_traits::Zero;
5use std::{collections::HashMap, io::Cursor};
6use zinc_piop::{
7 combined_poly_resolver::{self, CombinedPolyResolver},
8 ideal_check::{self, IdealCheckProtocol},
9 lookup::booleanity::{BoolVerifierSubclaim, BooleanityChecker, BooleanityProof},
10 multipoint_eval::{self, MultipointEval},
11 projections::{
12 ProjectedTrace, project_scalars, project_scalars_to_field, project_trace_coeffs_row_major,
13 },
14 sumcheck::multi_degree::MultiDegreeSumcheck,
15};
16use zinc_poly::{EvaluatablePolynomial, univariate::dynamic::over_field::DynamicPolynomialF};
17use zinc_transcript::{
18 Blake3Transcript,
19 traits::{ConstTranscribable, Transcript},
20};
21use zinc_uair::{
22 Uair, UairSignature, UairTrace,
23 constraint_counter::count_constraints,
24 ideal::{Ideal, IdealCheck},
25 ideal_collector::IdealOrZero,
26};
27use zinc_utils::{
28 add, from_ref::FromRef, inner_transparent_field::InnerTransparentField,
29 mul_by_scalar::MulByScalar, projectable_to_field::ProjectableToField,
30};
31use zip_plus::{
32 pcs::structs::{ZipPlus, ZipPlusParams, ZipTypes},
33 pcs_transcript::PcsVerifierTranscript,
34};
35
36#[derive(Clone, Debug)]
42pub struct VerifierBase<'a, Zt: ZincTypes<D, FD>, const D: usize, const FD: usize> {
43 num_vars: usize,
44 uair_signature: UairSignature,
45 pcs_transcript: PcsVerifierTranscript,
46 public_trace: &'a UairTrace<'a, Zt::Int, Zt::Int, D, D>,
47
48 vp_bin: &'a ZipPlusParams<Zt::BinaryZt, Zt::BinaryLc>,
50 vp_arb: &'a ZipPlusParams<Zt::ArbitraryZt, Zt::ArbitraryLc>,
51 vp_int: &'a ZipPlusParams<Zt::IntZt, Zt::IntLc>,
52}
53
54#[derive(Clone, Debug)]
60pub struct VerifierTranscriptReconstructed<
61 'a,
62 Zt: ZincTypes<D, FD>,
63 U: Uair,
64 F: PrimeField,
65 IdealOverF,
66 const D: usize,
67 const FD: usize,
68> {
69 base: VerifierBase<'a, Zt, D, FD>,
70
71 proof_commitments: (ZipPlusCommitment, ZipPlusCommitment, ZipPlusCommitment),
73 proof_ideal_check: IdealCheckProof<F>,
74 proof_resolver: CombinedPolyResolverProof<F>,
75 proof_combined_sumcheck: MultiDegreeSumcheckProof<F>,
76 proof_multipoint_eval: MultipointEvalProof<F>,
77 proof_witness_lifted_evals: Vec<DynamicPolynomialF<F>>,
78 proof_lookup_proof: Option<BatchedLookupProof<F>>,
79 proof_booleanity: Option<BooleanityProof<F>>,
80 _phantom: PhantomData<(U, IdealOverF)>,
81}
82
83#[derive(Clone, Debug)]
85pub struct VerifierPrimeProjected<
86 'a,
87 Zt: ZincTypes<D, FD>,
88 U: Uair,
89 F: PrimeField,
90 IdealOverF,
91 const D: usize,
92 const FD: usize,
93> {
94 base: VerifierBase<'a, Zt, D, FD>,
95 field_cfg: F::Config,
96
97 proof_commitments: (ZipPlusCommitment, ZipPlusCommitment, ZipPlusCommitment),
99 proof_ideal_check: IdealCheckProof<F>,
100 proof_resolver: CombinedPolyResolverProof<F>,
101 proof_combined_sumcheck: MultiDegreeSumcheckProof<F>,
102 proof_multipoint_eval: MultipointEvalProof<F>,
103 proof_witness_lifted_evals: Vec<DynamicPolynomialF<F>>,
104 proof_lookup_proof: Option<BatchedLookupProof<F>>,
105 proof_booleanity: Option<BooleanityProof<F>>,
106 _phantom: PhantomData<(U, IdealOverF)>,
107}
108
109#[derive(Clone, Debug)]
111pub struct VerifierIdealChecked<
112 'a,
113 Zt: ZincTypes<D, FD>,
114 U: Uair,
115 F: PrimeField,
116 IdealOverF,
117 const D: usize,
118 const FD: usize,
119> {
120 base: VerifierBase<'a, Zt, D, FD>,
121 field_cfg: F::Config,
122 ic_subclaim: ideal_check::VerifierSubclaim<F>,
123
124 proof_commitments: (ZipPlusCommitment, ZipPlusCommitment, ZipPlusCommitment),
126 proof_resolver: CombinedPolyResolverProof<F>,
127 proof_combined_sumcheck: MultiDegreeSumcheckProof<F>,
128 proof_multipoint_eval: MultipointEvalProof<F>,
129 proof_witness_lifted_evals: Vec<DynamicPolynomialF<F>>,
130 proof_lookup_proof: Option<BatchedLookupProof<F>>,
131 proof_booleanity: Option<BooleanityProof<F>>,
132 _phantom: PhantomData<(U, IdealOverF)>,
133}
134
135#[derive(Clone, Debug)]
137pub struct VerifierEvalProjected<
138 'a,
139 Zt: ZincTypes<D, FD>,
140 U: Uair,
141 F: PrimeField,
142 IdealOverF,
143 const D: usize,
144 const FD: usize,
145> {
146 base: VerifierBase<'a, Zt, D, FD>,
147 field_cfg: F::Config,
148 ic_subclaim: ideal_check::VerifierSubclaim<F>,
149 projecting_element_f: F,
150 projected_scalars_f: HashMap<U::Scalar, F>,
151
152 proof_commitments: (ZipPlusCommitment, ZipPlusCommitment, ZipPlusCommitment),
154 proof_resolver: CombinedPolyResolverProof<F>,
155 proof_combined_sumcheck: MultiDegreeSumcheckProof<F>,
156 proof_multipoint_eval: MultipointEvalProof<F>,
157 proof_witness_lifted_evals: Vec<DynamicPolynomialF<F>>,
158 proof_lookup_proof: Option<BatchedLookupProof<F>>,
159 proof_booleanity: Option<BooleanityProof<F>>,
160 _phantom: PhantomData<(U, IdealOverF)>,
161}
162
163#[derive(Clone, Debug)]
165pub struct VerifierSumchecked<
166 'a,
167 Zt: ZincTypes<D, FD>,
168 F: PrimeField,
169 IdealOverF,
170 const D: usize,
171 const FD: usize,
172> {
173 base: VerifierBase<'a, Zt, D, FD>,
174 field_cfg: F::Config,
175 projecting_element_f: F,
176 cpr_subclaim: combined_poly_resolver::VerifierSubclaim<F>,
177 bool_subclaim: Option<BoolVerifierSubclaim<F>>,
178
179 proof_commitments: (ZipPlusCommitment, ZipPlusCommitment, ZipPlusCommitment),
181 proof_multipoint_eval: MultipointEvalProof<F>,
182 proof_witness_lifted_evals: Vec<DynamicPolynomialF<F>>,
183 proof_lookup_proof: Option<BatchedLookupProof<F>>,
184 _phantom: PhantomData<IdealOverF>,
185}
186
187#[derive(Clone, Debug)]
189pub struct VerifierMultipointEvaled<
190 'a,
191 Zt: ZincTypes<D, FD>,
192 F: PrimeField,
193 IdealOverF,
194 const D: usize,
195 const FD: usize,
196> {
197 base: VerifierBase<'a, Zt, D, FD>,
198 field_cfg: F::Config,
199 projecting_element_f: F,
200 mp_subclaim: multipoint_eval::Subclaim<F>,
201 booleanity_present: bool,
205
206 proof_commitments: (ZipPlusCommitment, ZipPlusCommitment, ZipPlusCommitment),
208 proof_witness_lifted_evals: Vec<DynamicPolynomialF<F>>,
209 proof_lookup_proof: Option<BatchedLookupProof<F>>,
210 _phantom: PhantomData<IdealOverF>,
211}
212
213#[derive(Clone, Debug)]
215#[allow(dead_code)]
216pub struct VerifierLiftedEvalsChecked<
217 'a,
218 Zt: ZincTypes<D, FD>,
219 F: PrimeField,
220 IdealOverF,
221 const D: usize,
222 const FD: usize,
223> {
224 base: VerifierBase<'a, Zt, D, FD>,
225 field_cfg: F::Config,
226 mp_subclaim: multipoint_eval::Subclaim<F>,
227 all_lifted_evals: Vec<DynamicPolynomialF<F>>,
228
229 proof_commitments: (ZipPlusCommitment, ZipPlusCommitment, ZipPlusCommitment),
231 proof_lookup_proof: Option<BatchedLookupProof<F>>,
232 _phantom: PhantomData<IdealOverF>,
233}
234
235#[derive(Clone, Debug)]
238pub struct VerifierPcsVerified<IdealOverF> {
239 _phantom: PhantomData<IdealOverF>,
240}
241
242impl<Zt, U, F, const D: usize, const FD: usize> ZincPlusPiop<Zt, U, F, D, FD>
247where
248 Zt: ZincTypes<D, FD>,
249 U: Uair,
250 F: PrimeField,
251 F::Inner: ConstTranscribable,
252{
253 #[allow(clippy::type_complexity)]
256 pub fn step0_reconstruct_transcript<'a, IdealOverF>(
257 (vp_bin, vp_arb, vp_int): &'a (
258 ZipPlusParams<Zt::BinaryZt, Zt::BinaryLc>,
259 ZipPlusParams<Zt::ArbitraryZt, Zt::ArbitraryLc>,
260 ZipPlusParams<Zt::IntZt, Zt::IntLc>,
261 ),
262 mut proof: Proof<F>,
263 public_trace: &'a UairTrace<'a, Zt::Int, Zt::Int, D, D>,
264 num_vars: usize,
265 ) -> Result<
266 VerifierTranscriptReconstructed<'a, Zt, U, F, IdealOverF, D, FD>,
267 ProtocolError<F, IdealOverF>,
268 >
269 where
270 IdealOverF: Ideal,
271 {
272 let zip_proof = std::mem::take(&mut proof.zip);
273 let mut base = VerifierBase {
274 num_vars,
275 uair_signature: U::signature(),
276 public_trace,
277 pcs_transcript: PcsVerifierTranscript {
278 fs_transcript: Blake3Transcript::default(),
279 stream: Cursor::new(zip_proof),
280 },
281 vp_bin,
282 vp_arb,
283 vp_int,
284 };
285
286 for comm in [
287 &proof.commitments.0,
288 &proof.commitments.1,
289 &proof.commitments.2,
290 ] {
291 base.pcs_transcript.fs_transcript.absorb_slice(&comm.root);
292 }
293
294 absorb_public_columns(
295 &mut base.pcs_transcript.fs_transcript,
296 &base.public_trace.binary_poly,
297 );
298 absorb_public_columns(
299 &mut base.pcs_transcript.fs_transcript,
300 &base.public_trace.arbitrary_poly,
301 );
302 absorb_public_columns(
303 &mut base.pcs_transcript.fs_transcript,
304 &base.public_trace.int,
305 );
306
307 Ok(VerifierTranscriptReconstructed {
308 base,
309 proof_commitments: proof.commitments,
310 proof_ideal_check: proof.ideal_check,
311 proof_resolver: proof.resolver,
312 proof_combined_sumcheck: proof.combined_sumcheck,
313 proof_multipoint_eval: proof.multipoint_eval,
314 proof_witness_lifted_evals: proof.witness_lifted_evals,
315 proof_lookup_proof: proof.lookup_proof,
316 proof_booleanity: proof.booleanity_proof,
317 _phantom: PhantomData,
318 })
319 }
320}
321
322impl<'a, Zt, U, F, IdealOverF, const D: usize, const FD: usize>
323 VerifierTranscriptReconstructed<'a, Zt, U, F, IdealOverF, D, FD>
324where
325 Zt: ZincTypes<D, FD>,
326 F: InnerTransparentField + FromPrimitiveWithConfig + FromRef<F> + Send + Sync + 'static,
327 F::Inner: ConstIntSemiring + ConstTranscribable + Send + Sync + Zero + Default,
328 F::Modulus: ConstTranscribable + FromRef<Zt::Fmod>,
329 U: Uair,
330 IdealOverF: Ideal,
331{
332 #[allow(clippy::type_complexity)]
334 pub fn step1_prime_projection(
335 mut self,
336 ) -> Result<VerifierPrimeProjected<'a, Zt, U, F, IdealOverF, D, FD>, ProtocolError<F, IdealOverF>>
337 {
338 let field_cfg = self
339 .base
340 .pcs_transcript
341 .fs_transcript
342 .get_random_field_cfg::<F, Zt::Fmod, Zt::PrimeTest>();
343
344 Ok(VerifierPrimeProjected {
345 base: self.base,
346 field_cfg,
347 proof_commitments: self.proof_commitments,
348 proof_ideal_check: self.proof_ideal_check,
349 proof_resolver: self.proof_resolver,
350 proof_combined_sumcheck: self.proof_combined_sumcheck,
351 proof_multipoint_eval: self.proof_multipoint_eval,
352 proof_witness_lifted_evals: self.proof_witness_lifted_evals,
353 proof_lookup_proof: self.proof_lookup_proof,
354 proof_booleanity: self.proof_booleanity,
355 _phantom: PhantomData,
356 })
357 }
358}
359
360impl<'a, Zt, U, F, IdealOverF, const D: usize, const FD: usize>
361 VerifierPrimeProjected<'a, Zt, U, F, IdealOverF, D, FD>
362where
363 Zt: ZincTypes<D, FD>,
364 Zt::Int: ProjectableToField<F>,
365 <Zt::ArbitraryZt as ZipTypes>::Eval: ProjectableToField<F>,
366 F: InnerTransparentField
367 + FromPrimitiveWithConfig
368 + for<'b> FromWithConfig<&'b Zt::Int>
369 + for<'b> FromWithConfig<&'b Zt::CombR>
370 + for<'b> FromWithConfig<&'b Zt::Chal>
371 + for<'b> MulByScalar<&'b F>
372 + FromRef<F>
373 + Send
374 + Sync
375 + 'static,
376 F::Inner: ConstIntSemiring + ConstTranscribable + Send + Sync + Zero + Default,
377 F::Modulus: ConstTranscribable + FromRef<Zt::Fmod>,
378 U: Uair + 'static,
379 IdealOverF: Ideal + IdealCheck<DynamicPolynomialF<F>>,
380{
381 #[allow(clippy::type_complexity)]
383 pub fn step2_ideal_check(
384 mut self,
385 project_ideal: impl Fn(&IdealOrZero<U::Ideal>, &F::Config) -> IdealOverF,
386 ) -> Result<VerifierIdealChecked<'a, Zt, U, F, IdealOverF, D, FD>, ProtocolError<F, IdealOverF>>
387 {
388 let num_constraints = count_constraints::<U>();
389
390 let ic_subclaim = U::verify_as_subprotocol::<_, IdealOverF, _>(
391 &mut self.base.pcs_transcript.fs_transcript,
392 self.proof_ideal_check,
393 num_constraints,
394 self.base.num_vars,
395 |ideal| project_ideal(ideal, &self.field_cfg),
396 &self.field_cfg,
397 )?;
398
399 Ok(VerifierIdealChecked {
400 base: self.base,
401 field_cfg: self.field_cfg,
402 ic_subclaim,
403 proof_commitments: self.proof_commitments,
404 proof_resolver: self.proof_resolver,
405 proof_combined_sumcheck: self.proof_combined_sumcheck,
406 proof_multipoint_eval: self.proof_multipoint_eval,
407 proof_witness_lifted_evals: self.proof_witness_lifted_evals,
408 proof_lookup_proof: self.proof_lookup_proof,
409 proof_booleanity: self.proof_booleanity,
410 _phantom: PhantomData,
411 })
412 }
413}
414
415impl<'a, Zt, U, F, IdealOverF, const D: usize, const FD: usize>
416 VerifierIdealChecked<'a, Zt, U, F, IdealOverF, D, FD>
417where
418 Zt: ZincTypes<D, FD>,
419 F: InnerTransparentField
420 + for<'b> FromWithConfig<&'b Zt::Chal>
421 + FromRef<F>
422 + Send
423 + Sync
424 + 'static,
425 F::Inner: ConstIntSemiring + ConstTranscribable + Send + Sync + Zero + Default,
426 F::Modulus: ConstTranscribable + FromRef<Zt::Fmod>,
427 U: Uair + 'static,
428 IdealOverF: Ideal,
429{
430 pub fn step3_eval_projection(
432 mut self,
433 project_scalar: impl Fn(&U::Scalar, &F::Config) -> DynamicPolynomialF<F>,
434 ) -> Result<VerifierEvalProjected<'a, Zt, U, F, IdealOverF, D, FD>, ProtocolError<F, IdealOverF>>
435 {
436 let projecting_element: Zt::Chal = self.base.pcs_transcript.fs_transcript.get_challenge();
437 let projecting_element_f: F = F::from_with_cfg(&projecting_element, &self.field_cfg);
438
439 let projected_scalars_fx = project_scalars::<F, U>(|s| project_scalar(s, &self.field_cfg));
440 let projected_scalars_f =
441 project_scalars_to_field(projected_scalars_fx, &projecting_element_f)
442 .map_err(|(_s, _f, e)| ProtocolError::ScalarProjection(e))?;
443
444 Ok(VerifierEvalProjected {
445 base: self.base,
446 field_cfg: self.field_cfg,
447 ic_subclaim: self.ic_subclaim,
448 projecting_element_f,
449 projected_scalars_f,
450 proof_commitments: self.proof_commitments,
451 proof_resolver: self.proof_resolver,
452 proof_combined_sumcheck: self.proof_combined_sumcheck,
453 proof_multipoint_eval: self.proof_multipoint_eval,
454 proof_witness_lifted_evals: self.proof_witness_lifted_evals,
455 proof_lookup_proof: self.proof_lookup_proof,
456 proof_booleanity: self.proof_booleanity,
457 _phantom: PhantomData,
458 })
459 }
460}
461
462impl<'a, Zt, U, F, IdealOverF, const D: usize, const FD: usize>
463 VerifierEvalProjected<'a, Zt, U, F, IdealOverF, D, FD>
464where
465 Zt: ZincTypes<D, FD>,
466 Zt::Int: ProjectableToField<F>,
467 <Zt::ArbitraryZt as ZipTypes>::Eval: ProjectableToField<F>,
468 F: InnerTransparentField
469 + FromPrimitiveWithConfig
470 + for<'b> FromWithConfig<&'b Zt::Int>
471 + for<'b> FromWithConfig<&'b Zt::CombR>
472 + for<'b> FromWithConfig<&'b Zt::Chal>
473 + for<'b> MulByScalar<&'b F>
474 + FromRef<F>
475 + Send
476 + Sync
477 + 'static,
478 F::Inner: ConstIntSemiring + ConstTranscribable + Send + Sync + Zero + Default,
479 F::Modulus: ConstTranscribable + FromRef<Zt::Fmod>,
480 U: Uair + 'static,
481 IdealOverF: Ideal,
482{
483 pub fn step4_sumcheck_verify(
486 mut self,
487 ) -> Result<VerifierSumchecked<'a, Zt, F, IdealOverF, D, FD>, ProtocolError<F, IdealOverF>>
488 {
489 let num_constraints = count_constraints::<U>();
490
491 let cpr_verifier_ancillary = CombinedPolyResolver::prepare_verifier::<U>(
493 &mut self.base.pcs_transcript.fs_transcript,
494 &self.proof_resolver,
495 self.proof_combined_sumcheck.claimed_sums()[0].clone(),
496 &self.ic_subclaim,
497 num_constraints,
498 self.base.num_vars,
499 &self.projecting_element_f,
500 &self.field_cfg,
501 )?;
502
503 let sig = self.base.uair_signature.clone();
507 let num_pub_bin = sig.public_cols().num_binary_poly_cols();
508 let num_total_bin = sig.total_cols().num_binary_poly_cols();
509 let bool_present = num_total_bin > num_pub_bin;
510
511 let bool_verifier_ancillary = if bool_present {
512 let bool_claimed_sum = self
514 .proof_combined_sumcheck
515 .claimed_sums()
516 .get(1)
517 .ok_or(ProtocolError::BooleanityProofMissing)?;
518 let num_wit_bin = num_total_bin.saturating_sub(num_pub_bin);
519 let anc = BooleanityChecker::<F>::prepare_verifier(
520 &mut self.base.pcs_transcript.fs_transcript,
521 bool_claimed_sum,
522 num_wit_bin,
523 D,
524 self.base.num_vars,
525 &self.field_cfg,
526 )
527 .map_err(ProtocolError::Booleanity)?;
528 Some(anc)
529 } else {
530 None
531 };
532
533 let md_subclaims = MultiDegreeSumcheck::verify_as_subprotocol(
534 &mut self.base.pcs_transcript.fs_transcript,
535 self.base.num_vars,
536 &self.proof_combined_sumcheck,
537 &self.field_cfg,
538 )
539 .map_err(CombinedPolyResolverError::SumcheckError)?;
540
541 let cpr_subclaim = CombinedPolyResolver::finalize_verifier::<U>(
542 &mut self.base.pcs_transcript.fs_transcript,
543 self.proof_resolver,
544 md_subclaims.point().to_vec(),
545 md_subclaims.expected_evaluations()[0].clone(),
546 cpr_verifier_ancillary,
547 &self.projected_scalars_f,
548 &self.field_cfg,
549 )?;
550
551 let bool_subclaim = if let Some(anc) = bool_verifier_ancillary {
552 let booleanity_proof = self
553 .proof_booleanity
554 .take()
555 .ok_or(ProtocolError::BooleanityProofMissing)?;
556 let expected_evaluation = md_subclaims
557 .expected_evaluations()
558 .get(1)
559 .ok_or(ProtocolError::BooleanityProofMissing)?;
560 Some(
561 BooleanityChecker::<F>::finalize_verifier(
562 &mut self.base.pcs_transcript.fs_transcript,
563 booleanity_proof,
564 md_subclaims.point().to_vec(),
565 expected_evaluation,
566 anc,
567 &self.field_cfg,
568 )
569 .map_err(ProtocolError::Booleanity)?,
570 )
571 } else {
572 None
573 };
574
575 let _ = &self.proof_lookup_proof;
576
577 Ok(VerifierSumchecked {
578 base: self.base,
579 field_cfg: self.field_cfg,
580 projecting_element_f: self.projecting_element_f,
581 cpr_subclaim,
582 bool_subclaim,
583 proof_commitments: self.proof_commitments,
584 proof_multipoint_eval: self.proof_multipoint_eval,
585 proof_witness_lifted_evals: self.proof_witness_lifted_evals,
586 proof_lookup_proof: self.proof_lookup_proof,
587 _phantom: PhantomData,
588 })
589 }
590}
591
592impl<'a, Zt, F, IdealOverF, const D: usize, const FD: usize>
593 VerifierSumchecked<'a, Zt, F, IdealOverF, D, FD>
594where
595 Zt: ZincTypes<D, FD>,
596 F: InnerTransparentField + FromPrimitiveWithConfig + FromRef<F> + Send + Sync + 'static,
597 F::Inner: ConstIntSemiring + ConstTranscribable + Send + Sync + Zero + Default,
598 F::Modulus: ConstTranscribable + FromRef<Zt::Fmod>,
599 IdealOverF: Ideal,
600{
601 pub fn step5_multipoint_eval<U: Uair>(
603 mut self,
604 ) -> Result<VerifierMultipointEvaled<'a, Zt, F, IdealOverF, D, FD>, ProtocolError<F, IdealOverF>>
605 {
606 let extended_up_evals: Vec<F> = if let Some(ref bs) = self.bool_subclaim {
612 let mut v = self.cpr_subclaim.up_evals;
613 v.extend_from_slice(&bs.bit_slice_evals);
614 v
615 } else {
616 self.cpr_subclaim.up_evals
617 };
618
619 let mp_subclaim = MultipointEval::verify_as_subprotocol(
620 &mut self.base.pcs_transcript.fs_transcript,
621 self.proof_multipoint_eval,
622 &self.cpr_subclaim.evaluation_point,
623 &extended_up_evals,
624 &self.cpr_subclaim.down_evals,
625 self.base.uair_signature.shifts(),
626 self.base.num_vars,
627 &self.field_cfg,
628 )?;
629
630 Ok(VerifierMultipointEvaled {
631 base: self.base,
632 field_cfg: self.field_cfg,
633 projecting_element_f: self.projecting_element_f,
634 mp_subclaim,
635 booleanity_present: self.bool_subclaim.is_some(),
636 proof_commitments: self.proof_commitments,
637 proof_witness_lifted_evals: self.proof_witness_lifted_evals,
638 proof_lookup_proof: self.proof_lookup_proof,
639 _phantom: PhantomData,
640 })
641 }
642}
643
644impl<'a, Zt, F, IdealOverF, const D: usize, const FD: usize>
645 VerifierMultipointEvaled<'a, Zt, F, IdealOverF, D, FD>
646where
647 Zt: ZincTypes<D, FD>,
648 Zt::Int: ProjectableToField<F>,
649 <Zt::ArbitraryZt as ZipTypes>::Eval: ProjectableToField<F>,
650 F: InnerTransparentField
651 + FromPrimitiveWithConfig
652 + for<'b> FromWithConfig<&'b Zt::Int>
653 + for<'b> FromWithConfig<&'b Zt::Chal>
654 + for<'b> MulByScalar<&'b F>
655 + FromRef<F>
656 + Send
657 + Sync
658 + 'static,
659 F::Inner: ConstIntSemiring + ConstTranscribable + Send + Sync + Zero + Default,
660 F::Modulus: ConstTranscribable + FromRef<Zt::Fmod>,
661 IdealOverF: Ideal,
662{
663 pub fn step6_lifted_evals<U: Uair>(
666 mut self,
667 ) -> Result<
668 VerifierLiftedEvalsChecked<'a, Zt, F, IdealOverF, D, FD>,
669 ProtocolError<F, IdealOverF>,
670 > {
671 let r_0 = &self.mp_subclaim.sumcheck_subclaim.point;
672
673 let pub_cols = self.base.uair_signature.public_cols();
674 let num_pub_bin = pub_cols.num_binary_poly_cols();
675 let num_pub_arb = pub_cols.num_arbitrary_poly_cols();
676 let num_pub_int = pub_cols.num_int_cols();
677
678 let wit_cols = self.base.uair_signature.witness_cols();
679 let num_wit_bin = wit_cols.num_binary_poly_cols();
680 let num_wit_arb = wit_cols.num_arbitrary_poly_cols();
681
682 let public_lifted = if add!(add!(num_pub_bin, num_pub_arb), num_pub_int) > 0 {
683 let projected_public = project_trace_coeffs_row_major::<F, Zt::Int, Zt::Int, D, D>(
684 self.base.public_trace,
685 &self.field_cfg,
686 );
687 compute_lifted_evals::<F, D>(
688 r_0,
689 &self.base.public_trace.binary_poly,
690 &ProjectedTrace::RowMajor(projected_public),
691 &self.field_cfg,
692 )
693 } else {
694 Vec::new()
695 };
696
697 let witness_lifted_evals = &self.proof_witness_lifted_evals;
698
699 let all_lifted_evals: Vec<_> = public_lifted[..num_pub_bin]
700 .iter()
701 .chain(&witness_lifted_evals[..num_wit_bin])
702 .chain(&public_lifted[num_pub_bin..add!(num_pub_bin, num_pub_arb)])
703 .chain(&witness_lifted_evals[num_wit_bin..add!(num_wit_bin, num_wit_arb)])
704 .chain(&public_lifted[add!(num_pub_bin, num_pub_arb)..])
705 .chain(&witness_lifted_evals[add!(num_wit_bin, num_wit_arb)..])
706 .cloned()
707 .collect();
708
709 let mut open_evals: Vec<F> = all_lifted_evals
710 .iter()
711 .map(|bar_u| bar_u.evaluate_at_point(&self.projecting_element_f))
712 .collect::<Result<Vec<_>, _>>()
713 .map_err(ProtocolError::LiftedEvalProjection)?;
714
715 if self.booleanity_present {
721 let zero = F::zero_with_cfg(&self.field_cfg);
722 for bar_u in all_lifted_evals.iter().skip(num_pub_bin).take(num_wit_bin) {
723 for i in 0..D {
724 open_evals.push(bar_u.coeffs.get(i).cloned().unwrap_or_else(|| zero.clone()));
725 }
726 }
727 }
728
729 MultipointEval::verify_subclaim(
730 &self.mp_subclaim,
731 &open_evals,
732 self.base.uair_signature.shifts(),
733 &self.field_cfg,
734 )?;
735
736 let mut transcription_buf: Vec<u8> = vec![0; F::Inner::NUM_BYTES];
737 for bar_u in &all_lifted_evals {
738 self.base
739 .pcs_transcript
740 .fs_transcript
741 .absorb_random_field_slice(&bar_u.coeffs, &mut transcription_buf);
742 }
743
744 Ok(VerifierLiftedEvalsChecked {
745 base: self.base,
746 field_cfg: self.field_cfg,
747 mp_subclaim: self.mp_subclaim,
748 all_lifted_evals,
749 proof_commitments: self.proof_commitments,
750 proof_lookup_proof: self.proof_lookup_proof,
751 _phantom: PhantomData,
752 })
753 }
754}
755
756impl<'a, Zt, F, IdealOverF, const D: usize, const FD: usize>
757 VerifierLiftedEvalsChecked<'a, Zt, F, IdealOverF, D, FD>
758where
759 Zt: ZincTypes<D, FD>,
760 Zt::Int: ProjectableToField<F>,
761 <Zt::BinaryZt as ZipTypes>::Cw: ProjectableToField<F>,
762 <Zt::ArbitraryZt as ZipTypes>::Eval: ProjectableToField<F>,
763 <Zt::ArbitraryZt as ZipTypes>::Cw: ProjectableToField<F>,
764 <Zt::IntZt as ZipTypes>::Cw: ProjectableToField<F>,
765 F: InnerTransparentField
766 + FromPrimitiveWithConfig
767 + for<'b> FromWithConfig<&'b Zt::Int>
768 + for<'b> FromWithConfig<&'b Zt::CombR>
769 + for<'b> FromWithConfig<&'b Zt::Chal>
770 + for<'b> MulByScalar<&'b F>
771 + FromRef<F>
772 + Send
773 + Sync
774 + 'static,
775 F::Inner: ConstIntSemiring + ConstTranscribable + Send + Sync + Zero + Default,
776 F::Modulus: ConstTranscribable + FromRef<Zt::Fmod>,
777 IdealOverF: Ideal,
778{
779 pub fn step7_pcs_verify<U: Uair, const CHECK_FOR_OVERFLOW: bool>(
781 mut self,
782 ) -> Result<VerifierPcsVerified<IdealOverF>, ProtocolError<F, IdealOverF>> {
783 let r_0 = &self.mp_subclaim.sumcheck_subclaim.point;
784 let commitments = &self.proof_commitments;
785
786 let pub_cols = self.base.uair_signature.public_cols();
787 let num_pub_bin = pub_cols.num_binary_poly_cols();
788 let num_pub_arb = pub_cols.num_arbitrary_poly_cols();
789 let num_pub_int = pub_cols.num_int_cols();
790
791 let total = self.base.uair_signature.total_cols();
792 let num_total_bin = total.num_binary_poly_cols();
793 let num_total_arb = total.num_arbitrary_poly_cols();
794
795 let pcs_transcript = &mut self.base.pcs_transcript;
796 let field_cfg = &self.field_cfg;
797 let all_lifted_evals = &self.all_lifted_evals;
798
799 let zero = F::zero_with_cfg(field_cfg);
800
801 macro_rules! verify_pcs_batch {
802 ($Zt:ty, $Lc:ty, $vp:expr, $idx:tt, $pt:expr, [$evals_range:expr]) => {{
804 verify_pcs_batch!(
805 $Zt,
806 $Lc,
807 $vp,
808 $idx,
809 $pt,
810 [$evals_range],
811 |bar_u: &DynamicPolynomialF<F>, alphas: &[_]| {
812 let mut eval_j = zero.clone();
813 for (coeff, alpha) in bar_u.coeffs.iter().zip(alphas.iter()) {
814 let mut term = F::from_with_cfg(alpha, field_cfg);
815 term *= coeff;
816 eval_j += &term;
817 }
818 eval_j
819 }
820 )
821 }};
822
823 ($Zt:ty, $Lc:ty, $vp:expr, $idx:tt, $pt:expr, [$evals_range:expr], $compute_eval_j:expr) => {{
825 let comm = &commitments.$idx;
826 if comm.batch_size > 0 {
827 let per_poly_alphas = ZipPlus::<$Zt, $Lc>::sample_alphas(
828 &mut pcs_transcript.fs_transcript,
829 comm.batch_size,
830 );
831 let mut eval_f = zero.clone();
832 for (bar_u, alphas) in all_lifted_evals[$evals_range]
833 .iter()
834 .zip(per_poly_alphas.iter())
835 {
836 let eval_j = $compute_eval_j(bar_u, alphas);
837 eval_f += eval_j;
838 }
839 ZipPlus::<$Zt, $Lc>::verify_with_alphas::<F, CHECK_FOR_OVERFLOW>(
840 pcs_transcript,
841 $vp,
842 comm,
843 field_cfg,
844 $pt,
845 &eval_f,
846 &per_poly_alphas,
847 )
848 .map_err(|e| ProtocolError::PcsVerification($idx, e))?;
849 }
850 }};
851 }
852
853 let num_folding_challenges = Zt::BinaryFold::FOLDING_FACTOR.ilog2();
856 let folding_challenges = (0..num_folding_challenges)
857 .map(|_| {
858 let g_chal: Zt::Chal = pcs_transcript.fs_transcript.get_challenge();
859 F::from_with_cfg(&g_chal, &self.field_cfg)
860 })
861 .collect_vec();
862 let mut r_0_ext = r_0.clone();
863 r_0_ext.extend_from_slice(&folding_challenges);
864
865 verify_pcs_batch!(
866 Zt::BinaryZt,
867 Zt::BinaryLc,
868 self.base.vp_bin,
869 0,
870 &r_0_ext,
871 [num_pub_bin..num_total_bin],
872 |bar_u: &DynamicPolynomialF<F>, alphas: &[_]| {
873 Zt::BinaryFold::fold_eval_claim(
874 &bar_u.coeffs,
875 alphas,
876 &folding_challenges,
877 field_cfg,
878 )
879 }
880 );
881 verify_pcs_batch!(
882 Zt::ArbitraryZt,
883 Zt::ArbitraryLc,
884 self.base.vp_arb,
885 1,
886 &r_0,
887 [add!(num_total_bin, num_pub_arb)..add!(num_total_bin, num_total_arb)]
888 );
889 verify_pcs_batch!(
890 Zt::IntZt,
891 Zt::IntLc,
892 self.base.vp_int,
893 2,
894 &r_0,
895 [add!(add!(num_total_bin, num_total_arb), num_pub_int)..]
896 );
897
898 Ok(VerifierPcsVerified {
899 _phantom: PhantomData,
900 })
901 }
902}
903
904impl<IdealOverF: Ideal> VerifierPcsVerified<IdealOverF> {
905 pub fn finish<F: PrimeField>(self) -> Result<(), ProtocolError<F, IdealOverF>> {
907 Ok(())
908 }
909}
910
911impl<Zt, U, F, const D: usize, const FD: usize> ZincPlusPiop<Zt, U, F, D, FD>
916where
917 Zt: ZincTypes<D, FD>,
918 Zt::Int: ProjectableToField<F>,
919 <Zt::BinaryZt as ZipTypes>::Cw: ProjectableToField<F>,
920 <Zt::ArbitraryZt as ZipTypes>::Eval: ProjectableToField<F>,
921 <Zt::ArbitraryZt as ZipTypes>::Cw: ProjectableToField<F>,
922 <Zt::IntZt as ZipTypes>::Cw: ProjectableToField<F>,
923 F: InnerTransparentField
924 + FromPrimitiveWithConfig
925 + for<'a> FromWithConfig<&'a Zt::Int>
926 + for<'a> FromWithConfig<&'a Zt::CombR>
927 + for<'a> FromWithConfig<&'a Zt::Chal>
928 + for<'a> MulByScalar<&'a F>
929 + FromRef<F>
930 + Send
931 + Sync
932 + 'static,
933 F::Inner: ConstIntSemiring + ConstTranscribable + Send + Sync + Zero + Default,
934 F::Modulus: ConstTranscribable + FromRef<Zt::Fmod>,
935 U: Uair + 'static,
936{
937 #[allow(clippy::too_many_arguments, clippy::type_complexity)]
944 pub fn verify<IdealOverF, const CHECK_FOR_OVERFLOW: bool>(
945 vp: &(
946 ZipPlusParams<Zt::BinaryZt, Zt::BinaryLc>,
947 ZipPlusParams<Zt::ArbitraryZt, Zt::ArbitraryLc>,
948 ZipPlusParams<Zt::IntZt, Zt::IntLc>,
949 ),
950 proof: Proof<F>,
951 public_trace: &UairTrace<Zt::Int, Zt::Int, D, D>,
952 num_vars: usize,
953 project_scalar: impl Fn(&U::Scalar, &F::Config) -> DynamicPolynomialF<F>,
954 project_ideal: impl Fn(&IdealOrZero<U::Ideal>, &F::Config) -> IdealOverF,
955 ) -> Result<(), ProtocolError<F, IdealOverF>>
956 where
957 IdealOverF: Ideal + IdealCheck<DynamicPolynomialF<F>>,
958 {
959 ZincPlusPiop::<Zt, U, F, D, FD>::step0_reconstruct_transcript::<IdealOverF>(
960 vp,
961 proof,
962 public_trace,
963 num_vars,
964 )?
965 .step1_prime_projection()?
966 .step2_ideal_check(project_ideal)?
967 .step3_eval_projection(project_scalar)?
968 .step4_sumcheck_verify()?
969 .step5_multipoint_eval::<U>()?
970 .step6_lifted_evals::<U>()?
971 .step7_pcs_verify::<U, CHECK_FOR_OVERFLOW>()?
972 .finish::<F>()
973 }
974}