1use alloc::vec::Vec;
2
3use p3_challenger::{FieldChallenger, GrindingChallenger};
4use p3_field::{ExtensionField, Field, TwoAdicField};
5use p3_multilinear_util::point::Point;
6use serde::{Deserialize, Serialize};
7
8use crate::{SumcheckError, extrapolate_01inf};
9
10#[derive(Default, Serialize, Deserialize, Clone, Debug)]
15pub struct SumcheckData<F, EF> {
16 pub polynomial_evaluations: Vec<[EF; 2]>,
26
27 pub pow_witnesses: Vec<F>,
30}
31
32impl<F, EF> SumcheckData<F, EF> {
33 #[must_use]
35 pub fn polynomial_evaluations(&self) -> &[[EF; 2]] {
36 &self.polynomial_evaluations
37 }
38
39 #[must_use]
41 pub const fn num_rounds(&self) -> usize {
42 self.polynomial_evaluations.len()
43 }
44
45 pub fn observe_and_sample<Challenger, BF>(
60 &mut self,
61 challenger: &mut Challenger,
62 c0: EF,
63 c_inf: EF,
64 pow_bits: usize,
65 ) -> EF
66 where
67 BF: Field,
68 EF: ExtensionField<BF>,
69 F: Clone,
70 Challenger: FieldChallenger<BF> + GrindingChallenger<Witness = F>,
71 {
72 self.polynomial_evaluations.push([c0, c_inf]);
74
75 challenger.observe_algebra_slice(&[c0, c_inf]);
79
80 if pow_bits > 0 {
84 self.pow_witnesses.push(challenger.grind(pow_bits));
85 }
86
87 challenger.sample_algebra_element()
89 }
90
91 pub fn verify_rounds<Challenger>(
97 &self,
98 challenger: &mut Challenger,
99 claimed_sum: &mut EF,
100 pow_bits: usize,
101 ) -> Result<Point<EF>, SumcheckError>
102 where
103 F: TwoAdicField,
104 EF: ExtensionField<F> + TwoAdicField,
105 Challenger: FieldChallenger<F> + GrindingChallenger<Witness = F>,
106 {
107 let mut randomness = Vec::with_capacity(self.polynomial_evaluations.len());
108
109 if pow_bits > 0 && self.pow_witnesses.len() != self.polynomial_evaluations.len() {
113 return Err(SumcheckError::PowWitnessCountMismatch {
114 expected: self.polynomial_evaluations.len(),
115 actual: self.pow_witnesses.len(),
116 });
117 }
118
119 for (i, &[c0, c_inf]) in self.polynomial_evaluations.iter().enumerate() {
120 challenger.observe_algebra_slice(&[c0, c_inf]);
122
123 if pow_bits > 0 && !challenger.check_witness(pow_bits, self.pow_witnesses[i]) {
125 return Err(SumcheckError::InvalidPowWitness);
126 }
127
128 let r: EF = challenger.sample_algebra_element();
130 *claimed_sum = extrapolate_01inf(c0, *claimed_sum - c0, c_inf, r);
131 randomness.push(r);
132 }
133
134 Ok(Point::new(randomness))
135 }
136}
137
138pub fn verify_final_sumcheck_rounds<F, EF, Challenger>(
146 final_sumcheck: Option<&SumcheckData<F, EF>>,
147 challenger: &mut Challenger,
148 claimed_sum: &mut EF,
149 rounds: usize,
150 pow_bits: usize,
151) -> Result<Point<EF>, SumcheckError>
152where
153 F: TwoAdicField,
154 EF: ExtensionField<F> + TwoAdicField,
155 Challenger: FieldChallenger<F> + GrindingChallenger<Witness = F>,
156{
157 if rounds == 0 {
158 return Ok(Point::new(Vec::new()));
159 }
160
161 let sumcheck = final_sumcheck.ok_or(SumcheckError::MissingSumcheckData {
162 expected_rounds: rounds,
163 })?;
164
165 if sumcheck.polynomial_evaluations.len() != rounds {
166 return Err(SumcheckError::RoundCountMismatch {
167 expected: rounds,
168 actual: sumcheck.polynomial_evaluations.len(),
169 });
170 }
171 sumcheck.verify_rounds(challenger, claimed_sum, pow_bits)
172}