1use derive_where::derive_where;
2use slop_basefold::FriConfig;
3use slop_merkle_tree::MerkleTreeTcs;
4#[allow(clippy::disallowed_types)]
5use slop_stacked::{StackedBasefoldProof, StackedPcsVerifier};
6use slop_whir::{Verifier, WhirProofShape};
7use sp1_primitives::{SP1GlobalContext, SP1OuterGlobalContext};
8use std::{
9 collections::{BTreeMap, BTreeSet},
10 iter::once,
11 marker::PhantomData,
12 ops::Deref,
13};
14
15use itertools::Itertools;
16use slop_air::{Air, BaseAir};
17use slop_algebra::{AbstractField, PrimeField32, TwoAdicField};
18use slop_challenger::{CanObserve, FieldChallenger, IopCtx, VariableLengthChallenger};
19use slop_commit::Rounds;
20use slop_jagged::{JaggedPcsVerifier, JaggedPcsVerifierError};
21use slop_matrix::dense::RowMajorMatrixView;
22use slop_multilinear::{full_geq, Evaluations, Mle, MleEval, MultilinearPcsVerifier};
23use slop_sumcheck::{partially_verify_sumcheck_proof, SumcheckError};
24use thiserror::Error;
25
26use crate::{
27 air::MachineAir,
28 prover::{CoreProofShape, PcsProof, ZerocheckAir},
29 Chip, ChipOpenedValues, LogUpEvaluations, LogUpGkrVerifier, LogupGkrVerificationError, Machine,
30 ShardContext, ShardContextImpl, VerifierConstraintFolder, MAX_CONSTRAINT_DEGREE,
31 PROOF_MAX_NUM_PVS, SP1SC,
32};
33
34use super::{MachineVerifyingKey, ShardOpenedValues, ShardProof};
35
36pub const NUM_SP1_COMMITMENTS: usize = 2;
39
40pub const GKR_GRINDING_BITS: usize = 12;
42
43#[allow(clippy::disallowed_types)]
44pub type SP1Pcs<GC> = StackedPcsVerifier<GC>;
46
47pub type SP1InnerPcs = SP1Pcs<SP1GlobalContext>;
49
50pub type SP1OuterPcs = SP1Pcs<SP1OuterGlobalContext>;
52
53#[allow(clippy::disallowed_types)]
55pub type SP1PcsProof<GC> = StackedBasefoldProof<GC>;
56
57pub type SP1PcsProofInner = SP1PcsProof<SP1GlobalContext>;
59
60pub type SP1PcsProofOuter = SP1PcsProof<SP1OuterGlobalContext>;
62
63#[derive_where(Clone)]
65pub struct ShardVerifier<GC: IopCtx, SC: ShardContext<GC>> {
66 pub jagged_pcs_verifier: JaggedPcsVerifier<GC, SC::Config>,
68 pub machine: Machine<GC::F, SC::Air>,
70}
71
72#[derive(Debug, Error)]
74pub enum ShardVerifierError<EF, PcsError> {
75 #[error("invalid pcs opening proof: {0}")]
77 InvalidopeningArgument(#[from] JaggedPcsVerifierError<EF, PcsError>),
78 #[error("constraints check failed: {0}")]
80 ConstraintsCheckFailed(SumcheckError),
81 #[error("cumulative sums error: {0}")]
83 CumulativeSumsError(&'static str),
84 #[error("preprocessed chip id mismatch: {0}")]
86 PreprocessedChipIdMismatch(String, String),
87 #[error("preprocessed chip height mismatch: {0}")]
90 PreprocessedChipHeightMismatch(String),
91 #[error("chip opening length mismatch")]
93 ChipOpeningLengthMismatch,
94 #[error("missing cpu chip")]
96 MissingCpuChip,
97 #[error("opening shape mismatch: {0}")]
99 OpeningShapeMismatch(#[from] OpeningShapeError),
100 #[error("GKR verification failed: {0}")]
102 GkrVerificationFailed(LogupGkrVerificationError<EF>),
103 #[error("public values verification failed")]
105 InvalidPublicValues,
106 #[error("invalid shape of proof")]
108 InvalidShape,
109 #[error("invalid chip opening order: ({0}, {1})")]
111 InvalidChipOrder(String, String),
112 #[error("invalid height bit decomposition")]
114 InvalidHeightBitDecomposition,
115 #[error("height is larger than maximum possible value")]
117 HeightTooLarge,
118}
119
120pub type ShardVerifierConfigError<GC, C> =
122 ShardVerifierError<<GC as IopCtx>::EF, <C as MultilinearPcsVerifier<GC>>::VerifierError>;
123
124#[derive(Debug, Error)]
126pub enum OpeningShapeError {
127 #[error("preprocessed width mismatch: {0} != {1}")]
129 PreprocessedWidthMismatch(usize, usize),
130 #[error("main width mismatch: {0} != {1}")]
132 MainWidthMismatch(usize, usize),
133}
134
135impl<GC: IopCtx, SC: ShardContext<GC>> ShardVerifier<GC, SC> {
136 pub fn new(
138 pcs_verifier: JaggedPcsVerifier<GC, SC::Config>,
139 machine: Machine<GC::F, SC::Air>,
140 ) -> Self {
141 Self { jagged_pcs_verifier: pcs_verifier, machine }
142 }
143
144 #[must_use]
146 #[inline]
147 pub fn max_log_row_count(&self) -> usize {
148 self.jagged_pcs_verifier.max_log_row_count
149 }
150
151 #[must_use]
153 #[inline]
154 pub fn machine(&self) -> &Machine<GC::F, SC::Air> {
155 &self.machine
156 }
157
158 #[must_use]
160 #[inline]
161 pub fn log_stacking_height(&self) -> u32 {
162 <SC::Config>::log_stacking_height(&self.jagged_pcs_verifier.pcs_verifier)
163 }
164
165 #[must_use]
167 #[inline]
168 pub fn challenger(&self) -> GC::Challenger {
169 self.jagged_pcs_verifier.challenger()
170 }
171
172 pub fn shape_from_proof(
174 &self,
175 proof: &ShardProof<GC, PcsProof<GC, SC>>,
176 ) -> CoreProofShape<GC::F, SC::Air> {
177 let shard_chips = self
178 .machine()
179 .chips()
180 .iter()
181 .filter(|air| proof.opened_values.chips.keys().any(|k| k == air.name()))
182 .cloned()
183 .collect::<BTreeSet<_>>();
184 debug_assert_eq!(shard_chips.len(), proof.opened_values.chips.len());
185
186 let multiples = <SC::Config>::round_multiples(&proof.evaluation_proof.pcs_proof);
187 let preprocessed_multiple = multiples[0];
188 let main_multiple = multiples[1];
189
190 let added_columns: Vec<usize> = proof
191 .evaluation_proof
192 .row_counts_and_column_counts
193 .iter()
194 .map(|cc| cc[cc.len() - 2].1 + 1)
195 .collect();
196
197 CoreProofShape {
198 shard_chips,
199 preprocessed_multiple,
200 main_multiple,
201 preprocessed_padding_cols: added_columns[0],
202 main_padding_cols: added_columns[1],
203 }
204 }
205
206 pub fn compute_padded_row_adjustment(
208 chip: &Chip<GC::F, SC::Air>,
209 alpha: GC::EF,
210 public_values: &[GC::F],
211 ) -> GC::EF
212where {
213 let dummy_preprocessed_trace = vec![GC::EF::zero(); chip.preprocessed_width()];
214 let dummy_main_trace = vec![GC::EF::zero(); chip.width()];
215
216 let mut folder = VerifierConstraintFolder::<GC::F, GC::EF> {
217 preprocessed: RowMajorMatrixView::new_row(&dummy_preprocessed_trace),
218 main: RowMajorMatrixView::new_row(&dummy_main_trace),
219 alpha,
220 accumulator: GC::EF::zero(),
221 public_values,
222 _marker: PhantomData,
223 };
224
225 chip.eval(&mut folder);
226
227 folder.accumulator
228 }
229
230 pub fn eval_constraints(
232 chip: &Chip<GC::F, SC::Air>,
233 opening: &ChipOpenedValues<GC::F, GC::EF>,
234 alpha: GC::EF,
235 public_values: &[GC::F],
236 ) -> GC::EF
237where {
238 let mut folder = VerifierConstraintFolder::<GC::F, GC::EF> {
239 preprocessed: RowMajorMatrixView::new_row(&opening.preprocessed.local),
240 main: RowMajorMatrixView::new_row(&opening.main.local),
241 alpha,
242 accumulator: GC::EF::zero(),
243 public_values,
244 _marker: PhantomData,
245 };
246
247 chip.eval(&mut folder);
248
249 folder.accumulator
250 }
251
252 fn verify_opening_shape(
253 chip: &Chip<GC::F, SC::Air>,
254 opening: &ChipOpenedValues<GC::F, GC::EF>,
255 ) -> Result<(), OpeningShapeError> {
256 if opening.preprocessed.local.len() != chip.preprocessed_width() {
258 return Err(OpeningShapeError::PreprocessedWidthMismatch(
259 chip.preprocessed_width(),
260 opening.preprocessed.local.len(),
261 ));
262 }
263
264 if opening.main.local.len() != chip.width() {
266 return Err(OpeningShapeError::MainWidthMismatch(
267 chip.width(),
268 opening.main.local.len(),
269 ));
270 }
271
272 Ok(())
273 }
274}
275
276impl<GC: IopCtx, SC: ShardContext<GC>> ShardVerifier<GC, SC>
277where
278 GC::F: PrimeField32,
279{
280 #[allow(clippy::too_many_arguments)]
282 #[allow(clippy::type_complexity)]
283 pub fn verify_zerocheck(
284 &self,
285 shard_chips: &BTreeSet<Chip<GC::F, SC::Air>>,
286 opened_values: &ShardOpenedValues<GC::F, GC::EF>,
287 gkr_evaluations: &LogUpEvaluations<GC::EF>,
288 proof: &ShardProof<GC, PcsProof<GC, SC>>,
289 public_values: &[GC::F],
290 challenger: &mut GC::Challenger,
291 ) -> Result<
292 (),
293 ShardVerifierError<GC::EF, <SC::Config as MultilinearPcsVerifier<GC>>::VerifierError>,
294 >
295where {
296 let max_log_row_count = self.jagged_pcs_verifier.max_log_row_count;
297
298 let alpha = challenger.sample_ext_element::<GC::EF>();
300
301 let gkr_batch_open_challenge = challenger.sample_ext_element::<GC::EF>();
302
303 let lambda = challenger.sample_ext_element::<GC::EF>();
305
306 if gkr_evaluations.point.dimension() != max_log_row_count
307 || proof.zerocheck_proof.point_and_eval.0.dimension() != max_log_row_count
308 {
309 return Err(ShardVerifierError::InvalidShape);
310 }
311
312 let zerocheck_eq_val = Mle::full_lagrange_eval(
314 &gkr_evaluations.point,
315 &proof.zerocheck_proof.point_and_eval.0,
316 );
317
318 let mut rlc_eval = GC::EF::zero();
321 for (chip, (chip_name, openings)) in shard_chips.iter().zip_eq(opened_values.chips.iter()) {
322 assert_eq!(chip.name(), chip_name);
323 Self::verify_opening_shape(chip, openings)?;
325
326 let mut point_extended = proof.zerocheck_proof.point_and_eval.0.clone();
327 point_extended.add_dimension(GC::EF::zero());
328 for &x in openings.degree.iter() {
329 if x * (x - GC::F::one()) != GC::F::zero() {
330 return Err(ShardVerifierError::InvalidHeightBitDecomposition);
331 }
332 }
333 for &x in openings.degree.iter().skip(1) {
334 if x * *openings.degree.first().unwrap() != GC::F::zero() {
335 return Err(ShardVerifierError::HeightTooLarge);
336 }
337 }
338
339 let geq_val = full_geq(&openings.degree, &point_extended);
340
341 let padded_row_adjustment =
342 Self::compute_padded_row_adjustment(chip, alpha, public_values);
343
344 let constraint_eval = Self::eval_constraints(chip, openings, alpha, public_values)
345 - padded_row_adjustment * geq_val;
346
347 let openings_batch = openings
348 .main
349 .local
350 .iter()
351 .chain(openings.preprocessed.local.iter())
352 .copied()
353 .zip(gkr_batch_open_challenge.powers().skip(1))
354 .map(|(opening, power)| opening * power)
355 .sum::<GC::EF>();
356
357 rlc_eval = rlc_eval * lambda + zerocheck_eq_val * (constraint_eval + openings_batch);
359 }
360
361 if proof.zerocheck_proof.point_and_eval.1 != rlc_eval {
362 return Err(ShardVerifierError::<
363 _,
364 <SC::Config as MultilinearPcsVerifier<GC>>::VerifierError,
365 >::ConstraintsCheckFailed(SumcheckError::InconsistencyWithEval));
366 }
367
368 let zerocheck_sum_modifications_from_gkr = gkr_evaluations
369 .chip_openings
370 .values()
371 .map(|chip_evaluation| {
372 chip_evaluation
373 .main_trace_evaluations
374 .deref()
375 .iter()
376 .copied()
377 .chain(
378 chip_evaluation
379 .preprocessed_trace_evaluations
380 .as_ref()
381 .iter()
382 .flat_map(|&evals| evals.deref().iter().copied()),
383 )
384 .zip(gkr_batch_open_challenge.powers().skip(1))
385 .map(|(opening, power)| opening * power)
386 .sum::<GC::EF>()
387 })
388 .collect::<Vec<_>>();
389
390 let zerocheck_sum_modification = zerocheck_sum_modifications_from_gkr
391 .iter()
392 .fold(GC::EF::zero(), |acc, modification| lambda * acc + *modification);
393
394 if proof.zerocheck_proof.claimed_sum != zerocheck_sum_modification {
397 return Err(ShardVerifierError::<
398 _,
399 <SC::Config as MultilinearPcsVerifier<GC>>::VerifierError,
400 >::ConstraintsCheckFailed(
401 SumcheckError::InconsistencyWithClaimedSum
402 ));
403 }
404
405 partially_verify_sumcheck_proof(
407 &proof.zerocheck_proof,
408 challenger,
409 max_log_row_count,
410 MAX_CONSTRAINT_DEGREE + 1,
411 )
412 .map_err(|e| {
413 ShardVerifierError::<
414 _,
415 <SC::Config as MultilinearPcsVerifier<GC>>::VerifierError,
416 >::ConstraintsCheckFailed(e)
417 })?;
418
419 let len = shard_chips.len();
421 challenger.observe(GC::F::from_canonical_usize(len));
422 for (_, opening) in opened_values.chips.iter() {
423 challenger.observe_variable_length_extension_slice(&opening.preprocessed.local);
424 challenger.observe_variable_length_extension_slice(&opening.main.local);
425 }
426
427 Ok(())
428 }
429
430 #[allow(clippy::too_many_lines)]
432 pub fn verify_shard(
433 &self,
434 vk: &MachineVerifyingKey<GC>,
435 proof: &ShardProof<GC, PcsProof<GC, SC>>,
436 challenger: &mut GC::Challenger,
437 ) -> Result<(), ShardVerifierConfigError<GC, SC::Config>>
438where {
439 let ShardProof {
440 main_commitment,
441 opened_values,
442 evaluation_proof,
443 zerocheck_proof,
444 public_values,
445 logup_gkr_proof,
446 } = proof;
447
448 let max_log_row_count = self.jagged_pcs_verifier.max_log_row_count;
449
450 if public_values.len() != PROOF_MAX_NUM_PVS
451 || public_values.len() < self.machine.num_pv_elts()
452 {
453 tracing::error!("invalid public values length: {}", public_values.len());
454 return Err(ShardVerifierError::InvalidPublicValues);
455 }
456
457 if public_values[self.machine.num_pv_elts()..].iter().any(|v| *v != GC::F::zero()) {
458 return Err(ShardVerifierError::InvalidPublicValues);
459 }
460 let shard_chips = opened_values.chips.keys().cloned().collect::<BTreeSet<_>>();
461
462 challenger.observe_constant_length_extension_slice(public_values);
464 challenger.observe(*main_commitment);
466 let shard_chips_len = shard_chips.len();
468 challenger.observe(GC::F::from_canonical_usize(shard_chips_len));
469
470 let mut heights: BTreeMap<String, GC::F> = BTreeMap::new();
471 for (name, chip_values) in opened_values.chips.iter() {
472 if chip_values.degree.len() != max_log_row_count + 1 || chip_values.degree.len() >= 30 {
473 return Err(ShardVerifierError::InvalidShape);
474 }
475 let acc =
476 chip_values.degree.iter().fold(GC::F::zero(), |acc, &x| x + GC::F::two() * acc);
477 heights.insert(name.clone(), acc);
478 challenger.observe(acc);
479 challenger.observe(GC::F::from_canonical_usize(name.len()));
480 for byte in name.as_bytes() {
481 challenger.observe(GC::F::from_canonical_u8(*byte));
482 }
483 }
484
485 let machine_chip_names =
486 self.machine.chips().iter().map(|c| c.name().to_string()).collect::<BTreeSet<_>>();
487
488 let preprocessed_chips = self
489 .machine
490 .chips()
491 .iter()
492 .filter(|chip| chip.preprocessed_width() != 0)
493 .collect::<BTreeSet<_>>();
494
495 if !shard_chips.is_subset(&machine_chip_names)
502 || !preprocessed_chips
503 .iter()
504 .map(|chip| chip.name().to_string())
505 .collect::<BTreeSet<_>>()
506 .is_subset(&shard_chips)
507 || evaluation_proof.row_counts_and_column_counts[0]
508 .iter()
509 .map(|&(_, c)| c)
510 .take(preprocessed_chips.len())
511 .collect::<Vec<_>>()
512 != preprocessed_chips
513 .iter()
514 .map(|chip| chip.preprocessed_width())
515 .collect::<Vec<_>>()
516 {
517 return Err(ShardVerifierError::InvalidShape);
518 }
519
520 let shard_chips = self
521 .machine
522 .chips()
523 .iter()
524 .filter(|chip| shard_chips.contains(chip.name()))
525 .cloned()
526 .collect::<BTreeSet<_>>();
527
528 if shard_chips.len() != shard_chips_len || shard_chips_len == 0 {
529 return Err(ShardVerifierError::InvalidShape);
530 }
531
532 if !self.machine().shape().chip_clusters.contains(&shard_chips) {
533 return Err(ShardVerifierError::InvalidShape);
534 }
535
536 let degrees = opened_values
537 .chips
538 .iter()
539 .map(|x| (x.0.clone(), x.1.degree.clone()))
540 .collect::<BTreeMap<_, _>>();
541
542 if shard_chips.len() != opened_values.chips.len()
543 || shard_chips.len() != degrees.len()
544 || shard_chips.len() != logup_gkr_proof.logup_evaluations.chip_openings.len()
545 {
546 return Err(ShardVerifierError::InvalidShape);
547 }
548
549 for ((shard_chip, (chip_name, _)), (gkr_chip_name, gkr_opened_values)) in shard_chips
550 .iter()
551 .zip_eq(opened_values.chips.iter())
552 .zip_eq(logup_gkr_proof.logup_evaluations.chip_openings.iter())
553 {
554 if shard_chip.name() != chip_name.as_str() {
555 return Err(ShardVerifierError::InvalidChipOrder(
556 shard_chip.name().to_string(),
557 chip_name.clone(),
558 ));
559 }
560 if shard_chip.name() != gkr_chip_name.as_str() {
561 return Err(ShardVerifierError::InvalidChipOrder(
562 shard_chip.name().to_string(),
563 gkr_chip_name.clone(),
564 ));
565 }
566
567 if gkr_opened_values
568 .preprocessed_trace_evaluations
569 .as_ref()
570 .map_or(0, MleEval::num_polynomials)
571 != shard_chip.preprocessed_width()
572 {
573 return Err(ShardVerifierError::InvalidShape);
574 }
575
576 if gkr_opened_values.main_trace_evaluations.len() != shard_chip.width() {
577 return Err(ShardVerifierError::InvalidShape);
578 }
579 }
580
581 LogUpGkrVerifier::<GC, SC>::verify_logup_gkr(
583 &shard_chips,
584 °rees,
585 max_log_row_count,
586 logup_gkr_proof,
587 public_values,
588 challenger,
589 )
590 .map_err(ShardVerifierError::GkrVerificationFailed)?;
591
592 self.verify_zerocheck(
594 &shard_chips,
595 opened_values,
596 &logup_gkr_proof.logup_evaluations,
597 proof,
598 public_values,
599 challenger,
600 )?;
601
602 let (preprocessed_openings_for_proof, main_openings_for_proof): (Vec<_>, Vec<_>) = proof
606 .opened_values
607 .chips
608 .values()
609 .map(|opening| (opening.preprocessed.clone(), opening.main.clone()))
610 .unzip();
611
612 let preprocessed_openings = preprocessed_openings_for_proof
614 .iter()
615 .map(|x| x.local.iter().as_slice())
616 .collect::<Vec<_>>();
617
618 let main_openings = main_openings_for_proof
620 .iter()
621 .map(|x| x.local.iter().copied().collect::<MleEval<_>>())
622 .collect::<Evaluations<_>>();
623
624 let filtered_preprocessed_openings = preprocessed_openings
627 .into_iter()
628 .filter(|x| !x.is_empty())
629 .map(|x| x.iter().copied().collect::<MleEval<_>>())
630 .collect::<Evaluations<_>>();
631
632 let (commitments, openings) = (
633 vec![vk.preprocessed_commit, *main_commitment],
634 Rounds { rounds: vec![filtered_preprocessed_openings, main_openings] },
635 );
636
637 let flattened_openings = openings
638 .into_iter()
639 .map(|round| {
640 round
641 .into_iter()
642 .flat_map(std::iter::IntoIterator::into_iter)
643 .collect::<MleEval<_>>()
644 })
645 .collect::<Vec<_>>();
646
647 self.jagged_pcs_verifier
648 .verify_trusted_evaluations(
649 &commitments,
650 zerocheck_proof.point_and_eval.0.clone(),
651 flattened_openings.as_slice(),
652 evaluation_proof,
653 challenger,
654 )
655 .map_err(ShardVerifierError::InvalidopeningArgument)?;
656
657 let [mut preprocessed_row_counts, mut main_row_counts]: [Vec<usize>; 2] = proof
658 .evaluation_proof
659 .row_counts_and_column_counts
660 .clone()
661 .into_iter()
662 .map(|r_c| r_c.into_iter().map(|(r, _)| r).collect::<Vec<_>>())
663 .collect::<Vec<_>>()
664 .try_into()
665 .unwrap();
666
667 for _ in 0..2 {
670 preprocessed_row_counts.pop();
671 main_row_counts.pop();
672 }
673
674 let mut preprocessed_chip_degrees = vec![];
675 let mut main_chip_degrees = vec![];
676
677 for chip in shard_chips.iter() {
678 if chip.preprocessed_width() > 0 {
679 preprocessed_chip_degrees.push(
680 proof.opened_values.chips[chip.name()]
681 .degree
682 .bit_string_evaluation()
683 .as_canonical_u32(),
684 );
685 }
686 main_chip_degrees.push(
687 proof.opened_values.chips[chip.name()]
688 .degree
689 .bit_string_evaluation()
690 .as_canonical_u32(),
691 );
692 }
693
694 for (chip_opening_row_counts, proof_row_counts) in
697 [preprocessed_chip_degrees, main_chip_degrees]
698 .iter()
699 .zip_eq([preprocessed_row_counts, main_row_counts].iter())
700 {
701 if proof_row_counts.len() != chip_opening_row_counts.len() {
702 return Err(ShardVerifierError::InvalidShape);
703 }
704 for (a, b) in proof_row_counts.iter().zip(chip_opening_row_counts.iter()) {
705 if *a != *b as usize {
706 return Err(ShardVerifierError::InvalidShape);
707 }
708 }
709 }
710
711 if !proof
717 .evaluation_proof
718 .row_counts_and_column_counts
719 .iter()
720 .cloned()
721 .zip(
722 once(
723 shard_chips
724 .iter()
725 .map(MachineAir::<GC::F>::preprocessed_width)
726 .filter(|&width| width > 0)
727 .collect::<Vec<_>>(),
728 )
729 .chain(once(shard_chips.iter().map(Chip::width).collect())),
730 )
731 .all(|(a, b)| a[..a.len() - 2].iter().map(|(_, c)| *c).collect::<Vec<_>>() == b)
733 {
734 Err(ShardVerifierError::InvalidShape)
735 } else {
736 Ok(())
737 }
738 }
739}
740
741impl<GC: IopCtx<F: TwoAdicField, EF: TwoAdicField>, A> ShardVerifier<GC, SP1SC<GC, A>>
742where
743 A: ZerocheckAir<GC::F, GC::EF>,
744 GC::F: PrimeField32,
745{
746 #[must_use]
748 pub fn from_basefold_parameters(
749 fri_config: FriConfig<GC::F>,
750 log_stacking_height: u32,
751 max_log_row_count: usize,
752 machine: Machine<GC::F, A>,
753 ) -> Self {
754 let pcs_verifier = JaggedPcsVerifier::<GC, SP1Pcs<GC>>::new_from_basefold_params(
755 fri_config,
756 log_stacking_height,
757 max_log_row_count,
758 NUM_SP1_COMMITMENTS,
759 );
760 Self { jagged_pcs_verifier: pcs_verifier, machine }
761 }
762}
763
764impl<GC: IopCtx<F: TwoAdicField, EF: TwoAdicField>, A>
765 ShardVerifier<GC, ShardContextImpl<GC, Verifier<GC>, A>>
766where
767 A: ZerocheckAir<GC::F, GC::EF>,
768 GC::F: PrimeField32,
769{
770 #[must_use]
772 pub fn from_config(
773 config: &WhirProofShape<GC::F>,
774 max_log_row_count: usize,
775 machine: Machine<GC::F, A>,
776 num_expected_commitments: usize,
777 ) -> Self {
778 let merkle_verifier = MerkleTreeTcs::default();
779 let verifier =
780 Verifier::<GC>::new(merkle_verifier, config.clone(), num_expected_commitments);
781
782 let jagged_verifier =
783 JaggedPcsVerifier::<GC, Verifier<GC>>::new(verifier, max_log_row_count);
784 Self { jagged_pcs_verifier: jagged_verifier, machine }
785 }
786}