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