1use crate::{
17 SNARKError,
18 polycommit::sonic_pc,
19 snark::varuna::{CircuitId, ahp},
20};
21
22use ahp::prover::{FourthMessage, ThirdMessage};
23use snarkvm_curves::PairingEngine;
24use snarkvm_fields::PrimeField;
25use snarkvm_utilities::{FromBytes, ToBytes, into_io_error, serialize::*};
26
27use std::{
28 collections::BTreeMap,
29 io::{self, Read, Write},
30};
31
32#[derive(Clone, Debug, PartialEq, Eq, CanonicalSerialize, CanonicalDeserialize)]
33pub struct Commitments<E: PairingEngine> {
34 pub witness_commitments: Vec<WitnessCommitments<E>>,
35 pub mask_poly: Option<sonic_pc::Commitment<E>>,
37 pub h_0: sonic_pc::Commitment<E>,
39 pub g_1: sonic_pc::Commitment<E>,
41 pub h_1: sonic_pc::Commitment<E>,
43 pub g_a_commitments: Vec<sonic_pc::Commitment<E>>,
45 pub g_b_commitments: Vec<sonic_pc::Commitment<E>>,
47 pub g_c_commitments: Vec<sonic_pc::Commitment<E>>,
49 pub h_2: sonic_pc::Commitment<E>,
51}
52
53impl<E: PairingEngine> Commitments<E> {
54 fn serialize_with_mode<W: snarkvm_utilities::Write>(
55 &self,
56 mut writer: W,
57 compress: Compress,
58 ) -> Result<(), snarkvm_utilities::SerializationError> {
59 serialize_vec_without_len(self.witness_commitments.iter(), &mut writer, compress)?;
60 CanonicalSerialize::serialize_with_mode(&self.mask_poly, &mut writer, compress)?;
61 CanonicalSerialize::serialize_with_mode(&self.h_0, &mut writer, compress)?;
62 CanonicalSerialize::serialize_with_mode(&self.g_1, &mut writer, compress)?;
63 CanonicalSerialize::serialize_with_mode(&self.h_1, &mut writer, compress)?;
64 serialize_vec_without_len(self.g_a_commitments.iter(), &mut writer, compress)?;
65 serialize_vec_without_len(self.g_b_commitments.iter(), &mut writer, compress)?;
66 serialize_vec_without_len(self.g_c_commitments.iter(), &mut writer, compress)?;
67 CanonicalSerialize::serialize_with_mode(&self.h_2, &mut writer, compress)?;
68 Ok(())
69 }
70
71 fn serialized_size(&self, compress: Compress) -> usize {
72 serialized_vec_size_without_len(&self.witness_commitments, compress)
73 .saturating_add(CanonicalSerialize::serialized_size(&self.mask_poly, compress))
74 .saturating_add(CanonicalSerialize::serialized_size(&self.h_0, compress))
75 .saturating_add(CanonicalSerialize::serialized_size(&self.g_1, compress))
76 .saturating_add(CanonicalSerialize::serialized_size(&self.h_1, compress))
77 .saturating_add(serialized_vec_size_without_len(&self.g_a_commitments, compress))
78 .saturating_add(serialized_vec_size_without_len(&self.g_b_commitments, compress))
79 .saturating_add(serialized_vec_size_without_len(&self.g_c_commitments, compress))
80 .saturating_add(CanonicalSerialize::serialized_size(&self.h_2, compress))
81 }
82
83 fn deserialize_with_mode<R: snarkvm_utilities::Read>(
84 batch_sizes: &[usize],
85 mut reader: R,
86 compress: Compress,
87 validate: Validate,
88 ) -> Result<Self, snarkvm_utilities::SerializationError> {
89 let mut w = Vec::new();
90 for batch_size in batch_sizes {
91 w.extend(deserialize_vec_without_len(&mut reader, compress, validate, *batch_size)?);
92 }
93 Ok(Commitments {
94 witness_commitments: w,
95 mask_poly: CanonicalDeserialize::deserialize_with_mode(&mut reader, compress, validate)?,
96 h_0: CanonicalDeserialize::deserialize_with_mode(&mut reader, compress, validate)?,
97 g_1: CanonicalDeserialize::deserialize_with_mode(&mut reader, compress, validate)?,
98 h_1: CanonicalDeserialize::deserialize_with_mode(&mut reader, compress, validate)?,
99 g_a_commitments: deserialize_vec_without_len(&mut reader, compress, validate, batch_sizes.len())?,
100 g_b_commitments: deserialize_vec_without_len(&mut reader, compress, validate, batch_sizes.len())?,
101 g_c_commitments: deserialize_vec_without_len(&mut reader, compress, validate, batch_sizes.len())?,
102 h_2: CanonicalDeserialize::deserialize_with_mode(&mut reader, compress, validate)?,
103 })
104 }
105}
106#[derive(Clone, Debug, PartialEq, Eq, CanonicalSerialize, CanonicalDeserialize)]
108pub struct WitnessCommitments<E: PairingEngine> {
109 pub w: sonic_pc::Commitment<E>,
111}
112
113#[derive(Clone, Debug, PartialEq, Eq)]
114pub struct Evaluations<F: PrimeField> {
115 pub g_1_eval: F,
117 pub g_a_evals: Vec<F>,
119 pub g_b_evals: Vec<F>,
121 pub g_c_evals: Vec<F>,
123}
124
125impl<F: PrimeField> Evaluations<F> {
126 fn serialize_with_mode<W: snarkvm_utilities::Write>(
127 &self,
128 mut writer: W,
129 compress: Compress,
130 ) -> Result<(), snarkvm_utilities::SerializationError> {
131 CanonicalSerialize::serialize_with_mode(&self.g_1_eval, &mut writer, compress)?;
132 serialize_vec_without_len(self.g_a_evals.iter(), &mut writer, compress)?;
133 serialize_vec_without_len(self.g_b_evals.iter(), &mut writer, compress)?;
134 serialize_vec_without_len(self.g_c_evals.iter(), &mut writer, compress)?;
135 Ok(())
136 }
137
138 fn serialized_size(&self, compress: Compress) -> usize {
139 CanonicalSerialize::serialized_size(&self.g_1_eval, compress)
140 .saturating_add(serialized_vec_size_without_len(&self.g_a_evals, compress))
141 .saturating_add(serialized_vec_size_without_len(&self.g_b_evals, compress))
142 .saturating_add(serialized_vec_size_without_len(&self.g_c_evals, compress))
143 }
144
145 fn deserialize_with_mode<R: snarkvm_utilities::Read>(
146 batch_sizes: &[usize],
147 mut reader: R,
148 compress: Compress,
149 validate: Validate,
150 ) -> Result<Self, snarkvm_utilities::SerializationError> {
151 Ok(Evaluations {
152 g_1_eval: CanonicalDeserialize::deserialize_with_mode(&mut reader, compress, validate)?,
153 g_a_evals: deserialize_vec_without_len(&mut reader, compress, validate, batch_sizes.len())?,
154 g_b_evals: deserialize_vec_without_len(&mut reader, compress, validate, batch_sizes.len())?,
155 g_c_evals: deserialize_vec_without_len(&mut reader, compress, validate, batch_sizes.len())?,
156 })
157 }
158}
159
160impl<F: PrimeField> Evaluations<F> {
161 pub(crate) fn from_map(
162 map: &std::collections::BTreeMap<String, F>,
163 batch_sizes: BTreeMap<CircuitId, usize>,
164 ) -> Self {
165 let mut g_a_evals = Vec::with_capacity(batch_sizes.len());
166 let mut g_b_evals = Vec::with_capacity(batch_sizes.len());
167 let mut g_c_evals = Vec::with_capacity(batch_sizes.len());
168
169 for (label, value) in map {
170 if label == "g_1" {
171 continue;
172 }
173
174 if label.contains("g_a") {
175 g_a_evals.push(*value);
176 } else if label.contains("g_b") {
177 g_b_evals.push(*value);
178 } else if label.contains("g_c") {
179 g_c_evals.push(*value);
180 }
181 }
182 Self { g_1_eval: map["g_1"], g_a_evals, g_b_evals, g_c_evals }
183 }
184
185 pub(crate) fn get(&self, circuit_index: usize, label: &str) -> Option<F> {
186 if label == "g_1" {
187 return Some(self.g_1_eval);
188 }
189
190 if label.contains("g_a") {
191 self.g_a_evals.get(circuit_index).copied()
192 } else if label.contains("g_b") {
193 self.g_b_evals.get(circuit_index).copied()
194 } else if label.contains("g_c") {
195 self.g_c_evals.get(circuit_index).copied()
196 } else {
197 None
198 }
199 }
200
201 pub fn to_field_elements(&self) -> Vec<F> {
202 let mut result = Vec::with_capacity(1 + self.g_a_evals.len() + self.g_b_evals.len() + self.g_c_evals.len());
203 result.push(self.g_1_eval);
204 result.extend_from_slice(&self.g_a_evals);
205 result.extend_from_slice(&self.g_b_evals);
206 result.extend_from_slice(&self.g_c_evals);
207 result
208 }
209}
210
211impl<F: PrimeField> Valid for Evaluations<F> {
212 fn check(&self) -> Result<(), snarkvm_utilities::SerializationError> {
213 self.g_1_eval.check()?;
214 self.g_a_evals.check()?;
215 self.g_b_evals.check()?;
216 self.g_c_evals.check()
217 }
218}
219
220#[derive(Clone, Debug, PartialEq, Eq)]
222pub struct Proof<E: PairingEngine> {
223 batch_sizes: Vec<usize>,
225
226 pub commitments: Commitments<E>,
228
229 pub evaluations: Evaluations<E::Fr>,
231
232 pub third_msg: ThirdMessage<E::Fr>,
234
235 pub fourth_msg: FourthMessage<E::Fr>,
237
238 pub pc_proof: sonic_pc::BatchLCProof<E>,
240}
241
242impl<E: PairingEngine> Proof<E> {
243 pub fn new(
245 batch_sizes: BTreeMap<CircuitId, usize>,
246 commitments: Commitments<E>,
247 evaluations: Evaluations<E::Fr>,
248 third_msg: ThirdMessage<E::Fr>,
249 fourth_msg: FourthMessage<E::Fr>,
250 pc_proof: sonic_pc::BatchLCProof<E>,
251 ) -> Result<Self, SNARKError> {
252 let batch_sizes: Vec<usize> = batch_sizes.into_values().collect();
253 Ok(Self { batch_sizes, commitments, evaluations, third_msg, fourth_msg, pc_proof })
254 }
255
256 pub fn is_hiding(&self) -> bool {
257 self.pc_proof.is_hiding()
258 }
259
260 pub fn batch_sizes(&self) -> &[usize] {
261 &self.batch_sizes
262 }
263
264 pub fn check_batch_sizes(&self) -> Result<(), SNARKError> {
266 let total_instances = self
267 .batch_sizes
268 .iter()
269 .try_fold(0usize, |acc, &size| acc.checked_add(size))
270 .ok_or(SNARKError::BatchSizeMismatch)?;
271 if self.commitments.witness_commitments.len() != total_instances {
272 return Err(SNARKError::BatchSizeMismatch);
273 }
274 let g_comms =
275 [&self.commitments.g_a_commitments, &self.commitments.g_b_commitments, &self.commitments.g_c_commitments];
276 for comms in g_comms {
277 if comms.len() != self.batch_sizes.len() {
278 return Err(SNARKError::BatchSizeMismatch);
279 }
280 }
281 let g_evals = [&self.evaluations.g_a_evals, &self.evaluations.g_b_evals, &self.evaluations.g_c_evals];
282 for evals in g_evals {
283 if evals.len() != self.batch_sizes.len() {
284 return Err(SNARKError::BatchSizeMismatch);
285 }
286 }
287 if self.third_msg.sums.len() != self.batch_sizes.len() {
288 return Err(SNARKError::BatchSizeMismatch);
289 }
290 for (msg, &batch_size) in self.third_msg.sums.iter().zip(self.batch_sizes.iter()) {
291 if msg.len() != batch_size {
292 return Err(SNARKError::BatchSizeMismatch);
293 }
294 }
295 if self.fourth_msg.sums.len() != self.batch_sizes.len() {
296 return Err(SNARKError::BatchSizeMismatch);
297 }
298 Ok(())
299 }
300}
301
302impl<E: PairingEngine> CanonicalSerialize for Proof<E> {
303 fn serialize_with_mode<W: Write>(&self, mut writer: W, compress: Compress) -> Result<(), SerializationError> {
304 let batch_sizes: Vec<u64> = self.batch_sizes.iter().map(|x| u64::try_from(*x)).collect::<Result<_, _>>()?;
305 CanonicalSerialize::serialize_with_mode(&batch_sizes, &mut writer, compress)?;
306 Commitments::serialize_with_mode(&self.commitments, &mut writer, compress)?;
307 Evaluations::serialize_with_mode(&self.evaluations, &mut writer, compress)?;
308 for third_sums in self.third_msg.sums.iter() {
309 serialize_vec_without_len(third_sums.iter(), &mut writer, compress)?;
310 }
311 serialize_vec_without_len(self.fourth_msg.sums.iter(), &mut writer, compress)?;
312 CanonicalSerialize::serialize_with_mode(&self.pc_proof, &mut writer, compress)?;
313 Ok(())
314 }
315
316 fn serialized_size(&self, mode: Compress) -> usize {
317 let mut size = 0;
318 size += CanonicalSerialize::serialized_size(&self.batch_sizes, mode);
319 size += Commitments::serialized_size(&self.commitments, mode);
320 size += Evaluations::serialized_size(&self.evaluations, mode);
321 for third_sums in self.third_msg.sums.iter() {
322 size += serialized_vec_size_without_len(third_sums, mode);
323 }
324 size += serialized_vec_size_without_len(&self.fourth_msg.sums, mode);
325 size += CanonicalSerialize::serialized_size(&self.pc_proof, mode);
326 size
327 }
328}
329
330impl<E: PairingEngine> Valid for Proof<E> {
331 fn check(&self) -> Result<(), SerializationError> {
332 self.batch_sizes.check()?;
333 self.commitments.check()?;
334 self.evaluations.check()?;
335 self.third_msg.check()?;
336 self.fourth_msg.check()?;
337 self.pc_proof.check()
338 }
339}
340
341impl<E: PairingEngine> CanonicalDeserialize for Proof<E> {
342 fn deserialize_with_mode<R: Read>(
343 mut reader: R,
344 compress: Compress,
345 validate: Validate,
346 ) -> Result<Self, SerializationError> {
347 let batch_sizes: Vec<u64> = CanonicalDeserialize::deserialize_with_mode(&mut reader, compress, validate)?;
348 let batch_sizes: Vec<usize> = batch_sizes.into_iter().map(|x| x as usize).collect();
349 let commitments = Commitments::deserialize_with_mode(&batch_sizes, &mut reader, compress, validate)?;
350 let evaluations = Evaluations::deserialize_with_mode(&batch_sizes, &mut reader, compress, validate)?;
351 let third_msg_sums = batch_sizes
352 .iter()
353 .map(|&batch_size| deserialize_vec_without_len(&mut reader, compress, validate, batch_size))
354 .collect::<Result<Vec<_>, _>>()?;
355 let fourth_msg_sums = deserialize_vec_without_len(&mut reader, compress, validate, batch_sizes.len())?;
356 Ok(Proof {
357 commitments,
358 evaluations,
359 third_msg: ThirdMessage { sums: third_msg_sums },
360 fourth_msg: FourthMessage { sums: fourth_msg_sums },
361 pc_proof: CanonicalDeserialize::deserialize_with_mode(&mut reader, compress, validate)?,
362 batch_sizes,
363 })
364 }
365}
366
367impl<E: PairingEngine> ToBytes for Proof<E> {
368 fn write_le<W: Write>(&self, mut w: W) -> io::Result<()> {
369 Self::serialize_compressed(self, &mut w)
370 .map_err(|err| into_io_error(anyhow::Error::from(err).context("could not serialize Proof")))
371 }
372}
373
374impl<E: PairingEngine> FromBytes for Proof<E> {
375 fn read_le<R: Read>(mut r: R) -> io::Result<Self> {
376 Self::deserialize_compressed(&mut r)
377 .map_err(|err| into_io_error(anyhow::Error::from(err).context("could not deserialize Proof")))
378 }
379}
380
381#[cfg(test)]
382mod test {
383 #![allow(non_camel_case_types)]
384
385 use super::*;
386
387 use crate::{
388 polycommit::{
389 kzg10::{KZGCommitment, KZGProof},
390 sonic_pc::BatchProof,
391 },
392 snark::varuna::prover::MatrixSums,
393 };
394 use snarkvm_curves::{
395 AffineCurve,
396 bls12_377::{Bls12_377, Fr, G1Affine},
397 };
398 use snarkvm_utilities::{TestRng, Uniform};
399
400 const fn modes() -> [(Compress, Validate); 4] {
401 [
402 (Compress::No, Validate::No),
403 (Compress::Yes, Validate::No),
404 (Compress::No, Validate::Yes),
405 (Compress::Yes, Validate::Yes),
406 ]
407 }
408
409 fn sample_commit() -> KZGCommitment<Bls12_377> {
410 let buf = G1Affine::prime_subgroup_generator().to_bytes_le().unwrap();
411 FromBytes::read_le(buf.as_slice()).unwrap()
412 }
413
414 fn rand_commitments(j: usize, i: usize, test_with_none: bool) -> Commitments<Bls12_377> {
415 assert!(i > 0);
416 assert!(j > 0);
417 let sample_commit = sample_commit();
418 let mask_poly = if test_with_none { None } else { Some(sample_commit) };
419 Commitments {
420 witness_commitments: vec![WitnessCommitments { w: sample_commit }; i * j],
421 mask_poly,
422 h_0: sample_commit,
423 g_1: sample_commit,
424 h_1: sample_commit,
425 g_a_commitments: vec![sample_commit; i],
426 g_b_commitments: vec![sample_commit; i],
427 g_c_commitments: vec![sample_commit; i],
428 h_2: sample_commit,
429 }
430 }
431
432 fn rand_evaluations<F: PrimeField>(rng: &mut TestRng, i: usize) -> Evaluations<F> {
433 Evaluations {
434 g_1_eval: F::rand(rng),
435 g_a_evals: (0..i).map(|_| F::rand(rng)).collect(),
436 g_b_evals: (0..i).map(|_| F::rand(rng)).collect(),
437 g_c_evals: (0..i).map(|_| F::rand(rng)).collect(),
438 }
439 }
440
441 fn rand_sums<F: PrimeField>(rng: &mut TestRng) -> MatrixSums<F> {
442 MatrixSums::<F> { sum_a: F::rand(rng), sum_b: F::rand(rng), sum_c: F::rand(rng) }
443 }
444
445 fn rand_kzg_proof(rng: &mut TestRng, test_with_none: bool) -> KZGProof<Bls12_377> {
446 let random_v = if test_with_none { None } else { Some(Fr::rand(rng)) };
447 KZGProof::<Bls12_377> { w: G1Affine::prime_subgroup_generator(), random_v }
448 }
449
450 #[test]
451 fn test_serializing_commitments() {
452 for i in 1..11 {
453 for j in 1..11 {
454 let test_with_none = i * j % 2 == 0;
455 let commitments = rand_commitments(j, i, test_with_none);
456 let batch_sizes = vec![j; i];
457 let combinations = modes();
458 for (compress, validate) in combinations {
459 let size = Commitments::serialized_size(&commitments, compress);
460 let mut serialized = vec![0; size];
461 Commitments::serialize_with_mode(&commitments, &mut serialized[..], compress).unwrap();
462 let de =
463 Commitments::deserialize_with_mode(&batch_sizes, &serialized[..], compress, validate).unwrap();
464 assert_eq!(commitments, de);
465 }
466 }
467 }
468 }
469
470 #[test]
471 fn test_serializing_evaluations() {
472 let rng = &mut TestRng::default();
473
474 for i in 1..11 {
475 for j in 1..11 {
476 let evaluations: Evaluations<Fr> = rand_evaluations(rng, i);
477 let batch_sizes = vec![j; i];
478 let combinations = modes();
479 for (compress, validate) in combinations {
480 let size = Evaluations::serialized_size(&evaluations, compress);
481 let mut serialized = vec![0; size];
482 Evaluations::serialize_with_mode(&evaluations, &mut serialized[..], compress).unwrap();
483 let de =
484 Evaluations::deserialize_with_mode(&batch_sizes, &serialized[..], compress, validate).unwrap();
485 assert_eq!(evaluations, de);
486 }
487 }
488 }
489 }
490
491 #[test]
492 fn test_serializing_proof() {
493 let rng = &mut snarkvm_utilities::rand::TestRng::default();
494
495 for i in 1..11 {
496 for j in 1..11 {
497 let test_with_none = i * j % 2 == 0;
498 let batch_sizes = vec![j; i];
499 let commitments = rand_commitments(j, i, test_with_none);
500 let evaluations: Evaluations<Fr> = rand_evaluations(rng, i);
501 let third_msg = ThirdMessage::<Fr> { sums: vec![vec![rand_sums(rng); j]; i] };
502 let fourth_msg = FourthMessage::<Fr> { sums: vec![rand_sums(rng); i] };
503 let pc_proof =
504 sonic_pc::BatchLCProof { proof: BatchProof(vec![rand_kzg_proof(rng, test_with_none); j]) };
505 let proof = Proof { batch_sizes, commitments, evaluations, third_msg, fourth_msg, pc_proof };
506 let combinations = modes();
507 for (compress, validate) in combinations {
508 let size = Proof::serialized_size(&proof, compress);
509 let mut serialized = vec![0; size];
510 Proof::serialize_with_mode(&proof, &mut serialized[..], compress).unwrap();
511 let de = Proof::deserialize_with_mode(&serialized[..], compress, validate).unwrap();
512 assert_eq!(proof, de);
513 }
514 }
515 }
516 }
517}