use super::{circuits::AugmentedFCircuit, Nova, ProverParams}; pub use super::{CommittedInstance, Witness}; pub use crate::folding::circuits::{cyclefold::CycleFoldCircuit, CF2}; use crate::{ ccs::r1cs::extract_r1cs, commitment::CommitmentScheme, folding::circuits::CF1, frontend::FCircuit, }; use ark_crypto_primitives::sponge::{poseidon::PoseidonConfig, Absorb}; use ark_ec::{CurveGroup, Group}; use ark_ff::PrimeField; use ark_r1cs_std::{ groups::{CurveVar, GroupOpsBounds}, ToConstraintFieldGadget, }; use ark_relations::r1cs::ConstraintSynthesizer; use ark_relations::r1cs::ConstraintSystem; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, SerializationError, Write}; use std::marker::PhantomData; impl CanonicalSerialize for Nova where C1: CurveGroup, C2: CurveGroup, FC: FCircuit, CS1: CommitmentScheme, CS2: CommitmentScheme, ::BaseField: PrimeField, ::BaseField: PrimeField, ::ScalarField: Absorb, ::ScalarField: Absorb, C1: CurveGroup, for<'a> &'a GC1: GroupOpsBounds<'a, C1, GC1>, for<'a> &'a GC2: GroupOpsBounds<'a, C2, GC2>, GC1: CurveVar::ScalarField>, GC1: ToConstraintFieldGadget<::ScalarField>, GC2: CurveVar::BaseField>, { fn serialize_with_mode( &self, mut writer: W, compress: ark_serialize::Compress, ) -> Result<(), ark_serialize::SerializationError> { 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.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) } fn serialize_compressed( &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( &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) } } // Note that we can't derive or implement `CanonicalDeserialize` directly. // This is because `CurveVar` notably does not implement the `Sync` trait. impl Nova where C1: CurveGroup, C2: CurveGroup, FC: FCircuit, Params = ()>, CS1: CommitmentScheme, CS2: CommitmentScheme, ::BaseField: PrimeField, ::BaseField: PrimeField, ::ScalarField: Absorb, ::ScalarField: Absorb, C1: CurveGroup, for<'a> &'a GC1: GroupOpsBounds<'a, C1, GC1>, for<'a> &'a GC2: GroupOpsBounds<'a, C2, GC2>, GC1: CurveVar::ScalarField>, GC1: ToConstraintFieldGadget<::ScalarField>, GC2: CurveVar>, GC2: ToConstraintFieldGadget<::BaseField>, { pub fn deserialize_nova( mut reader: R, compress: ark_serialize::Compress, validate: ark_serialize::Validate, prover_params: ProverParams, poseidon_config: PoseidonConfig, ) -> Result { let i = C1::ScalarField::deserialize_with_mode(&mut reader, compress, validate)?; let z_0 = Vec::::deserialize_with_mode(&mut reader, compress, validate)?; let z_i = Vec::::deserialize_with_mode(&mut reader, compress, validate)?; let w_i = Witness::::deserialize_with_mode(&mut reader, compress, validate)?; let u_i = CommittedInstance::::deserialize_with_mode(&mut reader, compress, validate)?; let W_i = Witness::::deserialize_with_mode(&mut reader, compress, validate)?; let U_i = CommittedInstance::::deserialize_with_mode(&mut reader, compress, validate)?; let cf_W_i = Witness::::deserialize_with_mode(&mut reader, compress, validate)?; let cf_U_i = CommittedInstance::::deserialize_with_mode(&mut reader, compress, validate)?; let f_circuit = FC::new(()).unwrap(); let cs = ConstraintSystem::::new_ref(); let cs2 = ConstraintSystem::::new_ref(); let augmented_F_circuit = AugmentedFCircuit::::empty(&poseidon_config, f_circuit.clone()); let cf_circuit = CycleFoldCircuit::::empty(); augmented_F_circuit .generate_constraints(cs.clone()) .map_err(|_| SerializationError::InvalidData)?; cs.finalize(); let cs = cs.into_inner().ok_or(SerializationError::InvalidData)?; let r1cs = extract_r1cs::(&cs); cf_circuit .generate_constraints(cs2.clone()) .map_err(|_| SerializationError::InvalidData)?; cs2.finalize(); let cs2 = cs2.into_inner().ok_or(SerializationError::InvalidData)?; let cf_r1cs = extract_r1cs::(&cs2); Ok(Nova { _gc1: PhantomData, _c2: PhantomData, _gc2: PhantomData, cs_params: prover_params.cs_params, cf_cs_params: prover_params.cf_cs_params, i, z_0, z_i, w_i, u_i, W_i, U_i, cf_W_i, cf_U_i, r1cs, cf_r1cs, poseidon_config, F: f_circuit, }) } } #[cfg(test)] pub mod tests { use crate::{ commitment::{ kzg::{ProverKey as KZGProverKey, KZG}, pedersen::Pedersen, CommitmentScheme, }, folding::nova::{get_cs_params_len, Nova, ProverParams}, frontend::{tests::CubicFCircuit, FCircuit}, transcript::poseidon::poseidon_canonical_config, FoldingScheme, }; use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as Projective}; use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2}; use ark_poly_commit::kzg10::VerifierKey as KZGVerifierKey; use ark_serialize::{CanonicalSerialize, Compress, Validate}; use std::{fs, io::Write}; #[test] fn test_serde_nova() { let mut rng = ark_std::test_rng(); let poseidon_config = poseidon_canonical_config::(); let F_circuit = CubicFCircuit::::new(()).unwrap(); let (cs_len, cf_cs_len) = get_cs_params_len::>( &poseidon_config, F_circuit, ) .unwrap(); let (kzg_pk, _): (KZGProverKey, KZGVerifierKey) = KZG::::setup(&mut rng, cs_len).unwrap(); let (cf_pedersen_params, _) = Pedersen::::setup(&mut rng, cf_cs_len).unwrap(); // Initialize nova and make multiple `prove_step()` type NOVA = Nova, CS1, CS2>; let prover_params = ProverParams::, Pedersen> { poseidon_config: poseidon_config.clone(), cs_params: kzg_pk.clone(), cf_cs_params: cf_pedersen_params.clone(), }; let z_0 = vec![Fr::from(3_u32)]; let mut nova = NOVA::init(&prover_params, F_circuit, z_0.clone()).unwrap(); let num_steps: usize = 3; for _ in 0..num_steps { nova.prove_step(vec![]).unwrap(); } let mut writer = vec![]; assert!(nova .serialize_with_mode(&mut writer, ark_serialize::Compress::No) .is_ok()); let mut file = fs::OpenOptions::new() .create(true) .write(true) .open("./nova.serde") .unwrap(); file.write_all(&writer).unwrap(); let bytes = fs::read("./nova.serde").unwrap(); let mut deserialized_nova = Nova::< Projective, GVar, Projective2, GVar2, CubicFCircuit, KZG, Pedersen, >::deserialize_nova( bytes.as_slice(), Compress::No, Validate::No, prover_params, poseidon_config, ) .unwrap(); assert_eq!(nova.i, deserialized_nova.i); let num_steps: usize = 3; for _ in 0..num_steps { deserialized_nova.prove_step(vec![]).unwrap(); nova.prove_step(vec![]).unwrap(); } assert_eq!(deserialized_nova.w_i, nova.w_i); } }