Skip to content

Commit

Permalink
Add unified FS::ProverParam & VerifierParam serialization & deseriali…
Browse files Browse the repository at this point in the history
…zation (for all Nova, HyperNova and ProtoGalaxy), without serializing the R1CS/CCS and thus saving substantial serialized bytes space.
  • Loading branch information
arnaucube committed Oct 9, 2024
1 parent 9b36898 commit 0903e24
Show file tree
Hide file tree
Showing 7 changed files with 415 additions and 187 deletions.
26 changes: 5 additions & 21 deletions folding-schemes/src/folding/hypernova/decider_eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,9 +234,7 @@ pub mod tests {
use super::*;
use crate::commitment::{kzg::KZG, pedersen::Pedersen};
use crate::folding::hypernova::cccs::CCCS;
use crate::folding::hypernova::{
PreprocessorParam, ProverParams, VerifierParams as HyperNovaVerifierParams,
};
use crate::folding::hypernova::PreprocessorParam;
use crate::folding::nova::decider_eth::VerifierParam;
use crate::frontend::utils::CubicFCircuit;
use crate::transcript::poseidon::poseidon_canonical_config;
Expand Down Expand Up @@ -371,33 +369,19 @@ pub mod tests {
.serialize_compressed(&mut hypernova_vp_serialized)
.unwrap();

let hypernova_pp_deserialized = ProverParams::<
Projective,
Projective2,
KZG<'static, Bn254>,
Pedersen<Projective2>,
false,
>::deserialize_with_mode(
let hypernova_pp_deserialized = HN::pp_deserialize_with_mode(
hypernova_pp_serialized.as_slice(),
Compress::Yes,
Validate::No,
&hypernova_params.0.ccs,
&poseidon_config,
(), // FCircuit's Params
)
.unwrap();

let hypernova_vp_deserialized = HyperNovaVerifierParams::<
Projective,
Projective2,
KZG<'static, Bn254>,
Pedersen<Projective2>,
false,
>::deserialize_verifier_params(
let hypernova_vp_deserialized = HN::vp_deserialize_with_mode(
hypernova_vp_serialized.as_slice(),
Compress::Yes,
Validate::No,
&hypernova_params.0.ccs.unwrap(),
&poseidon_config,
(), // FCircuit's Params
)
.unwrap();

Expand Down
173 changes: 90 additions & 83 deletions folding-schemes/src/folding/hypernova/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ use ark_crypto_primitives::sponge::{
use ark_ec::{CurveGroup, Group};
use ark_ff::{BigInteger, PrimeField};
use ark_r1cs_std::{groups::GroupOpsBounds, prelude::CurveVar, ToConstraintFieldGadget};
use ark_serialize::{
CanonicalDeserialize, CanonicalSerialize, Compress, SerializationError, Validate,
};
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Compress, SerializationError};
use ark_std::{fmt::Debug, marker::PhantomData, rand::RngCore, One, Zero};

pub mod cccs;
Expand Down Expand Up @@ -39,6 +37,7 @@ use crate::folding::{
traits::{CommittedInstanceOps, Dummy, WitnessOps},
};
use crate::frontend::FCircuit;
use crate::transcript::poseidon::poseidon_canonical_config;
use crate::utils::{get_cm_coordinates, pp_hash};
use crate::Error;
use crate::{
Expand Down Expand Up @@ -140,86 +139,6 @@ impl<
}
}

impl<
C1: CurveGroup,
C2: CurveGroup,
CS1: CommitmentScheme<C1, H>,
CS2: CommitmentScheme<C2, H>,
const H: bool,
> ProverParams<C1, C2, CS1, CS2, H>
{
pub fn deserialize_with_mode<R: std::io::prelude::Read>(
mut reader: R,
compress: Compress,
validate: Validate,
ccs: &Option<CCS<C1::ScalarField>>,
poseidon_config: &PoseidonConfig<C1::ScalarField>,
) -> Result<Self, SerializationError> {
let cs_pp = CS1::ProverParams::deserialize_with_mode(&mut reader, compress, validate)?;
let cf_cs_pp = CS2::ProverParams::deserialize_with_mode(&mut reader, compress, validate)?;

Ok(ProverParams {
cs_pp,
cf_cs_pp,
ccs: ccs.clone(),
poseidon_config: poseidon_config.clone(),
})
}
}

impl<
C1: CurveGroup,
C2: CurveGroup,
CS1: CommitmentScheme<C1, H>,
CS2: CommitmentScheme<C2, H>,
const H: bool,
> CanonicalSerialize for VerifierParams<C1, C2, CS1, CS2, H>
{
fn serialize_with_mode<W: std::io::prelude::Write>(
&self,
mut writer: W,
compress: Compress,
) -> Result<(), SerializationError> {
self.cf_r1cs.serialize_with_mode(&mut writer, compress)?;
self.cs_vp.serialize_with_mode(&mut writer, compress)?;
self.cf_cs_vp.serialize_with_mode(&mut writer, compress)
}

fn serialized_size(&self, compress: Compress) -> usize {
self.cf_r1cs.serialized_size(compress)
+ self.cs_vp.serialized_size(compress)
+ self.cf_cs_vp.serialized_size(compress)
}
}

impl<
C1: CurveGroup,
C2: CurveGroup,
CS1: CommitmentScheme<C1, H>,
CS2: CommitmentScheme<C2, H>,
const H: bool,
> VerifierParams<C1, C2, CS1, CS2, H>
{
pub fn deserialize_verifier_params<R: std::io::Read>(
mut reader: R,
compress: Compress,
validate: Validate,
ccs: &CCS<C1::ScalarField>,
poseidon_config: &PoseidonConfig<C1::ScalarField>,
) -> Result<Self, SerializationError> {
let cf_r1cs = R1CS::deserialize_with_mode(&mut reader, compress, validate)?;
let cs_vp = CS1::VerifierParams::deserialize_with_mode(&mut reader, compress, validate)?;
let cf_cs_vp = CS2::VerifierParams::deserialize_with_mode(&mut reader, compress, validate)?;
Ok(VerifierParams {
ccs: ccs.clone(),
poseidon_config: poseidon_config.clone(),
cf_r1cs,
cs_vp,
cf_cs_vp,
})
}
}

/// Verification parameters for HyperNova-based IVC
#[derive(Debug, Clone)]
pub struct VerifierParams<
Expand All @@ -241,6 +160,27 @@ pub struct VerifierParams<
pub cf_cs_vp: CS2::VerifierParams,
}

impl<C1, C2, CS1, CS2, const H: bool> CanonicalSerialize for VerifierParams<C1, C2, CS1, CS2, H>
where
C1: CurveGroup,
C2: CurveGroup,
CS1: CommitmentScheme<C1, H>,
CS2: CommitmentScheme<C2, H>,
{
fn serialize_with_mode<W: std::io::prelude::Write>(
&self,
mut writer: W,
compress: ark_serialize::Compress,
) -> Result<(), ark_serialize::SerializationError> {
self.cs_vp.serialize_with_mode(&mut writer, compress)?;
self.cf_cs_vp.serialize_with_mode(&mut writer, compress)
}

fn serialized_size(&self, compress: ark_serialize::Compress) -> usize {
self.cs_vp.serialized_size(compress) + self.cf_cs_vp.serialized_size(compress)
}
}

impl<C1, C2, CS1, CS2, const H: bool> VerifierParams<C1, C2, CS1, CS2, H>
where
C1: CurveGroup,
Expand Down Expand Up @@ -541,6 +481,73 @@ where
type CFInstance = (CycleFoldCommittedInstance<C2>, CycleFoldWitness<C2>);
type IVCProof = IVCProof<C1, C2>;

fn pp_deserialize_with_mode<R: std::io::prelude::Read>(
mut reader: R,
compress: ark_serialize::Compress,
validate: ark_serialize::Validate,
fc_params: FC::Params,
) -> Result<Self::ProverParam, Error> {
let poseidon_config = poseidon_canonical_config::<C1::ScalarField>();

// generate the r1cs & cf_r1cs needed for the VerifierParams. In this way we avoid needing
// to serialize them, saving significant space in the VerifierParams serialized size.

// main circuit R1CS:
let f_circuit = FC::new(fc_params)?;
let augmented_F_circuit = AugmentedFCircuit::<C1, C2, GC2, FC, MU, NU>::empty(
&poseidon_config,
f_circuit.clone(),
None,
)?;
let ccs = augmented_F_circuit.ccs;

let cs_pp = CS1::ProverParams::deserialize_with_mode(&mut reader, compress, validate)?;
let cf_cs_pp = CS2::ProverParams::deserialize_with_mode(&mut reader, compress, validate)?;

Ok(ProverParams {
poseidon_config,
cs_pp,
cf_cs_pp,
ccs: Some(ccs),
})
}

fn vp_deserialize_with_mode<R: std::io::prelude::Read>(
mut reader: R,
compress: ark_serialize::Compress,
validate: ark_serialize::Validate,
fc_params: FC::Params,
) -> Result<Self::VerifierParam, Error> {
let poseidon_config = poseidon_canonical_config::<C1::ScalarField>();

// generate the r1cs & cf_r1cs needed for the VerifierParams. In this way we avoid needing
// to serialize them, saving significant space in the VerifierParams serialized size.

// main circuit R1CS:
let f_circuit = FC::new(fc_params)?;
let augmented_F_circuit = AugmentedFCircuit::<C1, C2, GC2, FC, MU, NU>::empty(
&poseidon_config,
f_circuit.clone(),
None,
)?;
let ccs = augmented_F_circuit.ccs;

// CycleFold circuit R1CS
let cf_circuit = HyperNovaCycleFoldCircuit::<C1, GC1, MU, NU>::empty();
let cf_r1cs = get_r1cs_from_cs::<C2::ScalarField>(cf_circuit)?;

let cs_vp = CS1::VerifierParams::deserialize_with_mode(&mut reader, compress, validate)?;
let cf_cs_vp = CS2::VerifierParams::deserialize_with_mode(&mut reader, compress, validate)?;

Ok(VerifierParams {
poseidon_config,
ccs,
cf_r1cs,
cs_vp,
cf_cs_vp,
})
}

fn preprocess(
mut rng: impl RngCore,
prep_param: &Self::PreprocessorParam,
Expand Down
44 changes: 42 additions & 2 deletions folding-schemes/src/folding/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,27 @@ pub mod tests {
// build the FS from the given IVCProof, FC::Params, ProverParams and VerifierParams
let mut new_fs = FS::from_ivc_proof(deserialized_ivc_proof, (), fs_params.clone()).unwrap();

// serialize the Nova params
let mut fs_pp_serialized = vec![];
fs_params
.0
.serialize_compressed(&mut fs_pp_serialized)
.unwrap();
let mut fs_vp_serialized = vec![];
fs_params
.1
.serialize_compressed(&mut fs_vp_serialized)
.unwrap();

// deserialize the Nova params. This would be done by the client reading from a file
let _fs_pp_deserialized = FS::pp_deserialize_with_mode(
&mut fs_pp_serialized.as_slice(),
ark_serialize::Compress::Yes,
ark_serialize::Validate::Yes,
(), // FCircuit's Params
)
.unwrap();

// perform several IVC steps on both the original FS instance and the recovered from the
// serialization new FS instance
let num_steps: usize = 3;
Expand All @@ -123,9 +144,28 @@ pub mod tests {
// check that the IVCProofs from both FS instances are equal
assert_eq!(new_fs.ivc_proof(), fs.ivc_proof());

// verify the last IVCProof from the recovered from serialization FS
let fs_vp_deserialized = FS::vp_deserialize_with_mode(
&mut fs_vp_serialized.as_slice(),
ark_serialize::Compress::Yes,
ark_serialize::Validate::Yes,
(), // fcircuit_params
)
.unwrap();

// get the IVCProof
let ivc_proof: FS::IVCProof = new_fs.ivc_proof();
FS::verify(fs_params.1.clone(), ivc_proof.clone()).unwrap();

// serialize IVCProof
let mut ivc_proof_serialized = vec![];
assert!(ivc_proof
.serialize_compressed(&mut ivc_proof_serialized)
.is_ok());
// deserialize IVCProof
let ivc_proof_deserialized =
FS::IVCProof::deserialize_compressed(ivc_proof_serialized.as_slice()).unwrap();

// verify the last IVCProof from the recovered from serialization FS
FS::verify(fs_vp_deserialized.clone(), ivc_proof_deserialized).unwrap();

Ok(())
}
Expand Down
12 changes: 4 additions & 8 deletions folding-schemes/src/folding/nova/decider_eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -343,9 +343,7 @@ pub mod tests {

use super::*;
use crate::commitment::pedersen::Pedersen;
use crate::folding::nova::{
PreprocessorParam, ProverParams as NovaProverParams, VerifierParams as NovaVerifierParams,
};
use crate::folding::nova::{PreprocessorParam, ProverParams as NovaProverParams};
use crate::frontend::utils::CubicFCircuit;
use crate::transcript::poseidon::poseidon_canonical_config;

Expand Down Expand Up @@ -490,13 +488,11 @@ pub mod tests {
&mut nova_pp_serialized.as_slice()
)
.unwrap();
let nova_vp_deserialized = NovaVerifierParams::<
let nova_vp_deserialized = <N as FoldingScheme<
Projective,
Projective2,
KZG<'static, Bn254>,
Pedersen<Projective2>,
false,
>::deserialize_with_mode::<GVar, GVar2, CubicFCircuit<Fr>, _>(
CubicFCircuit<Fr>,
>>::vp_deserialize_with_mode(
&mut nova_vp_serialized.as_slice(),
ark_serialize::Compress::Yes,
ark_serialize::Validate::Yes,
Expand Down
Loading

0 comments on commit 0903e24

Please sign in to comment.