arnaucube
arnaucube/sonobePublic Self-hosted repository
sonobe/folding-schemes/src/folding/nova/serialize.rs
folding-schemes/src/folding/nova/serialize.rsRaw
  1use ark_crypto_primitives::sponge::{poseidon::PoseidonConfig, Absorb};
  2use ark_ec::{CurveGroup, Group};
  3use ark_ff::PrimeField;
  4use ark_r1cs_std::{
  5    groups::{CurveVar, GroupOpsBounds},
  6    ToConstraintFieldGadget,
  7};
  8use ark_relations::r1cs::ConstraintSynthesizer;
  9use ark_relations::r1cs::ConstraintSystem;
 10use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, SerializationError, Write};
 11use std::marker::PhantomData;
 12
 13use super::{circuits::AugmentedFCircuit, Nova, ProverParams};
 14use super::{CommittedInstance, Witness};
 15use crate::folding::circuits::{cyclefold::CycleFoldCircuit, CF2};
 16use crate::{
 17    arith::r1cs::extract_r1cs, commitment::CommitmentScheme, folding::circuits::CF1,
 18    frontend::FCircuit,
 19};
 20
 21impl<C1, GC1, C2, GC2, FC, CS1, CS2> CanonicalSerialize for Nova<C1, GC1, C2, GC2, FC, CS1, CS2>
 22where
 23    C1: CurveGroup,
 24    C2: CurveGroup,
 25    FC: FCircuit<C1::ScalarField>,
 26    CS1: CommitmentScheme<C1>,
 27    CS2: CommitmentScheme<C2>,
 28    <C1 as CurveGroup>::BaseField: PrimeField,
 29    <C2 as CurveGroup>::BaseField: PrimeField,
 30    <C1 as Group>::ScalarField: Absorb,
 31    <C2 as Group>::ScalarField: Absorb,
 32    C1: CurveGroup<BaseField = C2::ScalarField, ScalarField = C2::BaseField>,
 33    for<'a> &'a GC1: GroupOpsBounds<'a, C1, GC1>,
 34    for<'a> &'a GC2: GroupOpsBounds<'a, C2, GC2>,
 35    GC1: CurveVar<C1, <C2 as Group>::ScalarField>,
 36    GC1: ToConstraintFieldGadget<<C2 as Group>::ScalarField>,
 37    GC2: CurveVar<C2, <C2 as CurveGroup>::BaseField>,
 38{
 39    fn serialize_with_mode<W: Write>(
 40        &self,
 41        mut writer: W,
 42        compress: ark_serialize::Compress,
 43    ) -> Result<(), ark_serialize::SerializationError> {
 44        self.pp_hash.serialize_with_mode(&mut writer, compress)?;
 45        self.i.serialize_with_mode(&mut writer, compress)?;
 46        self.z_0.serialize_with_mode(&mut writer, compress)?;
 47        self.z_i.serialize_with_mode(&mut writer, compress)?;
 48        self.w_i.serialize_with_mode(&mut writer, compress)?;
 49        self.u_i.serialize_with_mode(&mut writer, compress)?;
 50        self.W_i.serialize_with_mode(&mut writer, compress)?;
 51        self.U_i.serialize_with_mode(&mut writer, compress)?;
 52        self.cf_W_i.serialize_with_mode(&mut writer, compress)?;
 53        self.cf_U_i.serialize_with_mode(&mut writer, compress)
 54    }
 55
 56    fn serialized_size(&self, compress: ark_serialize::Compress) -> usize {
 57        self.pp_hash.serialized_size(compress)
 58            + self.i.serialized_size(compress)
 59            + self.z_0.serialized_size(compress)
 60            + self.z_i.serialized_size(compress)
 61            + self.w_i.serialized_size(compress)
 62            + self.u_i.serialized_size(compress)
 63            + self.W_i.serialized_size(compress)
 64            + self.U_i.serialized_size(compress)
 65            + self.cf_W_i.serialized_size(compress)
 66            + self.cf_U_i.serialized_size(compress)
 67    }
 68
 69    fn serialize_compressed<W: Write>(
 70        &self,
 71        writer: W,
 72    ) -> Result<(), ark_serialize::SerializationError> {
 73        self.serialize_with_mode(writer, ark_serialize::Compress::Yes)
 74    }
 75
 76    fn compressed_size(&self) -> usize {
 77        self.serialized_size(ark_serialize::Compress::Yes)
 78    }
 79
 80    fn serialize_uncompressed<W: Write>(
 81        &self,
 82        writer: W,
 83    ) -> Result<(), ark_serialize::SerializationError> {
 84        self.serialize_with_mode(writer, ark_serialize::Compress::No)
 85    }
 86
 87    fn uncompressed_size(&self) -> usize {
 88        self.serialized_size(ark_serialize::Compress::No)
 89    }
 90}
 91
 92// Note that we can't derive or implement `CanonicalDeserialize` directly.
 93// This is because `CurveVar` notably does not implement the `Sync` trait.
 94impl<C1, GC1, C2, GC2, FC, CS1, CS2> Nova<C1, GC1, C2, GC2, FC, CS1, CS2>
 95where
 96    C1: CurveGroup,
 97    C2: CurveGroup,
 98    FC: FCircuit<CF1<C1>, Params = ()>,
 99    CS1: CommitmentScheme<C1>,
