slop_sumcheck/
verifier.rs1use thiserror::Error;
2
3use slop_algebra::{ExtensionField, Field};
4use slop_challenger::{FieldChallenger, VariableLengthChallenger};
5use slop_multilinear::Point;
6
7use crate::PartialSumcheckProof;
8
9#[derive(Debug, Eq, PartialEq, Error)]
10pub enum SumcheckError {
11 #[error("invalid proof shape")]
12 InvalidProofShape,
13 #[error("sumcheck round inconsistency")]
14 SumcheckRoundInconsistency,
15 #[error("inconsistency of prover message with claimed sum")]
16 InconsistencyWithClaimedSum,
17 #[error("inconsistency of proof with evaluation claim")]
18 InconsistencyWithEval,
19}
20
21pub fn partially_verify_sumcheck_proof<
23 F: Field,
24 EF: ExtensionField<F>,
25 Challenger: FieldChallenger<F>,
26>(
27 proof: &PartialSumcheckProof<EF>,
28 challenger: &mut Challenger,
29 expected_num_variable: usize,
30 expected_degree: usize,
31) -> Result<(), SumcheckError> {
32 let num_variables = proof.univariate_polys.len();
33 let mut alpha_point = Point::default();
34
35 if num_variables != proof.point_and_eval.0.dimension() {
37 return Err(SumcheckError::InvalidProofShape);
38 }
39
40 if num_variables != expected_num_variable {
41 return Err(SumcheckError::InvalidProofShape);
42 }
43
44 if expected_num_variable == 0 {
45 return Err(SumcheckError::InvalidProofShape);
46 }
47
48 let first_poly = &proof.univariate_polys[0];
51 if first_poly.eval_one_plus_eval_zero() != proof.claimed_sum {
52 return Err(SumcheckError::InconsistencyWithClaimedSum);
53 }
54
55 if first_poly.coefficients.len() != expected_degree + 1 {
56 return Err(SumcheckError::InvalidProofShape);
57 }
58
59 challenger.observe_constant_length_extension_slice(&first_poly.coefficients);
63 let mut previous_poly = first_poly;
64
65 for poly in proof.univariate_polys.iter().skip(1) {
66 if poly.coefficients.len() != expected_degree + 1 {
67 return Err(SumcheckError::InvalidProofShape);
68 }
69 let alpha = challenger.sample_ext_element();
70 alpha_point.add_dimension(alpha);
71 let expected_eval = previous_poly.eval_at_point(alpha);
72 if expected_eval != poly.eval_one_plus_eval_zero() {
73 return Err(SumcheckError::SumcheckRoundInconsistency);
74 }
75 challenger.observe_constant_length_extension_slice(&poly.coefficients);
76 previous_poly = poly;
77 }
78
79 let alpha = challenger.sample_ext_element();
80 alpha_point.add_dimension(alpha);
81
82 if alpha_point != proof.point_and_eval.0 {
86 return Err(SumcheckError::InvalidProofShape);
87 }
88
89 if previous_poly.eval_at_point(alpha) != proof.point_and_eval.1 {
94 return Err(SumcheckError::InconsistencyWithEval);
95 }
96
97 Ok(())
98}