Browse Source

feat/hypernova serialization (#159)

* feat: implement serialization of hypernova prover and verifier params, proof and
public inputs

* chore: remove leftover comments

* chore: remove timers

* chore: improve typing and import naming
main
Pierre 1 month ago
committed by GitHub
parent
commit
1947ab0f51
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
5 changed files with 656 additions and 26 deletions
  1. +3
    -1
      folding-schemes/src/folding/hypernova/cccs.rs
  2. +202
    -18
      folding-schemes/src/folding/hypernova/decider_eth.rs
  3. +3
    -1
      folding-schemes/src/folding/hypernova/lcccs.rs
  4. +28
    -6
      folding-schemes/src/folding/hypernova/mod.rs
  5. +420
    -0
      folding-schemes/src/folding/hypernova/serialize.rs

+ 3
- 1
folding-schemes/src/folding/hypernova/cccs.rs

@ -1,6 +1,8 @@
use ark_crypto_primitives::sponge::Absorb; use ark_crypto_primitives::sponge::Absorb;
use ark_ec::CurveGroup; use ark_ec::CurveGroup;
use ark_ff::PrimeField; use ark_ff::PrimeField;
use ark_serialize::CanonicalDeserialize;
use ark_serialize::CanonicalSerialize;
use ark_std::One; use ark_std::One;
use ark_std::Zero; use ark_std::Zero;
use std::sync::Arc; use std::sync::Arc;
@ -17,7 +19,7 @@ use crate::utils::virtual_polynomial::{build_eq_x_r_vec, VirtualPolynomial};
use crate::Error; use crate::Error;
/// Committed CCS instance /// Committed CCS instance
#[derive(Debug, Clone)]
#[derive(Debug, Clone, CanonicalSerialize, CanonicalDeserialize)]
pub struct CCCS<C: CurveGroup> { pub struct CCCS<C: CurveGroup> {
// Commitment to witness // Commitment to witness
pub C: C, pub C: C,

+ 202
- 18
folding-schemes/src/folding/hypernova/decider_eth.rs

@ -3,6 +3,7 @@ use ark_crypto_primitives::sponge::Absorb;
use ark_ec::{CurveGroup, Group}; use ark_ec::{CurveGroup, Group};
use ark_ff::PrimeField; use ark_ff::PrimeField;
use ark_r1cs_std::{groups::GroupOpsBounds, prelude::CurveVar, ToConstraintFieldGadget}; use ark_r1cs_std::{groups::GroupOpsBounds, prelude::CurveVar, ToConstraintFieldGadget};
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use ark_snark::SNARK; use ark_snark::SNARK;
use ark_std::rand::{CryptoRng, RngCore}; use ark_std::rand::{CryptoRng, RngCore};
use ark_std::{One, Zero}; use ark_std::{One, Zero};
@ -14,11 +15,12 @@ use crate::commitment::{
kzg::Proof as KZGProof, pedersen::Params as PedersenParams, CommitmentScheme, kzg::Proof as KZGProof, pedersen::Params as PedersenParams, CommitmentScheme,
}; };
use crate::folding::circuits::{nonnative::affine::NonNativeAffineVar, CF2}; use crate::folding::circuits::{nonnative::affine::NonNativeAffineVar, CF2};
use crate::folding::nova::decider_eth::VerifierParam;
use crate::frontend::FCircuit; use crate::frontend::FCircuit;
use crate::Error; use crate::Error;
use crate::{Decider as DeciderTrait, FoldingScheme}; use crate::{Decider as DeciderTrait, FoldingScheme};
#[derive(Debug, Clone, Eq, PartialEq)]
#[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)]
pub struct Proof<C1, CS1, S> pub struct Proof<C1, CS1, S>
where where
C1: CurveGroup, C1: CurveGroup,
@ -85,8 +87,7 @@ where
type PreprocessorParam = (FS::ProverParam, FS::VerifierParam); type PreprocessorParam = (FS::ProverParam, FS::VerifierParam);
type ProverParam = (S::ProvingKey, CS1::ProverParams); type ProverParam = (S::ProvingKey, CS1::ProverParams);
type Proof = Proof<C1, CS1, S>; type Proof = Proof<C1, CS1, S>;
/// VerifierParam = (pp_hash, snark::vk, commitment_scheme::vk)
type VerifierParam = (C1::ScalarField, S::VerifyingKey, CS1::VerifierParams);
type VerifierParam = VerifierParam<C1, CS1::VerifierParams, S::VerifyingKey>;
type PublicInput = Vec<C1::ScalarField>; type PublicInput = Vec<C1::ScalarField>;
type CommittedInstance = (); type CommittedInstance = ();
@ -120,7 +121,12 @@ where
let pp_hash = hypernova_vp.pp_hash()?; let pp_hash = hypernova_vp.pp_hash()?;
let pp = (g16_pk, hypernova_pp.cs_pp); let pp = (g16_pk, hypernova_pp.cs_pp);
let vp = (pp_hash, g16_vk, hypernova_vp.cs_vp);
let vp = VerifierParam {
pp_hash,
snark_vp: g16_vk,
cs_vp: hypernova_vp.cs_vp,
};
Ok((pp, vp)) Ok((pp, vp))
} }
@ -183,7 +189,7 @@ where
} }
let (pp_hash, snark_vk, cs_vk): (C1::ScalarField, S::VerifyingKey, CS1::VerifierParams) = let (pp_hash, snark_vk, cs_vk): (C1::ScalarField, S::VerifyingKey, CS1::VerifierParams) =
vp;
(vp.pp_hash, vp.snark_vp, vp.cs_vp);
// Note: the NIMFS proof is checked inside the DeciderEthCircuit, which ensures that the // Note: the NIMFS proof is checked inside the DeciderEthCircuit, which ensures that the
// 'proof.U_i1' is correctly computed // 'proof.U_i1' is correctly computed
@ -223,11 +229,15 @@ pub mod tests {
use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as Projective}; use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as Projective};
use ark_groth16::Groth16; use ark_groth16::Groth16;
use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2}; use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2};
use std::time::Instant;
use ark_serialize::{Compress, Validate};
use super::*; use super::*;
use crate::commitment::{kzg::KZG, pedersen::Pedersen}; use crate::commitment::{kzg::KZG, pedersen::Pedersen};
use crate::folding::hypernova::PreprocessorParam;
use crate::folding::hypernova::cccs::CCCS;
use crate::folding::hypernova::{
PreprocessorParam, ProverParams, VerifierParams as HyperNovaVerifierParams,
};
use crate::folding::nova::decider_eth::VerifierParam;
use crate::frontend::utils::CubicFCircuit; use crate::frontend::utils::CubicFCircuit;
use crate::transcript::poseidon::poseidon_canonical_config; use crate::transcript::poseidon::poseidon_canonical_config;
@ -262,7 +272,7 @@ pub mod tests {
NU, NU,
>; >;
let mut rng = ark_std::test_rng();
let mut rng = rand::rngs::OsRng;
let poseidon_config = poseidon_canonical_config::<Fr>(); let poseidon_config = poseidon_canonical_config::<Fr>();
let F_circuit = CubicFCircuit::<Fr>::new(()).unwrap(); let F_circuit = CubicFCircuit::<Fr>::new(()).unwrap();
@ -271,31 +281,22 @@ pub mod tests {
let prep_param = PreprocessorParam::new(poseidon_config, F_circuit); let prep_param = PreprocessorParam::new(poseidon_config, F_circuit);
let hypernova_params = HN::preprocess(&mut rng, &prep_param).unwrap(); let hypernova_params = HN::preprocess(&mut rng, &prep_param).unwrap();
let start = Instant::now();
let mut hypernova = HN::init(&hypernova_params, F_circuit, z_0.clone()).unwrap(); let mut hypernova = HN::init(&hypernova_params, F_circuit, z_0.clone()).unwrap();
println!("Nova initialized, {:?}", start.elapsed());
let start = Instant::now();
hypernova hypernova
.prove_step(&mut rng, vec![], Some((vec![], vec![]))) .prove_step(&mut rng, vec![], Some((vec![], vec![])))
.unwrap(); .unwrap();
println!("prove_step, {:?}", start.elapsed());
hypernova hypernova
.prove_step(&mut rng, vec![], Some((vec![], vec![]))) .prove_step(&mut rng, vec![], Some((vec![], vec![])))
.unwrap(); // do a 2nd step .unwrap(); // do a 2nd step
let mut rng = rand::rngs::OsRng;
// prepare the Decider prover & verifier params // prepare the Decider prover & verifier params
let (decider_pp, decider_vp) = let (decider_pp, decider_vp) =
D::preprocess(&mut rng, hypernova_params, hypernova.clone()).unwrap(); D::preprocess(&mut rng, hypernova_params, hypernova.clone()).unwrap();
// decider proof generation // decider proof generation
let start = Instant::now();
let proof = D::prove(rng, decider_pp, hypernova.clone()).unwrap(); let proof = D::prove(rng, decider_pp, hypernova.clone()).unwrap();
println!("Decider prove, {:?}", start.elapsed());
// decider proof verification // decider proof verification
let start = Instant::now();
let verified = D::verify( let verified = D::verify(
decider_vp, decider_vp,
hypernova.i, hypernova.i,
@ -307,6 +308,189 @@ pub mod tests {
) )
.unwrap(); .unwrap();
assert!(verified); assert!(verified);
println!("Decider verify, {:?}", start.elapsed());
}
#[test]
fn test_decider_serialization() {
const MU: usize = 1;
const NU: usize = 1;
// use HyperNova as FoldingScheme
type HN = HyperNova<
Projective,
GVar,
Projective2,
GVar2,
CubicFCircuit<Fr>,
KZG<'static, Bn254>,
Pedersen<Projective2>,
MU,
NU,
false,
>;
type D = Decider<
Projective,
GVar,
Projective2,
GVar2,
CubicFCircuit<Fr>,
KZG<'static, Bn254>,
Pedersen<Projective2>,
Groth16<Bn254>, // here we define the Snark to use in the decider
HN, // here we define the FoldingScheme to use
MU,
NU,
>;
let mut rng = ark_std::test_rng();
let poseidon_config = poseidon_canonical_config::<Fr>();
let F_circuit = CubicFCircuit::<Fr>::new(()).unwrap();
let z_0 = vec![Fr::from(3_u32)];
let prep_param = PreprocessorParam::new(poseidon_config.clone(), F_circuit);
let hypernova_params = HN::preprocess(&mut rng, &prep_param).unwrap();
let hypernova = HN::init(&hypernova_params, F_circuit, z_0.clone()).unwrap();
let mut rng = rand::rngs::OsRng;
// prepare the Decider prover & verifier params
let (decider_pp, decider_vp) =
D::preprocess(&mut rng, hypernova_params.clone(), hypernova.clone()).unwrap();
let mut hypernova_pp_serialized = vec![];
hypernova_params
.0
.clone()
.serialize_compressed(&mut hypernova_pp_serialized)
.unwrap();
let mut hypernova_vp_serialized = vec![];
hypernova_params
.1
.clone()
.serialize_compressed(&mut hypernova_vp_serialized)
.unwrap();
let hypernova_pp_deserialized = ProverParams::<
Projective,
Projective2,
KZG<'static, Bn254>,
Pedersen<Projective2>,
false,
>::deserialize_prover_params(
hypernova_pp_serialized.as_slice(),
Compress::Yes,
Validate::No,
&hypernova_params.0.ccs,
&poseidon_config,
)
.unwrap();
let hypernova_vp_deserialized = HyperNovaVerifierParams::<
Projective,
Projective2,
KZG<'static, Bn254>,
Pedersen<Projective2>,
false,
>::deserialize_verifier_params(
hypernova_vp_serialized.as_slice(),
Compress::Yes,
Validate::No,
&hypernova_params.0.ccs.unwrap(),
&poseidon_config,
)
.unwrap();
let hypernova_params = (hypernova_pp_deserialized, hypernova_vp_deserialized);
let mut hypernova = HN::init(&hypernova_params, F_circuit, z_0.clone()).unwrap();
hypernova
.prove_step(&mut rng, vec![], Some((vec![], vec![])))
.unwrap();
hypernova
.prove_step(&mut rng, vec![], Some((vec![], vec![])))
.unwrap();
// decider proof generation
let proof = D::prove(rng, decider_pp, hypernova.clone()).unwrap();
let verified = D::verify(
decider_vp.clone(),
hypernova.i.clone(),
hypernova.z_0.clone(),
hypernova.z_i.clone(),
&(),
&(),
&proof,
)
.unwrap();
assert!(verified);
// The rest of this test will serialize the data and deserialize it back, and use it to
// verify the proof:
// serialize the verifier_params, proof and public inputs
let mut decider_vp_serialized = vec![];
decider_vp
.serialize_compressed(&mut decider_vp_serialized)
.unwrap();
let mut proof_serialized = vec![];
proof.serialize_compressed(&mut proof_serialized).unwrap();
// serialize the public inputs in a single packet
let mut public_inputs_serialized = vec![];
hypernova
.i
.serialize_compressed(&mut public_inputs_serialized)
.unwrap();
hypernova
.z_0
.serialize_compressed(&mut public_inputs_serialized)
.unwrap();
hypernova
.z_i
.serialize_compressed(&mut public_inputs_serialized)
.unwrap();
hypernova
.U_i
.serialize_compressed(&mut public_inputs_serialized)
.unwrap();
hypernova
.u_i
.serialize_compressed(&mut public_inputs_serialized)
.unwrap();
// deserialize back the verifier_params, proof and public inputs
let decider_vp_deserialized =
VerifierParam::<
Projective,
<KZG<'static, Bn254> as CommitmentScheme<Projective>>::VerifierParams,
<Groth16<Bn254> as SNARK<Fr>>::VerifyingKey,
>::deserialize_compressed(&mut decider_vp_serialized.as_slice())
.unwrap();
let proof_deserialized =
Proof::<Projective, KZG<'static, Bn254>, Groth16<Bn254>>::deserialize_compressed(
&mut proof_serialized.as_slice(),
)
.unwrap();
let mut reader = public_inputs_serialized.as_slice();
let i_deserialized = Fr::deserialize_compressed(&mut reader).unwrap();
let z_0_deserialized = Vec::<Fr>::deserialize_compressed(&mut reader).unwrap();
let z_i_deserialized = Vec::<Fr>::deserialize_compressed(&mut reader).unwrap();
let _U_i = LCCCS::<Projective>::deserialize_compressed(&mut reader).unwrap();
let _u_i = CCCS::<Projective>::deserialize_compressed(&mut reader).unwrap();
let verified = D::verify(
decider_vp_deserialized,
i_deserialized.clone(),
z_0_deserialized.clone(),
z_i_deserialized.clone(),
&(),
&(),
&proof_deserialized,
)
.unwrap();
assert!(verified);
} }
} }

