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