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