sonobe/folding-schemes/src/folding/hypernova/serialize.rs
folding-schemes/src/folding/hypernova/serialize.rsRaw
1use crate::arith::ccs::CCS;
2use crate::arith::r1cs::R1CS;
3use crate::folding::hypernova::ProverParams;
4use crate::folding::hypernova::VerifierParams;
5use ark_crypto_primitives::sponge::poseidon::PoseidonConfig;
6use ark_crypto_primitives::sponge::Absorb;
7use ark_ec::{CurveGroup, Group};
8use ark_ff::PrimeField;
9use ark_r1cs_std::groups::{CurveVar, GroupOpsBounds};
10use ark_r1cs_std::ToConstraintFieldGadget;
11use ark_serialize::CanonicalDeserialize;
12use ark_serialize::{CanonicalSerialize, Compress, SerializationError, Validate};
13use ark_std::marker::PhantomData;
14
15use crate::folding::hypernova::cccs::CCCS;
16use crate::folding::hypernova::lcccs::LCCCS;
17use crate::folding::hypernova::Witness;
18use crate::folding::nova::{
19 CommittedInstance as CycleFoldCommittedInstance, Witness as CycleFoldWitness,
20};
21use crate::FoldingScheme;
22use crate::{
23 commitment::CommitmentScheme,
24 folding::{circuits::CF2, nova::PreprocessorParam},
25 frontend::FCircuit,
26};
27
28use super::HyperNova;
29
30impl<C1, GC1, C2, GC2, FC, CS1, CS2, const MU: usize, const NU: usize, const H: bool>
31 CanonicalSerialize for HyperNova<C1, GC1, C2, GC2, FC, CS1, CS2, MU, NU, H>
32where
33 C1: CurveGroup,
34 GC1: CurveVar<C1, CF2<C1>> + ToConstraintFieldGadget<CF2<C1>>,
35 C2: CurveGroup,
36 GC2: CurveVar<C2, CF2<C2>>,
37 FC: FCircuit<C1::ScalarField>,
38 CS1: CommitmentScheme<C1, H>,
39 CS2: CommitmentScheme<C2, H>,
40{
41 fn serialize_compressed<W: std::io::prelude::Write>(
42 &self,
43 writer: W,
44 ) -> Result<(), ark_serialize::SerializationError> {
45 self.serialize_with_mode(writer, ark_serialize::Compress::Yes)
46 }
47
48 fn compressed_size(&self) -> usize {
49 self.serialized_size(ark_serialize::Compress::Yes)
50 }
51
52 fn serialize_uncompressed<W: std::io::prelude::Write>(
53 &self,
54 writer: W,
55 ) -> Result<(), ark_serialize::SerializationError> {
56 self.serialize_with_mode(writer, ark_serialize::Compress::No)
57 }
58
59 fn uncompressed_size(&self) -> usize {
60 self.serialized_size(ark_serialize::Compress::No)
61 }
62
63 fn serialize_with_mode<W: std::io::prelude::Write>(
64 &self,
65 mut writer: W,
66 compress: ark_serialize::Compress,
67 ) -> Result<(), ark_serialize::SerializationError> {
68 self.pp_hash.serialize_with_mode(&mut writer, compress)?;
69 self.i.serialize_with_mode(&mut writer, compress)?;
70 self.z_0.serialize_with_mode(&mut writer, compress)?;
71 self.z_i.serialize_with_mode(&mut writer, compress)?;
72 self.W_i.serialize_with_mode(&mut writer, compress)?;
73 self.U_i.serialize_with_mode(&mut writer, compress)?;
74 self.w_i.serialize_with_mode(&mut writer, compress)?;
75 self.u_i.serialize_with_mode(&mut writer, compress)?;
76 self.cf_W_i.serialize_with_mode(&mut writer, compress)?;
77 self.cf_U_i.serialize_with_mode(&mut writer, compress)
78 }
79
80 fn serialized_size(&self, compress: ark_serialize::Compress) -> usize {
81 self.pp_hash.serialized_size(compress)
82 + self.i.serialized_size(compress)
83 + self.z_0.serialized_size(compress)
84 + self.z_i.serialized_size(compress)
85 + self.W_i.serialized_size(compress)
86 + self.U_i.serialized_size(compress)
87 + self.w_i.serialized_size(compress)
88 + self.u_i.serialized_size(compress)
89 + self.cf_W_i.serialized_size(compress)
90 + self.cf_U_i.serialized_size(compress)
91 }
92}
93
94impl<C1, GC1, C2, GC2, FC, CS1, CS2, const MU: usize, const NU: usize, const H: bool>
95 HyperNova<C1, GC1, C2, GC2, FC, CS1, CS2, MU, NU, H>
96where
97 C1: CurveGroup,
98 GC1: CurveVar<C1, CF2<C1>> + ToConstraintFieldGadget<CF2<C1>>,
99 C2: CurveGroup,
100 GC2: CurveVar<C2, CF2<C2>> + ToConstraintFieldGadget<CF2<C2>>,
101 FC: FCircuit<C1::ScalarField, Params = ()>,
102 CS1: CommitmentScheme<C1, H>,
103 CS2: CommitmentScheme<C2, H>,
104 <C1 as CurveGroup>::BaseField: PrimeField,
105 <C2 as CurveGroup>::BaseField: PrimeField,
106 <C1 as Group>::ScalarField: Absorb,
107 <C2 as Group>::ScalarField: Absorb,
108 C1: CurveGroup<BaseField = C2::ScalarField, ScalarField = C2::BaseField>,
109 for<'a> &'a GC1: GroupOpsBounds<'a, C1, GC1>,
110 for<'a> &'a GC2: GroupOpsBounds<'a, C2, GC2>,
111{
112 #[allow(clippy::too_many_arguments)]
113 pub fn deserialize_hypernova<R: std::io::prelude::Read>(
114 mut reader: R,
115 compress: Compress,
116 validate: Validate,
117 poseidon_config: PoseidonConfig<C1::ScalarField>,
118 cs_pp: CS1::ProverParams,
119 cs_vp: CS1::VerifierParams,
120 cf_cs_pp: CS2::ProverParams,
121 cf_cs_vp: CS2::VerifierParams,
122 ) -> Result<Self, SerializationError> {
123 let f_circuit = FC::new(()).unwrap();
124 let prep_param = PreprocessorParam {
125 poseidon_config: poseidon_config.clone(),
126 F: f_circuit.clone(),
127 cs_pp: Some(cs_pp.clone()),
128 cs_vp: Some(cs_vp.clone()),
129 cf_cs_pp: Some(cf_cs_pp.clone()),
130 cf_cs_vp: Some(cf_cs_vp.clone()),
131 };
132 // `test_rng` won't be used in `preprocess`, since parameters have already been initialized
133 let (prover_params, verifier_params) = Self::preprocess(ark_std::test_rng(), &prep_param)
134 .or(Err(SerializationError::InvalidData))?;
135 let pp_hash = C1::ScalarField::deserialize_with_mode(&mut reader, compress, validate)?;
136 let i = C1::ScalarField::deserialize_with_mode(&mut reader, compress, validate)?;
137 let z_0 = Vec::<C1::ScalarField>::deserialize_with_mode(&mut reader, compress, validate)?;
138 let z_i = Vec::<C1::ScalarField>::deserialize_with_mode(&mut reader, compress, validate)?;
139 let W_i =
140 Witness::<C1::ScalarField>::deserialize_with_mode(&mut reader, compress, validate)?;
141 let U_i = LCCCS::<C1>::deserialize_with_mode(&mut reader, compress, validate)?;
142 let w_i =
143 Witness::<C1::ScalarField>::deserialize_with_mode(&mut reader, compress, validate)?;
144 let u_i = CCCS::<C1>::deserialize_with_mode(&mut reader, compress, validate)?;
145 let cf_W_i =
146 CycleFoldWitness::<C2>::deserialize_with_mode(&mut reader, compress, validate)?;
147 let cf_U_i = CycleFoldCommittedInstance::<C2>::deserialize_with_mode(
148 &mut reader,
149 compress,
150 validate,
151 )?;
152 let ccs = prover_params.ccs.ok_or(SerializationError::InvalidData)?;
153
154 Ok(HyperNova {
155 _gc1: PhantomData,
156 _c2: PhantomData,
157 _gc2: PhantomData,
158 ccs,
159 cf_r1cs: verifier_params.cf_r1cs,
160 poseidon_config,
161 cs_pp,
162 cf_cs_pp,
163 F: f_circuit,
164 pp_hash,
165 i,
166 z_0,
167 z_i,
168 W_i,
169 U_i,
170 w_i,
171 u_i,
172 cf_W_i,
173 cf_U_i,
174 })
175 }
176}
177
178impl<
179 C1: CurveGroup,
180 C2: CurveGroup,
181 CS1: CommitmentScheme<C1, H>,
182 CS2: CommitmentScheme<C2, H>,
183 const H: bool,
184 > CanonicalSerialize for ProverParams<C1, C2, CS1, CS2, H>
185{
186 fn serialize_compressed<W: std::io::prelude::Write>(
187 &self,
188 writer: W,
189 ) -> Result<(), SerializationError> {
190 self.serialize_with_mode(writer, Compress::Yes)
191 }
192
193 fn compressed_size(&self) -> usize {
194 self.serialized_size(Compress::Yes)
195 }
196
197 fn serialize_uncompressed<W: std::io::prelude::Write>(
198 &self,
199 writer: W,
200 ) -> Result<(), SerializationError> {
201 self.serialize_with_mode(writer, Compress::No)
202 }
203
204 fn uncompressed_size(&self) -> usize {
205 self.serialized_size(Compress::No)
206 }
207
208 fn serialize_with_mode<W: std::io::prelude::Write>(
209 &self,
210 mut writer: W,
211 compress: Compress,
212 ) -> Result<(), SerializationError> {
213 self.cs_pp.serialize_with_mode(&mut writer, compress)?;
214 self.cf_cs_pp.serialize_with_mode(&mut writer, compress)
215 }
216
217 fn serialized_size(&self, compress: Compress) -> usize {
218 self.cs_pp.serialized_size(compress) + self.cf_cs_pp.serialized_size(compress)
219 }
220}
221
222impl<
223 C1: CurveGroup,
224 C2: CurveGroup,
225 CS1: CommitmentScheme<C1, H>,
226 CS2: CommitmentScheme<C2, H>,
227 const H: bool,
228 > ProverParams<C1, C2, CS1, CS2, H>
229{
230 pub fn deserialize_prover_params<R: std::io::prelude::Read>(
231 mut reader: R,
232 compress: Compress,
233 validate: Validate,
234 ccs: &Option<CCS<C1::ScalarField>>,
235 poseidon_config: &PoseidonConfig<C1::ScalarField>,
236 ) -> Result<Self, SerializationError> {
237 let cs_pp = CS1::ProverParams::deserialize_with_mode(&mut reader, compress, validate)?;
238 let cf_cs_pp = CS2::ProverParams::deserialize_with_mode(&mut reader, compress, validate)?;
239
240 Ok(ProverParams {
241 cs_pp,
242 cf_cs_pp,
243 ccs: ccs.clone(),
244 poseidon_config: poseidon_config.clone(),
245 })
246 }
247}
248
249impl<
250 C1: CurveGroup,
251 C2: CurveGroup,
252 CS1: CommitmentScheme<C1, H>,
253 CS2: CommitmentScheme<C2, H>,
254 const H: bool,
255 > CanonicalSerialize for VerifierParams<C1, C2, CS1, CS2, H>
256{
257 fn serialize_compressed<W: std::io::prelude::Write>(
258 &self,
259 writer: W,
260 ) -> Result<(), SerializationError> {
261 self.serialize_with_mode(writer, Compress::Yes)
262 }
263
264 fn compressed_size(&self) -> usize {
265 self.serialized_size(Compress::Yes)
266 }
267
268 fn serialize_uncompressed<W: std::io::prelude::Write>(
269 &self,
270 writer: W,
271 ) -> Result<(), SerializationError> {
272 self.serialize_with_mode(writer, Compress::No)
273 }
274
275 fn uncompressed_size(&self) -> usize {
276 self.serialized_size(Compress::No)
277 }
278
279 fn serialize_with_mode<W: std::io::prelude::Write>(
280 &self,
281 mut writer: W,
282 compress: Compress,
283 ) -> Result<(), SerializationError> {
284 self.cf_r1cs.serialize_with_mode(&mut writer, compress)?;
285 self.cs_vp.serialize_with_mode(&mut writer, compress)?;
286 self.cf_cs_vp.serialize_with_mode(&mut writer, compress)
287 }
288
289 fn serialized_size(&self, compress: Compress) -> usize {
290 self.cf_r1cs.serialized_size(compress)
291 + self.cs_vp.serialized_size(compress)
292 + self.cf_cs_vp.serialized_size(compress)
293 }
294}
295
296impl<
297 C1: CurveGroup,
298 C2: CurveGroup,
299 CS1: CommitmentScheme<C1, H>,
300 CS2: CommitmentScheme<C2, H>,
301 const H: bool,
302 > VerifierParams<C1, C2, CS1, CS2, H>
303{
304 pub fn deserialize_verifier_params<R: std::io::Read>(
305 mut reader: R,
306 compress: Compress,
307 validate: Validate,
308 ccs: &CCS<C1::ScalarField>,
309 poseidon_config: &PoseidonConfig<C1::ScalarField>,
310 ) -> Result<Self, SerializationError> {
311 let cf_r1cs = R1CS::deserialize_with_mode(&mut reader, compress, validate)?;
312 let cs_vp = CS1::VerifierParams::deserialize_with_mode(&mut reader, compress, validate)?;
313 let cf_cs_vp = CS2::VerifierParams::deserialize_with_mode(&mut reader, compress, validate)?;
314 Ok(VerifierParams {
315 ccs: ccs.clone(),
316 poseidon_config: poseidon_config.clone(),
317 cf_r1cs,
318 cs_vp,
319 cf_cs_vp,
320 })
321 }
322}
323
324#[cfg(test)]
325pub mod tests {
326 use crate::FoldingScheme;
327 use crate::MultiFolding;
328 use ark_serialize::{Compress, Validate, Write};
329 use std::fs;
330
331 use crate::{
332 commitment::{kzg::KZG, pedersen::Pedersen},
333 folding::hypernova::{tests::test_ivc_opt, HyperNova},
334 frontend::{utils::CubicFCircuit, FCircuit},
335 transcript::poseidon::poseidon_canonical_config,
336 };
337 use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as Projective};
338 use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2};
339 use ark_serialize::CanonicalSerialize;
340
341 #[test]
342 fn test_serde_hypernova() {
343 let poseidon_config = poseidon_canonical_config::<Fr>();
344 let F_circuit = CubicFCircuit::<Fr>::new(()).unwrap();
345 let (mut hn, (_, verifier_params), _, _, _) = test_ivc_opt::<
346 KZG<Bn254>,
347 Pedersen<Projective2>,
348 false,
349 >(poseidon_config.clone(), F_circuit);
350
351 let mut writer = vec![];
352 assert!(hn.serialize_compressed(&mut writer).is_ok());
353 let mut writer = vec![];
354 assert!(hn.serialize_uncompressed(&mut writer).is_ok());
355
356 let mut file = fs::OpenOptions::new()
357 .create(true)
358 .write(true)
359 .open("./hypernova.serde")
360 .unwrap();
361
362 file.write_all(&writer).unwrap();
363
364 let bytes = fs::read("./hypernova.serde").unwrap();
365
366 let mut hn_deserialized = HyperNova::<
367 Projective,
368 GVar,
369 Projective2,
370 GVar2,
371 CubicFCircuit<Fr>,
372 KZG<Bn254>,
373 Pedersen<Projective2>,
374 2,
375 3,
376 false,
377 >::deserialize_hypernova(
378 bytes.as_slice(),
379 Compress::No,
380 Validate::No,
381 poseidon_config,
382 hn.cs_pp.clone(),
383 verifier_params.cs_vp,
384 hn.cf_cs_pp.clone(),
385 verifier_params.cf_cs_vp,
386 )
387 .unwrap();
388
389 assert_eq!(hn.i, hn_deserialized.i);
390
391 let mut rng = ark_std::test_rng();
392 for _ in 0..3 {
393 // prepare some new instances to fold in the multifolding step
394 let mut lcccs = vec![];
395 for j in 0..1 {
396 let instance_state = vec![Fr::from(j as u32 + 85_u32)];
397 let (U, W) = hn
398 .new_running_instance(&mut rng, instance_state, vec![])
399 .unwrap();
400 lcccs.push((U, W));
401 }
402 let mut cccs = vec![];
403 for j in 0..2 {
404 let instance_state = vec![Fr::from(j as u32 + 15_u32)];
405 let (u, w) = hn
406 .new_incoming_instance(&mut rng, instance_state, vec![])
407 .unwrap();
408 cccs.push((u, w));
409 }
410
411 hn.prove_step(&mut rng, vec![], Some((lcccs.clone(), cccs.clone())))
412 .unwrap();
413 hn_deserialized
414 .prove_step(&mut rng, vec![], Some((lcccs, cccs)))
415 .unwrap();
416 }
417
418 assert_eq!(hn.z_i, hn_deserialized.z_i);
419 }
420}