mirror of
https://github.com/arnaucube/sonobe.git
synced 2026-01-10 16:01:35 +01:00
Feature/sumcheck (#40)
* feat: init sumcheck.rs * chore: rename * feat: update lib and add trait for transcript with vec storing challenges * bugfix: mut self ref of transcript * feat: tentative sum-check using poseidon * refactor: remove extension trait and use initial trait * refactor: stop using extension trait, use initial Transcript trait * feat: generic over CurveGroup sum-check verifier and algorithm * feat: implement generic sum-check veriy * bugfix: cargo clippy --fix * chore: cargo fmt * feat: (unstable) sum-check implementation * feat: start benches * chore: run clippy * chore: run cargo fmt * feat: add sum-check tests + benches * chore: clippy + fmt * chore: remove unstable sumcheck * chore: delete duplicated sum-check code * chore: remove deleted sum-check code from lib.rs imports * feat: remove non generic traits, implement sum-check with generic trait and add test * chore: remove non-generic struct * chore: remove non generic verifier * feat: make nifms generic over transcript and update to use poseidon transcript * chore: cargo fmt * chore: remove tmp benches * chore: update cargo.toml * refactor: remove Generic suffix * feat: prover state generic over CurveGroup * chore: disable clippy type complexity warning * refactor: remove Transcript type and espresso transcript dependency * refactor: SumCheckProver generic over CurveGroup * chore: add line to eof for `Cargo.toml` * bugfix: add error handling on sum-check prove and verify * chore: clippy fix * chore: add line at eof * fix: use `map_err` and call `to_string()` on `PolyIOPErrors`
This commit is contained in:
@@ -20,7 +20,6 @@ color-eyre = "=0.6.2"
|
|||||||
# tmp imports for espresso's sumcheck
|
# tmp imports for espresso's sumcheck
|
||||||
ark-serialize = "^0.4.0"
|
ark-serialize = "^0.4.0"
|
||||||
espresso_subroutines = {git="https://github.com/EspressoSystems/hyperplonk", package="subroutines"}
|
espresso_subroutines = {git="https://github.com/EspressoSystems/hyperplonk", package="subroutines"}
|
||||||
espresso_transcript = {git="https://github.com/EspressoSystems/hyperplonk", package="transcript"}
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
ark-pallas = {version="0.4.0", features=["r1cs"]}
|
ark-pallas = {version="0.4.0", features=["r1cs"]}
|
||||||
@@ -47,3 +46,4 @@ parallel = [
|
|||||||
# changes done between v0.4.0 and this fix which would break compatibility.
|
# changes done between v0.4.0 and this fix which would break compatibility.
|
||||||
[patch.crates-io]
|
[patch.crates-io]
|
||||||
ark-r1cs-std = { git = "https://github.com/arnaucube/ark-r1cs-std-cherry-picked/" }
|
ark-r1cs-std = { git = "https://github.com/arnaucube/ark-r1cs-std-cherry-picked/" }
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,21 @@
|
|||||||
use ark_ec::CurveGroup;
|
use ark_crypto_primitives::sponge::Absorb;
|
||||||
|
use ark_ec::{CurveGroup, Group};
|
||||||
use ark_ff::{Field, PrimeField};
|
use ark_ff::{Field, PrimeField};
|
||||||
use ark_std::{One, Zero};
|
use ark_std::{One, Zero};
|
||||||
|
|
||||||
use espresso_subroutines::PolyIOP;
|
|
||||||
use espresso_transcript::IOPTranscript;
|
|
||||||
|
|
||||||
use super::cccs::{Witness, CCCS};
|
use super::cccs::{Witness, CCCS};
|
||||||
use super::lcccs::LCCCS;
|
use super::lcccs::LCCCS;
|
||||||
use super::utils::{compute_c_from_sigmas_and_thetas, compute_g, compute_sigmas_and_thetas};
|
use super::utils::{compute_c_from_sigmas_and_thetas, compute_g, compute_sigmas_and_thetas};
|
||||||
use crate::ccs::CCS;
|
use crate::ccs::CCS;
|
||||||
|
use crate::transcript::Transcript;
|
||||||
use crate::utils::hypercube::BooleanHypercube;
|
use crate::utils::hypercube::BooleanHypercube;
|
||||||
use crate::utils::sum_check::structs::IOPProof as SumCheckProof;
|
use crate::utils::sum_check::structs::IOPProof as SumCheckProof;
|
||||||
use crate::utils::sum_check::{verifier::interpolate_uni_poly, SumCheck};
|
use crate::utils::sum_check::verifier::interpolate_uni_poly;
|
||||||
|
use crate::utils::sum_check::{IOPSumCheck, SumCheck};
|
||||||
use crate::utils::virtual_polynomial::VPAuxInfo;
|
use crate::utils::virtual_polynomial::VPAuxInfo;
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
|
|
||||||
|
use std::fmt::Debug;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
/// Proof defines a multifolding proof
|
/// Proof defines a multifolding proof
|
||||||
@@ -30,11 +31,15 @@ pub struct SigmasThetas<F: PrimeField>(pub Vec<Vec<F>>, pub Vec<Vec<F>>);
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
/// Implements the Non-Interactive Multi Folding Scheme described in section 5 of
|
/// Implements the Non-Interactive Multi Folding Scheme described in section 5 of
|
||||||
/// [HyperNova](https://eprint.iacr.org/2023/573.pdf)
|
/// [HyperNova](https://eprint.iacr.org/2023/573.pdf)
|
||||||
pub struct NIMFS<C: CurveGroup> {
|
pub struct NIMFS<C: CurveGroup, T: Transcript<C>> {
|
||||||
pub _c: PhantomData<C>,
|
pub _c: PhantomData<C>,
|
||||||
|
pub _t: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: CurveGroup> NIMFS<C> {
|
impl<C: CurveGroup, T: Transcript<C>> NIMFS<C, T>
|
||||||
|
where
|
||||||
|
<C as Group>::ScalarField: Absorb,
|
||||||
|
{
|
||||||
pub fn fold(
|
pub fn fold(
|
||||||
lcccs: &[LCCCS<C>],
|
lcccs: &[LCCCS<C>],
|
||||||
cccs: &[CCCS<C>],
|
cccs: &[CCCS<C>],
|
||||||
@@ -144,7 +149,7 @@ impl<C: CurveGroup> NIMFS<C> {
|
|||||||
/// contains the sumcheck proof and the helper sumcheck claim sigmas and thetas.
|
/// contains the sumcheck proof and the helper sumcheck claim sigmas and thetas.
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
pub fn prove(
|
pub fn prove(
|
||||||
transcript: &mut IOPTranscript<C::ScalarField>,
|
transcript: &mut impl Transcript<C>,
|
||||||
ccs: &CCS<C>,
|
ccs: &CCS<C>,
|
||||||
running_instances: &[LCCCS<C>],
|
running_instances: &[LCCCS<C>],
|
||||||
new_instances: &[CCCS<C>],
|
new_instances: &[CCCS<C>],
|
||||||
@@ -185,17 +190,19 @@ impl<C: CurveGroup> NIMFS<C> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Step 1: Get some challenges
|
// Step 1: Get some challenges
|
||||||
let gamma: C::ScalarField = transcript.get_and_append_challenge(b"gamma").unwrap();
|
let gamma_scalar = C::ScalarField::from_le_bytes_mod_order(b"gamma");
|
||||||
let beta: Vec<C::ScalarField> = transcript
|
let beta_scalar = C::ScalarField::from_le_bytes_mod_order(b"beta");
|
||||||
.get_and_append_challenge_vectors(b"beta", ccs.s)
|
transcript.absorb(&gamma_scalar);
|
||||||
.unwrap();
|
let gamma: C::ScalarField = transcript.get_challenge();
|
||||||
|
transcript.absorb(&beta_scalar);
|
||||||
|
let beta: Vec<C::ScalarField> = transcript.get_challenges(ccs.s);
|
||||||
|
|
||||||
// Compute g(x)
|
// Compute g(x)
|
||||||
let g = compute_g(ccs, running_instances, &z_lcccs, &z_cccs, gamma, &beta);
|
let g = compute_g(ccs, running_instances, &z_lcccs, &z_cccs, gamma, &beta);
|
||||||
|
|
||||||
// Step 3: Run the sumcheck prover
|
// Step 3: Run the sumcheck prover
|
||||||
let sumcheck_proof =
|
let sumcheck_proof = IOPSumCheck::<C, T>::prove(&g, transcript)
|
||||||
<PolyIOP<C::ScalarField> as SumCheck<C::ScalarField>>::prove(&g, transcript).unwrap(); // XXX unwrap
|
.map_err(|err| Error::SumCheckProveError(err.to_string()))?;
|
||||||
|
|
||||||
// Note: The following two "sanity checks" are done for this prototype, in a final version
|
// Note: The following two "sanity checks" are done for this prototype, in a final version
|
||||||
// they should be removed.
|
// they should be removed.
|
||||||
@@ -209,8 +216,8 @@ impl<C: CurveGroup> NIMFS<C> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// note: this is the sum of g(x) over the whole boolean hypercube
|
// note: this is the sum of g(x) over the whole boolean hypercube
|
||||||
let extracted_sum =
|
let extracted_sum = IOPSumCheck::<C, T>::extract_sum(&sumcheck_proof);
|
||||||
<PolyIOP<C::ScalarField> as SumCheck<C::ScalarField>>::extract_sum(&sumcheck_proof);
|
|
||||||
if extracted_sum != g_over_bhc {
|
if extracted_sum != g_over_bhc {
|
||||||
return Err(Error::NotEqual);
|
return Err(Error::NotEqual);
|
||||||
}
|
}
|
||||||
@@ -238,7 +245,9 @@ impl<C: CurveGroup> NIMFS<C> {
|
|||||||
let sigmas_thetas = compute_sigmas_and_thetas(ccs, &z_lcccs, &z_cccs, &r_x_prime);
|
let sigmas_thetas = compute_sigmas_and_thetas(ccs, &z_lcccs, &z_cccs, &r_x_prime);
|
||||||
|
|
||||||
// Step 6: Get the folding challenge
|
// Step 6: Get the folding challenge
|
||||||
let rho: C::ScalarField = transcript.get_and_append_challenge(b"rho").unwrap();
|
let rho_scalar = C::ScalarField::from_le_bytes_mod_order(b"rho");
|
||||||
|
transcript.absorb(&rho_scalar);
|
||||||
|
let rho: C::ScalarField = transcript.get_challenge();
|
||||||
|
|
||||||
// Step 7: Create the folded instance
|
// Step 7: Create the folded instance
|
||||||
let folded_lcccs = Self::fold(
|
let folded_lcccs = Self::fold(
|
||||||
@@ -266,7 +275,7 @@ impl<C: CurveGroup> NIMFS<C> {
|
|||||||
/// into a single LCCCS instance.
|
/// into a single LCCCS instance.
|
||||||
/// Returns the folded LCCCS instance.
|
/// Returns the folded LCCCS instance.
|
||||||
pub fn verify(
|
pub fn verify(
|
||||||
transcript: &mut IOPTranscript<C::ScalarField>,
|
transcript: &mut impl Transcript<C>,
|
||||||
ccs: &CCS<C>,
|
ccs: &CCS<C>,
|
||||||
running_instances: &[LCCCS<C>],
|
running_instances: &[LCCCS<C>],
|
||||||
new_instances: &[CCCS<C>],
|
new_instances: &[CCCS<C>],
|
||||||
@@ -282,10 +291,13 @@ impl<C: CurveGroup> NIMFS<C> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Step 1: Get some challenges
|
// Step 1: Get some challenges
|
||||||
let gamma: C::ScalarField = transcript.get_and_append_challenge(b"gamma").unwrap();
|
let gamma_scalar = C::ScalarField::from_le_bytes_mod_order(b"gamma");
|
||||||
let beta: Vec<C::ScalarField> = transcript
|
transcript.absorb(&gamma_scalar);
|
||||||
.get_and_append_challenge_vectors(b"beta", ccs.s)
|
let gamma: C::ScalarField = transcript.get_challenge();
|
||||||
.unwrap();
|
|
||||||
|
let beta_scalar = C::ScalarField::from_le_bytes_mod_order(b"beta");
|
||||||
|
transcript.absorb(&beta_scalar);
|
||||||
|
let beta: Vec<C::ScalarField> = transcript.get_challenges(ccs.s);
|
||||||
|
|
||||||
let vp_aux_info = VPAuxInfo::<C::ScalarField> {
|
let vp_aux_info = VPAuxInfo::<C::ScalarField> {
|
||||||
max_degree: ccs.d + 1,
|
max_degree: ccs.d + 1,
|
||||||
@@ -304,13 +316,9 @@ impl<C: CurveGroup> NIMFS<C> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Verify the interactive part of the sumcheck
|
// Verify the interactive part of the sumcheck
|
||||||
let sumcheck_subclaim = <PolyIOP<C::ScalarField> as SumCheck<C::ScalarField>>::verify(
|
let sumcheck_subclaim =
|
||||||
sum_v_j_gamma,
|
IOPSumCheck::<C, T>::verify(sum_v_j_gamma, &proof.sc_proof, &vp_aux_info, transcript)
|
||||||
&proof.sc_proof,
|
.map_err(|err| Error::SumCheckVerifyError(err.to_string()))?;
|
||||||
&vp_aux_info,
|
|
||||||
transcript,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Step 2: Dig into the sumcheck claim and extract the randomness used
|
// Step 2: Dig into the sumcheck claim and extract the randomness used
|
||||||
let r_x_prime = sumcheck_subclaim.point.clone();
|
let r_x_prime = sumcheck_subclaim.point.clone();
|
||||||
@@ -347,7 +355,9 @@ impl<C: CurveGroup> NIMFS<C> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Step 6: Get the folding challenge
|
// Step 6: Get the folding challenge
|
||||||
let rho: C::ScalarField = transcript.get_and_append_challenge(b"rho").unwrap();
|
let rho_scalar = C::ScalarField::from_le_bytes_mod_order(b"rho");
|
||||||
|
transcript.absorb(&rho_scalar);
|
||||||
|
let rho: C::ScalarField = transcript.get_challenge();
|
||||||
|
|
||||||
// Step 7: Compute the folded instance
|
// Step 7: Compute the folded instance
|
||||||
Ok(Self::fold(
|
Ok(Self::fold(
|
||||||
@@ -364,6 +374,8 @@ impl<C: CurveGroup> NIMFS<C> {
|
|||||||
pub mod tests {
|
pub mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::ccs::tests::{get_test_ccs, get_test_z};
|
use crate::ccs::tests::{get_test_ccs, get_test_z};
|
||||||
|
use crate::transcript::poseidon::tests::poseidon_test_config;
|
||||||
|
use crate::transcript::poseidon::PoseidonTranscript;
|
||||||
use ark_std::test_rng;
|
use ark_std::test_rng;
|
||||||
use ark_std::UniformRand;
|
use ark_std::UniformRand;
|
||||||
|
|
||||||
@@ -395,9 +407,16 @@ pub mod tests {
|
|||||||
let mut rng = test_rng();
|
let mut rng = test_rng();
|
||||||
let rho = Fr::rand(&mut rng);
|
let rho = Fr::rand(&mut rng);
|
||||||
|
|
||||||
let folded = NIMFS::<Projective>::fold(&[lcccs], &[cccs], &sigmas_thetas, r_x_prime, rho);
|
let folded = NIMFS::<Projective, PoseidonTranscript<Projective>>::fold(
|
||||||
|
&[lcccs],
|
||||||
|
&[cccs],
|
||||||
|
&sigmas_thetas,
|
||||||
|
r_x_prime,
|
||||||
|
rho,
|
||||||
|
);
|
||||||
|
|
||||||
let w_folded = NIMFS::<Projective>::fold_witness(&[w1], &[w2], rho);
|
let w_folded =
|
||||||
|
NIMFS::<Projective, PoseidonTranscript<Projective>>::fold_witness(&[w1], &[w2], rho);
|
||||||
|
|
||||||
// check lcccs relation
|
// check lcccs relation
|
||||||
folded
|
folded
|
||||||
@@ -425,11 +444,14 @@ pub mod tests {
|
|||||||
let (new_instance, w2) = ccs.to_cccs(&mut rng, &pedersen_params, &z_2).unwrap();
|
let (new_instance, w2) = ccs.to_cccs(&mut rng, &pedersen_params, &z_2).unwrap();
|
||||||
|
|
||||||
// Prover's transcript
|
// Prover's transcript
|
||||||
let mut transcript_p = IOPTranscript::<Fr>::new(b"multifolding");
|
let poseidon_config = poseidon_test_config::<Fr>();
|
||||||
transcript_p.append_message(b"init", b"init").unwrap();
|
let mut transcript_p: PoseidonTranscript<Projective> =
|
||||||
|
PoseidonTranscript::<Projective>::new(&poseidon_config);
|
||||||
|
transcript_p.absorb(&Fr::from_le_bytes_mod_order(b"init init"));
|
||||||
|
|
||||||
// Run the prover side of the multifolding
|
// Run the prover side of the multifolding
|
||||||
let (proof, folded_lcccs, folded_witness) = NIMFS::<Projective>::prove(
|
let (proof, folded_lcccs, folded_witness) =
|
||||||
|
NIMFS::<Projective, PoseidonTranscript<Projective>>::prove(
|
||||||
&mut transcript_p,
|
&mut transcript_p,
|
||||||
&ccs,
|
&ccs,
|
||||||
&[running_instance.clone()],
|
&[running_instance.clone()],
|
||||||
@@ -440,11 +462,12 @@ pub mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Verifier's transcript
|
// Verifier's transcript
|
||||||
let mut transcript_v = IOPTranscript::<Fr>::new(b"multifolding");
|
let mut transcript_v: PoseidonTranscript<Projective> =
|
||||||
transcript_v.append_message(b"init", b"init").unwrap();
|
PoseidonTranscript::<Projective>::new(&poseidon_config);
|
||||||
|
transcript_v.absorb(&Fr::from_le_bytes_mod_order(b"init init"));
|
||||||
|
|
||||||
// Run the verifier side of the multifolding
|
// Run the verifier side of the multifolding
|
||||||
let folded_lcccs_v = NIMFS::<Projective>::verify(
|
let folded_lcccs_v = NIMFS::<Projective, PoseidonTranscript<Projective>>::verify(
|
||||||
&mut transcript_v,
|
&mut transcript_v,
|
||||||
&ccs,
|
&ccs,
|
||||||
&[running_instance.clone()],
|
&[running_instance.clone()],
|
||||||
@@ -474,10 +497,15 @@ pub mod tests {
|
|||||||
let (mut running_instance, mut w1) =
|
let (mut running_instance, mut w1) =
|
||||||
ccs.to_lcccs(&mut rng, &pedersen_params, &z_1).unwrap();
|
ccs.to_lcccs(&mut rng, &pedersen_params, &z_1).unwrap();
|
||||||
|
|
||||||
let mut transcript_p = IOPTranscript::<Fr>::new(b"multifolding");
|
let poseidon_config = poseidon_test_config::<Fr>();
|
||||||
let mut transcript_v = IOPTranscript::<Fr>::new(b"multifolding");
|
|
||||||
transcript_p.append_message(b"init", b"init").unwrap();
|
let mut transcript_p: PoseidonTranscript<Projective> =
|
||||||
transcript_v.append_message(b"init", b"init").unwrap();
|
PoseidonTranscript::<Projective>::new(&poseidon_config);
|
||||||
|
transcript_p.absorb(&Fr::from_le_bytes_mod_order(b"init init"));
|
||||||
|
|
||||||
|
let mut transcript_v: PoseidonTranscript<Projective> =
|
||||||
|
PoseidonTranscript::<Projective>::new(&poseidon_config);
|
||||||
|
transcript_v.absorb(&Fr::from_le_bytes_mod_order(b"init init"));
|
||||||
|
|
||||||
let n: usize = 10;
|
let n: usize = 10;
|
||||||
for i in 3..n {
|
for i in 3..n {
|
||||||
@@ -490,7 +518,8 @@ pub mod tests {
|
|||||||
let (new_instance, w2) = ccs.to_cccs(&mut rng, &pedersen_params, &z_2).unwrap();
|
let (new_instance, w2) = ccs.to_cccs(&mut rng, &pedersen_params, &z_2).unwrap();
|
||||||
|
|
||||||
// run the prover side of the multifolding
|
// run the prover side of the multifolding
|
||||||
let (proof, folded_lcccs, folded_witness) = NIMFS::<Projective>::prove(
|
let (proof, folded_lcccs, folded_witness) =
|
||||||
|
NIMFS::<Projective, PoseidonTranscript<Projective>>::prove(
|
||||||
&mut transcript_p,
|
&mut transcript_p,
|
||||||
&ccs,
|
&ccs,
|
||||||
&[running_instance.clone()],
|
&[running_instance.clone()],
|
||||||
@@ -501,7 +530,7 @@ pub mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// run the verifier side of the multifolding
|
// run the verifier side of the multifolding
|
||||||
let folded_lcccs_v = NIMFS::<Projective>::verify(
|
let folded_lcccs_v = NIMFS::<Projective, PoseidonTranscript<Projective>>::verify(
|
||||||
&mut transcript_v,
|
&mut transcript_v,
|
||||||
&ccs,
|
&ccs,
|
||||||
&[running_instance.clone()],
|
&[running_instance.clone()],
|
||||||
@@ -509,7 +538,6 @@ pub mod tests {
|
|||||||
proof,
|
proof,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(folded_lcccs, folded_lcccs_v);
|
assert_eq!(folded_lcccs, folded_lcccs_v);
|
||||||
|
|
||||||
// check that the folded instance with the folded witness holds the LCCCS relation
|
// check that the folded instance with the folded witness holds the LCCCS relation
|
||||||
@@ -565,11 +593,14 @@ pub mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Prover's transcript
|
// Prover's transcript
|
||||||
let mut transcript_p = IOPTranscript::<Fr>::new(b"multifolding");
|
let poseidon_config = poseidon_test_config::<Fr>();
|
||||||
transcript_p.append_message(b"init", b"init").unwrap();
|
let mut transcript_p: PoseidonTranscript<Projective> =
|
||||||
|
PoseidonTranscript::<Projective>::new(&poseidon_config);
|
||||||
|
transcript_p.absorb(&Fr::from_le_bytes_mod_order(b"init init"));
|
||||||
|
|
||||||
// Run the prover side of the multifolding
|
// Run the prover side of the multifolding
|
||||||
let (proof, folded_lcccs, folded_witness) = NIMFS::<Projective>::prove(
|
let (proof, folded_lcccs, folded_witness) =
|
||||||
|
NIMFS::<Projective, PoseidonTranscript<Projective>>::prove(
|
||||||
&mut transcript_p,
|
&mut transcript_p,
|
||||||
&ccs,
|
&ccs,
|
||||||
&lcccs_instances,
|
&lcccs_instances,
|
||||||
@@ -580,11 +611,12 @@ pub mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Verifier's transcript
|
// Verifier's transcript
|
||||||
let mut transcript_v = IOPTranscript::<Fr>::new(b"multifolding");
|
let mut transcript_v: PoseidonTranscript<Projective> =
|
||||||
transcript_v.append_message(b"init", b"init").unwrap();
|
PoseidonTranscript::<Projective>::new(&poseidon_config);
|
||||||
|
transcript_v.absorb(&Fr::from_le_bytes_mod_order(b"init init"));
|
||||||
|
|
||||||
// Run the verifier side of the multifolding
|
// Run the verifier side of the multifolding
|
||||||
let folded_lcccs_v = NIMFS::<Projective>::verify(
|
let folded_lcccs_v = NIMFS::<Projective, PoseidonTranscript<Projective>>::verify(
|
||||||
&mut transcript_v,
|
&mut transcript_v,
|
||||||
&ccs,
|
&ccs,
|
||||||
&lcccs_instances,
|
&lcccs_instances,
|
||||||
@@ -610,13 +642,16 @@ pub mod tests {
|
|||||||
let ccs = get_test_ccs::<Projective>();
|
let ccs = get_test_ccs::<Projective>();
|
||||||
let pedersen_params = Pedersen::new_params(&mut rng, ccs.n - ccs.l - 1);
|
let pedersen_params = Pedersen::new_params(&mut rng, ccs.n - ccs.l - 1);
|
||||||
|
|
||||||
|
let poseidon_config = poseidon_test_config::<Fr>();
|
||||||
// Prover's transcript
|
// Prover's transcript
|
||||||
let mut transcript_p = IOPTranscript::<Fr>::new(b"multifolding");
|
let mut transcript_p: PoseidonTranscript<Projective> =
|
||||||
transcript_p.append_message(b"init", b"init").unwrap();
|
PoseidonTranscript::<Projective>::new(&poseidon_config);
|
||||||
|
transcript_p.absorb(&Fr::from_le_bytes_mod_order(b"init init"));
|
||||||
|
|
||||||
// Verifier's transcript
|
// Verifier's transcript
|
||||||
let mut transcript_v = IOPTranscript::<Fr>::new(b"multifolding");
|
let mut transcript_v: PoseidonTranscript<Projective> =
|
||||||
transcript_v.append_message(b"init", b"init").unwrap();
|
PoseidonTranscript::<Projective>::new(&poseidon_config);
|
||||||
|
transcript_v.absorb(&Fr::from_le_bytes_mod_order(b"init init"));
|
||||||
|
|
||||||
let n_steps = 3;
|
let n_steps = 3;
|
||||||
|
|
||||||
@@ -655,7 +690,8 @@ pub mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Run the prover side of the multifolding
|
// Run the prover side of the multifolding
|
||||||
let (proof, folded_lcccs, folded_witness) = NIMFS::<Projective>::prove(
|
let (proof, folded_lcccs, folded_witness) =
|
||||||
|
NIMFS::<Projective, PoseidonTranscript<Projective>>::prove(
|
||||||
&mut transcript_p,
|
&mut transcript_p,
|
||||||
&ccs,
|
&ccs,
|
||||||
&lcccs_instances,
|
&lcccs_instances,
|
||||||
@@ -666,7 +702,7 @@ pub mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Run the verifier side of the multifolding
|
// Run the verifier side of the multifolding
|
||||||
let folded_lcccs_v = NIMFS::<Projective>::verify(
|
let folded_lcccs_v = NIMFS::<Projective, PoseidonTranscript<Projective>>::verify(
|
||||||
&mut transcript_v,
|
&mut transcript_v,
|
||||||
&ccs,
|
&ccs,
|
||||||
&lcccs_instances,
|
&lcccs_instances,
|
||||||
@@ -674,6 +710,7 @@ pub mod tests {
|
|||||||
proof,
|
proof,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(folded_lcccs, folded_lcccs_v);
|
assert_eq!(folded_lcccs, folded_lcccs_v);
|
||||||
|
|
||||||
// Check that the folded LCCCS instance is a valid instance with respect to the folded witness
|
// Check that the folded LCCCS instance is a valid instance with respect to the folded witness
|
||||||
|
|||||||
@@ -43,6 +43,10 @@ pub enum Error {
|
|||||||
R1CSUnrelaxedFail,
|
R1CSUnrelaxedFail,
|
||||||
#[error("Could not find the inner ConstraintSystem")]
|
#[error("Could not find the inner ConstraintSystem")]
|
||||||
NoInnerConstraintSystem,
|
NoInnerConstraintSystem,
|
||||||
|
#[error("Sum-check prove failed: {0}")]
|
||||||
|
SumCheckProveError(String),
|
||||||
|
#[error("Sum-check verify failed: {0}")]
|
||||||
|
SumCheckVerifyError(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// FoldingScheme defines trait that is implemented by the diverse folding schemes. It is defined
|
/// FoldingScheme defines trait that is implemented by the diverse folding schemes. It is defined
|
||||||
|
|||||||
@@ -9,60 +9,56 @@
|
|||||||
|
|
||||||
//! This module implements the sum check protocol.
|
//! This module implements the sum check protocol.
|
||||||
|
|
||||||
use crate::utils::virtual_polynomial::{VPAuxInfo, VirtualPolynomial};
|
use crate::{
|
||||||
|
transcript::Transcript,
|
||||||
|
utils::virtual_polynomial::{VPAuxInfo, VirtualPolynomial},
|
||||||
|
};
|
||||||
|
use ark_ec::{CurveGroup, Group};
|
||||||
use ark_ff::PrimeField;
|
use ark_ff::PrimeField;
|
||||||
use ark_poly::DenseMultilinearExtension;
|
use ark_poly::DenseMultilinearExtension;
|
||||||
use ark_std::{end_timer, start_timer};
|
use ark_std::{end_timer, start_timer};
|
||||||
use std::{fmt::Debug, sync::Arc};
|
use std::{fmt::Debug, marker::PhantomData, sync::Arc};
|
||||||
|
|
||||||
use espresso_subroutines::poly_iop::{prelude::PolyIOPErrors, PolyIOP};
|
use crate::utils::sum_check::structs::IOPProverMessage;
|
||||||
use espresso_transcript::IOPTranscript;
|
use crate::utils::sum_check::structs::IOPVerifierState;
|
||||||
use structs::{IOPProof, IOPProverState, IOPVerifierState};
|
use espresso_subroutines::poly_iop::prelude::PolyIOPErrors;
|
||||||
|
use structs::{IOPProof, IOPProverState};
|
||||||
|
|
||||||
mod prover;
|
mod prover;
|
||||||
pub mod structs;
|
pub mod structs;
|
||||||
pub mod verifier;
|
pub mod verifier;
|
||||||
|
|
||||||
/// Trait for doing sum check protocols.
|
/// A generic sum-check trait over a curve group
|
||||||
pub trait SumCheck<F: PrimeField> {
|
pub trait SumCheck<C: CurveGroup> {
|
||||||
type VirtualPolynomial;
|
type VirtualPolynomial;
|
||||||
type VPAuxInfo;
|
type VPAuxInfo;
|
||||||
type MultilinearExtension;
|
type MultilinearExtension;
|
||||||
|
|
||||||
type SumCheckProof: Clone + Debug + Default + PartialEq;
|
type SumCheckProof: Clone + Debug + Default + PartialEq;
|
||||||
type Transcript;
|
|
||||||
type SumCheckSubClaim: Clone + Debug + Default + PartialEq;
|
type SumCheckSubClaim: Clone + Debug + Default + PartialEq;
|
||||||
|
|
||||||
/// Extract sum from the proof
|
/// Extract sum from the proof
|
||||||
fn extract_sum(proof: &Self::SumCheckProof) -> F;
|
fn extract_sum(proof: &Self::SumCheckProof) -> C::ScalarField;
|
||||||
|
|
||||||
/// Initialize the system with a transcript
|
|
||||||
///
|
|
||||||
/// This function is optional -- in the case where a SumCheck is
|
|
||||||
/// an building block for a more complex protocol, the transcript
|
|
||||||
/// may be initialized by this complex protocol, and passed to the
|
|
||||||
/// SumCheck prover/verifier.
|
|
||||||
fn init_transcript() -> Self::Transcript;
|
|
||||||
|
|
||||||
/// Generate proof of the sum of polynomial over {0,1}^`num_vars`
|
/// Generate proof of the sum of polynomial over {0,1}^`num_vars`
|
||||||
///
|
///
|
||||||
/// The polynomial is represented in the form of a VirtualPolynomial.
|
/// The polynomial is represented in the form of a VirtualPolynomial.
|
||||||
fn prove(
|
fn prove(
|
||||||
poly: &Self::VirtualPolynomial,
|
poly: &Self::VirtualPolynomial,
|
||||||
transcript: &mut Self::Transcript,
|
transcript: &mut impl Transcript<C>,
|
||||||
) -> Result<Self::SumCheckProof, PolyIOPErrors>;
|
) -> Result<Self::SumCheckProof, PolyIOPErrors>;
|
||||||
|
|
||||||
/// Verify the claimed sum using the proof
|
/// Verify the claimed sum using the proof
|
||||||
fn verify(
|
fn verify(
|
||||||
sum: F,
|
sum: C::ScalarField,
|
||||||
proof: &Self::SumCheckProof,
|
proof: &Self::SumCheckProof,
|
||||||
aux_info: &Self::VPAuxInfo,
|
aux_info: &Self::VPAuxInfo,
|
||||||
transcript: &mut Self::Transcript,
|
transcript: &mut impl Transcript<C>,
|
||||||
) -> Result<Self::SumCheckSubClaim, PolyIOPErrors>;
|
) -> Result<Self::SumCheckSubClaim, PolyIOPErrors>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait for sum check protocol prover side APIs.
|
/// Trait for sum check protocol prover side APIs.
|
||||||
pub trait SumCheckProver<F: PrimeField>
|
pub trait SumCheckProver<C: CurveGroup>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
@@ -79,16 +75,15 @@ where
|
|||||||
/// Main algorithm used is from section 3.2 of [XZZPS19](https://eprint.iacr.org/2019/317.pdf#subsection.3.2).
|
/// Main algorithm used is from section 3.2 of [XZZPS19](https://eprint.iacr.org/2019/317.pdf#subsection.3.2).
|
||||||
fn prove_round_and_update_state(
|
fn prove_round_and_update_state(
|
||||||
&mut self,
|
&mut self,
|
||||||
challenge: &Option<F>,
|
challenge: &Option<C::ScalarField>,
|
||||||
) -> Result<Self::ProverMessage, PolyIOPErrors>;
|
) -> Result<Self::ProverMessage, PolyIOPErrors>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait for sum check protocol verifier side APIs.
|
/// Trait for sum check protocol verifier side APIs.
|
||||||
pub trait SumCheckVerifier<F: PrimeField> {
|
pub trait SumCheckVerifier<C: CurveGroup> {
|
||||||
type VPAuxInfo;
|
type VPAuxInfo;
|
||||||
type ProverMessage;
|
type ProverMessage;
|
||||||
type Challenge;
|
type Challenge;
|
||||||
type Transcript;
|
|
||||||
type SumCheckSubClaim;
|
type SumCheckSubClaim;
|
||||||
|
|
||||||
/// Initialize the verifier's state.
|
/// Initialize the verifier's state.
|
||||||
@@ -103,7 +98,7 @@ pub trait SumCheckVerifier<F: PrimeField> {
|
|||||||
fn verify_round_and_update_state(
|
fn verify_round_and_update_state(
|
||||||
&mut self,
|
&mut self,
|
||||||
prover_msg: &Self::ProverMessage,
|
prover_msg: &Self::ProverMessage,
|
||||||
transcript: &mut Self::Transcript,
|
transcript: &mut impl Transcript<C>,
|
||||||
) -> Result<Self::Challenge, PolyIOPErrors>;
|
) -> Result<Self::Challenge, PolyIOPErrors>;
|
||||||
|
|
||||||
/// This function verifies the deferred checks in the interactive version of
|
/// This function verifies the deferred checks in the interactive version of
|
||||||
@@ -116,7 +111,7 @@ pub trait SumCheckVerifier<F: PrimeField> {
|
|||||||
/// Larger field size guarantees smaller soundness error.
|
/// Larger field size guarantees smaller soundness error.
|
||||||
fn check_and_generate_subclaim(
|
fn check_and_generate_subclaim(
|
||||||
&self,
|
&self,
|
||||||
asserted_sum: &F,
|
asserted_sum: &C::ScalarField,
|
||||||
) -> Result<Self::SumCheckSubClaim, PolyIOPErrors>;
|
) -> Result<Self::SumCheckSubClaim, PolyIOPErrors>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,52 +126,52 @@ pub struct SumCheckSubClaim<F: PrimeField> {
|
|||||||
pub expected_evaluation: F,
|
pub expected_evaluation: F,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: PrimeField> SumCheck<F> for PolyIOP<F> {
|
#[derive(Clone, Debug, Default, Copy, PartialEq, Eq)]
|
||||||
type SumCheckProof = IOPProof<F>;
|
pub struct IOPSumCheck<C: CurveGroup, T: Transcript<C>> {
|
||||||
type VirtualPolynomial = VirtualPolynomial<F>;
|
#[doc(hidden)]
|
||||||
type VPAuxInfo = VPAuxInfo<F>;
|
phantom: PhantomData<C>,
|
||||||
type MultilinearExtension = Arc<DenseMultilinearExtension<F>>;
|
#[doc(hidden)]
|
||||||
type SumCheckSubClaim = SumCheckSubClaim<F>;
|
phantom2: PhantomData<T>,
|
||||||
type Transcript = IOPTranscript<F>;
|
}
|
||||||
|
|
||||||
fn extract_sum(proof: &Self::SumCheckProof) -> F {
|
impl<C: CurveGroup, T: Transcript<C>> SumCheck<C> for IOPSumCheck<C, T> {
|
||||||
|
type SumCheckProof = IOPProof<C::ScalarField>;
|
||||||
|
type VirtualPolynomial = VirtualPolynomial<C::ScalarField>;
|
||||||
|
type VPAuxInfo = VPAuxInfo<C::ScalarField>;
|
||||||
|
type MultilinearExtension = Arc<DenseMultilinearExtension<C::ScalarField>>;
|
||||||
|
type SumCheckSubClaim = SumCheckSubClaim<C::ScalarField>;
|
||||||
|
|
||||||
|
fn extract_sum(proof: &Self::SumCheckProof) -> C::ScalarField {
|
||||||
let start = start_timer!(|| "extract sum");
|
let start = start_timer!(|| "extract sum");
|
||||||
let res = proof.proofs[0].evaluations[0] + proof.proofs[0].evaluations[1];
|
let res = proof.proofs[0].evaluations[0] + proof.proofs[0].evaluations[1];
|
||||||
end_timer!(start);
|
end_timer!(start);
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_transcript() -> Self::Transcript {
|
|
||||||
let start = start_timer!(|| "init transcript");
|
|
||||||
let res = IOPTranscript::<F>::new(b"Initializing SumCheck transcript");
|
|
||||||
end_timer!(start);
|
|
||||||
res
|
|
||||||
}
|
|
||||||
|
|
||||||
fn prove(
|
fn prove(
|
||||||
poly: &Self::VirtualPolynomial,
|
poly: &VirtualPolynomial<C::ScalarField>,
|
||||||
transcript: &mut Self::Transcript,
|
transcript: &mut impl Transcript<C>,
|
||||||
) -> Result<Self::SumCheckProof, PolyIOPErrors> {
|
) -> Result<IOPProof<C::ScalarField>, PolyIOPErrors> {
|
||||||
let start = start_timer!(|| "sum check prove");
|
transcript.absorb(&<C as Group>::ScalarField::from(
|
||||||
|
poly.aux_info.num_variables as u64,
|
||||||
transcript.append_serializable_element(b"aux info", &poly.aux_info)?;
|
));
|
||||||
|
transcript.absorb(&<C as Group>::ScalarField::from(
|
||||||
let mut prover_state = IOPProverState::prover_init(poly)?;
|
poly.aux_info.max_degree as u64,
|
||||||
let mut challenge = None;
|
));
|
||||||
let mut prover_msgs = Vec::with_capacity(poly.aux_info.num_variables);
|
let mut prover_state: IOPProverState<C> = IOPProverState::prover_init(poly)?;
|
||||||
|
let mut challenge: Option<C::ScalarField> = None;
|
||||||
|
let mut prover_msgs: Vec<IOPProverMessage<C::ScalarField>> =
|
||||||
|
Vec::with_capacity(poly.aux_info.num_variables);
|
||||||
for _ in 0..poly.aux_info.num_variables {
|
for _ in 0..poly.aux_info.num_variables {
|
||||||
let prover_msg =
|
let prover_msg: IOPProverMessage<C::ScalarField> =
|
||||||
IOPProverState::prove_round_and_update_state(&mut prover_state, &challenge)?;
|
IOPProverState::prove_round_and_update_state(&mut prover_state, &challenge)?;
|
||||||
transcript.append_serializable_element(b"prover msg", &prover_msg)?;
|
transcript.absorb_vec(&prover_msg.evaluations);
|
||||||
prover_msgs.push(prover_msg);
|
prover_msgs.push(prover_msg);
|
||||||
challenge = Some(transcript.get_and_append_challenge(b"Internal round")?);
|
challenge = Some(transcript.get_challenge());
|
||||||
}
|
}
|
||||||
// pushing the last challenge point to the state
|
|
||||||
if let Some(p) = challenge {
|
if let Some(p) = challenge {
|
||||||
prover_state.challenges.push(p)
|
prover_state.challenges.push(p)
|
||||||
};
|
};
|
||||||
|
|
||||||
end_timer!(start);
|
|
||||||
Ok(IOPProof {
|
Ok(IOPProof {
|
||||||
point: prover_state.challenges,
|
point: prover_state.challenges,
|
||||||
proofs: prover_msgs,
|
proofs: prover_msgs,
|
||||||
@@ -184,18 +179,19 @@ impl<F: PrimeField> SumCheck<F> for PolyIOP<F> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn verify(
|
fn verify(
|
||||||
claimed_sum: F,
|
claimed_sum: C::ScalarField,
|
||||||
proof: &Self::SumCheckProof,
|
proof: &IOPProof<C::ScalarField>,
|
||||||
aux_info: &Self::VPAuxInfo,
|
aux_info: &VPAuxInfo<C::ScalarField>,
|
||||||
transcript: &mut Self::Transcript,
|
transcript: &mut impl Transcript<C>,
|
||||||
) -> Result<Self::SumCheckSubClaim, PolyIOPErrors> {
|
) -> Result<SumCheckSubClaim<C::ScalarField>, PolyIOPErrors> {
|
||||||
let start = start_timer!(|| "sum check verify");
|
transcript.absorb(&<C as Group>::ScalarField::from(
|
||||||
|
aux_info.num_variables as u64,
|
||||||
transcript.append_serializable_element(b"aux info", aux_info)?;
|
));
|
||||||
|
transcript.absorb(&<C as Group>::ScalarField::from(aux_info.max_degree as u64));
|
||||||
let mut verifier_state = IOPVerifierState::verifier_init(aux_info);
|
let mut verifier_state = IOPVerifierState::verifier_init(aux_info);
|
||||||
for i in 0..aux_info.num_variables {
|
for i in 0..aux_info.num_variables {
|
||||||
let prover_msg = proof.proofs.get(i).expect("proof is incomplete");
|
let prover_msg = proof.proofs.get(i).expect("proof is incomplete");
|
||||||
transcript.append_serializable_element(b"prover msg", prover_msg)?;
|
transcript.absorb_vec(&prover_msg.evaluations);
|
||||||
IOPVerifierState::verify_round_and_update_state(
|
IOPVerifierState::verify_round_and_update_state(
|
||||||
&mut verifier_state,
|
&mut verifier_state,
|
||||||
prover_msg,
|
prover_msg,
|
||||||
@@ -203,9 +199,57 @@ impl<F: PrimeField> SumCheck<F> for PolyIOP<F> {
|
|||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = IOPVerifierState::check_and_generate_subclaim(&verifier_state, &claimed_sum);
|
IOPVerifierState::check_and_generate_subclaim(&verifier_state, &claimed_sum)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
end_timer!(start);
|
#[cfg(test)]
|
||||||
res
|
pub mod tests {
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use ark_ff::Field;
|
||||||
|
use ark_pallas::Fr;
|
||||||
|
use ark_pallas::Projective;
|
||||||
|
use ark_poly::DenseMultilinearExtension;
|
||||||
|
use ark_poly::MultilinearExtension;
|
||||||
|
use ark_std::test_rng;
|
||||||
|
|
||||||
|
use crate::transcript::poseidon::tests::poseidon_test_config;
|
||||||
|
use crate::transcript::poseidon::PoseidonTranscript;
|
||||||
|
use crate::transcript::Transcript;
|
||||||
|
use crate::utils::sum_check::SumCheck;
|
||||||
|
use crate::utils::virtual_polynomial::VirtualPolynomial;
|
||||||
|
|
||||||
|
use super::IOPSumCheck;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn sumcheck_poseidon() {
|
||||||
|
let mut rng = test_rng();
|
||||||
|
let poly_mle = DenseMultilinearExtension::rand(5, &mut rng);
|
||||||
|
let virtual_poly = VirtualPolynomial::new_from_mle(&Arc::new(poly_mle), Fr::ONE);
|
||||||
|
let poseidon_config = poseidon_test_config::<Fr>();
|
||||||
|
|
||||||
|
// sum-check prove
|
||||||
|
let mut poseidon_transcript_prove: PoseidonTranscript<Projective> =
|
||||||
|
PoseidonTranscript::<Projective>::new(&poseidon_config);
|
||||||
|
let sum_check = IOPSumCheck::<Projective, PoseidonTranscript<Projective>>::prove(
|
||||||
|
&virtual_poly,
|
||||||
|
&mut poseidon_transcript_prove,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// sum-check verify
|
||||||
|
let claimed_sum =
|
||||||
|
IOPSumCheck::<Projective, PoseidonTranscript<Projective>>::extract_sum(&sum_check);
|
||||||
|
let mut poseidon_transcript_verify: PoseidonTranscript<Projective> =
|
||||||
|
PoseidonTranscript::<Projective>::new(&poseidon_config);
|
||||||
|
let res_verify = IOPSumCheck::<Projective, PoseidonTranscript<Projective>>::verify(
|
||||||
|
claimed_sum,
|
||||||
|
&sum_check,
|
||||||
|
&virtual_poly.aux_info,
|
||||||
|
&mut poseidon_transcript_verify,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(res_verify.is_ok());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,8 @@
|
|||||||
use super::SumCheckProver;
|
use super::SumCheckProver;
|
||||||
use crate::utils::multilinear_polynomial::fix_variables;
|
use crate::utils::multilinear_polynomial::fix_variables;
|
||||||
use crate::utils::virtual_polynomial::VirtualPolynomial;
|
use crate::utils::virtual_polynomial::VirtualPolynomial;
|
||||||
|
use ark_ec::CurveGroup;
|
||||||
|
use ark_ff::Field;
|
||||||
use ark_ff::{batch_inversion, PrimeField};
|
use ark_ff::{batch_inversion, PrimeField};
|
||||||
use ark_poly::DenseMultilinearExtension;
|
use ark_poly::DenseMultilinearExtension;
|
||||||
use ark_std::{cfg_into_iter, end_timer, start_timer, vec::Vec};
|
use ark_std::{cfg_into_iter, end_timer, start_timer, vec::Vec};
|
||||||
@@ -24,9 +26,9 @@ use espresso_subroutines::poly_iop::prelude::PolyIOPErrors;
|
|||||||
// #[cfg(feature = "parallel")]
|
// #[cfg(feature = "parallel")]
|
||||||
use rayon::iter::{IntoParallelRefMutIterator, ParallelIterator};
|
use rayon::iter::{IntoParallelRefMutIterator, ParallelIterator};
|
||||||
|
|
||||||
impl<F: PrimeField> SumCheckProver<F> for IOPProverState<F> {
|
impl<C: CurveGroup> SumCheckProver<C> for IOPProverState<C> {
|
||||||
type VirtualPolynomial = VirtualPolynomial<F>;
|
type VirtualPolynomial = VirtualPolynomial<C::ScalarField>;
|
||||||
type ProverMessage = IOPProverMessage<F>;
|
type ProverMessage = IOPProverMessage<C::ScalarField>;
|
||||||
|
|
||||||
/// Initialize the prover state to argue for the sum of the input polynomial
|
/// Initialize the prover state to argue for the sum of the input polynomial
|
||||||
/// over {0,1}^`num_vars`.
|
/// over {0,1}^`num_vars`.
|
||||||
@@ -45,7 +47,9 @@ impl<F: PrimeField> SumCheckProver<F> for IOPProverState<F> {
|
|||||||
poly: polynomial.clone(),
|
poly: polynomial.clone(),
|
||||||
extrapolation_aux: (1..polynomial.aux_info.max_degree)
|
extrapolation_aux: (1..polynomial.aux_info.max_degree)
|
||||||
.map(|degree| {
|
.map(|degree| {
|
||||||
let points = (0..1 + degree as u64).map(F::from).collect::<Vec<_>>();
|
let points = (0..1 + degree as u64)
|
||||||
|
.map(C::ScalarField::from)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
let weights = barycentric_weights(&points);
|
let weights = barycentric_weights(&points);
|
||||||
(points, weights)
|
(points, weights)
|
||||||
})
|
})
|
||||||
@@ -59,7 +63,7 @@ impl<F: PrimeField> SumCheckProver<F> for IOPProverState<F> {
|
|||||||
/// Main algorithm used is from section 3.2 of [XZZPS19](https://eprint.iacr.org/2019/317.pdf#subsection.3.2).
|
/// Main algorithm used is from section 3.2 of [XZZPS19](https://eprint.iacr.org/2019/317.pdf#subsection.3.2).
|
||||||
fn prove_round_and_update_state(
|
fn prove_round_and_update_state(
|
||||||
&mut self,
|
&mut self,
|
||||||
challenge: &Option<F>,
|
challenge: &Option<C::ScalarField>,
|
||||||
) -> Result<Self::ProverMessage, PolyIOPErrors> {
|
) -> Result<Self::ProverMessage, PolyIOPErrors> {
|
||||||
// let start =
|
// let start =
|
||||||
// start_timer!(|| format!("sum check prove {}-th round and update state",
|
// start_timer!(|| format!("sum check prove {}-th round and update state",
|
||||||
@@ -84,7 +88,7 @@ impl<F: PrimeField> SumCheckProver<F> for IOPProverState<F> {
|
|||||||
// g(r_1, ..., r_{m-1}, x_m ... x_n)
|
// g(r_1, ..., r_{m-1}, x_m ... x_n)
|
||||||
//
|
//
|
||||||
// eval g over r_m, and mutate g to g(r_1, ... r_m,, x_{m+1}... x_n)
|
// eval g over r_m, and mutate g to g(r_1, ... r_m,, x_{m+1}... x_n)
|
||||||
let mut flattened_ml_extensions: Vec<DenseMultilinearExtension<F>> = self
|
let mut flattened_ml_extensions: Vec<DenseMultilinearExtension<C::ScalarField>> = self
|
||||||
.poly
|
.poly
|
||||||
.flattened_ml_extensions
|
.flattened_ml_extensions
|
||||||
.par_iter()
|
.par_iter()
|
||||||
@@ -118,7 +122,7 @@ impl<F: PrimeField> SumCheckProver<F> for IOPProverState<F> {
|
|||||||
self.round += 1;
|
self.round += 1;
|
||||||
|
|
||||||
let products_list = self.poly.products.clone();
|
let products_list = self.poly.products.clone();
|
||||||
let mut products_sum = vec![F::zero(); self.poly.aux_info.max_degree + 1];
|
let mut products_sum = vec![C::ScalarField::ZERO; self.poly.aux_info.max_degree + 1];
|
||||||
|
|
||||||
// Step 2: generate sum for the partial evaluated polynomial:
|
// Step 2: generate sum for the partial evaluated polynomial:
|
||||||
// f(r_1, ... r_m,, x_{m+1}... x_n)
|
// f(r_1, ... r_m,, x_{m+1}... x_n)
|
||||||
@@ -128,8 +132,8 @@ impl<F: PrimeField> SumCheckProver<F> for IOPProverState<F> {
|
|||||||
.fold(
|
.fold(
|
||||||
|| {
|
|| {
|
||||||
(
|
(
|
||||||
vec![(F::zero(), F::zero()); products.len()],
|
vec![(C::ScalarField::ZERO, C::ScalarField::ZERO); products.len()],
|
||||||
vec![F::zero(); products.len() + 1],
|
vec![C::ScalarField::ZERO; products.len() + 1],
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|(mut buf, mut acc), b| {
|
|(mut buf, mut acc), b| {
|
||||||
@@ -140,17 +144,17 @@ impl<F: PrimeField> SumCheckProver<F> for IOPProverState<F> {
|
|||||||
*eval = table[b << 1];
|
*eval = table[b << 1];
|
||||||
*step = table[(b << 1) + 1] - table[b << 1];
|
*step = table[(b << 1) + 1] - table[b << 1];
|
||||||
});
|
});
|
||||||
acc[0] += buf.iter().map(|(eval, _)| eval).product::<F>();
|
acc[0] += buf.iter().map(|(eval, _)| eval).product::<C::ScalarField>();
|
||||||
acc[1..].iter_mut().for_each(|acc| {
|
acc[1..].iter_mut().for_each(|acc| {
|
||||||
buf.iter_mut().for_each(|(eval, step)| *eval += step as &_);
|
buf.iter_mut().for_each(|(eval, step)| *eval += step as &_);
|
||||||
*acc += buf.iter().map(|(eval, _)| eval).product::<F>();
|
*acc += buf.iter().map(|(eval, _)| eval).product::<C::ScalarField>();
|
||||||
});
|
});
|
||||||
(buf, acc)
|
(buf, acc)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.map(|(_, partial)| partial)
|
.map(|(_, partial)| partial)
|
||||||
.reduce(
|
.reduce(
|
||||||
|| vec![F::zero(); products.len() + 1],
|
|| vec![C::ScalarField::ZERO; products.len() + 1],
|
||||||
|mut sum, partial| {
|
|mut sum, partial| {
|
||||||
sum.iter_mut()
|
sum.iter_mut()
|
||||||
.zip(partial.iter())
|
.zip(partial.iter())
|
||||||
@@ -162,7 +166,7 @@ impl<F: PrimeField> SumCheckProver<F> for IOPProverState<F> {
|
|||||||
let extraploation = cfg_into_iter!(0..self.poly.aux_info.max_degree - products.len())
|
let extraploation = cfg_into_iter!(0..self.poly.aux_info.max_degree - products.len())
|
||||||
.map(|i| {
|
.map(|i| {
|
||||||
let (points, weights) = &self.extrapolation_aux[products.len() - 1];
|
let (points, weights) = &self.extrapolation_aux[products.len() - 1];
|
||||||
let at = F::from((products.len() + 1 + i) as u64);
|
let at = C::ScalarField::from((products.len() + 1 + i) as u64);
|
||||||
extrapolate(points, weights, &sum, &at)
|
extrapolate(points, weights, &sum, &at)
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
//! This module defines structs that are shared by all sub protocols.
|
//! This module defines structs that are shared by all sub protocols.
|
||||||
|
|
||||||
use crate::utils::virtual_polynomial::VirtualPolynomial;
|
use crate::utils::virtual_polynomial::VirtualPolynomial;
|
||||||
|
use ark_ec::CurveGroup;
|
||||||
use ark_ff::PrimeField;
|
use ark_ff::PrimeField;
|
||||||
use ark_serialize::CanonicalSerialize;
|
use ark_serialize::CanonicalSerialize;
|
||||||
|
|
||||||
@@ -32,28 +33,29 @@ pub struct IOPProverMessage<F: PrimeField> {
|
|||||||
|
|
||||||
/// Prover State of a PolyIOP.
|
/// Prover State of a PolyIOP.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct IOPProverState<F: PrimeField> {
|
pub struct IOPProverState<C: CurveGroup> {
|
||||||
/// sampled randomness given by the verifier
|
/// sampled randomness given by the verifier
|
||||||
pub challenges: Vec<F>,
|
pub challenges: Vec<C::ScalarField>,
|
||||||
/// the current round number
|
/// the current round number
|
||||||
pub(crate) round: usize,
|
pub(crate) round: usize,
|
||||||
/// pointer to the virtual polynomial
|
/// pointer to the virtual polynomial
|
||||||
pub(crate) poly: VirtualPolynomial<F>,
|
pub(crate) poly: VirtualPolynomial<C::ScalarField>,
|
||||||
/// points with precomputed barycentric weights for extrapolating smaller
|
/// points with precomputed barycentric weights for extrapolating smaller
|
||||||
/// degree uni-polys to `max_degree + 1` evaluations.
|
/// degree uni-polys to `max_degree + 1` evaluations.
|
||||||
pub(crate) extrapolation_aux: Vec<(Vec<F>, Vec<F>)>,
|
#[allow(clippy::type_complexity)]
|
||||||
|
pub(crate) extrapolation_aux: Vec<(Vec<C::ScalarField>, Vec<C::ScalarField>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prover State of a PolyIOP
|
/// Verifier State of a PolyIOP, generic over a curve group
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct IOPVerifierState<F: PrimeField> {
|
pub struct IOPVerifierState<C: CurveGroup> {
|
||||||
pub(crate) round: usize,
|
pub(crate) round: usize,
|
||||||
pub(crate) num_vars: usize,
|
pub(crate) num_vars: usize,
|
||||||
pub(crate) max_degree: usize,
|
pub(crate) max_degree: usize,
|
||||||
pub(crate) finished: bool,
|
pub(crate) finished: bool,
|
||||||
/// a list storing the univariate polynomial in evaluation form sent by the
|
/// a list storing the univariate polynomial in evaluation form sent by the
|
||||||
/// prover at each round
|
/// prover at each round
|
||||||
pub(crate) polynomials_received: Vec<Vec<F>>,
|
pub(crate) polynomials_received: Vec<Vec<C::ScalarField>>,
|
||||||
/// a list storing the randomness sampled by the verifier at each round
|
/// a list storing the randomness sampled by the verifier at each round
|
||||||
pub(crate) challenges: Vec<F>,
|
pub(crate) challenges: Vec<C::ScalarField>,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,24 +9,25 @@
|
|||||||
|
|
||||||
//! Verifier subroutines for a SumCheck protocol.
|
//! Verifier subroutines for a SumCheck protocol.
|
||||||
|
|
||||||
use super::{SumCheckSubClaim, SumCheckVerifier};
|
use super::{
|
||||||
use crate::utils::virtual_polynomial::VPAuxInfo;
|
structs::{IOPProverMessage, IOPVerifierState},
|
||||||
|
SumCheckSubClaim, SumCheckVerifier,
|
||||||
|
};
|
||||||
|
use crate::{transcript::Transcript, utils::virtual_polynomial::VPAuxInfo};
|
||||||
|
use ark_ec::CurveGroup;
|
||||||
use ark_ff::PrimeField;
|
use ark_ff::PrimeField;
|
||||||
use ark_std::{end_timer, start_timer};
|
use ark_std::{end_timer, start_timer};
|
||||||
|
|
||||||
use super::structs::{IOPProverMessage, IOPVerifierState};
|
|
||||||
use espresso_subroutines::poly_iop::prelude::PolyIOPErrors;
|
use espresso_subroutines::poly_iop::prelude::PolyIOPErrors;
|
||||||
use espresso_transcript::IOPTranscript;
|
|
||||||
|
|
||||||
#[cfg(feature = "parallel")]
|
#[cfg(feature = "parallel")]
|
||||||
use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator};
|
use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator};
|
||||||
|
|
||||||
impl<F: PrimeField> SumCheckVerifier<F> for IOPVerifierState<F> {
|
impl<C: CurveGroup> SumCheckVerifier<C> for IOPVerifierState<C> {
|
||||||
type VPAuxInfo = VPAuxInfo<F>;
|
type VPAuxInfo = VPAuxInfo<C::ScalarField>;
|
||||||
type ProverMessage = IOPProverMessage<F>;
|
type ProverMessage = IOPProverMessage<C::ScalarField>;
|
||||||
type Challenge = F;
|
type Challenge = C::ScalarField;
|
||||||
type Transcript = IOPTranscript<F>;
|
type SumCheckSubClaim = SumCheckSubClaim<C::ScalarField>;
|
||||||
type SumCheckSubClaim = SumCheckSubClaim<F>;
|
|
||||||
|
|
||||||
/// Initialize the verifier's state.
|
/// Initialize the verifier's state.
|
||||||
fn verifier_init(index_info: &Self::VPAuxInfo) -> Self {
|
fn verifier_init(index_info: &Self::VPAuxInfo) -> Self {
|
||||||
@@ -43,17 +44,11 @@ impl<F: PrimeField> SumCheckVerifier<F> for IOPVerifierState<F> {
|
|||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run verifier for the current round, given a prover message.
|
|
||||||
///
|
|
||||||
/// Note that `verify_round_and_update_state` only samples and stores
|
|
||||||
/// challenges; and update the verifier's state accordingly. The actual
|
|
||||||
/// verifications are deferred (in batch) to `check_and_generate_subclaim`
|
|
||||||
/// at the last step.
|
|
||||||
fn verify_round_and_update_state(
|
fn verify_round_and_update_state(
|
||||||
&mut self,
|
&mut self,
|
||||||
prover_msg: &Self::ProverMessage,
|
prover_msg: &<IOPVerifierState<C> as SumCheckVerifier<C>>::ProverMessage,
|
||||||
transcript: &mut Self::Transcript,
|
transcript: &mut impl Transcript<C>,
|
||||||
) -> Result<Self::Challenge, PolyIOPErrors> {
|
) -> Result<<IOPVerifierState<C> as SumCheckVerifier<C>>::Challenge, PolyIOPErrors> {
|
||||||
let start =
|
let start =
|
||||||
start_timer!(|| format!("sum check verify {}-th round and update state", self.round));
|
start_timer!(|| format!("sum check verify {}-th round and update state", self.round));
|
||||||
|
|
||||||
@@ -70,8 +65,7 @@ impl<F: PrimeField> SumCheckVerifier<F> for IOPVerifierState<F> {
|
|||||||
//
|
//
|
||||||
// When we turn the protocol to a non-interactive one, it is sufficient to defer
|
// When we turn the protocol to a non-interactive one, it is sufficient to defer
|
||||||
// such checks to `check_and_generate_subclaim` after the last round.
|
// such checks to `check_and_generate_subclaim` after the last round.
|
||||||
|
let challenge = transcript.get_challenge();
|
||||||
let challenge = transcript.get_and_append_challenge(b"Internal round")?;
|
|
||||||
self.challenges.push(challenge);
|
self.challenges.push(challenge);
|
||||||
self.polynomials_received
|
self.polynomials_received
|
||||||
.push(prover_msg.evaluations.to_vec());
|
.push(prover_msg.evaluations.to_vec());
|
||||||
@@ -88,17 +82,9 @@ impl<F: PrimeField> SumCheckVerifier<F> for IOPVerifierState<F> {
|
|||||||
Ok(challenge)
|
Ok(challenge)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function verifies the deferred checks in the interactive version of
|
|
||||||
/// the protocol; and generate the subclaim. Returns an error if the
|
|
||||||
/// proof failed to verify.
|
|
||||||
///
|
|
||||||
/// If the asserted sum is correct, then the multilinear polynomial
|
|
||||||
/// evaluated at `subclaim.point` will be `subclaim.expected_evaluation`.
|
|
||||||
/// Otherwise, it is highly unlikely that those two will be equal.
|
|
||||||
/// Larger field size guarantees smaller soundness error.
|
|
||||||
fn check_and_generate_subclaim(
|
fn check_and_generate_subclaim(
|
||||||
&self,
|
&self,
|
||||||
asserted_sum: &F,
|
asserted_sum: &C::ScalarField,
|
||||||
) -> Result<Self::SumCheckSubClaim, PolyIOPErrors> {
|
) -> Result<Self::SumCheckSubClaim, PolyIOPErrors> {
|
||||||
let start = start_timer!(|| "sum check check and generate subclaim");
|
let start = start_timer!(|| "sum check check and generate subclaim");
|
||||||
if !self.finished {
|
if !self.finished {
|
||||||
@@ -129,7 +115,7 @@ impl<F: PrimeField> SumCheckVerifier<F> for IOPVerifierState<F> {
|
|||||||
self.max_degree + 1
|
self.max_degree + 1
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
interpolate_uni_poly::<F>(&evaluations, challenge)
|
interpolate_uni_poly::<C::ScalarField>(&evaluations, challenge)
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>, PolyIOPErrors>>()?;
|
.collect::<Result<Vec<_>, PolyIOPErrors>>()?;
|
||||||
|
|
||||||
@@ -160,6 +146,9 @@ impl<F: PrimeField> SumCheckVerifier<F> for IOPVerifierState<F> {
|
|||||||
.zip(expected_vec.iter())
|
.zip(expected_vec.iter())
|
||||||
.take(self.num_vars)
|
.take(self.num_vars)
|
||||||
{
|
{
|
||||||
|
let eval_: C::ScalarField = evaluations[0] + evaluations[1];
|
||||||
|
|
||||||
|
println!("evaluations: {:?}, expected: {:?}", eval_, expected);
|
||||||
// the deferred check during the interactive phase:
|
// the deferred check during the interactive phase:
|
||||||
// 1. check if the received 'P(0) + P(1) = expected`.
|
// 1. check if the received 'P(0) + P(1) = expected`.
|
||||||
if evaluations[0] + evaluations[1] != expected {
|
if evaluations[0] + evaluations[1] != expected {
|
||||||
|
|||||||
Reference in New Issue
Block a user