1use crate::{
17 SNARKError,
18 polycommit::{kzg10::KZGCommitment, sonic_pc},
19 snark::varuna::{CircuitId, VarunaVersion, ahp},
20};
21
22use ahp::prover::{FourthMessage, ThirdMessage};
23use snarkvm_curves::PairingEngine;
24use snarkvm_fields::{One, PrimeField};
25use snarkvm_utilities::{FromBytes, ToBytes, into_io_error, serialize::*};
26
27use anyhow::{Result, anyhow};
28use std::{
29 collections::BTreeMap,
30 io::{self, Read, Write},
31};
32
33use std::mem::size_of;
34
35#[derive(Clone, Debug, PartialEq, Eq, CanonicalSerialize, CanonicalDeserialize)]
36pub struct Commitments<E: PairingEngine> {
37 pub witness_commitments: Vec<WitnessCommitments<E>>,
38 pub mask_poly: Option<sonic_pc::Commitment<E>>,
40 pub h_0: sonic_pc::Commitment<E>,
42 pub g_1: sonic_pc::Commitment<E>,
44 pub h_1: sonic_pc::Commitment<E>,
46 pub g_a_commitments: Vec<sonic_pc::Commitment<E>>,
48 pub g_b_commitments: Vec<sonic_pc::Commitment<E>>,
50 pub g_c_commitments: Vec<sonic_pc::Commitment<E>>,
52 pub h_2: sonic_pc::Commitment<E>,
54}
55
56impl<E: PairingEngine> Commitments<E> {
57 fn serialize_with_mode<W: snarkvm_utilities::Write>(
58 &self,
59 mut writer: W,
60 compress: Compress,
61 ) -> Result<(), snarkvm_utilities::SerializationError> {
62 serialize_vec_without_len(self.witness_commitments.iter(), &mut writer, compress)?;
63 CanonicalSerialize::serialize_with_mode(&self.mask_poly, &mut writer, compress)?;
64 CanonicalSerialize::serialize_with_mode(&self.h_0, &mut writer, compress)?;
65 CanonicalSerialize::serialize_with_mode(&self.g_1, &mut writer, compress)?;
66 CanonicalSerialize::serialize_with_mode(&self.h_1, &mut writer, compress)?;
67 serialize_vec_without_len(self.g_a_commitments.iter(), &mut writer, compress)?;
68 serialize_vec_without_len(self.g_b_commitments.iter(), &mut writer, compress)?;
69 serialize_vec_without_len(self.g_c_commitments.iter(), &mut writer, compress)?;
70 CanonicalSerialize::serialize_with_mode(&self.h_2, &mut writer, compress)?;
71 Ok(())
72 }
73
74 fn serialized_size(&self, compress: Compress) -> usize {
75 serialized_vec_size_without_len(&self.witness_commitments, compress)
76 .saturating_add(CanonicalSerialize::serialized_size(&self.mask_poly, compress))
77 .saturating_add(CanonicalSerialize::serialized_size(&self.h_0, compress))
78 .saturating_add(CanonicalSerialize::serialized_size(&self.g_1, compress))
79 .saturating_add(CanonicalSerialize::serialized_size(&self.h_1, compress))
80 .saturating_add(serialized_vec_size_without_len(&self.g_a_commitments, compress))
81 .saturating_add(serialized_vec_size_without_len(&self.g_b_commitments, compress))
82 .saturating_add(serialized_vec_size_without_len(&self.g_c_commitments, compress))
83 .saturating_add(CanonicalSerialize::serialized_size(&self.h_2, compress))
84 }
85
86 fn deserialize_with_mode<R: snarkvm_utilities::Read>(
87 batch_sizes: &[usize],
88 mut reader: R,
89 compress: Compress,
90 validate: Validate,
91 ) -> Result<Self, snarkvm_utilities::SerializationError> {
92 let mut w = Vec::new();
93 for batch_size in batch_sizes {
94 w.extend(deserialize_vec_without_len(&mut reader, compress, validate, *batch_size)?);
95 }
96 Ok(Commitments {
97 witness_commitments: w,
98 mask_poly: CanonicalDeserialize::deserialize_with_mode(&mut reader, compress, validate)?,
99 h_0: CanonicalDeserialize::deserialize_with_mode(&mut reader, compress, validate)?,
100 g_1: CanonicalDeserialize::deserialize_with_mode(&mut reader, compress, validate)?,
101 h_1: CanonicalDeserialize::deserialize_with_mode(&mut reader, compress, validate)?,
102 g_a_commitments: deserialize_vec_without_len(&mut reader, compress, validate, batch_sizes.len())?,
103 g_b_commitments: deserialize_vec_without_len(&mut reader, compress, validate, batch_sizes.len())?,
104 g_c_commitments: deserialize_vec_without_len(&mut reader, compress, validate, batch_sizes.len())?,
105 h_2: CanonicalDeserialize::deserialize_with_mode(&mut reader, compress, validate)?,
106 })
107 }
108}
109#[derive(Clone, Debug, PartialEq, Eq, CanonicalSerialize, CanonicalDeserialize)]
111pub struct WitnessCommitments<E: PairingEngine> {
112 pub w: sonic_pc::Commitment<E>,
114}
115
116#[derive(Clone, Debug, PartialEq, Eq)]
117pub struct Evaluations<F: PrimeField> {
118 pub g_1_eval: F,
120 pub g_a_evals: Vec<F>,
122 pub g_b_evals: Vec<F>,
124 pub g_c_evals: Vec<F>,
126}
127
128impl<F: PrimeField> Evaluations<F> {
129 fn serialize_with_mode<W: snarkvm_utilities::Write>(
130 &self,
131 mut writer: W,
132 compress: Compress,
133 ) -> Result<(), snarkvm_utilities::SerializationError> {
134 CanonicalSerialize::serialize_with_mode(&self.g_1_eval, &mut writer, compress)?;
135 serialize_vec_without_len(self.g_a_evals.iter(), &mut writer, compress)?;
136 serialize_vec_without_len(self.g_b_evals.iter(), &mut writer, compress)?;
137 serialize_vec_without_len(self.g_c_evals.iter(), &mut writer, compress)?;
138 Ok(())
139 }
140
141 fn serialized_size(&self, compress: Compress) -> usize {
142 CanonicalSerialize::serialized_size(&self.g_1_eval, compress)
143 .saturating_add(serialized_vec_size_without_len(&self.g_a_evals, compress))
144 .saturating_add(serialized_vec_size_without_len(&self.g_b_evals, compress))
145 .saturating_add(serialized_vec_size_without_len(&self.g_c_evals, compress))
146 }
147
148 fn deserialize_with_mode<R: snarkvm_utilities::Read>(
149 batch_sizes: &[usize],
150 mut reader: R,
151 compress: Compress,
152 validate: Validate,
153 ) -> Result<Self, snarkvm_utilities::SerializationError> {
154 Ok(Evaluations {
155 g_1_eval: CanonicalDeserialize::deserialize_with_mode(&mut reader, compress, validate)?,
156 g_a_evals: deserialize_vec_without_len(&mut reader, compress, validate, batch_sizes.len())?,
157 g_b_evals: deserialize_vec_without_len(&mut reader, compress, validate, batch_sizes.len())?,
158 g_c_evals: deserialize_vec_without_len(&mut reader, compress, validate, batch_sizes.len())?,
159 })
160 }
161}
162
163impl<F: PrimeField> Evaluations<F> {
164 pub(crate) fn from_map(
165 map: &std::collections::BTreeMap<String, F>,
166 batch_sizes: BTreeMap<CircuitId, usize>,
167 ) -> Self {
168 let mut g_a_evals = Vec::with_capacity(batch_sizes.len());
169 let mut g_b_evals = Vec::with_capacity(batch_sizes.len());
170 let mut g_c_evals = Vec::with_capacity(batch_sizes.len());
171
172 for (label, value) in map {
173 if label == "g_1" {
174 continue;
175 }
176
177 if label.contains("g_a") {
178 g_a_evals.push(*value);
179 } else if label.contains("g_b") {
180 g_b_evals.push(*value);
181 } else if label.contains("g_c") {
182 g_c_evals.push(*value);
183 }
184 }
185 Self { g_1_eval: map["g_1"], g_a_evals, g_b_evals, g_c_evals }
186 }
187
188 pub(crate) fn get(&self, circuit_index: usize, label: &str) -> Option<F> {
189 if label == "g_1" {
190 return Some(self.g_1_eval);
191 }
192
193 if label.contains("g_a") {
194 self.g_a_evals.get(circuit_index).copied()
195 } else if label.contains("g_b") {
196 self.g_b_evals.get(circuit_index).copied()
197 } else if label.contains("g_c") {
198 self.g_c_evals.get(circuit_index).copied()
199 } else {
200 None
201 }
202 }
203
204 pub fn to_field_elements(&self) -> Vec<F> {
205 let mut result = Vec::with_capacity(1 + self.g_a_evals.len() + self.g_b_evals.len() + self.g_c_evals.len());
206 result.push(self.g_1_eval);
207 result.extend_from_slice(&self.g_a_evals);
208 result.extend_from_slice(&self.g_b_evals);
209 result.extend_from_slice(&self.g_c_evals);
210 result
211 }
212}
213
214impl<F: PrimeField> Valid for Evaluations<F> {
215 fn check(&self) -> Result<(), snarkvm_utilities::SerializationError> {
216 self.g_1_eval.check()?;
217 self.g_a_evals.check()?;
218 self.g_b_evals.check()?;
219 self.g_c_evals.check()
220 }
221}
222
223#[derive(Clone, Debug, PartialEq, Eq)]
225pub struct Proof<E: PairingEngine> {
226 batch_sizes: Vec<usize>,
228
229 pub commitments: Commitments<E>,
231
232 pub evaluations: Evaluations<E::Fr>,
234
235 pub third_msg: ThirdMessage<E::Fr>,
237
238 pub fourth_msg: FourthMessage<E::Fr>,
240
241 pub pc_proof: sonic_pc::BatchLCProof<E>,
243}
244
245impl<E: PairingEngine> Proof<E> {
246 pub fn new(
248 batch_sizes: BTreeMap<CircuitId, usize>,
249 commitments: Commitments<E>,
250 evaluations: Evaluations<E::Fr>,
251 third_msg: ThirdMessage<E::Fr>,
252 fourth_msg: FourthMessage<E::Fr>,
253 pc_proof: sonic_pc::BatchLCProof<E>,
254 ) -> Result<Self, SNARKError> {
255 let batch_sizes: Vec<usize> = batch_sizes.into_values().collect();
256 Ok(Self { batch_sizes, commitments, evaluations, third_msg, fourth_msg, pc_proof })
257 }
258
259 pub fn is_hiding(&self) -> bool {
260 self.pc_proof.is_hiding()
261 }
262
263 pub fn batch_sizes(&self) -> &[usize] {
264 &self.batch_sizes
265 }
266
267 pub fn check_batch_sizes(&self) -> Result<(), SNARKError> {
269 let total_instances = self
270 .batch_sizes
271 .iter()
272 .try_fold(0usize, |acc, &size| acc.checked_add(size))
273 .ok_or(SNARKError::BatchSizeMismatch)?;
274 if self.commitments.witness_commitments.len() != total_instances {
275 return Err(SNARKError::BatchSizeMismatch);
276 }
277 let g_comms =
278 [&self.commitments.g_a_commitments, &self.commitments.g_b_commitments, &self.commitments.g_c_commitments];
279 for comms in g_comms {
280 if comms.len() != self.batch_sizes.len() {
281 return Err(SNARKError::BatchSizeMismatch);
282 }
283 }
284 let g_evals = [&self.evaluations.g_a_evals, &self.evaluations.g_b_evals, &self.evaluations.g_c_evals];
285 for evals in g_evals {
286 if evals.len() != self.batch_sizes.len() {
287 return Err(SNARKError::BatchSizeMismatch);
288 }
289 }
290 if self.third_msg.sums.len() != self.batch_sizes.len() {
291 return Err(SNARKError::BatchSizeMismatch);
292 }
293 for (msg, &batch_size) in self.third_msg.sums.iter().zip(self.batch_sizes.iter()) {
294 if msg.len() != batch_size {
295 return Err(SNARKError::BatchSizeMismatch);
296 }
297 }
298 if self.fourth_msg.sums.len() != self.batch_sizes.len() {
299 return Err(SNARKError::BatchSizeMismatch);
300 }
301 Ok(())
302 }
303}
304
305impl<E: PairingEngine> CanonicalSerialize for Proof<E> {
306 fn serialize_with_mode<W: Write>(&self, mut writer: W, compress: Compress) -> Result<(), SerializationError> {
307 let batch_sizes: Vec<u64> = self.batch_sizes.iter().map(|x| u64::try_from(*x)).collect::<Result<_, _>>()?;
308 CanonicalSerialize::serialize_with_mode(&batch_sizes, &mut writer, compress)?;
309 Commitments::serialize_with_mode(&self.commitments, &mut writer, compress)?;
310 Evaluations::serialize_with_mode(&self.evaluations, &mut writer, compress)?;
311 for third_sums in self.third_msg.sums.iter() {
312 serialize_vec_without_len(third_sums.iter(), &mut writer, compress)?;
313 }
314 serialize_vec_without_len(self.fourth_msg.sums.iter(), &mut writer, compress)?;
315 CanonicalSerialize::serialize_with_mode(&self.pc_proof, &mut writer, compress)?;
316 Ok(())
317 }
318
319 fn serialized_size(&self, mode: Compress) -> usize {
320 let mut size = 0;
321 size += CanonicalSerialize::serialized_size(&self.batch_sizes, mode);
322 size += Commitments::serialized_size(&self.commitments, mode);
323 size += Evaluations::serialized_size(&self.evaluations, mode);
324 for third_sums in self.third_msg.sums.iter() {
325 size += serialized_vec_size_without_len(third_sums, mode);
326 }
327 size += serialized_vec_size_without_len(&self.fourth_msg.sums, mode);
328 size += CanonicalSerialize::serialized_size(&self.pc_proof, mode);
329 size
330 }
331}
332
333impl<E: PairingEngine> Valid for Proof<E> {
334 fn check(&self) -> Result<(), SerializationError> {
335 self.batch_sizes.check()?;
336 self.commitments.check()?;
337 self.evaluations.check()?;
338 self.third_msg.check()?;
339 self.fourth_msg.check()?;
340 self.pc_proof.check()
341 }
342}
343
344impl<E: PairingEngine> CanonicalDeserialize for Proof<E> {
345 fn deserialize_with_mode<R: Read>(
346 mut reader: R,
347 compress: Compress,
348 validate: Validate,
349 ) -> Result<Self, SerializationError> {
350 let batch_sizes: Vec<u64> = CanonicalDeserialize::deserialize_with_mode(&mut reader, compress, validate)?;
351 let batch_sizes: Vec<usize> = batch_sizes.into_iter().map(|x| x as usize).collect();
352 let commitments = Commitments::deserialize_with_mode(&batch_sizes, &mut reader, compress, validate)?;
353 let evaluations = Evaluations::deserialize_with_mode(&batch_sizes, &mut reader, compress, validate)?;
354 let third_msg_sums = batch_sizes
355 .iter()
356 .map(|&batch_size| deserialize_vec_without_len(&mut reader, compress, validate, batch_size))
357 .collect::<Result<Vec<_>, _>>()?;
358 let fourth_msg_sums = deserialize_vec_without_len(&mut reader, compress, validate, batch_sizes.len())?;
359 Ok(Proof {
360 commitments,
361 evaluations,
362 third_msg: ThirdMessage { sums: third_msg_sums },
363 fourth_msg: FourthMessage { sums: fourth_msg_sums },
364 pc_proof: CanonicalDeserialize::deserialize_with_mode(&mut reader, compress, validate)?,
365 batch_sizes,
366 })
367 }
368}
369
370impl<E: PairingEngine> ToBytes for Proof<E> {
371 fn write_le<W: Write>(&self, mut w: W) -> io::Result<()> {
372 Self::serialize_compressed(self, &mut w)
373 .map_err(|err| into_io_error(anyhow::Error::from(err).context("could not serialize Proof")))
374 }
375}
376
377impl<E: PairingEngine> FromBytes for Proof<E> {
378 fn read_le<R: Read>(mut r: R) -> io::Result<Self> {
379 Self::deserialize_compressed(&mut r)
380 .map_err(|err| into_io_error(anyhow::Error::from(err).context("could not deserialize Proof")))
381 }
382}
383
384pub fn proof_size<E: PairingEngine>(
398 batch_sizes: &[usize],
399 varuna_version: VarunaVersion,
400 hiding: bool,
401) -> Result<usize> {
402 let n_circuits: usize = batch_sizes.len();
403 let n_instances: usize = batch_sizes.iter().sum();
404
405 match varuna_version {
406 VarunaVersion::V1 => Err(anyhow!("Proof-size calculation not implemented for Varuna version V1")),
407 VarunaVersion::V2 => {
408 let n_bool = 1;
434 let n_u64 = 1;
435 let n_field_elements = 1 + 6 * n_circuits + 3 * n_instances;
436 let n_commitments = 4 + n_instances + (if hiding { 1 } else { 0 }) + 3 * n_circuits;
437
438 let size_bool = size_of::<bool>();
440 let size_u64 = size_of::<u64>();
441
442 let size_field_element = E::Fr::one().compressed_size();
447 let size_commitment = KZGCommitment::<E>::empty().compressed_size();
448
449 let size_pc_proof = size_u64 + 3 * (size_commitment + 1) + if hiding { size_field_element } else { 0 };
450
451 Ok(n_bool * size_bool
452 + (n_u64 + batch_sizes.len()) * size_u64
453 + n_field_elements * size_field_element
454 + n_commitments * size_commitment
455 + size_pc_proof)
456 }
457 }
458}
459
460#[cfg(test)]
461mod test {
462 #![allow(non_camel_case_types)]
463
464 use super::*;
465
466 use crate::{
467 polycommit::{
468 kzg10::{KZGCommitment, KZGProof},
469 sonic_pc::BatchProof,
470 },
471 snark::varuna::prover::MatrixSums,
472 };
473 use snarkvm_curves::{
474 AffineCurve,
475 bls12_377::{Bls12_377, Fr, G1Affine},
476 };
477 use snarkvm_utilities::{TestRng, Uniform};
478
479 const fn modes() -> [(Compress, Validate); 4] {
480 [
481 (Compress::No, Validate::No),
482 (Compress::Yes, Validate::No),
483 (Compress::No, Validate::Yes),
484 (Compress::Yes, Validate::Yes),
485 ]
486 }
487
488 fn sample_commit() -> KZGCommitment<Bls12_377> {
489 let buf = G1Affine::prime_subgroup_generator().to_bytes_le().unwrap();
490 FromBytes::read_le(buf.as_slice()).unwrap()
491 }
492
493 fn rand_commitments(j: usize, i: usize, test_with_none: bool) -> Commitments<Bls12_377> {
494 assert!(i > 0);
495 assert!(j > 0);
496 let sample_commit = sample_commit();
497 let mask_poly = if test_with_none { None } else { Some(sample_commit) };
498 Commitments {
499 witness_commitments: vec![WitnessCommitments { w: sample_commit }; i * j],
500 mask_poly,
501 h_0: sample_commit,
502 g_1: sample_commit,
503 h_1: sample_commit,
504 g_a_commitments: vec![sample_commit; i],
505 g_b_commitments: vec![sample_commit; i],
506 g_c_commitments: vec![sample_commit; i],
507 h_2: sample_commit,
508 }
509 }
510
511 fn rand_evaluations<F: PrimeField>(rng: &mut TestRng, i: usize) -> Evaluations<F> {
512 Evaluations {
513 g_1_eval: F::rand(rng),
514 g_a_evals: (0..i).map(|_| F::rand(rng)).collect(),
515 g_b_evals: (0..i).map(|_| F::rand(rng)).collect(),
516 g_c_evals: (0..i).map(|_| F::rand(rng)).collect(),
517 }
518 }
519
520 fn rand_sums<F: PrimeField>(rng: &mut TestRng) -> MatrixSums<F> {
521 MatrixSums::<F> { sum_a: F::rand(rng), sum_b: F::rand(rng), sum_c: F::rand(rng) }
522 }
523
524 fn rand_kzg_proof(rng: &mut TestRng, test_with_none: bool) -> KZGProof<Bls12_377> {
525 let random_v = if test_with_none { None } else { Some(Fr::rand(rng)) };
526 KZGProof::<Bls12_377> { w: G1Affine::prime_subgroup_generator(), random_v }
527 }
528
529 #[test]
530 fn test_serializing_commitments() {
531 for i in 1..11 {
532 for j in 1..11 {
533 let test_with_none = i * j % 2 == 0;
534 let commitments = rand_commitments(j, i, test_with_none);
535 let batch_sizes = vec![j; i];
536 let combinations = modes();
537 for (compress, validate) in combinations {
538 let size = Commitments::serialized_size(&commitments, compress);
539 let mut serialized = vec![0; size];
540 Commitments::serialize_with_mode(&commitments, &mut serialized[..], compress).unwrap();
541 let de =
542 Commitments::deserialize_with_mode(&batch_sizes, &serialized[..], compress, validate).unwrap();
543 assert_eq!(commitments, de);
544 }
545 }
546 }
547 }
548
549 #[test]
550 fn test_serializing_evaluations() {
551 let rng = &mut TestRng::default();
552
553 for i in 1..11 {
554 for j in 1..11 {
555 let evaluations: Evaluations<Fr> = rand_evaluations(rng, i);
556 let batch_sizes = vec![j; i];
557 let combinations = modes();
558 for (compress, validate) in combinations {
559 let size = Evaluations::serialized_size(&evaluations, compress);
560 let mut serialized = vec![0; size];
561 Evaluations::serialize_with_mode(&evaluations, &mut serialized[..], compress).unwrap();
562 let de =
563 Evaluations::deserialize_with_mode(&batch_sizes, &serialized[..], compress, validate).unwrap();
564 assert_eq!(evaluations, de);
565 }
566 }
567 }
568 }
569
570 #[test]
571 fn test_serializing_proof() {
572 let rng = &mut snarkvm_utilities::rand::TestRng::default();
573
574 for i in 1..11 {
575 for j in 1..11 {
576 let test_with_none = i * j % 2 == 0;
577 let batch_sizes = vec![j; i];
578 let commitments = rand_commitments(j, i, test_with_none);
579 let evaluations: Evaluations<Fr> = rand_evaluations(rng, i);
580 let third_msg = ThirdMessage::<Fr> { sums: vec![vec![rand_sums(rng); j]; i] };
581 let fourth_msg = FourthMessage::<Fr> { sums: vec![rand_sums(rng); i] };
582 let pc_proof =
583 sonic_pc::BatchLCProof { proof: BatchProof(vec![rand_kzg_proof(rng, test_with_none); j]) };
584 let proof = Proof { batch_sizes, commitments, evaluations, third_msg, fourth_msg, pc_proof };
585 let combinations = modes();
586 for (compress, validate) in combinations {
587 let size = Proof::serialized_size(&proof, compress);
588 let mut serialized = vec![0; size];
589 Proof::serialize_with_mode(&proof, &mut serialized[..], compress).unwrap();
590 let de = Proof::deserialize_with_mode(&serialized[..], compress, validate).unwrap();
591 assert_eq!(proof, de);
592 }
593 }
594 }
595 }
596}