arnaucube
arnaucube/sonobePublic Self-hosted repository
sonobe/src/utils/espresso/sum_check/mod.rs
src/utils/espresso/sum_check/mod.rsRaw
  1// code forked from:
  2// https://github.com/EspressoSystems/hyperplonk/tree/main/subroutines/src/poly_iop/sum_check
  3//
  4// Copyright (c) 2023 Espresso Systems (espressosys.com)
  5// This file is part of the HyperPlonk library.
  6
  7// You should have received a copy of the MIT License
  8// along with the HyperPlonk library. If not, see <https://mit-license.org/>.
  9
 10//! This module implements the sum check protocol.
 11
 12use crate::{
 13    transcript::Transcript,
 14    utils::virtual_polynomial::{VPAuxInfo, VirtualPolynomial},
 15};
 16use ark_ec::{CurveGroup, Group};
 17use ark_ff::PrimeField;
 18use ark_poly::DenseMultilinearExtension;
 19use ark_std::{end_timer, start_timer};
 20use std::{fmt::Debug, marker::PhantomData, sync::Arc};
 21
 22use crate::utils::sum_check::structs::IOPProverMessage;
 23use crate::utils::sum_check::structs::IOPVerifierState;
 24use espresso_subroutines::poly_iop::prelude::PolyIOPErrors;
 25use structs::{IOPProof, IOPProverState};
 26
 27mod prover;
 28pub mod structs;
 29pub mod verifier;
 30
 31/// A generic sum-check trait over a curve group
 32pub trait SumCheck<C: CurveGroup> {
 33    type VirtualPolynomial;
 34    type VPAuxInfo;
 35    type MultilinearExtension;
 36
 37    type SumCheckProof: Clone + Debug + Default + PartialEq;
 38    type SumCheckSubClaim: Clone + Debug + Default + PartialEq;
 39
 40    /// Extract sum from the proof
 41    fn extract_sum(proof: &Self::SumCheckProof) -> C::ScalarField;
 42
 43    /// Generate proof of the sum of polynomial over {0,1}^`num_vars`
 44    ///
 45    /// The polynomial is represented in the form of a VirtualPolynomial.
 46    fn prove(
 47        poly: &Self::VirtualPolynomial,
 48        transcript: &mut impl Transcript<C>,
 49    ) -> Result<Self::SumCheckProof, PolyIOPErrors>;
 50
 51    /// Verify the claimed sum using the proof
 52    fn verify(
 53        sum: C::ScalarField,
 54        proof: &Self::SumCheckProof,
 55        aux_info: &Self::VPAuxInfo,
 56        transcript: &mut impl Transcript<C>,
 57    ) -> Result<Self::SumCheckSubClaim, PolyIOPErrors>;
 58}
 59
 60/// Trait for sum check protocol prover side APIs.
 61pub trait SumCheckProver<C: CurveGroup>
 62where
 63    Self: Sized,
 64{
 65    type VirtualPolynomial;
 66    type ProverMessage;
 67
 68    /// Initialize the prover state to argue for the sum of the input polynomial
 69    /// over {0,1}^`num_vars`.
 70    fn prover_init(polynomial: &Self::VirtualPolynomial) -> Result<Self, PolyIOPErrors>;
 71
 72    /// Receive message from verifier, generate prover message, and proceed to
 73    /// next round.
 74    ///
 75    /// Main algorithm used is from section 3.2 of [XZZPS19](https://eprint.iacr.org/2019/317.pdf#subsection.3.2).
 76    fn prove_round_and_update_state(
 77        &mut self,
 78        challenge: &Option<C::ScalarField>,
 79    ) -> Result<Self::ProverMessage, PolyIOPErrors>;
 80}
 81
 82/// Trait for sum check protocol verifier side APIs.
 83pub trait SumCheckVerifier<C: CurveGroup> {
 84    type VPAuxInfo;
 85    type ProverMessage;
 86    type Challenge;
 87    type SumCheckSubClaim;
 88
 89    /// Initialize the verifier's state.
 90    fn verifier_init(index_info: &Self::VPAuxInfo) -> Self;
 91
 92    /// Run verifier for the current round, given a prover message.
 93    ///
 94    /// Note that `verify_round_and_update_state` only samples and stores
 95    /// challenges; and update the verifier's state accordingly. The actual
 96    /// verifications are deferred (in batch) to `check_and_generate_subclaim`
 97    /// at the last step.
 98    fn verify_round_and_update_state(
 99        &mut self,
100        prover_msg: &Self::ProverMessage,
101        transcript: &mut impl Transcript<C>,
102    ) -> Result<Self::Challenge, PolyIOPErrors>;
103
104    /// This function verifies the deferred checks in the interactive version of
105    /// the protocol; and generate the subclaim. Returns an error if the
106    /// proof failed to verify.
107    ///
108    /// If the asserted sum is correct, then the multilinear polynomial
109    /// evaluated at `subclaim.point` will be `subclaim.expected_evaluation`.
110    /// Otherwise, it is highly unlikely that those two will be equal.
111    /// Larger field size guarantees smaller soundness error.
112    fn check_and_generate_subclaim(
113        &self,
114        asserted_sum: &C::ScalarField,
115    ) -> Result<Self::SumCheckSubClaim, PolyIOPErrors>;
116}
117
118/// A SumCheckSubClaim is a claim generated by the verifier at the end of
119/// verification when it is convinced.
120#[derive(Clone, Debug, Default, PartialEq, Eq)]
121pub struct SumCheckSubClaim<F: PrimeField> {
122    /// the multi-dimensional point that this multilinear extension is evaluated
123    /// to
124    pub point: Vec<F>,
125    /// the expected evaluation
126    pub expected_evaluation: F,
127}
128
129#[derive(Clone, Debug, Default, Copy, PartialEq, Eq)]
130pub struct IOPSumCheck<C: CurveGroup, T: Transcript<C>> {
131    #[doc(hidden)]
132    phantom: PhantomData<C>,
133    #[doc(hidden)]
134    phantom2: PhantomData<T>,
135}
136
137impl<C: CurveGroup, T: Transcript<C>> SumCheck<C> for IOPSumCheck<C, T> {
138    type SumCheckProof = IOPProof<C::ScalarField>;
139    type VirtualPolynomial = VirtualPolynomial<C::ScalarField>;
140    type VPAuxInfo = VPAuxInfo<C::ScalarField>;
141    type MultilinearExtension = Arc<DenseMultilinearExtension<C::ScalarField>>;
142    type SumCheckSubClaim = SumCheckSubClaim<C::ScalarField>;
143
144    fn extract_sum(proof: &Self::SumCheckProof) -> C::ScalarField {
145        let start = start_timer!(|| "extract sum");
146        let res = proof.proofs[0].evaluations[0] + proof.proofs[0].evaluations[1];
147        end_timer!(start);
148        res
149    }
150
151    fn prove(
152        poly: &VirtualPolynomial<C::ScalarField>,
153        transcript: &mut impl Transcript<C>,
154    ) -> Result<IOPProof<C::ScalarField>, PolyIOPErrors> {
155        transcript.absorb(&<C as Group>::ScalarField::from(
156            poly.aux_info.num_variables as u64,
157        ));
158        transcript.absorb(&<C as Group>::ScalarField::from(
159            poly.aux_info.max_degree as u64,
160        ));
161        let mut prover_state: IOPProverState<C> = IOPProverState::prover_init(poly)?;
162        let mut challenge: Option<C::ScalarField> = None;
163        let mut prover_msgs: Vec<IOPProverMessage<C::ScalarField>> =
164            Vec::with_capacity(poly.aux_info.num_variables);
165        for _ in 0..poly.aux_info.num_variables {
166            let prover_msg: IOPProverMessage<C::ScalarField> =
167                IOPProverState::prove_round_and_update_state(&mut prover_state, &challenge)?;
168            transcript.absorb_vec(&prover_msg.evaluations);
169            prover_msgs.push(prover_msg);
170            challenge = Some(transcript.get_challenge());
171        }
172        if let Some(p) = challenge {
173            prover_state.challenges.push(p)
174        };
175        Ok(IOPProof {
176            point: prover_state.challenges,
177            proofs: prover_msgs,
178        })
179    }
180
181    fn verify(
182        claimed_sum: C::ScalarField,
183        proof: &IOPProof<C::ScalarField>,
184        aux_info: &VPAuxInfo<C::ScalarField>,
185        transcript: &mut impl Transcript<C>,
186    ) -> Result<SumCheckSubClaim<C::ScalarField>, PolyIOPErrors> {
187        transcript.absorb(&<C as Group>::ScalarField::from(
188            aux_info.num_variables as u64,
189        ));
190        transcript.absorb(&<C as Group>::ScalarField::from(aux_info.max_degree as u64));
191        let mut verifier_state = IOPVerifierState::verifier_init(aux_info);
192        for i in 0..aux_info.num_variables {
193            let prover_msg = proof.proofs.get(i).expect("proof is incomplete");
194            transcript.absorb_vec(&prover_msg.evaluations);
195            IOPVerifierState::verify_round_and_update_state(
196                &mut verifier_state,
197                prover_msg,
198                transcript,
199            )?;
200        }
201
202        IOPVerifierState::check_and_generate_subclaim(&verifier_state, &claimed_sum)
203    }
204}
205
206#[cfg(test)]
207pub mod tests {
208    use std::sync::Arc;
209
210    use ark_ff::Field;
211    use ark_pallas::Fr;
212    use ark_pallas::Projective;
213    use ark_poly::DenseMultilinearExtension;
214    use ark_poly::MultilinearExtension;
215    use ark_std::test_rng;
216
217    use crate::transcript::poseidon::tests::poseidon_test_config;
218    use crate::transcript::poseidon::PoseidonTranscript;
219    use crate::transcript::Transcript;
220    use crate::utils::sum_check::SumCheck;
221    use crate::utils::virtual_polynomial::VirtualPolynomial;
222
223    use super::IOPSumCheck;
224
225    #[test]
226    pub fn sumcheck_poseidon() {
227        let mut rng = test_rng();
228        let poly_mle = DenseMultilinearExtension::rand(5, &mut rng);
229        let virtual_poly = VirtualPolynomial::new_from_mle(&Arc::new(poly_mle), Fr::ONE);
230        let poseidon_config = poseidon_test_config::<Fr>();
231
232        // sum-check prove
233        let mut poseidon_transcript_prove: PoseidonTranscript<Projective> =
234            PoseidonTranscript::<Projective>::new(&poseidon_config);
235        let sum_check = IOPSumCheck::<Projective, PoseidonTranscript<Projective>>::prove(
236            &virtual_poly,
237            &mut poseidon_transcript_prove,
238        )
239        .unwrap();
240
241        // sum-check verify
242        let claimed_sum =
243            IOPSumCheck::<Projective, PoseidonTranscript<Projective>>::extract_sum(&sum_check);
244        let mut poseidon_transcript_verify: PoseidonTranscript<Projective> =
245            PoseidonTranscript::<Projective>::new(&poseidon_config);
246        let res_verify = IOPSumCheck::<Projective, PoseidonTranscript<Projective>>::verify(
247            claimed_sum,
248            &sum_check,
249            &virtual_poly.aux_info,
250            &mut poseidon_transcript_verify,
251        );
252
253        assert!(res_verify.is_ok());
254    }
255}