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}