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}