mirror of
https://github.com/arnaucube/sonobe.git
synced 2026-01-07 14:31:31 +01:00
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
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
use ark_crypto_primitives::sponge::Absorb;
|
||||
use ark_ec::CurveGroup;
|
||||
use ark_ff::PrimeField;
|
||||
use ark_serialize::CanonicalDeserialize;
|
||||
use ark_serialize::CanonicalSerialize;
|
||||
use ark_std::One;
|
||||
use ark_std::Zero;
|
||||
use std::sync::Arc;
|
||||
@@ -17,7 +19,7 @@ use crate::utils::virtual_polynomial::{build_eq_x_r_vec, VirtualPolynomial};
|
||||
use crate::Error;
|
||||
|
||||
/// Committed CCS instance
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, CanonicalSerialize, CanonicalDeserialize)]
|
||||
pub struct CCCS<C: CurveGroup> {
|
||||
// Commitment to witness
|
||||
pub C: C,
|
||||
|
||||
@@ -3,6 +3,7 @@ use ark_crypto_primitives::sponge::Absorb;
|
||||
use ark_ec::{CurveGroup, Group};
|
||||
use ark_ff::PrimeField;
|
||||
use ark_r1cs_std::{groups::GroupOpsBounds, prelude::CurveVar, ToConstraintFieldGadget};
|
||||
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
|
||||
use ark_snark::SNARK;
|
||||
use ark_std::rand::{CryptoRng, RngCore};
|
||||
use ark_std::{One, Zero};
|
||||
@@ -14,11 +15,12 @@ use crate::commitment::{
|
||||
kzg::Proof as KZGProof, pedersen::Params as PedersenParams, CommitmentScheme,
|
||||
};
|
||||
use crate::folding::circuits::{nonnative::affine::NonNativeAffineVar, CF2};
|
||||
use crate::folding::nova::decider_eth::VerifierParam;
|
||||
use crate::frontend::FCircuit;
|
||||
use crate::Error;
|
||||
use crate::{Decider as DeciderTrait, FoldingScheme};
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)]
|
||||
pub struct Proof<C1, CS1, S>
|
||||
where
|
||||
C1: CurveGroup,
|
||||
@@ -85,8 +87,7 @@ where
|
||||
type PreprocessorParam = (FS::ProverParam, FS::VerifierParam);
|
||||
type ProverParam = (S::ProvingKey, CS1::ProverParams);
|
||||
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 CommittedInstance = ();
|
||||
|
||||
@@ -120,7 +121,12 @@ where
|
||||
let pp_hash = hypernova_vp.pp_hash()?;
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
@@ -183,7 +189,7 @@ where
|
||||
}
|
||||
|
||||
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
|
||||
// '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_groth16::Groth16;
|
||||
use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2};
|
||||
use std::time::Instant;
|
||||
use ark_serialize::{Compress, Validate};
|
||||
|
||||
use super::*;
|
||||
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::transcript::poseidon::poseidon_canonical_config;
|
||||
|
||||
@@ -262,51 +272,225 @@ pub mod tests {
|
||||
NU,
|
||||
>;
|
||||
|
||||
let mut rng = rand::rngs::OsRng;
|
||||
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, F_circuit);
|
||||
let hypernova_params = HN::preprocess(&mut rng, &prep_param).unwrap();
|
||||
|
||||
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(); // do a 2nd step
|
||||
|
||||
// prepare the Decider prover & verifier params
|
||||
let (decider_pp, decider_vp) =
|
||||
D::preprocess(&mut rng, hypernova_params, hypernova.clone()).unwrap();
|
||||
|
||||
// decider proof generation
|
||||
let proof = D::prove(rng, decider_pp, hypernova.clone()).unwrap();
|
||||
|
||||
// decider proof verification
|
||||
let verified = D::verify(
|
||||
decider_vp,
|
||||
hypernova.i,
|
||||
hypernova.z_0,
|
||||
hypernova.z_i,
|
||||
&(),
|
||||
&(),
|
||||
&proof,
|
||||
)
|
||||
.unwrap();
|
||||
assert!(verified);
|
||||
}
|
||||
|
||||
#[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, F_circuit);
|
||||
let prep_param = PreprocessorParam::new(poseidon_config.clone(), F_circuit);
|
||||
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();
|
||||
println!("Nova initialized, {:?}", start.elapsed());
|
||||
let start = Instant::now();
|
||||
hypernova
|
||||
.prove_step(&mut rng, vec![], Some((vec![], vec![])))
|
||||
.unwrap();
|
||||
println!("prove_step, {:?}", start.elapsed());
|
||||
hypernova
|
||||
.prove_step(&mut rng, vec![], Some((vec![], vec![])))
|
||||
.unwrap(); // do a 2nd step
|
||||
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, hypernova.clone()).unwrap();
|
||||
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 start = Instant::now();
|
||||
let proof = D::prove(rng, decider_pp, hypernova.clone()).unwrap();
|
||||
println!("Decider prove, {:?}", start.elapsed());
|
||||
|
||||
// decider proof verification
|
||||
let start = Instant::now();
|
||||
let verified = D::verify(
|
||||
decider_vp,
|
||||
hypernova.i,
|
||||
hypernova.z_0,
|
||||
hypernova.z_i,
|
||||
decider_vp.clone(),
|
||||
hypernova.i.clone(),
|
||||
hypernova.z_0.clone(),
|
||||
hypernova.z_i.clone(),
|
||||
&(),
|
||||
&(),
|
||||
&proof,
|
||||
)
|
||||
.unwrap();
|
||||
assert!(verified);
|
||||
println!("Decider verify, {:?}", start.elapsed());
|
||||
|
||||
// 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,6 +3,8 @@ use ark_ec::{CurveGroup, Group};
|
||||
use ark_ff::PrimeField;
|
||||
use ark_poly::DenseMultilinearExtension;
|
||||
use ark_poly::MultilinearExtension;
|
||||
use ark_serialize::CanonicalDeserialize;
|
||||
use ark_serialize::CanonicalSerialize;
|
||||
use ark_std::rand::Rng;
|
||||
use ark_std::Zero;
|
||||
|
||||
@@ -15,7 +17,7 @@ use crate::utils::vec::mat_vec_mul;
|
||||
use crate::Error;
|
||||
|
||||
/// Linearized Committed CCS instance
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)]
|
||||
pub struct LCCCS<C: CurveGroup> {
|
||||
// Commitment to witness
|
||||
pub C: C,
|
||||
|
||||
@@ -6,6 +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};
|
||||
use ark_std::{fmt::Debug, marker::PhantomData, rand::RngCore, One, Zero};
|
||||
|
||||
pub mod cccs;
|
||||
@@ -14,6 +15,7 @@ pub mod decider_eth;
|
||||
pub mod decider_eth_circuit;
|
||||
pub mod lcccs;
|
||||
pub mod nimfs;
|
||||
pub mod serialize;
|
||||
pub mod utils;
|
||||
|
||||
use cccs::CCCS;
|
||||
@@ -62,7 +64,7 @@ pub type HyperNovaCycleFoldCircuit<C, GC, const MU: usize, const NU: usize> =
|
||||
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.
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)]
|
||||
pub struct Witness<F: PrimeField> {
|
||||
pub w: Vec<F>,
|
||||
pub r_w: F,
|
||||
@@ -939,13 +941,25 @@ mod tests {
|
||||
}
|
||||
|
||||
// test_ivc allowing to choose the CommitmentSchemes
|
||||
fn test_ivc_opt<
|
||||
pub fn test_ivc_opt<
|
||||
CS1: CommitmentScheme<Projective, H>,
|
||||
CS2: CommitmentScheme<Projective2, H>,
|
||||
const H: bool,
|
||||
>(
|
||||
poseidon_config: PoseidonConfig<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();
|
||||
|
||||
@@ -1001,14 +1015,22 @@ mod tests {
|
||||
|
||||
let (running_instance, incoming_instance, cyclefold_instance) = hypernova.instances();
|
||||
HN::verify(
|
||||
hypernova_params.1, // verifier_params
|
||||
hypernova_params.1.clone(), // verifier_params
|
||||
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,
|
||||
incoming_instance,
|
||||
cyclefold_instance,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
420
folding-schemes/src/folding/hypernova/serialize.rs
Normal file
420
folding-schemes/src/folding/hypernova/serialize.rs
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user