100    CS2: CommitmentScheme<C2>,
101    <C1 as CurveGroup>::BaseField: PrimeField,
102    <C2 as CurveGroup>::BaseField: PrimeField,
103    <C1 as Group>::ScalarField: Absorb,
104    <C2 as Group>::ScalarField: Absorb,
105    C1: CurveGroup<BaseField = C2::ScalarField, ScalarField = C2::BaseField>,
106    for<'a> &'a GC1: GroupOpsBounds<'a, C1, GC1>,
107    for<'a> &'a GC2: GroupOpsBounds<'a, C2, GC2>,
108    GC1: CurveVar<C1, <C2 as Group>::ScalarField>,
109    GC1: ToConstraintFieldGadget<<C2 as Group>::ScalarField>,
110    GC2: CurveVar<C2, CF2<C2>>,
111    GC2: ToConstraintFieldGadget<<C2 as CurveGroup>::BaseField>,
112{
113    pub fn deserialize_nova<R: std::io::prelude::Read>(
114        mut reader: R,
115        compress: ark_serialize::Compress,
116        validate: ark_serialize::Validate,
117        prover_params: ProverParams<C1, C2, CS1, CS2>,
118        poseidon_config: PoseidonConfig<C1::ScalarField>,
119    ) -> Result<Self, ark_serialize::SerializationError> {
120        let pp_hash = C1::ScalarField::deserialize_with_mode(&mut reader, compress, validate)?;
121        let i = C1::ScalarField::deserialize_with_mode(&mut reader, compress, validate)?;
122        let z_0 = Vec::<C1::ScalarField>::deserialize_with_mode(&mut reader, compress, validate)?;
123        let z_i = Vec::<C1::ScalarField>::deserialize_with_mode(&mut reader, compress, validate)?;
124        let w_i = Witness::<C1>::deserialize_with_mode(&mut reader, compress, validate)?;
125        let u_i = CommittedInstance::<C1>::deserialize_with_mode(&mut reader, compress, validate)?;
126        let W_i = Witness::<C1>::deserialize_with_mode(&mut reader, compress, validate)?;
127        let U_i = CommittedInstance::<C1>::deserialize_with_mode(&mut reader, compress, validate)?;
128        let cf_W_i = Witness::<C2>::deserialize_with_mode(&mut reader, compress, validate)?;
129        let cf_U_i =
130            CommittedInstance::<C2>::deserialize_with_mode(&mut reader, compress, validate)?;
131
132        let f_circuit = FC::new(()).unwrap();
133        let cs = ConstraintSystem::<C1::ScalarField>::new_ref();
134        let cs2 = ConstraintSystem::<C1::BaseField>::new_ref();
135        let augmented_F_circuit =
136            AugmentedFCircuit::<C1, C2, GC2, FC>::empty(&poseidon_config, f_circuit.clone());
137        let cf_circuit = CycleFoldCircuit::<C1, GC1>::empty();
138
139        augmented_F_circuit
140            .generate_constraints(cs.clone())
141            .map_err(|_| SerializationError::InvalidData)?;
142        cs.finalize();
143        let cs = cs.into_inner().ok_or(SerializationError::InvalidData)?;
144        let r1cs = extract_r1cs::<C1::ScalarField>(&cs);
145
146        cf_circuit
147            .generate_constraints(cs2.clone())
148            .map_err(|_| SerializationError::InvalidData)?;
149        cs2.finalize();
150        let cs2 = cs2.into_inner().ok_or(SerializationError::InvalidData)?;
151        let cf_r1cs = extract_r1cs::<C1::BaseField>(&cs2);
152
153        Ok(Nova {
154            _gc1: PhantomData,
155            _c2: PhantomData,
156            _gc2: PhantomData,
157            r1cs,
158            cf_r1cs,
159            poseidon_config,
160            cs_pp: prover_params.cs_pp,
161            cf_cs_pp: prover_params.cf_cs_pp,
162            F: f_circuit,
163            pp_hash,
164            i,
165            z_0,
166            z_i,
167            w_i,
168            u_i,
169            W_i,
170            U_i,
171            cf_W_i,
172            cf_U_i,
173        })
174    }
175}
176
177#[cfg(test)]
178pub mod tests {
179    use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as Projective};
180    use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2};
181    use ark_serialize::{CanonicalSerialize, Compress, Validate};
182    use std::{fs, io::Write};
183
184    use crate::{
185        commitment::{kzg::KZG, pedersen::Pedersen},
186        folding::nova::{Nova, PreprocessorParam},
187        frontend::{tests::CubicFCircuit, FCircuit},
188        transcript::poseidon::poseidon_canonical_config,
189        FoldingScheme,
190    };
191
192    #[test]
193    fn test_serde_nova() {
194        let mut rng = ark_std::test_rng();
195        let poseidon_config = poseidon_canonical_config::<Fr>();
196        let F_circuit = CubicFCircuit::<Fr>::new(()).unwrap();
197
198        // Initialize nova and make multiple `prove_step()`
199        type N = Nova<
200            Projective,
201            GVar,
202            Projective2,
203            GVar2,
204            CubicFCircuit<Fr>,
205            KZG<'static, Bn254>,
206            Pedersen<Projective2>,
207        >;
208        let prep_param = PreprocessorParam::new(poseidon_config.clone(), F_circuit);
209        let nova_params = N::preprocess(&mut rng, &prep_param).unwrap();
210
211        let z_0 = vec![Fr::from(3_u32)];
212        let mut nova = N::init(nova_params.clone(), F_circuit, z_0.clone()).unwrap();
213
214        let num_steps: usize = 3;
215        for _ in 0..num_steps {
216            nova.prove_step(&mut rng, vec![]).unwrap();
217        }
218
219        let mut writer = vec![];
220        assert!(nova
221            .serialize_with_mode(&mut writer, ark_serialize::Compress::No)
222            .is_ok());
223
224        let mut file = fs::OpenOptions::new()
225            .create(true)
226            .write(true)
227            .open("./nova.serde")
228            .unwrap();
229
230        file.write_all(&writer).unwrap();
231
232        let bytes = fs::read("./nova.serde").unwrap();
233
234        let mut deserialized_nova = Nova::<
235            Projective,
236            GVar,
237            Projective2,
238            GVar2,
239            CubicFCircuit<Fr>,
240            KZG<Bn254>,
241            Pedersen<Projective2>,
242        >::deserialize_nova(
243            bytes.as_slice(),
244            Compress::No,
245            Validate::No,
246            nova_params.0, // Nova's prover params
247            poseidon_config,
248        )
249        .unwrap();
250
251        assert_eq!(nova.i, deserialized_nova.i);
252
253        let num_steps: usize = 3;
254        for _ in 0..num_steps {
255            deserialized_nova.prove_step(&mut rng, vec![]).unwrap();
256            nova.prove_step(&mut rng, vec![]).unwrap();
257        }
258
259        assert_eq!(deserialized_nova.w_i, nova.w_i);
260    }
261}