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