use alloc::vec::Vec;
use p3_challenger::{FieldChallenger, GrindingChallenger};
use p3_field::{ExtensionField, Field, TwoAdicField};
use p3_multilinear_util::point::Point;
use serde::{Deserialize, Serialize};
use crate::{SumcheckError, extrapolate_01inf};
#[derive(Default, Serialize, Deserialize, Clone, Debug)]
pub struct SumcheckData<F, EF> {
pub polynomial_evaluations: Vec<[EF; 2]>,
pub pow_witnesses: Vec<F>,
}
impl<F, EF> SumcheckData<F, EF> {
#[must_use]
pub fn polynomial_evaluations(&self) -> &[[EF; 2]] {
&self.polynomial_evaluations
}
#[must_use]
pub const fn num_rounds(&self) -> usize {
self.polynomial_evaluations.len()
}
pub fn observe_and_sample<Challenger, BF>(
&mut self,
challenger: &mut Challenger,
c0: EF,
c_inf: EF,
pow_bits: usize,
) -> EF
where
BF: Field,
EF: ExtensionField<BF>,
F: Clone,
Challenger: FieldChallenger<BF> + GrindingChallenger<Witness = F>,
{
self.polynomial_evaluations.push([c0, c_inf]);
challenger.observe_algebra_slice(&[c0, c_inf]);
if pow_bits > 0 {
self.pow_witnesses.push(challenger.grind(pow_bits));
}
challenger.sample_algebra_element()
}
pub fn verify_rounds<Challenger>(
&self,
challenger: &mut Challenger,
claimed_sum: &mut EF,
pow_bits: usize,
) -> Result<Point<EF>, SumcheckError>
where
F: TwoAdicField,
EF: ExtensionField<F> + TwoAdicField,
Challenger: FieldChallenger<F> + GrindingChallenger<Witness = F>,
{
let mut randomness = Vec::with_capacity(self.polynomial_evaluations.len());
if pow_bits > 0 && self.pow_witnesses.len() != self.polynomial_evaluations.len() {
return Err(SumcheckError::PowWitnessCountMismatch {
expected: self.polynomial_evaluations.len(),
actual: self.pow_witnesses.len(),
});
}
for (i, &[c0, c_inf]) in self.polynomial_evaluations.iter().enumerate() {
challenger.observe_algebra_slice(&[c0, c_inf]);
if pow_bits > 0 && !challenger.check_witness(pow_bits, self.pow_witnesses[i]) {
return Err(SumcheckError::InvalidPowWitness);
}
let r: EF = challenger.sample_algebra_element();
*claimed_sum = extrapolate_01inf(c0, *claimed_sum - c0, c_inf, r);
randomness.push(r);
}
Ok(Point::new(randomness))
}
}
pub fn verify_final_sumcheck_rounds<F, EF, Challenger>(
final_sumcheck: Option<&SumcheckData<F, EF>>,
challenger: &mut Challenger,
claimed_sum: &mut EF,
rounds: usize,
pow_bits: usize,
) -> Result<Point<EF>, SumcheckError>
where
F: TwoAdicField,
EF: ExtensionField<F> + TwoAdicField,
Challenger: FieldChallenger<F> + GrindingChallenger<Witness = F>,
{
if rounds == 0 {
return Ok(Point::new(Vec::new()));
}
let sumcheck = final_sumcheck.ok_or(SumcheckError::MissingSumcheckData {
expected_rounds: rounds,
})?;
if sumcheck.polynomial_evaluations.len() != rounds {
return Err(SumcheckError::RoundCountMismatch {
expected: rounds,
actual: sumcheck.polynomial_evaluations.len(),
});
}
sumcheck.verify_rounds(challenger, claimed_sum, pow_bits)
}