1use super::*;
2use itertools::Itertools;
3use std::{
4 borrow::Cow,
5 fmt::{Debug, Display},
6};
7use zinc_piop::{
8 combined_poly_resolver::CombinedPolyResolver,
9 ideal_check::{IdealCheckProtocol, Proof as IdealCheckProof},
10 lookup::booleanity::{BoolProverAncillary, BooleanityChecker, BooleanityProof},
11 multipoint_eval::{MultipointEval, MultipointEvalFamilyInputs, Proof as MultipointEvalProof},
12 projections::{
13 ColumnMajorTrace, ProjectedScalars, ProjectedTrace, RowMajorTrace,
14 build_bit_op_virtual_mle, evaluate_trace_to_column_mles, project_scalars,
15 project_scalars_to_field, project_trace_coeffs_column_major,
16 project_trace_coeffs_row_major,
17 },
18 sumcheck::multi_degree::{MultiDegreeSumcheck, MultiDegreeSumcheckGroup},
19};
20use zinc_poly::{mle::DenseMultilinearExtension, univariate::dynamic::DynamicPolynomial};
21use zinc_transcript::traits::{ConstTranscribable, Transcript};
22use zinc_uair::{
23 Uair, UairSignature, UairTrace, constraint_counter::count_constraints,
24 degree_counter::count_max_degree,
25};
26use zinc_utils::{
27 add, cfg_iter, cfg_join, mul_by_scalar::MulByScalar, powers,
28 projectable_to_field::ProjectableToField,
29};
30use zip_plus::{
31 pcs::structs::{ZipPlus, ZipPlusHint, ZipPlusParams, ZipTypes},
32 pcs_transcript::PcsProverTranscript,
33};
34
35#[derive(Clone, Debug)]
42pub struct ProverFolded<
43 'a,
44 Zt: ZincTypes<D, FD>,
45 U: Uair,
46 C: BaseFieldConfig,
47 const D: usize,
48 const FD: usize,
49> {
50 uair_signature: UairSignature<Zt::Fmod>,
51 original_trace: &'a UairTrace<'static, Zt::Int, Zt::Int, D, D>,
52 folded_witness_trace: UairTrace<'a, Zt::Int, Zt::Int, FD, D>,
53
54 _phantom: PhantomData<(&'a u8, U, C)>,
55}
56
57#[derive(Clone, Debug)]
62pub struct ProverCommitted<
63 'a,
64 Zt: ZincTypes<D, FD>,
65 U: Uair,
66 C: BaseFieldConfig,
67 const D: usize,
68 const FD: usize,
69> {
70 num_vars: usize,
71 uair_signature: UairSignature<Zt::Fmod>,
72 original_trace: &'a UairTrace<'static, Zt::Int, Zt::Int, D, D>,
73 folded_witness_trace: UairTrace<'a, Zt::Int, Zt::Int, FD, D>,
74 pcs_transcript: PcsProverTranscript,
75
76 pp_bin: &'a ZipPlusParams<Zt::BinaryZt, Zt::BinaryLc>,
78 pp_arb: &'a ZipPlusParams<Zt::ArbitraryZt, Zt::ArbitraryLc>,
79 pp_int: &'a ZipPlusParams<Zt::IntZt, Zt::IntLc>,
80 hint_bin: Option<ZipPlusHint<<Zt::BinaryZt as ZipTypes>::Cw>>,
81 hint_arb: Option<ZipPlusHint<<Zt::ArbitraryZt as ZipTypes>::Cw>>,
82 hint_int: Option<ZipPlusHint<<Zt::IntZt as ZipTypes>::Cw>>,
83 commitment_bin: ZipPlusCommitment,
84 commitment_arb: ZipPlusCommitment,
85 commitment_int: ZipPlusCommitment,
86
87 _phantom: PhantomData<(U, C)>,
88}
89
90#[derive(Clone, Debug)]
93pub struct ProverProjectedCombined<
94 'a,
95 Zt: ZincTypes<D, FD>,
96 U: Uair,
97 C: BaseFieldConfig,
98 const D: usize,
99 const FD: usize,
100> {
101 base: ProverCommitted<'a, Zt, U, C, D, FD>,
102 field_cfg: C,
103 projected_trace: RowMajorTrace<C::Element>,
104 projected_scalars_fx: ProjectedScalars<U::Scalar, DynamicPolynomial<C::Element>>,
105 all_field_cfgs: Vec<C>,
109 q_star_idx: usize,
111 fq_staging: Vec<FqProjStaging<U, C::Element>>,
119}
120
121#[derive(Clone, Debug)]
124pub struct ProverProjectedMleFirst<
125 'a,
126 Zt: ZincTypes<D, FD>,
127 U: Uair,
128 C: BaseFieldConfig,
129 const D: usize,
130 const FD: usize,
131> {
132 base: ProverCommitted<'a, Zt, U, C, D, FD>,
133 field_cfg: C,
134 projected_trace: ColumnMajorTrace<C::Element>,
135 projected_scalars_fx: ProjectedScalars<U::Scalar, DynamicPolynomial<C::Element>>,
136 all_field_cfgs: Vec<C>,
140 q_star_idx: usize,
142 fq_staging: Vec<FqProjStaging<U, C::Element>>,
149}
150
151#[derive(Clone, Debug)]
160pub struct FqProjStaging<U: Uair, F: Clone> {
161 projected_trace: ProjectedTrace<F>,
162 projected_scalars_fx: ProjectedScalars<U::Scalar, DynamicPolynomial<F>>,
163}
164
165#[derive(Clone, Debug)]
167pub struct ProverIdealChecked<
168 'a,
169 Zt: ZincTypes<D, FD>,
170 U: Uair,
171 C: BaseFieldConfig,
172 const D: usize,
173 const FD: usize,
174> {
175 base: ProverCommitted<'a, Zt, U, C, D, FD>,
176 field_cfg: C,
177 all_field_cfgs: Vec<C>,
181 q_star_idx: usize,
183 projected_trace: ProjectedTrace<C::Element>,
184 projected_scalars_fx: ProjectedScalars<U::Scalar, DynamicPolynomial<C::Element>>,
185 fq_staging: Vec<FqProjStaging<U, C::Element>>,
190
191 ic_proof: IdealCheckProof<C::Element>,
193 ic_eval_points: Vec<Vec<C::Element>>,
198 ic_proof_fq: Vec<IdealCheckProof<C::Element>>,
201}
202
203#[derive(Clone, Debug)]
205pub struct ProverEvalProjected<
206 'a,
207 Zt: ZincTypes<D, FD>,
208 U: Uair,
209 C: BaseFieldConfig,
210 const D: usize,
211 const FD: usize,
212> {
213 base: ProverCommitted<'a, Zt, U, C, D, FD>,
214 field_cfg: C,
215 all_field_cfgs: Vec<C>,
218 q_star_idx: usize,
220 projected_trace: ProjectedTrace<C::Element>,
221 projected_trace_fq: Vec<ProjectedTrace<C::Element>>,
226 ic_proof: IdealCheckProof<C::Element>,
227 ic_eval_points: Vec<Vec<C::Element>>,
231 ic_proof_fq: Vec<IdealCheckProof<C::Element>>,
232
233 projected_trace_f: Vec<DenseMultilinearExtension<C::Element>>,
235 bit_op_mles: Vec<DenseMultilinearExtension<C::Element>>,
238 projected_scalars_f: ProjectedScalars<U::Scalar, C::Element>,
239 projected_trace_f_fq: Vec<Vec<DenseMultilinearExtension<C::Element>>>,
245 bit_op_mles_fq: Vec<Vec<DenseMultilinearExtension<C::Element>>>,
248 projected_scalars_f_fq: Vec<ProjectedScalars<U::Scalar, C::Element>>,
253}
254
255#[allow(clippy::type_complexity)]
257#[derive(Clone, Debug)]
258pub struct ProverSumchecked<
259 'a,
260 Zt: ZincTypes<D, FD>,
261 U: Uair,
262 C: BaseFieldConfig,
263 const D: usize,
264 const FD: usize,
265> {
266 base: ProverCommitted<'a, Zt, U, C, D, FD>,
267 field_cfg: C,
268 all_field_cfgs: Vec<C>,
270 q_star_idx: usize,
272 projected_trace: ProjectedTrace<C::Element>,
273 projected_trace_fq: Vec<ProjectedTrace<C::Element>>,
277 ic_proof: IdealCheckProof<C::Element>,
278 ic_proof_fq: Vec<IdealCheckProof<C::Element>>,
279 projected_trace_f: Vec<DenseMultilinearExtension<C::Element>>,
286 bit_op_mles: Vec<DenseMultilinearExtension<C::Element>>,
288 projected_trace_f_fq: Vec<Vec<DenseMultilinearExtension<C::Element>>>,
293 bit_op_mles_fq: Vec<Vec<DenseMultilinearExtension<C::Element>>>,
295
296 cpr_proof: CombinedPolyResolverProof<C::Element>,
298 cpr_eval_point: Vec<C::Element>,
299 combined_sumcheck: MultiDegreeSumcheckProof<C::Element>,
300 cpr_proofs_fq: Vec<CombinedPolyResolverProof<C::Element>>,
304 cpr_eval_points_fq: Vec<Vec<C::Element>>,
308 combined_sumchecks_fq: Vec<MultiDegreeSumcheckProof<C::Element>>,
311 lookup_proof: Option<BatchedLookupProof<C::Element>>,
312 booleanity_proof: Option<BooleanityProof<C::Element>>,
313 affine_booleanity_proof: Option<BooleanityProof<C::Element>>,
314 alpha_prime_f: Option<C::Element>,
323}
324
325#[derive(Clone, Debug)]
327pub struct ProverMultipointEvaled<
328 'a,
329 Zt: ZincTypes<D, FD>,
330 U: Uair,
331 C: BaseFieldConfig,
332 const D: usize,
333 const FD: usize,
334> {
335 base: ProverCommitted<'a, Zt, U, C, D, FD>,
336 field_cfg: C,
337 all_field_cfgs: Vec<C>,
340 projected_trace: ProjectedTrace<C::Element>,
341 projected_trace_fq: Vec<ProjectedTrace<C::Element>>,
345 ic_proof: IdealCheckProof<C::Element>,
346 ic_proof_fq: Vec<IdealCheckProof<C::Element>>,
347 cpr_proof: CombinedPolyResolverProof<C::Element>,
348 combined_sumcheck: MultiDegreeSumcheckProof<C::Element>,
349 cpr_proofs_fq: Vec<CombinedPolyResolverProof<C::Element>>,
351 combined_sumchecks_fq: Vec<MultiDegreeSumcheckProof<C::Element>>,
353 lookup_proof: Option<BatchedLookupProof<C::Element>>,
354 booleanity_proof: Option<BooleanityProof<C::Element>>,
355 affine_booleanity_proof: Option<BooleanityProof<C::Element>>,
356
357 mp_proof: MultipointEvalProof<C::Element>,
359 r_0: Vec<C::Element>,
360 mp_proofs_fq: Vec<MultipointEvalProof<C::Element>>,
364 r_0_fq: Vec<Vec<C::Element>>,
369}
370
371#[derive(Clone, Debug)]
373pub struct ProverLifted<
374 'a,
375 Zt: ZincTypes<D, FD>,
376 U: Uair,
377 C: BaseFieldConfig,
378 const D: usize,
379 const FD: usize,
380> {
381 base: ProverCommitted<'a, Zt, U, C, D, FD>,
382 field_cfg: C,
383 ic_proof: IdealCheckProof<C::Element>,
384 ic_proof_fq: Vec<IdealCheckProof<C::Element>>,
385 cpr_proof: CombinedPolyResolverProof<C::Element>,
386 combined_sumcheck: MultiDegreeSumcheckProof<C::Element>,
387 cpr_proofs_fq: Vec<CombinedPolyResolverProof<C::Element>>,
388 combined_sumchecks_fq: Vec<MultiDegreeSumcheckProof<C::Element>>,
389 lookup_proof: Option<BatchedLookupProof<C::Element>>,
390 booleanity_proof: Option<BooleanityProof<C::Element>>,
391 affine_booleanity_proof: Option<BooleanityProof<C::Element>>,
392 mp_proof: MultipointEvalProof<C::Element>,
393 mp_proofs_fq: Vec<MultipointEvalProof<C::Element>>,
396
397 lifted_evals: Vec<Vec<DynamicPolynomial<C::Element>>>,
403 lifted_evals_pp: Option<Vec<DynamicPolynomial<C::Element>>>,
411 q_pp_cfg: C,
413 r_star: Vec<C::Element>,
416}
417
418#[derive(Clone, Debug)]
423pub struct ProverPcsOpened<
424 'a,
425 Zt: ZincTypes<D, FD>,
426 U: Uair,
427 C: BaseFieldConfig,
428 const D: usize,
429 const FD: usize,
430> {
431 base: ProverCommitted<'a, Zt, U, C, D, FD>,
432 field_cfg: C,
433 q_pp_cfg: C,
436 ic_proof: IdealCheckProof<C::Element>,
437 ic_proof_fq: Vec<IdealCheckProof<C::Element>>,
438 cpr_proof: CombinedPolyResolverProof<C::Element>,
439 combined_sumcheck: MultiDegreeSumcheckProof<C::Element>,
440 cpr_proofs_fq: Vec<CombinedPolyResolverProof<C::Element>>,
441 combined_sumchecks_fq: Vec<MultiDegreeSumcheckProof<C::Element>>,
442 lookup_proof: Option<BatchedLookupProof<C::Element>>,
443 booleanity_proof: Option<BooleanityProof<C::Element>>,
444 affine_booleanity_proof: Option<BooleanityProof<C::Element>>,
445 mp_proof: MultipointEvalProof<C::Element>,
446 mp_proofs_fq: Vec<MultipointEvalProof<C::Element>>,
448 lifted_evals: Vec<Vec<DynamicPolynomial<C::Element>>>,
452 lifted_evals_pp: Option<Vec<DynamicPolynomial<C::Element>>>,
454}
455
456macro_rules! impl_with_type_bounds {
463 ($type_name:ident { $($code:tt)* }) => {
464 impl<'a, Zt, U, C, const D: usize, const FD: usize> $type_name<'a, Zt, U, C, D, FD>
465 where
466 Zt: ZincTypes<D, FD>,
467 Zt::Int: ProjectableToField<C>,
468 Zt::CombR: MulByScalar<Zt::Chal>,
469 <Zt::ArbitraryZt as ZipTypes>::Eval: ProjectableToField<C>,
470 U: Uair<Prime = Zt::Fmod> + 'static,
471 C: BaseFieldConfig<Integer = Zt::Fmod>
472 + ProjectPrimitiveIntegersWithConfig
473 + ProjectElementWithConfig<Zt::Int>
474 + ProjectElementWithConfig<Zt::CombR>
475 + ProjectElementWithConfig<Zt::Chal>
476 + 'static,
477 C::Integer: ConstTranscribable,
478 {
479 $($code)*
480 }
481 };
482}
483
484impl<Zt, U, C, const D: usize, const FD: usize> ZincPlusPiop<Zt, U, C, D, FD>
485where
486 Zt: ZincTypes<D, FD>,
487 U: Uair<Prime = Zt::Fmod>,
488 C: BaseFieldConfig,
489 C::Integer: ConstTranscribable,
490{
491 #[allow(clippy::type_complexity)]
493 pub fn step0_fold<'a>(
494 trace: &'a UairTrace<'static, Zt::Int, Zt::Int, D, D>,
495 ) -> Result<ProverFolded<'a, Zt, U, C, D, FD>, ProtocolError<C::Element>> {
496 let uair_signature = U::signature();
497 let witness_trace = trace.witness(&uair_signature);
498
499 let folded_bin_witness_trace = cfg_iter!(witness_trace.binary_poly)
500 .map(Zt::BinaryFold::fold_trace_mle)
501 .collect();
502
503 let folded_witness_trace = UairTrace {
504 binary_poly: Cow::Owned(folded_bin_witness_trace),
505 arbitrary_poly: witness_trace.arbitrary_poly.clone(),
506 int: witness_trace.int.clone(),
507 };
508
509 Ok(ProverFolded {
510 uair_signature,
511 original_trace: trace,
512 folded_witness_trace,
513 _phantom: PhantomData,
514 })
515 }
516}
517
518impl_with_type_bounds!(ProverFolded
519{
520 #[allow(clippy::type_complexity)]
524 pub fn step1_commit(
525 self,
526 (pp_bin, pp_arb, pp_int): &'a (
527 ZipPlusParams<Zt::BinaryZt, Zt::BinaryLc>,
528 ZipPlusParams<Zt::ArbitraryZt, Zt::ArbitraryLc>,
529 ZipPlusParams<Zt::IntZt, Zt::IntLc>,
530 ),
531 num_vars: usize,
532 ) -> Result<ProverCommitted<'a, Zt, U, C, D, FD>, ProtocolError<C::Element>> {
533 let sig = &self.uair_signature;
534 let public_trace = self.original_trace.public(sig);
535
536 let (res_bin, (res_arb, res_int)) = cfg_join!(
537 commit_optionally(pp_bin, &self.folded_witness_trace.binary_poly),
538 commit_optionally(pp_arb, &self.folded_witness_trace.arbitrary_poly),
539 commit_optionally(pp_int, &self.folded_witness_trace.int),
540 );
541 let (hint_bin, commitment_bin) = res_bin?;
542 let (hint_arb, commitment_arb) = res_arb?;
543 let (hint_int, commitment_int) = res_int?;
544
545 let mut pcs_transcript = PcsProverTranscript::new_from_commitments(
546 [&commitment_bin, &commitment_arb, &commitment_int].into_iter(),
547 );
548
549 absorb_public_columns(&mut pcs_transcript.fs_transcript, &public_trace.binary_poly);
550 absorb_public_columns(
551 &mut pcs_transcript.fs_transcript,
552 &public_trace.arbitrary_poly,
553 );
554 absorb_public_columns(&mut pcs_transcript.fs_transcript, &public_trace.int);
555
556 Ok(ProverCommitted {
557 num_vars,
558 uair_signature: self.uair_signature,
559 original_trace: self.original_trace,
560 folded_witness_trace: self.folded_witness_trace,
561 pcs_transcript,
562 pp_bin,
563 pp_arb,
564 pp_int,
565 hint_bin,
566 hint_arb,
567 hint_int,
568 commitment_bin,
569 commitment_arb,
570 commitment_int,
571 _phantom: PhantomData,
572 })
573 }
574});
575
576impl_with_type_bounds!(ProverCommitted
577{
578 #[allow(clippy::type_complexity)]
579 fn project_common<S: Fn(&U::Scalar, &C) -> DynamicPolynomial<C::Element>>(
580 &mut self,
581 project_scalar: S,
582 ) -> Result<(C, ProjectedScalars<U::Scalar, DynamicPolynomial<C::Element>>), ProtocolError<C::Element>>
583 {
584 let field_cfg = self
585 .pcs_transcript
586 .fs_transcript
587 .get_random_field_cfg::<C, Zt::Fmod, Zt::PrimeTest>();
588
589 let projected_scalars_fx = project_scalars::<C, U>(&field_cfg, |s| project_scalar(s, &field_cfg));
590 Ok((field_cfg, projected_scalars_fx))
591 }
592
593 pub fn step2_combined<S: Fn(&U::Scalar, &C) -> DynamicPolynomial<C::Element> + Copy>(
598 mut self,
599 project_scalar: S,
600 ) -> Result<ProverProjectedCombined<'a, Zt, U, C, D, FD>, ProtocolError<C::Element>> {
601 let (field_cfg, projected_scalars_fx) = self.project_common(project_scalar)?;
602 let all_field_cfgs = build_all_cfgs::<C>(&self.uair_signature, field_cfg.clone());
603
604 let projected_trace = project_trace_coeffs_row_major(self.original_trace, &field_cfg);
605
606 let fq_cfgs = &all_field_cfgs[1..];
610 let mut fq_staging: Vec<FqProjStaging<U, C::Element>> = Vec::with_capacity(fq_cfgs.len());
611 for cfg_q_i in fq_cfgs.iter() {
612 let projected_trace_i =
613 project_trace_coeffs_row_major(self.original_trace, cfg_q_i);
614 let projected_scalars_i = project_scalars::<C, U>(cfg_q_i, |s| project_scalar(s, cfg_q_i));
615 fq_staging.push(FqProjStaging {
616 projected_trace: ProjectedTrace::RowMajor(projected_trace_i),
617 projected_scalars_fx: projected_scalars_i,
618 });
619 }
620
621 let q_star_idx = shared_challenge::compute_q_star_idx::<C>(&all_field_cfgs);
622
623 Ok(ProverProjectedCombined {
624 base: self,
625 field_cfg,
626 projected_trace,
627 projected_scalars_fx,
628 all_field_cfgs,
629 q_star_idx,
630 fq_staging,
631 })
632 }
633
634 pub fn step2_mle_first<S: Fn(&U::Scalar, &C) -> DynamicPolynomial<C::Element> + Copy>(
638 mut self,
639 project_scalar: S,
640 ) -> Result<ProverProjectedMleFirst<'a, Zt, U, C, D, FD>, ProtocolError<C::Element>> {
641 let (field_cfg, projected_scalars_fx) = self.project_common(project_scalar)?;
642 let all_field_cfgs = build_all_cfgs::<C>(&self.uair_signature, field_cfg.clone());
643
644 let projected_trace = project_trace_coeffs_column_major(self.original_trace, &field_cfg);
645
646 let fq_cfgs = &all_field_cfgs[1..];
647 let mut fq_staging: Vec<FqProjStaging<U, C::Element>> = Vec::with_capacity(fq_cfgs.len());
648 for cfg_q_i in fq_cfgs.iter() {
649 let projected_trace_i =
650 project_trace_coeffs_column_major(self.original_trace, cfg_q_i);
651 let projected_scalars_i = project_scalars::<C, U>(cfg_q_i, |s| project_scalar(s, cfg_q_i));
652 fq_staging.push(FqProjStaging {
653 projected_trace: ProjectedTrace::ColumnMajor(projected_trace_i),
654 projected_scalars_fx: projected_scalars_i,
655 });
656 }
657
658 let q_star_idx = shared_challenge::compute_q_star_idx::<C>(&all_field_cfgs);
659
660 Ok(ProverProjectedMleFirst {
661 base: self,
662 field_cfg,
663 projected_trace,
664 projected_scalars_fx,
665 all_field_cfgs,
666 q_star_idx,
667 fq_staging,
668 })
669 }
670});
671
672impl_with_type_bounds!(ProverProjectedCombined
673{
674 pub fn step3_ideal_check(
689 mut self,
690 ) -> Result<ProverIdealChecked<'a, Zt, U, C, D, FD>, ProtocolError<C::Element>> {
691 let num_constraints = count_constraints::<U>();
692
693 let q_star_cfg = &self.all_field_cfgs[self.q_star_idx];
696 let shared_eval_points: Vec<Vec<C::Element>> =
697 shared_challenge::sample_shared_field_challenges::<C>(
698 &mut self.base.pcs_transcript.fs_transcript,
699 self.base.num_vars,
700 q_star_cfg,
701 &self.all_field_cfgs,
702 );
703
704 let ic_proof = IdealCheckProtocol::<U>::prove_combined::<_, D>(
705 &mut self.base.pcs_transcript.fs_transcript,
706 &self.projected_trace,
707 &self.projected_scalars_fx,
708 0,
709 num_constraints.q,
710 &shared_eval_points[0],
711 &self.field_cfg,
712 )?;
713
714 let fq_cfgs = &self.all_field_cfgs[1..];
717 let mut ic_proof_fq: Vec<IdealCheckProof<C::Element>> = Vec::with_capacity(fq_cfgs.len());
718 for (prime_idx, (cfg_q_i, staging)) in
719 fq_cfgs.iter().zip(self.fq_staging.iter()).enumerate()
720 {
721 let family_idx = add!(prime_idx, 1);
722 let ProjectedTrace::RowMajor(ref trace_row) = staging.projected_trace else {
723 unreachable!("should be row-major staging")
724 };
725 let ic_proof_i = IdealCheckProtocol::<U>::prove_combined::<_, D>(
726 &mut self.base.pcs_transcript.fs_transcript,
727 trace_row,
728 &staging.projected_scalars_fx,
729 family_idx,
730 num_constraints.for_prime(prime_idx),
731 &shared_eval_points[family_idx],
732 cfg_q_i,
733 )
734 .map_err(|source| ProtocolError::FqIdealCheck {
735 prime_idx,
736 q: cfg_q_i.modulus().to_string(),
737 source,
738 })?;
739
740 ic_proof_fq.push(ic_proof_i);
741 }
742
743 Ok(ProverIdealChecked {
744 base: self.base,
745 field_cfg: self.field_cfg,
746 all_field_cfgs: self.all_field_cfgs,
747 q_star_idx: self.q_star_idx,
748 projected_trace: ProjectedTrace::RowMajor(self.projected_trace),
749 projected_scalars_fx: self.projected_scalars_fx,
750 fq_staging: self.fq_staging,
751 ic_proof,
752 ic_eval_points: shared_eval_points,
753 ic_proof_fq,
754 })
755 }
756});
757
758impl_with_type_bounds!(ProverProjectedMleFirst
759{
760 pub fn step3_ideal_check(
771 mut self,
772 ) -> Result<ProverIdealChecked<'a, Zt, U, C, D, FD>, ProtocolError<C::Element>> {
773 let num_constraints = count_constraints::<U>();
776
777 let q_star_cfg = &self.all_field_cfgs[self.q_star_idx];
780 let shared_eval_points: Vec<Vec<C::Element>> =
781 shared_challenge::sample_shared_field_challenges::<C>(
782 &mut self.base.pcs_transcript.fs_transcript,
783 self.base.num_vars,
784 q_star_cfg,
785 &self.all_field_cfgs,
786 );
787
788 let ic_proof = IdealCheckProtocol::<U>::prove_mle_first::<_, D>(
789 &mut self.base.pcs_transcript.fs_transcript,
790 &self.projected_trace,
791 &self.projected_scalars_fx,
792 0,
793 num_constraints.q,
794 &shared_eval_points[0],
795 &self.field_cfg,
796 )?;
797
798 let fq_cfgs = &self.all_field_cfgs[1..];
802 let mut ic_proof_fq: Vec<IdealCheckProof<C::Element>> = Vec::with_capacity(fq_cfgs.len());
803 for (prime_idx, (cfg_q_i, staging)) in
804 fq_cfgs.iter().zip(self.fq_staging.iter()).enumerate()
805 {
806 let family_idx = add!(prime_idx, 1);
807 let ProjectedTrace::ColumnMajor(ref trace_col) = staging.projected_trace else {
808 unreachable!("should be column-major staging")
809 };
810 let ic_proof_i = IdealCheckProtocol::<U>::prove_mle_first::<_, D>(
811 &mut self.base.pcs_transcript.fs_transcript,
812 trace_col,
813 &staging.projected_scalars_fx,
814 family_idx,
815 num_constraints.for_prime(prime_idx),
816 &shared_eval_points[family_idx],
817 cfg_q_i,
818 )
819 .map_err(|source| ProtocolError::FqIdealCheck {
820 prime_idx,
821 q: cfg_q_i.modulus().to_string(),
822 source,
823 })?;
824
825 ic_proof_fq.push(ic_proof_i);
826 }
827
828 Ok(ProverIdealChecked {
829 base: self.base,
830 field_cfg: self.field_cfg,
831 all_field_cfgs: self.all_field_cfgs,
832 q_star_idx: self.q_star_idx,
833 projected_trace: ProjectedTrace::ColumnMajor(self.projected_trace),
834 projected_scalars_fx: self.projected_scalars_fx,
835 fq_staging: self.fq_staging,
836 ic_proof,
837 ic_eval_points: shared_eval_points,
838 ic_proof_fq,
839 })
840 }
841});
842
843impl_with_type_bounds!(ProverIdealChecked
844{
845 pub fn step4_eval_projection(
859 mut self,
860 ) -> Result<ProverEvalProjected<'a, Zt, U, C, D, FD>, ProtocolError<C::Element>> {
861 let q_star_cfg = &self.all_field_cfgs[self.q_star_idx];
862 let projecting_elements: Vec<C::Element> = shared_challenge::sample_shared_field_challenge::<C>(
863 &mut self.base.pcs_transcript.fs_transcript,
864 q_star_cfg,
865 &self.all_field_cfgs,
866 );
867
868 let projected_trace_f = evaluate_trace_to_column_mles(
870 &self.field_cfg,
871 &self.projected_trace,
872 &projecting_elements[0],
873 );
874
875 let bit_op_specs = self.base.uair_signature.bit_op_specs().to_vec();
876 let bit_op_mles = bit_op_specs
877 .iter()
878 .map(|spec| {
879 build_bit_op_virtual_mle::<C, D>(
880 &self.projected_trace,
881 spec,
882 &projecting_elements[0],
883 &self.field_cfg,
884 )
885 })
886 .collect();
887
888 let projected_scalars_f = project_scalars_to_field(
889 &self.field_cfg,
890 self.projected_scalars_fx,
891 &projecting_elements[0],
892 )
893 .map_err(|(_s, _f, e)| ProtocolError::ScalarProjection(e))?;
894
895 let n_fq = self.fq_staging.len();
902 let mut projected_trace_fq: Vec<ProjectedTrace<C::Element>> = Vec::with_capacity(n_fq);
903 let mut projected_trace_f_fq: Vec<Vec<DenseMultilinearExtension<C::Element>>> =
904 Vec::with_capacity(n_fq);
905 let mut bit_op_mles_fq: Vec<Vec<DenseMultilinearExtension<C::Element>>> =
906 Vec::with_capacity(n_fq);
907 let mut projected_scalars_f_fq: Vec<ProjectedScalars<U::Scalar, C::Element>> =
908 Vec::with_capacity(n_fq);
909 for (prime_idx, staging) in self.fq_staging.into_iter().enumerate() {
910 let family_idx = add!(prime_idx, 1);
911 let FqProjStaging {
912 projected_trace: projected_trace_i,
913 projected_scalars_fx: scalars_fx_i,
914 } = staging;
915 let trace_f_i = evaluate_trace_to_column_mles(
916 &self.all_field_cfgs[family_idx],
917 &projected_trace_i,
918 &projecting_elements[family_idx],
919 );
920 let bit_op_mles_i = bit_op_specs
921 .iter()
922 .map(|spec| {
923 build_bit_op_virtual_mle::<C, D>(
924 &projected_trace_i,
925 spec,
926 &projecting_elements[family_idx],
927 &self.all_field_cfgs[family_idx],
928 )
929 })
930 .collect();
931 let scalars_f_i = project_scalars_to_field(
932 &self.all_field_cfgs[family_idx],
933 scalars_fx_i,
934 &projecting_elements[family_idx],
935 )
936 .map_err(|(_s, _f, e)| ProtocolError::ScalarProjection(e))?;
937 projected_trace_fq.push(projected_trace_i);
938 projected_trace_f_fq.push(trace_f_i);
939 bit_op_mles_fq.push(bit_op_mles_i);
940 projected_scalars_f_fq.push(scalars_f_i);
941 }
942
943 Ok(ProverEvalProjected {
944 base: self.base,
945 field_cfg: self.field_cfg,
946 all_field_cfgs: self.all_field_cfgs,
947 q_star_idx: self.q_star_idx,
948 projected_trace: self.projected_trace,
949 projected_trace_fq,
950 ic_proof: self.ic_proof,
951 ic_eval_points: self.ic_eval_points,
952 ic_proof_fq: self.ic_proof_fq,
953 projected_trace_f,
954 bit_op_mles,
955 projected_scalars_f,
956 projected_trace_f_fq,
957 bit_op_mles_fq,
958 projected_scalars_f_fq,
959 })
960 }
961});
962
963impl_with_type_bounds!(ProverEvalProjected
964{
965 pub fn step5_sumcheck(
993 mut self,
994 ) -> Result<ProverSumchecked<'a, Zt, U, C, D, FD>, ProtocolError<C::Element>> {
995 let num_constraints = count_constraints::<U>();
996 let max_degree = count_max_degree::<U>();
997
998 let q_star_cfg_owned = self.all_field_cfgs[self.q_star_idx].clone();
1003 let folding_challenges: Vec<C::Element> = shared_challenge::sample_shared_field_challenge::<C>(
1004 &mut self.base.pcs_transcript.fs_transcript,
1005 &q_star_cfg_owned,
1006 &self.all_field_cfgs,
1007 );
1008
1009 let (q_cpr_group, q_cpr_ancillary) = CombinedPolyResolver::prepare_sumcheck_group::<U>(
1011 self.projected_trace_f.clone(),
1012 self.bit_op_mles.clone(),
1013 &self.ic_eval_points[0],
1014 &self.projected_scalars_f,
1015 0,
1016 num_constraints.q,
1017 self.base.num_vars,
1018 max_degree,
1019 &folding_challenges[0],
1020 &self.field_cfg,
1021 )?;
1022
1023 let mut q_groups = vec![q_cpr_group];
1024
1025 let sig = &self.base.uair_signature;
1028 let num_pub_bin = sig.public_cols().num_binary_poly_cols();
1029 let num_total_bin = sig.total_cols().num_binary_poly_cols();
1030 let trace_wit_bin_poly = &self.base.original_trace.binary_poly[num_pub_bin..num_total_bin];
1031
1032 let bool_ancillary = if !trace_wit_bin_poly.is_empty() {
1033 let (bool_group, anc) = BooleanityChecker::prepare_sumcheck_group::<D>(
1034 &mut self.base.pcs_transcript.fs_transcript,
1035 trace_wit_bin_poly,
1036 self.base.num_vars,
1037 &self.field_cfg,
1038 )
1039 .map_err(ProtocolError::Booleanity)?;
1040 q_groups.push(bool_group);
1041 Some(anc)
1042 } else {
1043 None
1044 };
1045
1046 let affine_bool_ancillary = if sig.affine_virtual_specs().is_empty() {
1050 None
1051 } else {
1052 let (affine_group, anc) =
1053 BooleanityChecker::prepare_affine_virtual_sumcheck_group::<D>(
1054 &mut self.base.pcs_transcript.fs_transcript,
1055 &self.base.original_trace.binary_poly,
1056 sig.affine_virtual_specs(),
1057 self.base.num_vars,
1058 &self.field_cfg,
1059 )
1060 .map_err(ProtocolError::Booleanity)?;
1061 q_groups.push(affine_group);
1062 Some(anc)
1063 };
1064
1065 let n_fq = self.projected_trace_f_fq.len();
1073 let mut fq_cpr_ancillaries: Vec<_> = Vec::with_capacity(n_fq);
1074 let mut fq_family_groups: Vec<Vec<MultiDegreeSumcheckGroup<C>>> =
1075 Vec::with_capacity(n_fq);
1076 for prime_idx in 0..n_fq {
1077 let family_idx = add!(prime_idx, 1);
1078 let cfg_i = &self.all_field_cfgs[family_idx];
1079 let trace_f_i = self.projected_trace_f_fq[prime_idx].clone();
1080 let scalars_f_i = &self.projected_scalars_f_fq[prime_idx];
1081 let eval_point_i = &self.ic_eval_points[family_idx];
1082 let folding_i = &folding_challenges[family_idx];
1083 let (cpr_group_i, cpr_ancillary_i) =
1084 CombinedPolyResolver::prepare_sumcheck_group::<U>(
1085 trace_f_i,
1086 self.bit_op_mles_fq[prime_idx].clone(),
1087 eval_point_i,
1088 scalars_f_i,
1089 family_idx,
1090 num_constraints.for_prime(prime_idx),
1091 self.base.num_vars,
1092 max_degree,
1093 folding_i,
1094 cfg_i,
1095 )?;
1096 fq_family_groups.push(vec![cpr_group_i]);
1097 fq_cpr_ancillaries.push(cpr_ancillary_i);
1098 }
1099
1100 let mut md_sc_families: Vec<(Vec<MultiDegreeSumcheckGroup<C>>, &C)> =
1104 Vec::with_capacity(add!(n_fq, 1));
1105 md_sc_families.push((q_groups, &self.field_cfg));
1106 for (prime_idx, groups) in fq_family_groups.into_iter().enumerate() {
1107 let family_idx = add!(prime_idx, 1);
1108 md_sc_families.push((groups, &self.all_field_cfgs[family_idx]));
1109 }
1110
1111 let mut sumcheck_outputs = MultiDegreeSumcheck::prove_as_subprotocol(
1112 &mut self.base.pcs_transcript.fs_transcript,
1113 md_sc_families,
1114 self.base.num_vars,
1115 &q_star_cfg_owned,
1116 )
1117 .into_iter();
1118
1119 let (combined_sumcheck, md_states) =
1121 sumcheck_outputs.next().expect("Q[X] family always present");
1122 let mut md_iter = md_states.into_iter();
1123
1124 let (cpr_proof, cpr_prover_state) = CombinedPolyResolver::finalize_prover::<U>(
1125 &mut self.base.pcs_transcript.fs_transcript,
1126 md_iter.next().expect("CPR group always present"),
1127 q_cpr_ancillary,
1128 &self.field_cfg,
1129 )?;
1130
1131 let mut finalize_booleanity_group = |ancillary: Option<BoolProverAncillary>| {
1132 ancillary
1133 .map(|ancillary| {
1134 BooleanityChecker::finalize_prover(
1135 &mut self.base.pcs_transcript.fs_transcript,
1136 md_iter.next().expect("booleanity group present"),
1137 ancillary,
1138 &self.field_cfg,
1139 )
1140 .map_err(ProtocolError::Booleanity)
1141 })
1142 .transpose()
1143 };
1144 let booleanity_proof = finalize_booleanity_group(bool_ancillary)?;
1145 let affine_booleanity_proof = finalize_booleanity_group(affine_bool_ancillary)?;
1146 debug_assert!(md_iter.next().is_none());
1147
1148 let lookup_proof = None;
1150
1151 let mut cpr_proofs_fq: Vec<CombinedPolyResolverProof<C::Element>> = Vec::with_capacity(n_fq);
1156 let mut cpr_eval_points_fq: Vec<Vec<C::Element>> = Vec::with_capacity(n_fq);
1157 let mut combined_sumchecks_fq: Vec<MultiDegreeSumcheckProof<C::Element>> =
1158 Vec::with_capacity(n_fq);
1159 for (prime_idx, cpr_ancillary_i) in fq_cpr_ancillaries.into_iter().enumerate() {
1160 let family_idx = add!(prime_idx, 1);
1161 let cfg_i = &self.all_field_cfgs[family_idx];
1162 let (sumcheck_i, states_i) =
1163 sumcheck_outputs.next().expect("fq family sumcheck output");
1164 let mut states_iter_i = states_i.into_iter();
1165 let (cpr_proof_i, cpr_state_i) = CombinedPolyResolver::finalize_prover::<U>(
1166 &mut self.base.pcs_transcript.fs_transcript,
1167 states_iter_i.next().expect("CPR group always present"),
1168 cpr_ancillary_i,
1169 cfg_i,
1170 )?;
1171 combined_sumchecks_fq.push(sumcheck_i);
1172 cpr_proofs_fq.push(cpr_proof_i);
1173 cpr_eval_points_fq.push(cpr_state_i.evaluation_point);
1174 }
1175
1176 let alpha_prime_f: Option<C::Element> =
1179 (booleanity_proof.is_some() || affine_booleanity_proof.is_some()).then(|| {
1180 self.base
1181 .pcs_transcript
1182 .fs_transcript
1183 .get_field_challenge(&self.field_cfg)
1184 });
1185
1186 Ok(ProverSumchecked {
1187 base: self.base,
1188 field_cfg: self.field_cfg,
1189 all_field_cfgs: self.all_field_cfgs,
1190 q_star_idx: self.q_star_idx,
1191 projected_trace: self.projected_trace,
1192 projected_trace_fq: self.projected_trace_fq,
1193 ic_proof: self.ic_proof,
1194 ic_proof_fq: self.ic_proof_fq,
1195 projected_trace_f: self.projected_trace_f,
1196 bit_op_mles: self.bit_op_mles,
1197 projected_trace_f_fq: self.projected_trace_f_fq,
1198 bit_op_mles_fq: self.bit_op_mles_fq,
1199 cpr_proof,
1200 cpr_eval_point: cpr_prover_state.evaluation_point,
1201 combined_sumcheck,
1202 cpr_proofs_fq,
1203 cpr_eval_points_fq,
1204 combined_sumchecks_fq,
1205 lookup_proof,
1206 booleanity_proof,
1207 affine_booleanity_proof,
1208 alpha_prime_f,
1209 })
1210 }
1211});
1212
1213impl_with_type_bounds!(ProverSumchecked
1214{
1215 #[allow(clippy::arithmetic_side_effects, clippy::too_many_lines)]
1239 pub fn step6_multipoint_eval(
1240 mut self,
1241 ) -> Result<ProverMultipointEvaled<'a, Zt, U, C, D, FD>, ProtocolError<C::Element>> {
1242 let n_fq = self.projected_trace_f_fq.len();
1243 let q_star_cfg = self.all_field_cfgs[self.q_star_idx].clone();
1244 let shifts = self.base.uair_signature.shifts();
1245 let num_vars = self.base.num_vars;
1246
1247 let mut projected_trace_f = self.projected_trace_f;
1260 let (q_up_evals, num_wit_bin) = if let Some(alpha_prime) =
1261 &self.alpha_prime_f
1262 {
1263 let sig = &self.base.uair_signature;
1264 let num_pub_bin = sig.public_cols().num_binary_poly_cols();
1265 let num_total_bin = sig.total_cols().num_binary_poly_cols();
1266 let num_wit_bin = num_total_bin.saturating_sub(num_pub_bin);
1267
1268 let alpha_powers: Vec<C::Element> = powers(&self.field_cfg, alpha_prime, D);
1272 let bin_cols = &self.base.original_trace.binary_poly[num_pub_bin..num_total_bin];
1273 let extra_trace_mles: Vec<DenseMultilinearExtension<C::Element>> = cfg_iter!(bin_cols)
1274 .map(|col| project_binary_col_at_field::<C, D>(col, &alpha_powers, &self.field_cfg))
1275 .collect();
1276 debug_assert_eq!(extra_trace_mles.len(), num_wit_bin);
1277
1278 let extra_up_evals = if num_wit_bin == 0 {
1279 debug_assert!(self.booleanity_proof.is_none());
1280 Vec::new()
1281 } else {
1282 let proof = self
1283 .booleanity_proof
1284 .as_ref()
1285 .expect("witness binary columns require a booleanity proof");
1286 collapse_bit_slice_evals::<C, D>(
1287 &proof.bit_slice_evals,
1288 num_wit_bin,
1289 alpha_prime,
1290 &self.field_cfg,
1291 )
1292 };
1293
1294 projected_trace_f.extend(extra_trace_mles);
1295
1296 let mut up_evals = self.cpr_proof.up_evals.clone();
1297 up_evals.extend(extra_up_evals);
1298 (up_evals, num_wit_bin)
1299 } else {
1300 (self.cpr_proof.up_evals.clone(), 0)
1301 };
1302
1303 let extension_size = 1usize << num_vars;
1312 let mut fq_trace_mles_padded: Vec<Vec<DenseMultilinearExtension<C::Element>>> =
1313 Vec::with_capacity(n_fq);
1314 let mut fq_up_evals_padded: Vec<Vec<C::Element>> = Vec::with_capacity(n_fq);
1315 for (prime_idx, mut trace_i) in self.projected_trace_f_fq.into_iter().enumerate() {
1316 let family_idx = add!(prime_idx, 1);
1317 let cfg_i = &self.all_field_cfgs[family_idx];
1318 let zero_i = cfg_i.zero();
1319
1320 if num_wit_bin > 0 {
1321 let zero_mle = DenseMultilinearExtension::from_evaluations_vec(
1322 num_vars,
1323 vec![zero_i.clone(); extension_size],
1324 zero_i.clone(),
1325 );
1326 trace_i.extend((0..num_wit_bin).map(|_| zero_mle.clone()));
1327 }
1328 fq_trace_mles_padded.push(trace_i);
1329
1330 let mut up_i = self.cpr_proofs_fq[prime_idx].up_evals.clone();
1331 up_i.extend((0..num_wit_bin).map(|_| zero_i.clone()));
1332 fq_up_evals_padded.push(up_i);
1333 }
1334
1335 let mut all_families: Vec<MultipointEvalFamilyInputs<'_, C>> =
1341 Vec::with_capacity(add!(n_fq, 1));
1342 all_families.push(MultipointEvalFamilyInputs {
1343 field_cfg: &self.field_cfg,
1344 trace_mles: &projected_trace_f,
1345 bit_op_mles: &self.bit_op_mles,
1346 eval_point: &self.cpr_eval_point,
1347 up_evals: &q_up_evals,
1348 bit_op_evals: &self.cpr_proof.bit_op_evals,
1349 down_evals: &self.cpr_proof.down_evals,
1350 });
1351 for prime_idx in 0..n_fq {
1352 let family_idx = add!(prime_idx, 1);
1353 all_families.push(MultipointEvalFamilyInputs {
1354 field_cfg: &self.all_field_cfgs[family_idx],
1355 trace_mles: &fq_trace_mles_padded[prime_idx],
1356 bit_op_mles: &self.bit_op_mles_fq[prime_idx],
1357 eval_point: &self.cpr_eval_points_fq[prime_idx],
1358 up_evals: &fq_up_evals_padded[prime_idx],
1359 bit_op_evals: &self.cpr_proofs_fq[prime_idx].bit_op_evals,
1360 down_evals: &self.cpr_proofs_fq[prime_idx].down_evals,
1361 });
1362 }
1363
1364 let mut outputs_iter = MultipointEval::prove_as_subprotocol(
1365 &mut self.base.pcs_transcript.fs_transcript,
1366 all_families,
1367 shifts,
1368 &q_star_cfg,
1369 )?
1370 .into_iter();
1371
1372 let (mp_proof_q, q_state) = outputs_iter.next().expect("Q-family present");
1373 let r_0_q = q_state.eval_point;
1374
1375 let mut mp_proofs_fq: Vec<MultipointEvalProof<C::Element>> = Vec::with_capacity(n_fq);
1376 let mut r_0_fq: Vec<Vec<C::Element>> = Vec::with_capacity(n_fq);
1377 for (proof_i, state_i) in outputs_iter {
1378 mp_proofs_fq.push(proof_i);
1379 r_0_fq.push(state_i.eval_point);
1380 }
1381
1382 Ok(ProverMultipointEvaled {
1383 base: self.base,
1384 field_cfg: self.field_cfg,
1385 all_field_cfgs: self.all_field_cfgs,
1386 projected_trace: self.projected_trace,
1387 projected_trace_fq: self.projected_trace_fq,
1388 ic_proof: self.ic_proof,
1389 ic_proof_fq: self.ic_proof_fq,
1390 cpr_proof: self.cpr_proof,
1391 combined_sumcheck: self.combined_sumcheck,
1392 cpr_proofs_fq: self.cpr_proofs_fq,
1393 combined_sumchecks_fq: self.combined_sumchecks_fq,
1394 lookup_proof: self.lookup_proof,
1395 booleanity_proof: self.booleanity_proof,
1396 affine_booleanity_proof: self.affine_booleanity_proof,
1397 mp_proof: mp_proof_q,
1398 r_0: r_0_q,
1399 mp_proofs_fq,
1400 r_0_fq,
1401 })
1402 }
1403});
1404
1405impl_with_type_bounds!(ProverMultipointEvaled
1406{
1407 #[allow(clippy::arithmetic_side_effects)]
1441 pub fn step7_lift_and_project(
1442 mut self,
1443 ) -> Result<ProverLifted<'a, Zt, U, C, D, FD>, ProtocolError<C::Element>> {
1444 let n_fq = self.r_0_fq.len();
1445
1446 let (q_pp_cfg, r_star) = if n_fq == 0 {
1453 (self.field_cfg.clone(), self.r_0.clone())
1454 } else {
1455 let cfg = self.base
1456 .pcs_transcript
1457 .fs_transcript
1458 .get_random_field_cfg::<C, Zt::Fmod, Zt::PrimeTest>();
1459 let r_star = self
1460 .r_0
1461 .iter()
1462 .map(|x| self.field_cfg.lift(x))
1463 .map(|x| cfg.project(&x))
1464 .collect();
1465 (cfg, r_star)
1466 };
1467
1468 let sig = self.base.uair_signature.clone();
1472 let pub_cols = sig.public_cols();
1473 let num_pub_bin = pub_cols.num_binary_poly_cols();
1474 let num_pub_arb = pub_cols.num_arbitrary_poly_cols();
1475 let num_pub_int = pub_cols.num_int_cols();
1476 let total = sig.total_cols();
1477 let num_total_bin = total.num_binary_poly_cols();
1478 let num_total_arb = total.num_arbitrary_poly_cols();
1479 let witness = sig.witness_cols();
1480 let witness_arb_offset = add!(num_total_bin, num_pub_arb);
1481 let witness_arb_end = add!(witness_arb_offset, witness.num_arbitrary_poly_cols());
1482 let witness_int_offset = add!(add!(num_total_bin, num_total_arb), num_pub_int);
1483
1484 let witness_only =
1485 |all: &[DynamicPolynomial<C::Element>]| -> Vec<DynamicPolynomial<C::Element>> {
1486 all[num_pub_bin..num_total_bin]
1487 .iter()
1488 .chain(&all[witness_arb_offset..witness_arb_end])
1489 .chain(&all[witness_int_offset..])
1490 .cloned()
1491 .collect()
1492 };
1493
1494 let mut lifted_evals: Vec<Vec<DynamicPolynomial<C::Element>>> =
1498 Vec::with_capacity(add!(n_fq, 1));
1499
1500 let q_lifted_all = compute_lifted_evals(
1505 &self.r_0,
1506 &self.base.original_trace.binary_poly,
1507 &self.projected_trace,
1508 &self.field_cfg,
1509 );
1510 lifted_evals.push(witness_only(&q_lifted_all));
1511
1512 debug_assert_eq!(self.projected_trace_fq.len(), n_fq);
1517 for (prime_idx, projected_trace_i) in self.projected_trace_fq.iter().enumerate() {
1518 let family_idx = add!(prime_idx, 1);
1519 let cfg_i = &self.all_field_cfgs[family_idx];
1520 let r_0_i = &self.r_0_fq[prime_idx];
1521 let lifted_evals_i = compute_lifted_evals(
1522 r_0_i,
1523 &self.base.original_trace.binary_poly,
1524 projected_trace_i,
1525 cfg_i,
1526 );
1527 lifted_evals.push(witness_only(&lifted_evals_i));
1528 }
1529
1530 let lifted_evals_pp = if n_fq == 0 {
1536 None
1537 } else {
1538 let projected_trace_pp = project_trace_coeffs_row_major::<C, Zt::Int, Zt::Int, D, D>(
1539 self.base.original_trace,
1540 &q_pp_cfg,
1541 );
1542 let lifted_evals_pp_full = compute_lifted_evals(
1543 &r_star,
1544 &self.base.original_trace.binary_poly,
1545 &ProjectedTrace::RowMajor(projected_trace_pp),
1546 &q_pp_cfg,
1547 );
1548 Some(witness_only(&lifted_evals_pp_full))
1549 };
1550
1551 let mut transcription_buf: Vec<u8> = vec![0; C::Integer::NUM_BYTES];
1555 debug_assert_eq!(self.all_field_cfgs.len(), lifted_evals.len());
1556 for (cfg_i, lifted_i) in self.all_field_cfgs.iter().zip(&lifted_evals) {
1557 for bar_u in lifted_i {
1558 self.base
1559 .pcs_transcript
1560 .fs_transcript
1561 .absorb_field_element_slice(cfg_i, &bar_u.coeffs, &mut transcription_buf);
1562 }
1563 }
1564 if let Some(ref lifted_pp) = lifted_evals_pp {
1565 for bar_u in lifted_pp.iter() {
1566 self.base
1567 .pcs_transcript
1568 .fs_transcript
1569 .absorb_field_element_slice(&q_pp_cfg, &bar_u.coeffs, &mut transcription_buf);
1570 }
1571 }
1572
1573 Ok(ProverLifted {
1574 base: self.base,
1575 field_cfg: self.field_cfg,
1576 ic_proof: self.ic_proof,
1577 ic_proof_fq: self.ic_proof_fq,
1578 cpr_proof: self.cpr_proof,
1579 combined_sumcheck: self.combined_sumcheck,
1580 cpr_proofs_fq: self.cpr_proofs_fq,
1581 combined_sumchecks_fq: self.combined_sumchecks_fq,
1582 lookup_proof: self.lookup_proof,
1583 booleanity_proof: self.booleanity_proof,
1584 affine_booleanity_proof: self.affine_booleanity_proof,
1585 mp_proof: self.mp_proof,
1586 mp_proofs_fq: self.mp_proofs_fq,
1587 lifted_evals,
1588 lifted_evals_pp,
1589 q_pp_cfg,
1590 r_star,
1591 })
1592 }
1593});
1594
1595impl_with_type_bounds!(ProverLifted
1596{
1597 pub fn step8_pcs_open<const CHECK_FOR_OVERFLOW: bool>(
1612 mut self,
1613 ) -> Result<ProverPcsOpened<'a, Zt, U, C, D, FD>, ProtocolError<C::Element>> {
1614 let witness_trace = &self.base.folded_witness_trace;
1615 let q_pp_cfg = &self.q_pp_cfg;
1616 let r_star = &self.r_star;
1617
1618 let mut r_star_ext = r_star.clone();
1622 let num_folding_challenges = Zt::BinaryFold::FOLDING_FACTOR.ilog2();
1623 (0..num_folding_challenges).for_each(|_| {
1624 let g_chal: Zt::Chal = self.base.pcs_transcript.fs_transcript.get_challenge();
1625 let gamma = q_pp_cfg.project(&g_chal);
1626 r_star_ext.push(gamma);
1627 });
1628
1629 if let Some(hint_bin) = &self.base.hint_bin {
1630 let _ = ZipPlus::<Zt::BinaryZt, Zt::BinaryLc>::prove_f::<_, CHECK_FOR_OVERFLOW>(
1631 &mut self.base.pcs_transcript,
1632 self.base.pp_bin,
1633 &witness_trace.binary_poly,
1634 &r_star_ext,
1635 hint_bin,
1636 q_pp_cfg,
1637 )?;
1638 }
1639 if let Some(hint_arb) = &self.base.hint_arb {
1640 let _ = ZipPlus::<Zt::ArbitraryZt, Zt::ArbitraryLc>::prove_f::<_, CHECK_FOR_OVERFLOW>(
1641 &mut self.base.pcs_transcript,
1642 self.base.pp_arb,
1643 &witness_trace.arbitrary_poly,
1644 r_star,
1645 hint_arb,
1646 q_pp_cfg,
1647 )?;
1648 }
1649 if let Some(hint_int) = &self.base.hint_int {
1650 let _ = ZipPlus::<Zt::IntZt, Zt::IntLc>::prove_f::<_, CHECK_FOR_OVERFLOW>(
1651 &mut self.base.pcs_transcript,
1652 self.base.pp_int,
1653 &witness_trace.int,
1654 r_star,
1655 hint_int,
1656 q_pp_cfg,
1657 )?;
1658 }
1659
1660 Ok(ProverPcsOpened {
1661 base: self.base,
1662 field_cfg: self.field_cfg,
1663 q_pp_cfg: self.q_pp_cfg,
1664 ic_proof: self.ic_proof,
1665 ic_proof_fq: self.ic_proof_fq,
1666 cpr_proof: self.cpr_proof,
1667 combined_sumcheck: self.combined_sumcheck,
1668 cpr_proofs_fq: self.cpr_proofs_fq,
1669 combined_sumchecks_fq: self.combined_sumchecks_fq,
1670 lookup_proof: self.lookup_proof,
1671 booleanity_proof: self.booleanity_proof,
1672 affine_booleanity_proof: self.affine_booleanity_proof,
1673 mp_proof: self.mp_proof,
1674 mp_proofs_fq: self.mp_proofs_fq,
1675 lifted_evals: self.lifted_evals,
1676 lifted_evals_pp: self.lifted_evals_pp,
1677 })
1678 }
1679});
1680
1681impl_with_type_bounds!(ProverPcsOpened
1682{
1683 pub fn finish(self) -> Result<Proof<Zt::Fmod>, ProtocolError<C::Element>> {
1686 let zip_proof = self.base.pcs_transcript.stream.into_inner();
1687 let commitments = (
1688 self.base.commitment_bin,
1689 self.base.commitment_arb,
1690 self.base.commitment_int,
1691 );
1692 let all_cfgs = build_all_cfgs::<C>(&self.base.uair_signature, self.field_cfg.clone());
1693
1694 macro_rules! lift {
1696 ($cfg:expr, $section:expr) => {
1697 $section.try_map(|e| Ok::<Zt::Fmod, ProtocolError<C::Element>>($cfg.lift(e)))
1698 };
1699 }
1700 macro_rules! lift_fq_vec {
1701 ($section:expr) => {
1702 $section
1703 .iter()
1704 .enumerate()
1705 .map(|(i, p)| lift!(all_cfgs[add!(i, 1)], p))
1706 .try_collect()
1707 };
1708 }
1709 let lift_polys = |cfg: &C,
1710 polys: &[DynamicPolynomial<C::Element>]|
1711 -> Result<Vec<DynamicPolynomial<Zt::Fmod>>, ProtocolError<C::Element>> {
1712 polys
1713 .iter()
1714 .map(|p| p.try_map(|e| Ok(cfg.lift(e))))
1715 .collect()
1716 };
1717
1718 let witness_lifted_evals = self
1719 .lifted_evals
1720 .iter()
1721 .enumerate()
1722 .map(|(i, polys)| lift_polys(&all_cfgs[i], polys))
1723 .collect::<Result<Vec<_>, _>>()?;
1724 let witness_lifted_evals_pp = self
1725 .lifted_evals_pp
1726 .as_ref()
1727 .map(|polys| lift_polys(&self.q_pp_cfg, polys))
1728 .transpose()?;
1729
1730 Ok(Proof {
1731 commitments,
1732 ideal_check: lift!(self.field_cfg, self.ic_proof)?,
1733 cpr_proof: lift!(self.field_cfg, self.cpr_proof)?,
1734 combined_sumcheck: lift!(self.field_cfg, self.combined_sumcheck)?,
1735 multipoint_eval: lift!(self.field_cfg, self.mp_proof)?,
1736 zip: zip_proof,
1737 witness_lifted_evals,
1738 lookup_proof: match &self.lookup_proof {
1739 Some(p) => Some(lift!(self.field_cfg, p)?),
1740 None => None,
1741 },
1742 booleanity_proof: match &self.booleanity_proof {
1743 Some(p) => Some(lift!(self.field_cfg, p)?),
1744 None => None,
1745 },
1746 affine_booleanity_proof: match &self.affine_booleanity_proof {
1747 Some(p) => Some(lift!(self.field_cfg, p)?),
1748 None => None,
1749 },
1750 ideal_checks_fq: lift_fq_vec!(self.ic_proof_fq)?,
1751 cpr_proofs_fq: lift_fq_vec!(self.cpr_proofs_fq)?,
1752 combined_sumchecks_fq: lift_fq_vec!(self.combined_sumchecks_fq)?,
1753 multipoint_evals_fq: lift_fq_vec!(self.mp_proofs_fq)?,
1754 witness_lifted_evals_pp,
1755 })
1756 }
1757});
1758
1759impl<Zt, U, C, const D: usize, const FD: usize> ZincPlusPiop<Zt, U, C, D, FD>
1764where
1765 Zt: ZincTypes<D, FD>,
1766 Zt::Int: ProjectableToField<C>,
1767 Zt::CombR: MulByScalar<Zt::Chal>,
1768 <Zt::ArbitraryZt as ZipTypes>::Eval: ProjectableToField<C>,
1769 C: BaseFieldConfig<Integer = Zt::Fmod>
1770 + ProjectPrimitiveIntegersWithConfig
1771 + ProjectElementWithConfig<Zt::Int>
1772 + ProjectElementWithConfig<Zt::CombR>
1773 + ProjectElementWithConfig<Zt::Chal>
1774 + Clone
1775 + Send
1776 + Sync
1777 + 'static,
1778 C::Integer: Display,
1779 U: Uair<Prime = Zt::Fmod> + 'static,
1780{
1781 #[allow(clippy::too_many_arguments, clippy::type_complexity)]
1787 pub fn prove<const MLE_FIRST: bool, const CHECK_FOR_OVERFLOW: bool>(
1788 pp: &(
1789 ZipPlusParams<Zt::BinaryZt, Zt::BinaryLc>,
1790 ZipPlusParams<Zt::ArbitraryZt, Zt::ArbitraryLc>,
1791 ZipPlusParams<Zt::IntZt, Zt::IntLc>,
1792 ),
1793 trace: &UairTrace<'static, Zt::Int, Zt::Int, D, D>,
1794 num_vars: usize,
1795 project_scalar: impl Fn(&U::Scalar, &C) -> DynamicPolynomial<C::Element> + Copy,
1796 ) -> Result<Proof<Zt::Fmod>, ProtocolError<C::Element>> {
1797 let committed = Self::step0_fold(trace)?.step1_commit(pp, num_vars)?;
1798
1799 let ideal_checked = if MLE_FIRST {
1800 committed
1801 .step2_mle_first(project_scalar)?
1802 .step3_ideal_check()?
1803 } else {
1804 committed
1805 .step2_combined(project_scalar)?
1806 .step3_ideal_check()?
1807 };
1808
1809 ideal_checked
1810 .step4_eval_projection()?
1811 .step5_sumcheck()?
1812 .step6_multipoint_eval()?
1813 .step7_lift_and_project()?
1814 .step8_pcs_open::<CHECK_FOR_OVERFLOW>()?
1815 .finish()
1816 }
1817}
1818
1819#[allow(clippy::type_complexity)]
1820fn commit_optionally<Zt: ZipTypes, Lc: LinearCode<Zt>>(
1821 pp: &ZipPlusParams<Zt, Lc>,
1822 trace: &[DenseMultilinearExtension<Zt::Eval>],
1823) -> Result<(Option<ZipPlusHint<Zt::Cw>>, ZipPlusCommitment), ZipError> {
1824 if trace.is_empty() {
1825 Ok((
1826 None,
1827 ZipPlusCommitment {
1828 root: Default::default(),
1829 batch_size: 0,
1830 },
1831 ))
1832 } else {
1833 let (hint, commitment) = ZipPlus::commit(pp, trace)?;
1834 Ok((Some(hint), commitment))
1835 }
1836}