proof.rs
  1  // Copyright (c) 2025-2026 ACDC Network
  2  // This file is part of the alphavm library.
  3  //
  4  // Alpha Chain | Delta Chain Protocol
  5  // International Monetary Graphite.
  6  //
  7  // Derived from Aleo (https://aleo.org) and ProvableHQ (https://provable.com).
  8  // They built world-class ZK infrastructure. We installed the EASY button.
  9  // Their cryptography: elegant. Our modifications: bureaucracy-compatible.
 10  // Original brilliance: theirs. Robert's Rules: ours. Bugs: definitely ours.
 11  //
 12  // Original Aleo/ProvableHQ code subject to Apache 2.0 https://www.apache.org/licenses/LICENSE-2.0
 13  // All modifications and new work: CC0 1.0 Universal Public Domain Dedication.
 14  // No rights reserved. No permission required. No warranty. No refunds.
 15  //
 16  // https://creativecommons.org/publicdomain/zero/1.0/
 17  // SPDX-License-Identifier: CC0-1.0
 18  
 19  use crate::{
 20      polycommit::{kzg10::KZGCommitment, sonic_pc},
 21      snark::varuna::{ahp, CircuitId, VarunaVersion},
 22      SNARKError,
 23  };
 24  
 25  use ahp::prover::{FourthMessage, ThirdMessage};
 26  use alphavm_curves::PairingEngine;
 27  use alphavm_fields::{One, PrimeField};
 28  use alphavm_utilities::{into_io_error, serialize::*, FromBytes, ToBytes};
 29  
 30  use anyhow::{anyhow, Result};
 31  use std::{
 32      collections::BTreeMap,
 33      io::{self, Read, Write},
 34  };
 35  
 36  use std::mem::size_of;
 37  
 38  #[derive(Clone, Debug, PartialEq, Eq, CanonicalSerialize, CanonicalDeserialize)]
 39  pub struct Commitments<E: PairingEngine> {
 40      pub witness_commitments: Vec<WitnessCommitments<E>>,
 41      /// Commitment to the masking polynomial.
 42      pub mask_poly: Option<sonic_pc::Commitment<E>>,
 43      /// Commitment to the `h_0` polynomial.
 44      pub h_0: sonic_pc::Commitment<E>,
 45      /// Commitment to the `g_1` polynomial.
 46      pub g_1: sonic_pc::Commitment<E>,
 47      /// Commitment to the `h_1` polynomial.
 48      pub h_1: sonic_pc::Commitment<E>,
 49      /// Commitment to the `g_a` polynomials.
 50      pub g_a_commitments: Vec<sonic_pc::Commitment<E>>,
 51      /// Commitment to the `g_b` polynomials.
 52      pub g_b_commitments: Vec<sonic_pc::Commitment<E>>,
 53      /// Commitment to the `g_c` polynomials.
 54      pub g_c_commitments: Vec<sonic_pc::Commitment<E>>,
 55      /// Commitment to the `h_2` polynomial.
 56      pub h_2: sonic_pc::Commitment<E>,
 57  }
 58  
 59  impl<E: PairingEngine> Commitments<E> {
 60      fn serialize_with_mode<W: alphavm_utilities::Write>(
 61          &self,
 62          mut writer: W,
 63          compress: Compress,
 64      ) -> Result<(), alphavm_utilities::SerializationError> {
 65          serialize_vec_without_len(self.witness_commitments.iter(), &mut writer, compress)?;
 66          CanonicalSerialize::serialize_with_mode(&self.mask_poly, &mut writer, compress)?;
 67          CanonicalSerialize::serialize_with_mode(&self.h_0, &mut writer, compress)?;
 68          CanonicalSerialize::serialize_with_mode(&self.g_1, &mut writer, compress)?;
 69          CanonicalSerialize::serialize_with_mode(&self.h_1, &mut writer, compress)?;
 70          serialize_vec_without_len(self.g_a_commitments.iter(), &mut writer, compress)?;
 71          serialize_vec_without_len(self.g_b_commitments.iter(), &mut writer, compress)?;
 72          serialize_vec_without_len(self.g_c_commitments.iter(), &mut writer, compress)?;
 73          CanonicalSerialize::serialize_with_mode(&self.h_2, &mut writer, compress)?;
 74          Ok(())
 75      }
 76  
 77      fn serialized_size(&self, compress: Compress) -> usize {
 78          serialized_vec_size_without_len(&self.witness_commitments, compress)
 79              .saturating_add(CanonicalSerialize::serialized_size(&self.mask_poly, compress))
 80              .saturating_add(CanonicalSerialize::serialized_size(&self.h_0, compress))
 81              .saturating_add(CanonicalSerialize::serialized_size(&self.g_1, compress))
 82              .saturating_add(CanonicalSerialize::serialized_size(&self.h_1, compress))
 83              .saturating_add(serialized_vec_size_without_len(&self.g_a_commitments, compress))
 84              .saturating_add(serialized_vec_size_without_len(&self.g_b_commitments, compress))
 85              .saturating_add(serialized_vec_size_without_len(&self.g_c_commitments, compress))
 86              .saturating_add(CanonicalSerialize::serialized_size(&self.h_2, compress))
 87      }
 88  
 89      fn deserialize_with_mode<R: alphavm_utilities::Read>(
 90          batch_sizes: &[usize],
 91          mut reader: R,
 92          compress: Compress,
 93          validate: Validate,
 94      ) -> Result<Self, alphavm_utilities::SerializationError> {
 95          let mut w = Vec::new();
 96          for batch_size in batch_sizes {
 97              w.extend(deserialize_vec_without_len(&mut reader, compress, validate, *batch_size)?);
 98          }
 99          Ok(Commitments {
100              witness_commitments: w,
101              mask_poly: CanonicalDeserialize::deserialize_with_mode(&mut reader, compress, validate)?,
102              h_0: CanonicalDeserialize::deserialize_with_mode(&mut reader, compress, validate)?,
103              g_1: CanonicalDeserialize::deserialize_with_mode(&mut reader, compress, validate)?,
104              h_1: CanonicalDeserialize::deserialize_with_mode(&mut reader, compress, validate)?,
105              g_a_commitments: deserialize_vec_without_len(&mut reader, compress, validate, batch_sizes.len())?,
106              g_b_commitments: deserialize_vec_without_len(&mut reader, compress, validate, batch_sizes.len())?,
107              g_c_commitments: deserialize_vec_without_len(&mut reader, compress, validate, batch_sizes.len())?,
108              h_2: CanonicalDeserialize::deserialize_with_mode(&mut reader, compress, validate)?,
109          })
110      }
111  }
112  /// Commitments to the `w` polynomials.
113  #[derive(Clone, Debug, PartialEq, Eq, CanonicalSerialize, CanonicalDeserialize)]
114  pub struct WitnessCommitments<E: PairingEngine> {
115      /// Commitment to the `w` polynomial.
116      pub w: sonic_pc::Commitment<E>,
117  }
118  
119  #[derive(Clone, Debug, PartialEq, Eq)]
120  pub struct Evaluations<F: PrimeField> {
121      /// Evaluation of `g_1` at `beta`.
122      pub g_1_eval: F,
123      /// Evaluation of `g_a_i`'s at `beta`.
124      pub g_a_evals: Vec<F>,
125      /// Evaluation of `g_b_i`'s at `gamma`.
126      pub g_b_evals: Vec<F>,
127      /// Evaluation of `g_c_i`'s at `gamma`.
128      pub g_c_evals: Vec<F>,
129  }
130  
131  impl<F: PrimeField> Evaluations<F> {
132      fn serialize_with_mode<W: alphavm_utilities::Write>(
133          &self,
134          mut writer: W,
135          compress: Compress,
136      ) -> Result<(), alphavm_utilities::SerializationError> {
137          CanonicalSerialize::serialize_with_mode(&self.g_1_eval, &mut writer, compress)?;
138          serialize_vec_without_len(self.g_a_evals.iter(), &mut writer, compress)?;
139          serialize_vec_without_len(self.g_b_evals.iter(), &mut writer, compress)?;
140          serialize_vec_without_len(self.g_c_evals.iter(), &mut writer, compress)?;
141          Ok(())
142      }
143  
144      fn serialized_size(&self, compress: Compress) -> usize {
145          CanonicalSerialize::serialized_size(&self.g_1_eval, compress)
146              .saturating_add(serialized_vec_size_without_len(&self.g_a_evals, compress))
147              .saturating_add(serialized_vec_size_without_len(&self.g_b_evals, compress))
148              .saturating_add(serialized_vec_size_without_len(&self.g_c_evals, compress))
149      }
150  
151      fn deserialize_with_mode<R: alphavm_utilities::Read>(
152          batch_sizes: &[usize],
153          mut reader: R,
154          compress: Compress,
155          validate: Validate,
156      ) -> Result<Self, alphavm_utilities::SerializationError> {
157          Ok(Evaluations {
158              g_1_eval: CanonicalDeserialize::deserialize_with_mode(&mut reader, compress, validate)?,
159              g_a_evals: deserialize_vec_without_len(&mut reader, compress, validate, batch_sizes.len())?,
160              g_b_evals: deserialize_vec_without_len(&mut reader, compress, validate, batch_sizes.len())?,
161              g_c_evals: deserialize_vec_without_len(&mut reader, compress, validate, batch_sizes.len())?,
162          })
163      }
164  }
165  
166  impl<F: PrimeField> Evaluations<F> {
167      pub(crate) fn from_map(
168          map: &std::collections::BTreeMap<String, F>,
169          batch_sizes: BTreeMap<CircuitId, usize>,
170      ) -> Self {
171          let mut g_a_evals = Vec::with_capacity(batch_sizes.len());
172          let mut g_b_evals = Vec::with_capacity(batch_sizes.len());
173          let mut g_c_evals = Vec::with_capacity(batch_sizes.len());
174  
175          for (label, value) in map {
176              if label == "g_1" {
177                  continue;
178              }
179  
180              if label.contains("g_a") {
181                  g_a_evals.push(*value);
182              } else if label.contains("g_b") {
183                  g_b_evals.push(*value);
184              } else if label.contains("g_c") {
185                  g_c_evals.push(*value);
186              }
187          }
188          Self { g_1_eval: map["g_1"], g_a_evals, g_b_evals, g_c_evals }
189      }
190  
191      pub(crate) fn get(&self, circuit_index: usize, label: &str) -> Option<F> {
192          if label == "g_1" {
193              return Some(self.g_1_eval);
194          }
195  
196          if label.contains("g_a") {
197              self.g_a_evals.get(circuit_index).copied()
198          } else if label.contains("g_b") {
199              self.g_b_evals.get(circuit_index).copied()
200          } else if label.contains("g_c") {
201              self.g_c_evals.get(circuit_index).copied()
202          } else {
203              None
204          }
205      }
206  
207      pub fn to_field_elements(&self) -> Vec<F> {
208          let mut result = Vec::with_capacity(1 + self.g_a_evals.len() + self.g_b_evals.len() + self.g_c_evals.len());
209          result.push(self.g_1_eval);
210          result.extend_from_slice(&self.g_a_evals);
211          result.extend_from_slice(&self.g_b_evals);
212          result.extend_from_slice(&self.g_c_evals);
213          result
214      }
215  }
216  
217  impl<F: PrimeField> Valid for Evaluations<F> {
218      fn check(&self) -> Result<(), alphavm_utilities::SerializationError> {
219          self.g_1_eval.check()?;
220          self.g_a_evals.check()?;
221          self.g_b_evals.check()?;
222          self.g_c_evals.check()
223      }
224  }
225  
226  /// A zkSNARK proof.
227  #[derive(Clone, Debug, PartialEq, Eq)]
228  pub struct Proof<E: PairingEngine> {
229      /// The number of instances being proven in this proof.
230      batch_sizes: Vec<usize>,
231  
232      /// Commitments to prover polynomials.
233      pub commitments: Commitments<E>,
234  
235      /// Evaluations of some of the committed polynomials.
236      pub evaluations: Evaluations<E::Fr>,
237  
238      /// Prover message: sum_a, sum_b, sum_c for each instance
239      pub third_msg: ThirdMessage<E::Fr>,
240  
241      /// Prover message: sum_a, sum_b, sum_c for each circuit
242      pub fourth_msg: FourthMessage<E::Fr>,
243  
244      /// An evaluation proof from the polynomial commitment.
245      pub pc_proof: sonic_pc::BatchLCProof<E>,
246  }
247  
248  impl<E: PairingEngine> Proof<E> {
249      /// Construct a new proof.
250      pub fn new(
251          batch_sizes: BTreeMap<CircuitId, usize>,
252          commitments: Commitments<E>,
253          evaluations: Evaluations<E::Fr>,
254          third_msg: ThirdMessage<E::Fr>,
255          fourth_msg: FourthMessage<E::Fr>,
256          pc_proof: sonic_pc::BatchLCProof<E>,
257      ) -> Result<Self, SNARKError> {
258          let batch_sizes: Vec<usize> = batch_sizes.into_values().collect();
259          Ok(Self { batch_sizes, commitments, evaluations, third_msg, fourth_msg, pc_proof })
260      }
261  
262      pub fn is_hiding(&self) -> bool {
263          self.pc_proof.is_hiding()
264      }
265  
266      pub fn batch_sizes(&self) -> &[usize] {
267          &self.batch_sizes
268      }
269  
270      /// Check that the number of messages is consistent with our batch size
271      pub fn check_batch_sizes(&self) -> Result<(), SNARKError> {
272          let total_instances = self
273              .batch_sizes
274              .iter()
275              .try_fold(0usize, |acc, &size| acc.checked_add(size))
276              .ok_or(SNARKError::BatchSizeMismatch)?;
277          if self.commitments.witness_commitments.len() != total_instances {
278              return Err(SNARKError::BatchSizeMismatch);
279          }
280          let g_comms =
281              [&self.commitments.g_a_commitments, &self.commitments.g_b_commitments, &self.commitments.g_c_commitments];
282          for comms in g_comms {
283              if comms.len() != self.batch_sizes.len() {
284                  return Err(SNARKError::BatchSizeMismatch);
285              }
286          }
287          let g_evals = [&self.evaluations.g_a_evals, &self.evaluations.g_b_evals, &self.evaluations.g_c_evals];
288          for evals in g_evals {
289              if evals.len() != self.batch_sizes.len() {
290                  return Err(SNARKError::BatchSizeMismatch);
291              }
292          }
293          if self.third_msg.sums.len() != self.batch_sizes.len() {
294              return Err(SNARKError::BatchSizeMismatch);
295          }
296          for (msg, &batch_size) in self.third_msg.sums.iter().zip(self.batch_sizes.iter()) {
297              if msg.len() != batch_size {
298                  return Err(SNARKError::BatchSizeMismatch);
299              }
300          }
301          if self.fourth_msg.sums.len() != self.batch_sizes.len() {
302              return Err(SNARKError::BatchSizeMismatch);
303          }
304          Ok(())
305      }
306  }
307  
308  impl<E: PairingEngine> CanonicalSerialize for Proof<E> {
309      fn serialize_with_mode<W: Write>(&self, mut writer: W, compress: Compress) -> Result<(), SerializationError> {
310          let batch_sizes: Vec<u64> = self.batch_sizes.iter().map(|x| u64::try_from(*x)).collect::<Result<_, _>>()?;
311          CanonicalSerialize::serialize_with_mode(&batch_sizes, &mut writer, compress)?;
312          Commitments::serialize_with_mode(&self.commitments, &mut writer, compress)?;
313          Evaluations::serialize_with_mode(&self.evaluations, &mut writer, compress)?;
314          for third_sums in self.third_msg.sums.iter() {
315              serialize_vec_without_len(third_sums.iter(), &mut writer, compress)?;
316          }
317          serialize_vec_without_len(self.fourth_msg.sums.iter(), &mut writer, compress)?;
318          CanonicalSerialize::serialize_with_mode(&self.pc_proof, &mut writer, compress)?;
319          Ok(())
320      }
321  
322      fn serialized_size(&self, mode: Compress) -> usize {
323          let mut size = 0;
324          size += CanonicalSerialize::serialized_size(&self.batch_sizes, mode);
325          size += Commitments::serialized_size(&self.commitments, mode);
326          size += Evaluations::serialized_size(&self.evaluations, mode);
327          for third_sums in self.third_msg.sums.iter() {
328              size += serialized_vec_size_without_len(third_sums, mode);
329          }
330          size += serialized_vec_size_without_len(&self.fourth_msg.sums, mode);
331          size += CanonicalSerialize::serialized_size(&self.pc_proof, mode);
332          size
333      }
334  }
335  
336  impl<E: PairingEngine> Valid for Proof<E> {
337      fn check(&self) -> Result<(), SerializationError> {
338          self.batch_sizes.check()?;
339          self.commitments.check()?;
340          self.evaluations.check()?;
341          self.third_msg.check()?;
342          self.fourth_msg.check()?;
343          self.pc_proof.check()
344      }
345  }
346  
347  impl<E: PairingEngine> CanonicalDeserialize for Proof<E> {
348      fn deserialize_with_mode<R: Read>(
349          mut reader: R,
350          compress: Compress,
351          validate: Validate,
352      ) -> Result<Self, SerializationError> {
353          let batch_sizes: Vec<u64> = CanonicalDeserialize::deserialize_with_mode(&mut reader, compress, validate)?;
354          let batch_sizes: Vec<usize> = batch_sizes.into_iter().map(|x| x as usize).collect();
355          let commitments = Commitments::deserialize_with_mode(&batch_sizes, &mut reader, compress, validate)?;
356          let evaluations = Evaluations::deserialize_with_mode(&batch_sizes, &mut reader, compress, validate)?;
357          let third_msg_sums = batch_sizes
358              .iter()
359              .map(|&batch_size| deserialize_vec_without_len(&mut reader, compress, validate, batch_size))
360              .collect::<Result<Vec<_>, _>>()?;
361          let fourth_msg_sums = deserialize_vec_without_len(&mut reader, compress, validate, batch_sizes.len())?;
362          Ok(Proof {
363              commitments,
364              evaluations,
365              third_msg: ThirdMessage { sums: third_msg_sums },
366              fourth_msg: FourthMessage { sums: fourth_msg_sums },
367              pc_proof: CanonicalDeserialize::deserialize_with_mode(&mut reader, compress, validate)?,
368              batch_sizes,
369          })
370      }
371  }
372  
373  impl<E: PairingEngine> ToBytes for Proof<E> {
374      fn write_le<W: Write>(&self, mut w: W) -> io::Result<()> {
375          Self::serialize_compressed(self, &mut w)
376              .map_err(|err| into_io_error(anyhow::Error::from(err).context("could not serialize Proof")))
377      }
378  }
379  
380  impl<E: PairingEngine> FromBytes for Proof<E> {
381      fn read_le<R: Read>(mut r: R) -> io::Result<Self> {
382          Self::deserialize_compressed(&mut r)
383              .map_err(|err| into_io_error(anyhow::Error::from(err).context("could not deserialize Proof")))
384      }
385  
386      fn read_le_unchecked<R: Read>(mut r: R) -> io::Result<Self> {
387          Self::deserialize_compressed_unchecked(&mut r)
388              .map_err(|err| into_io_error(anyhow::Error::from(err).context("could not deserialize Proof")))
389      }
390  }
391  
392  /// Computes the size in bytes of a Varuna proof as produced by
393  /// `Proof::serialize_compressed` without needing to receive the proof itself.
394  ///
395  /// *Arguments*:
396  ///  - `batch_sizes`: the batch sizes of the circuits and instances being
397  ///    proved.
398  ///  - `varuna_version`: the version of Varuna being used
399  ///  - `hiding`: indicates whether the proof system is run in ZK mode
400  ///
401  /// *Returns*:
402  ///  - `Ok(size)` for `VarunaVersion::V2`, where `size` is the size of the proof
403  ///    in bytes.
404  ///  - `Err` for `VarunaVersion::V1`.
405  pub fn proof_size<E: PairingEngine>(
406      batch_sizes: &[usize],
407      varuna_version: VarunaVersion,
408      hiding: bool,
409  ) -> Result<usize> {
410      let n_circuits: usize = batch_sizes.len();
411      let n_instances: usize = batch_sizes.iter().sum();
412  
413      match varuna_version {
414          VarunaVersion::V1 => Err(anyhow!("Proof-size calculation not implemented for Varuna version V1")),
415          VarunaVersion::V2 => {
416              // All fields are serialised in Compressed mode The breakdown is as
417              // follows:
418              // - batch sizes: one `usize` (which is serialised as a `u64`) for each batch
419              //   size, plus one `u64` for the number of batches. This contains the size
420              //   information for the vectors in all other fields, which are therefore
421              //   serialised without their length prefix.
422              // - commitments:
423              //   + witness_commitments: n_instances commitments
424              //   + mask_poly: 1 byte to encode the enum tag (a bool) plus one commitment if
425              //     the variant is Some (if and only if the proof system is run in ZK mode)
426              //   + h_0, g_1, g_2, h_2: four commitments
427              //   + g_a, g_b, g_c: 3 * n_circuits commitments
428              // - evaluations:
429              //   + g_1_eval: one field element
430              //   + g_a_evals, g_b_evals, g_c_evals: 3 * n_circuits field elements
431              // - third_msg:
432              //   + 3 * n_instances field elements
433              // - fourth_msg:
434              //   + 3 * n_circuits field elements
435              // - pc_proof:
436              //   + one usize for the size of the vector (which is always 3)
437              //   + three of [1 commitment + 1 bool (for the Option tag) + {1 field element
438              //     if the variant is Some (if and only if the proof system is run in ZK
439              //     mode)}]
440  
441              let n_bool = 1;
442              let n_u64 = 1;
443              let n_field_elements = 1 + 6 * n_circuits + 3 * n_instances;
444              let n_commitments = 4 + n_instances + (if hiding { 1 } else { 0 }) + 3 * n_circuits;
445  
446              // The next three sizes are const functions
447              let size_bool = size_of::<bool>();
448              let size_u64 = size_of::<u64>();
449  
450              // The next two can be hard-coded if performance becomes critical
451              // and they are considered fully stable. They are 32 and 48 bytes at
452              // the time of writing, respectively (commitments are affine points
453              // written in compressed form).
454              let size_field_element = E::Fr::one().compressed_size();
455              let size_commitment = KZGCommitment::<E>::empty().compressed_size();
456  
457              let size_pc_proof = size_u64 + 3 * (size_commitment + 1) + if hiding { size_field_element } else { 0 };
458  
459              Ok(n_bool * size_bool
460                  + (n_u64 + batch_sizes.len()) * size_u64
461                  + n_field_elements * size_field_element
462                  + n_commitments * size_commitment
463                  + size_pc_proof)
464          }
465      }
466  }
467  
468  #[cfg(test)]
469  mod test {
470      #![allow(non_camel_case_types)]
471  
472      use super::*;
473  
474      use crate::{
475          polycommit::{
476              kzg10::{KZGCommitment, KZGProof},
477              sonic_pc::BatchProof,
478          },
479          snark::varuna::prover::MatrixSums,
480      };
481      use alphavm_curves::{
482          bls12_377::{Bls12_377, Fr, G1Affine},
483          AffineCurve,
484      };
485      use alphavm_utilities::{TestRng, Uniform};
486  
487      const fn modes() -> [(Compress, Validate); 4] {
488          [
489              (Compress::No, Validate::No),
490              (Compress::Yes, Validate::No),
491              (Compress::No, Validate::Yes),
492              (Compress::Yes, Validate::Yes),
493          ]
494      }
495  
496      fn sample_commit() -> KZGCommitment<Bls12_377> {
497          let buf = G1Affine::prime_subgroup_generator().to_bytes_le().unwrap();
498          FromBytes::read_le(buf.as_slice()).unwrap()
499      }
500  
501      fn rand_commitments(j: usize, i: usize, test_with_none: bool) -> Commitments<Bls12_377> {
502          assert!(i > 0);
503          assert!(j > 0);
504          let sample_commit = sample_commit();
505          let mask_poly = if test_with_none { None } else { Some(sample_commit) };
506          Commitments {
507              witness_commitments: vec![WitnessCommitments { w: sample_commit }; i * j],
508              mask_poly,
509              h_0: sample_commit,
510              g_1: sample_commit,
511              h_1: sample_commit,
512              g_a_commitments: vec![sample_commit; i],
513              g_b_commitments: vec![sample_commit; i],
514              g_c_commitments: vec![sample_commit; i],
515              h_2: sample_commit,
516          }
517      }
518  
519      fn rand_evaluations<F: PrimeField>(rng: &mut TestRng, i: usize) -> Evaluations<F> {
520          Evaluations {
521              g_1_eval: F::rand(rng),
522              g_a_evals: (0..i).map(|_| F::rand(rng)).collect(),
523              g_b_evals: (0..i).map(|_| F::rand(rng)).collect(),
524              g_c_evals: (0..i).map(|_| F::rand(rng)).collect(),
525          }
526      }
527  
528      fn rand_sums<F: PrimeField>(rng: &mut TestRng) -> MatrixSums<F> {
529          MatrixSums::<F> { sum_a: F::rand(rng), sum_b: F::rand(rng), sum_c: F::rand(rng) }
530      }
531  
532      fn rand_kzg_proof(rng: &mut TestRng, test_with_none: bool) -> KZGProof<Bls12_377> {
533          let random_v = if test_with_none { None } else { Some(Fr::rand(rng)) };
534          KZGProof::<Bls12_377> { w: G1Affine::prime_subgroup_generator(), random_v }
535      }
536  
537      #[test]
538      fn test_serializing_commitments() {
539          for i in 1..11 {
540              for j in 1..11 {
541                  let test_with_none = i * j % 2 == 0;
542                  let commitments = rand_commitments(j, i, test_with_none);
543                  let batch_sizes = vec![j; i];
544                  let combinations = modes();
545                  for (compress, validate) in combinations {
546                      let size = Commitments::serialized_size(&commitments, compress);
547                      let mut serialized = vec![0; size];
548                      Commitments::serialize_with_mode(&commitments, &mut serialized[..], compress).unwrap();
549                      let de =
550                          Commitments::deserialize_with_mode(&batch_sizes, &serialized[..], compress, validate).unwrap();
551                      assert_eq!(commitments, de);
552                  }
553              }
554          }
555      }
556  
557      #[test]
558      fn test_serializing_evaluations() {
559          let rng = &mut TestRng::default();
560  
561          for i in 1..11 {
562              for j in 1..11 {
563                  let evaluations: Evaluations<Fr> = rand_evaluations(rng, i);
564                  let batch_sizes = vec![j; i];
565                  let combinations = modes();
566                  for (compress, validate) in combinations {
567                      let size = Evaluations::serialized_size(&evaluations, compress);
568                      let mut serialized = vec![0; size];
569                      Evaluations::serialize_with_mode(&evaluations, &mut serialized[..], compress).unwrap();
570                      let de =
571                          Evaluations::deserialize_with_mode(&batch_sizes, &serialized[..], compress, validate).unwrap();
572                      assert_eq!(evaluations, de);
573                  }
574              }
575          }
576      }
577  
578      #[test]
579      fn test_serializing_proof() {
580          let rng = &mut alphavm_utilities::rand::TestRng::default();
581  
582          for i in 1..11 {
583              for j in 1..11 {
584                  let test_with_none = i * j % 2 == 0;
585                  let batch_sizes = vec![j; i];
586                  let commitments = rand_commitments(j, i, test_with_none);
587                  let evaluations: Evaluations<Fr> = rand_evaluations(rng, i);
588                  let third_msg = ThirdMessage::<Fr> { sums: vec![vec![rand_sums(rng); j]; i] };
589                  let fourth_msg = FourthMessage::<Fr> { sums: vec![rand_sums(rng); i] };
590                  let pc_proof =
591                      sonic_pc::BatchLCProof { proof: BatchProof(vec![rand_kzg_proof(rng, test_with_none); j]) };
592                  let proof = Proof { batch_sizes, commitments, evaluations, third_msg, fourth_msg, pc_proof };
593                  let combinations = modes();
594                  for (compress, validate) in combinations {
595                      let size = Proof::serialized_size(&proof, compress);
596                      let mut serialized = vec![0; size];
597                      Proof::serialize_with_mode(&proof, &mut serialized[..], compress).unwrap();
598                      let de = Proof::deserialize_with_mode(&serialized[..], compress, validate).unwrap();
599                      assert_eq!(proof, de);
600                  }
601              }
602          }
603      }
604  }