+ 3
- 1
folding-schemes/src/folding/hypernova/lcccs.rs

@ -3,6 +3,8 @@ use ark_ec::{CurveGroup, Group};
use ark_ff::PrimeField; use ark_ff::PrimeField;
use ark_poly::DenseMultilinearExtension; use ark_poly::DenseMultilinearExtension;
use ark_poly::MultilinearExtension; use ark_poly::MultilinearExtension;
use ark_serialize::CanonicalDeserialize;
use ark_serialize::CanonicalSerialize;
use ark_std::rand::Rng; use ark_std::rand::Rng;
use ark_std::Zero; use ark_std::Zero;
@ -15,7 +17,7 @@ use crate::utils::vec::mat_vec_mul;
use crate::Error; use crate::Error;
/// Linearized Committed CCS instance /// Linearized Committed CCS instance
#[derive(Debug, Clone, Eq, PartialEq)]
#[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)]
pub struct LCCCS<C: CurveGroup> { pub struct LCCCS<C: CurveGroup> {
// Commitment to witness // Commitment to witness
pub C: C, pub C: C,

+ 28
- 6
folding-schemes/src/folding/hypernova/mod.rs

@ -6,6 +6,7 @@ use ark_crypto_primitives::sponge::{
use ark_ec::{CurveGroup, Group}; use ark_ec::{CurveGroup, Group};
use ark_ff::{BigInteger, PrimeField}; use ark_ff::{BigInteger, PrimeField};
use ark_r1cs_std::{groups::GroupOpsBounds, prelude::CurveVar, ToConstraintFieldGadget}; use ark_r1cs_std::{groups::GroupOpsBounds, prelude::CurveVar, ToConstraintFieldGadget};
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use ark_std::{fmt::Debug, marker::PhantomData, rand::RngCore, One, Zero}; use ark_std::{fmt::Debug, marker::PhantomData, rand::RngCore, One, Zero};
pub mod cccs; pub mod cccs;
@ -14,6 +15,7 @@ pub mod decider_eth;
pub mod decider_eth_circuit; pub mod decider_eth_circuit;
pub mod lcccs; pub mod lcccs;
pub mod nimfs; pub mod nimfs;
pub mod serialize;
pub mod utils; pub mod utils;
use cccs::CCCS; use cccs::CCCS;
@ -62,7 +64,7 @@ pub type HyperNovaCycleFoldCircuit =
CycleFoldCircuit<HyperNovaCycleFoldConfig<C, MU, NU>, GC>; CycleFoldCircuit<HyperNovaCycleFoldConfig<C, MU, NU>, GC>;
/// Witness for the LCCCS & CCCS, containing the w vector, and the r_w used as randomness in the Pedersen commitment. /// Witness for the LCCCS & CCCS, containing the w vector, and the r_w used as randomness in the Pedersen commitment.
#[derive(Debug, Clone, Eq, PartialEq)]
#[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)]
pub struct Witness<F: PrimeField> { pub struct Witness<F: PrimeField> {
pub w: Vec<F>, pub w: Vec<F>,
pub r_w: F, pub r_w: F,
@ -939,13 +941,25 @@ mod tests {
} }
// test_ivc allowing to choose the CommitmentSchemes // test_ivc allowing to choose the CommitmentSchemes
fn test_ivc_opt<
pub fn test_ivc_opt<
CS1: CommitmentScheme<Projective, H>, CS1: CommitmentScheme<Projective, H>,
CS2: CommitmentScheme<Projective2, H>, CS2: CommitmentScheme<Projective2, H>,
const H: bool, const H: bool,
>( >(
poseidon_config: PoseidonConfig<Fr>, poseidon_config: PoseidonConfig<Fr>,
F_circuit: CubicFCircuit<Fr>, F_circuit: CubicFCircuit<Fr>,
) -> (
HyperNova<Projective, GVar, Projective2, GVar2, CubicFCircuit<Fr>, CS1, CS2, 2, 3, H>,
(
ProverParams<Projective, Projective2, CS1, CS2, H>,
VerifierParams<Projective, Projective2, CS1, CS2, H>,
),
(LCCCS<Projective>, Witness<Fr>),
(CCCS<Projective>, Witness<Fr>),
(
CycleFoldCommittedInstance<Projective2>,
CycleFoldWitness<Projective2>,
),
) { ) {
let mut rng = ark_std::test_rng(); let mut rng = ark_std::test_rng();
@ -1001,14 +1015,22 @@ mod tests {
let (running_instance, incoming_instance, cyclefold_instance) = hypernova.instances(); let (running_instance, incoming_instance, cyclefold_instance) = hypernova.instances();
HN::verify( HN::verify(
hypernova_params.1, // verifier_params
hypernova_params.1.clone(), // verifier_params
z_0, z_0,
hypernova.z_i,
hypernova.i,
hypernova.z_i.clone(),
hypernova.i.clone(),
running_instance.clone(),
incoming_instance.clone(),
cyclefold_instance.clone(),
)
.unwrap();
(
hypernova,
hypernova_params,
running_instance, running_instance,
incoming_instance, incoming_instance,
cyclefold_instance, cyclefold_instance,
) )
.unwrap();
} }
} }

+ 420
- 0
folding-schemes/src/folding/hypernova/serialize.rs

@ -0,0 +1,420 @@
use crate::arith::ccs::CCS;
use crate::arith::r1cs::R1CS;
use crate::folding::hypernova::ProverParams;
use crate::folding::hypernova::VerifierParams;
use ark_crypto_primitives::sponge::poseidon::PoseidonConfig;
use ark_crypto_primitives::sponge::Absorb;
use ark_ec::{CurveGroup, Group};
use ark_ff::PrimeField;
use ark_r1cs_std::groups::{CurveVar, GroupOpsBounds};
use ark_r1cs_std::ToConstraintFieldGadget;
use ark_serialize::CanonicalDeserialize;
use ark_serialize::{CanonicalSerialize, Compress, SerializationError, Validate};
use ark_std::marker::PhantomData;
use crate::folding::hypernova::cccs::CCCS;
use crate::folding::hypernova::lcccs::LCCCS;
use crate::folding::hypernova::Witness;
use crate::folding::nova::{
CommittedInstance as CycleFoldCommittedInstance, Witness as CycleFoldWitness,
};
use crate::FoldingScheme;
use crate::{
commitment::CommitmentScheme,
folding::{circuits::CF2, nova::PreprocessorParam},
frontend::FCircuit,
};
use super::HyperNova;
impl<C1, GC1, C2, GC2, FC, CS1, CS2, const MU: usize, const NU: usize, const H: bool>
CanonicalSerialize for HyperNova<C1, GC1, C2, GC2, FC, CS1, CS2, MU, NU, H>
where
C1: CurveGroup,
GC1: CurveVar<C1, CF2<C1>> + ToConstraintFieldGadget<CF2<C1>>,
C2: CurveGroup,
GC2: CurveVar<C2, CF2<C2>>,
FC: FCircuit<C1::ScalarField>,
CS1: CommitmentScheme<C1, H>,
CS2: CommitmentScheme<C2, H>,
{
fn serialize_compressed<W: std::io::prelude::Write>(
&self,
writer: W,
) -> Result<(), ark_serialize::SerializationError> {
self.serialize_with_mode(writer, ark_serialize::Compress::Yes)
}
fn compressed_size(&self) -> usize {
self.serialized_size(ark_serialize::Compress::Yes)
}
fn serialize_uncompressed<W: std::io::prelude::Write>(
&self,
writer: W,
) -> Result<(), ark_serialize::SerializationError> {
self.serialize_with_mode(writer, ark_serialize::Compress::No)
}
fn uncompressed_size(&self) -> usize {
self.serialized_size(ark_serialize::Compress::No)
}
fn serialize_with_mode<W: std::io::prelude::Write>(
&self,
mut writer: W,
compress: ark_serialize::Compress,
) -> Result<(), ark_serialize::SerializationError> {
self.pp_hash.serialize_with_mode(&mut writer, compress)?;
self.i.serialize_with_mode(&mut writer, compress)?;
self.z_0.serialize_with_mode(&mut writer, compress)?;
self.z_i.serialize_with_mode(&mut writer, compress)?;
self.W_i.serialize_with_mode(&mut writer, compress)?;
self.U_i.serialize_with_mode(&mut writer, compress)?;
self.w_i.serialize_with_mode(&mut writer, compress)?;
self.u_i.serialize_with_mode(&mut writer, compress)?;
self.cf_W_i.serialize_with_mode(&mut writer, compress)?;
self.cf_U_i.serialize_with_mode(&mut writer, compress)
}
fn serialized_size(&self, compress: ark_serialize::Compress) -> usize {
self.pp_hash.serialized_size(compress)
+ self.i.serialized_size(compress)
+ self.z_0.serialized_size(compress)
+ self.z_i.serialized_size(compress)
+ self.W_i.serialized_size(compress)
+ self.U_i.serialized_size(compress)
+ self.w_i.serialized_size(compress)
+ self.u_i.serialized_size(compress)
+ self.cf_W_i.serialized_size(compress)
+ self.cf_U_i.serialized_size(compress)
}
}
impl<C1, GC1, C2, GC2, FC, CS1, CS2, const MU: usize, const NU: usize, const H: bool>
HyperNova<C1, GC1, C2, GC2, FC, CS1, CS2, MU, NU, H>
where
C1: CurveGroup,
GC1: CurveVar<C1, CF2<C1>> + ToConstraintFieldGadget<CF2<C1>>,
C2: CurveGroup,
GC2: CurveVar<C2, CF2<C2>> + ToConstraintFieldGadget<CF2<C2>>,
FC: FCircuit<C1::ScalarField, Params = ()>,
CS1: CommitmentScheme<C1, H>,
CS2: CommitmentScheme<C2, H>,
<C1 as CurveGroup>::BaseField: PrimeField,
<C2 as CurveGroup>::BaseField: PrimeField,
<C1 as Group>::ScalarField: Absorb,
<C2 as Group>::ScalarField: Absorb,
C1: CurveGroup<BaseField = C2::ScalarField, ScalarField = C2::BaseField>,
for<'a> &'a GC1: GroupOpsBounds<'a, C1, GC1>,
for<'a> &'a GC2: GroupOpsBounds<'a, C2, GC2>,
{
#[allow(clippy::too_many_arguments)]
pub fn deserialize_hypernova<R: std::io::prelude::Read>(
mut reader: R,
compress: Compress,
validate: Validate,
poseidon_config: PoseidonConfig<C1::ScalarField>,
cs_pp: CS1::ProverParams,
cs_vp: CS1::VerifierParams,
cf_cs_pp: CS2::ProverParams,
cf_cs_vp: CS2::VerifierParams,
) -> Result<Self, SerializationError> {
let f_circuit = FC::new(()).unwrap();
let prep_param = PreprocessorParam {
poseidon_config: poseidon_config.clone(),
F: f_circuit.clone(),
cs_pp: Some(cs_pp.clone()),
cs_vp: Some(cs_vp.clone()),
cf_cs_pp: Some(cf_cs_pp.clone()),
cf_cs_vp: Some(cf_cs_vp.clone()),
};
// `test_rng` won't be used in `preprocess`, since parameters have already been initialized
let (prover_params, verifier_params) = Self::preprocess(ark_std::test_rng(), &prep_param)
.or(Err(SerializationError::InvalidData))?;
let pp_hash = C1::ScalarField::deserialize_with_mode(&mut reader, compress, validate)?;
let i = C1::ScalarField::deserialize_with_mode(&mut reader, compress, validate)?;
let z_0 = Vec::<C1::ScalarField>::deserialize_with_mode(&mut reader, compress, validate)?;
let z_i = Vec::<C1::ScalarField>::deserialize_with_mode(&mut reader, compress, validate)?;
let W_i =
Witness::<C1::ScalarField>::deserialize_with_mode(&mut reader, compress, validate)?;
let U_i = LCCCS::<C1>::deserialize_with_mode(&mut reader, compress, validate)?;
let w_i =
Witness::<C1::ScalarField>::deserialize_with_mode(&mut reader, compress, validate)?;
let u_i = CCCS::<C1>::deserialize_with_mode(&mut reader, compress, validate)?;
let cf_W_i =
CycleFoldWitness::<C2>::deserialize_with_mode(&mut reader, compress, validate)?;
let cf_U_i = CycleFoldCommittedInstance::<C2>::deserialize_with_mode(
&mut reader,
compress,
validate,
)?;
let ccs = prover_params.ccs.ok_or(SerializationError::InvalidData)?;
Ok(HyperNova {
_gc1: PhantomData,
_c2: PhantomData,
_gc2: PhantomData,
ccs,
cf_r1cs: verifier_params.cf_r1cs,
poseidon_config,
cs_pp,
cf_cs_pp,
F: f_circuit,
pp_hash,
i,
z_0,
z_i,
W_i,
U_i,
w_i,
u_i,
cf_W_i,
cf_U_i,
})
}
}
impl<
C1: CurveGroup,
C2: CurveGroup,
CS1: CommitmentScheme<C1, H>,
CS2: CommitmentScheme<C2, H>,
const H: bool,
> CanonicalSerialize for ProverParams<C1, C2, CS1, CS2, H>
{
fn serialize_compressed<W: std::io::prelude::Write>(
&self,
writer: W,
) -> Result<(), SerializationError> {
self.serialize_with_mode(writer, Compress::Yes)
}
fn compressed_size(&self) -> usize {
self.serialized_size(Compress::Yes)
}
fn serialize_uncompressed<W: std::io::prelude::Write>(
&self,
writer: W,
) -> Result<(), SerializationError> {
self.serialize_with_mode(writer, Compress::No)
}
fn uncompressed_size(&self) -> usize {
self.serialized_size(Compress::No)
}
fn serialize_with_mode<W: std::io::prelude::Write>(
&self,
mut writer: W,
compress: Compress,
) -> Result<(), SerializationError> {
self.cs_pp.serialize_with_mode(&mut writer, compress)?;
self.cf_cs_pp.serialize_with_mode(&mut writer, compress)
}
fn serialized_size(&self, compress: Compress) -> usize {
self.cs_pp.serialized_size(compress) + self.cf_cs_pp.serialized_size(compress)
}
}
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_prover_params<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_compressed<W: std::io::prelude::Write>(
&self,
writer: W,
) -> Result<(), SerializationError> {
self.serialize_with_mode(writer, Compress::Yes)
}
fn compressed_size(&self) -> usize {
self.serialized_size(Compress::Yes)
}
fn serialize_uncompressed<W: std::io::prelude::Write>(
&self,
writer: W,
) -> Result<(), SerializationError> {
self.serialize_with_mode(writer, Compress::No)
}
fn uncompressed_size(&self) -> usize {
self.serialized_size(Compress::No)
}
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,
})
}
}
#[cfg(test)]
pub mod tests {
use crate::FoldingScheme;
use crate::MultiFolding;
use ark_serialize::{Compress, Validate, Write};
use std::fs;
use crate::{
commitment::{kzg::KZG, pedersen::Pedersen},
folding::hypernova::{tests::test_ivc_opt, HyperNova},
frontend::{utils::CubicFCircuit, FCircuit},
transcript::poseidon::poseidon_canonical_config,
};
use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as Projective};
use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2};
use ark_serialize::CanonicalSerialize;
#[test]
fn test_serde_hypernova() {
let poseidon_config = poseidon_canonical_config::<Fr>();
let F_circuit = CubicFCircuit::<Fr>::new(()).unwrap();
let (mut hn, (_, verifier_params), _, _, _) = test_ivc_opt::<
KZG<Bn254>,
Pedersen<Projective2>,
false,
>(poseidon_config.clone(), F_circuit);
let mut writer = vec![];
assert!(hn.serialize_compressed(&mut writer).is_ok());
let mut writer = vec![];
assert!(hn.serialize_uncompressed(&mut writer).is_ok());
let mut file = fs::OpenOptions::new()
.create(true)
.write(true)
.open("./hypernova.serde")
.unwrap();
file.write_all(&writer).unwrap();
let bytes = fs::read("./hypernova.serde").unwrap();
let mut hn_deserialized = HyperNova::<
Projective,
GVar,
Projective2,
GVar2,
CubicFCircuit<Fr>,
KZG<Bn254>,
Pedersen<Projective2>,
2,
3,
false,
>::deserialize_hypernova(
bytes.as_slice(),
Compress::No,
Validate::No,
poseidon_config,
hn.cs_pp.clone(),
verifier_params.cs_vp,
hn.cf_cs_pp.clone(),
verifier_params.cf_cs_vp,
)
.unwrap();
assert_eq!(hn.i, hn_deserialized.i);
let mut rng = ark_std::test_rng();
for _ in 0..3 {
// prepare some new instances to fold in the multifolding step
let mut lcccs = vec![];
for j in 0..1 {
let instance_state = vec![Fr::from(j as u32 + 85_u32)];
let (U, W) = hn
.new_running_instance(&mut rng, instance_state, vec![])
.unwrap();
lcccs.push((U, W));
}
let mut cccs = vec![];
for j in 0..2 {
let instance_state = vec![Fr::from(j as u32 + 15_u32)];
let (u, w) = hn
.new_incoming_instance(&mut rng, instance_state, vec![])
.unwrap();
cccs.push((u, w));
}
hn.prove_step(&mut rng, vec![], Some((lcccs.clone(), cccs.clone())))
.unwrap();
hn_deserialized
.prove_step(&mut rng, vec![], Some((lcccs, cccs)))
.unwrap();
}
assert_eq!(hn.z_i, hn_deserialized.z_i);
}
}

Loading…
Cancel
Save