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