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}