arnaucube
arnaucube/hyperplonkPublic Self-hosted repository
hyperplonk/poly-iop/src/sum_check/prover.rs
poly-iop/src/sum_check/prover.rsRaw
  1//! Prover
  2
  3use super::SumCheckProver;
  4use crate::{
  5    errors::PolyIOPErrors,
  6    structs::{IOPProverMessage, IOPProverState},
  7    virtual_poly::VirtualPolynomial,
  8};
  9use ark_ff::PrimeField;
 10use ark_poly::{DenseMultilinearExtension, MultilinearExtension};
 11use ark_std::{end_timer, start_timer, vec::Vec};
 12use std::rc::Rc;
 13
 14#[cfg(feature = "parallel")]
 15use rayon::iter::{IndexedParallelIterator, IntoParallelRefMutIterator, ParallelIterator};
 16
 17impl<F: PrimeField> SumCheckProver<F> for IOPProverState<F> {
 18    type PolyList = VirtualPolynomial<F>;
 19    type ProverMessage = IOPProverMessage<F>;
 20
 21    /// Initialize the prover to argue for the sum of polynomial over
 22    /// {0,1}^`num_vars`
 23    fn prover_init(polynomial: &Self::PolyList) -> Result<Self, PolyIOPErrors> {
 24        let start = start_timer!(|| "sum check prover init");
 25        if polynomial.domain_info.num_variables == 0 {
 26            return Err(PolyIOPErrors::InvalidParameters(
 27                "Attempt to prove a constant.".to_string(),
 28            ));
 29        }
 30        end_timer!(start);
 31
 32        Ok(Self {
 33            challenges: Vec::with_capacity(polynomial.domain_info.num_variables),
 34            round: 0,
 35            poly: polynomial.clone(),
 36        })
 37    }
 38
 39    /// Receive message from verifier, generate prover message, and proceed to
 40    /// next round
 41    ///
 42    /// Main algorithm used is from section 3.2 of [XZZPS19](https://eprint.iacr.org/2019/317.pdf#subsection.3.2).
 43    fn prove_round_and_update_state(
 44        &mut self,
 45        challenge: &Option<F>,
 46    ) -> Result<Self::ProverMessage, PolyIOPErrors> {
 47        let start =
 48            start_timer!(|| format!("sum check prove {}-th round and update state", self.round));
 49
 50        let fix_argument = start_timer!(|| "fix argument");
 51
 52        let mut flattened_ml_extensions: Vec<DenseMultilinearExtension<F>> = self
 53            .poly
 54            .flattened_ml_extensions
 55            .iter()
 56            .map(|x| x.as_ref().clone())
 57            .collect();
 58
 59        if let Some(chal) = challenge {
 60            if self.round == 0 {
 61                return Err(PolyIOPErrors::InvalidProver(
 62                    "first round should be prover first.".to_string(),
 63                ));
 64            }
 65            self.challenges.push(*chal);
 66
 67            // fix argument
 68            let i = self.round;
 69            let r = self.challenges[i - 1];
 70            #[cfg(feature = "parallel")]
 71            flattened_ml_extensions
 72                .par_iter_mut()
 73                .for_each(|multiplicand| *multiplicand = multiplicand.fix_variables(&[r]));
 74
 75            #[cfg(not(feature = "parallel"))]
 76            flattened_ml_extensions
 77                .iter_mut()
 78                .for_each(|multiplicand| *multiplicand = multiplicand.fix_variables(&[r]));
 79        } else if self.round > 0 {
 80            return Err(PolyIOPErrors::InvalidProver(
 81                "verifier message is empty".to_string(),
 82            ));
 83        }
 84        end_timer!(fix_argument);
 85
 86        self.round += 1;
 87
 88        if self.round > self.poly.domain_info.num_variables {
 89            return Err(PolyIOPErrors::InvalidProver(
 90                "Prover is not active".to_string(),
 91            ));
 92        }
 93
 94        let products_list = self.poly.products.clone();
 95        let i = self.round;
 96        let nv = self.poly.domain_info.num_variables;
 97        let degree = self.poly.domain_info.max_degree; // the degree of univariate polynomial sent by prover at this round
 98
 99        let mut products_sum = Vec::with_capacity(degree + 1);
100        products_sum.resize(degree + 1, F::zero());
101
102        let compute_sum = start_timer!(|| "compute sum");
103        // generate sum
104        #[cfg(feature = "parallel")]
105        products_sum.par_iter_mut().enumerate().for_each(|(t, e)| {
106            for b in 0..1 << (nv - i) {
107                // evaluate P_round(t)
108                for (coefficient, products) in products_list.iter() {
109                    let num_multiplicands = products.len();
110                    let mut product = *coefficient;
111                    for &f in products.iter().take(num_multiplicands) {
112                        let table = &flattened_ml_extensions[f]; // f's range is checked in init
113                        product *= table[b << 1] * (F::one() - F::from(t as u64))
114                            + table[(b << 1) + 1] * F::from(t as u64);
115                    }
116                    *e += product;
117                }
118            }
119        });
120
121        #[cfg(not(feature = "parallel"))]
122        for b in 0..1 << (nv - i) {
123            products_sum
124                .iter_mut()
125                .take(degree + 1)
126                .enumerate()
127                .for_each(|(t, e)| {
128                    // evaluate P_round(t)
129                    for (coefficient, products) in products_list.iter() {
130                        let num_multiplicands = products.len();
131                        let mut product = *coefficient;
132                        for &f in products.iter().take(num_multiplicands) {
133                            let table = &flattened_ml_extensions[f]; // f's range is checked in init
134                            product *= table[b << 1] * (F::one() - F::from(t as u64))
135                                + table[(b << 1) + 1] * F::from(t as u64);
136                        }
137                        *e += product;
138                    }
139                });
140        }
141
142        self.poly.flattened_ml_extensions = flattened_ml_extensions
143            .iter()
144            .map(|x| Rc::new(x.clone()))
145            .collect();
146
147        end_timer!(compute_sum);
148        end_timer!(start);
149        Ok(IOPProverMessage {
150            evaluations: products_sum,
151        })
152    }
153}