snarkvm_algorithms/snark/varuna/data_structures/
proof.rs

1// Copyright 2024 Aleo Network Foundation
2// This file is part of the snarkVM library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7
8// http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use 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::{
26    FromBytes,
27    ToBytes,
28    error,
29    io::{self, Read, Write},
30    serialize::*,
31};
32
33use std::collections::BTreeMap;
34
35#[derive(Clone, Debug, PartialEq, Eq, CanonicalSerialize, CanonicalDeserialize)]
36pub struct Commitments<E: PairingEngine> {
37    pub witness_commitments: Vec<WitnessCommitments<E>>,
38    /// Commitment to the masking polynomial.
39    pub mask_poly: Option<sonic_pc::Commitment<E>>,
40    /// Commitment to the `h_0` polynomial.
41    pub h_0: sonic_pc::Commitment<E>,
42    /// Commitment to the `g_1` polynomial.
43    pub g_1: sonic_pc::Commitment<E>,
44    /// Commitment to the `h_1` polynomial.
45    pub h_1: sonic_pc::Commitment<E>,
46    /// Commitment to the `g_a` polynomials.
47    pub g_a_commitments: Vec<sonic_pc::Commitment<E>>,
48    /// Commitment to the `g_b` polynomials.
49    pub g_b_commitments: Vec<sonic_pc::Commitment<E>>,
50    /// Commitment to the `g_c` polynomials.
51    pub g_c_commitments: Vec<sonic_pc::Commitment<E>>,
52    /// Commitment to the `h_2` polynomial.
53    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/// Commitments to the `w` polynomials.
110#[derive(Clone, Debug, PartialEq, Eq, CanonicalSerialize, CanonicalDeserialize)]
111pub struct WitnessCommitments<E: PairingEngine> {
112    /// Commitment to the `w` polynomial.
113    pub w: sonic_pc::Commitment<E>,
114}
115
116#[derive(Clone, Debug, PartialEq, Eq)]
117pub struct Evaluations<F: PrimeField> {
118    /// Evaluation of `g_1` at `beta`.
119    pub g_1_eval: F,
120    /// Evaluation of `g_a_i`'s at `beta`.
121    pub g_a_evals: Vec<F>,
122    /// Evaluation of `g_b_i`'s at `gamma`.
123    pub g_b_evals: Vec<F>,
124    /// Evaluation of `g_c_i`'s at `gamma`.
125    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/// A zkSNARK proof.
224#[derive(Clone, Debug, PartialEq, Eq)]
225pub struct Proof<E: PairingEngine> {
226    /// The number of instances being proven in this proof.
227    batch_sizes: Vec<usize>,
228
229    /// Commitments to prover polynomials.
230    pub commitments: Commitments<E>,
231
232    /// Evaluations of some of the committed polynomials.
233    pub evaluations: Evaluations<E::Fr>,
234
235    /// Prover message: sum_a, sum_b, sum_c for each instance
236    pub third_msg: ThirdMessage<E::Fr>,
237
238    /// Prover message: sum_a, sum_b, sum_c for each circuit
239    pub fourth_msg: FourthMessage<E::Fr>,
240
241    /// An evaluation proof from the polynomial commitment.
242    pub pc_proof: sonic_pc::BatchLCProof<E>,
243}
244
245impl<E: PairingEngine> Proof<E> {
246    /// Construct a new proof.
247    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    /// Check that the number of messages is consistent with our batch size
268    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).map_err(|_| error("could not serialize Proof"))
373    }
374}
375
376impl<E: PairingEngine> FromBytes for Proof<E> {
377    fn read_le<R: Read>(mut r: R) -> io::Result<Self> {
378        Self::deserialize_compressed(&mut r).map_err(|_| error("could not deserialize Proof"))
379    }
380}
381
382#[cfg(test)]
383mod test {
384    #![allow(non_camel_case_types)]
385
386    use super::*;
387
388    use crate::{
389        polycommit::{
390            kzg10::{KZGCommitment, KZGProof},
391            sonic_pc::BatchProof,
392        },
393        snark::varuna::prover::MatrixSums,
394    };
395    use snarkvm_curves::{
396        AffineCurve,
397        bls12_377::{Bls12_377, Fr, G1Affine},
398    };
399    use snarkvm_utilities::{TestRng, Uniform};
400
401    const fn modes() -> [(Compress, Validate); 4] {
402        [
403            (Compress::No, Validate::No),
404            (Compress::Yes, Validate::No),
405            (Compress::No, Validate::Yes),
406            (Compress::Yes, Validate::Yes),
407        ]
408    }
409
410    fn sample_commit() -> KZGCommitment<Bls12_377> {
411        let buf = G1Affine::prime_subgroup_generator().to_bytes_le().unwrap();
412        FromBytes::read_le(buf.as_slice()).unwrap()
413    }
414
415    fn rand_commitments(j: usize, i: usize, test_with_none: bool) -> Commitments<Bls12_377> {
416        assert!(i > 0);
417        assert!(j > 0);
418        let sample_commit = sample_commit();
419        let mask_poly = if test_with_none { None } else { Some(sample_commit) };
420        Commitments {
421            witness_commitments: vec![WitnessCommitments { w: sample_commit }; i * j],
422            mask_poly,
423            h_0: sample_commit,
424            g_1: sample_commit,
425            h_1: sample_commit,
426            g_a_commitments: vec![sample_commit; i],
427            g_b_commitments: vec![sample_commit; i],
428            g_c_commitments: vec![sample_commit; i],
429            h_2: sample_commit,
430        }
431    }
432
433    fn rand_evaluations<F: PrimeField>(rng: &mut TestRng, i: usize) -> Evaluations<F> {
434        Evaluations {
435            g_1_eval: F::rand(rng),
436            g_a_evals: (0..i).map(|_| F::rand(rng)).collect(),
437            g_b_evals: (0..i).map(|_| F::rand(rng)).collect(),
438            g_c_evals: (0..i).map(|_| F::rand(rng)).collect(),
439        }
440    }
441
442    fn rand_sums<F: PrimeField>(rng: &mut TestRng) -> MatrixSums<F> {
443        MatrixSums::<F> { sum_a: F::rand(rng), sum_b: F::rand(rng), sum_c: F::rand(rng) }
444    }
445
446    fn rand_kzg_proof(rng: &mut TestRng, test_with_none: bool) -> KZGProof<Bls12_377> {
447        let random_v = if test_with_none { None } else { Some(Fr::rand(rng)) };
448        KZGProof::<Bls12_377> { w: G1Affine::prime_subgroup_generator(), random_v }
449    }
450
451    #[test]
452    fn test_serializing_commitments() {
453        for i in 1..11 {
454            for j in 1..11 {
455                let test_with_none = i * j % 2 == 0;
456                let commitments = rand_commitments(j, i, test_with_none);
457                let batch_sizes = vec![j; i];
458                let combinations = modes();
459                for (compress, validate) in combinations {
460                    let size = Commitments::serialized_size(&commitments, compress);
461                    let mut serialized = vec![0; size];
462                    Commitments::serialize_with_mode(&commitments, &mut serialized[..], compress).unwrap();
463                    let de =
464                        Commitments::deserialize_with_mode(&batch_sizes, &serialized[..], compress, validate).unwrap();
465                    assert_eq!(commitments, de);
466                }
467            }
468        }
469    }
470
471    #[test]
472    fn test_serializing_evaluations() {
473        let rng = &mut TestRng::default();
474
475        for i in 1..11 {
476            for j in 1..11 {
477                let evaluations: Evaluations<Fr> = rand_evaluations(rng, i);
478                let batch_sizes = vec![j; i];
479                let combinations = modes();
480                for (compress, validate) in combinations {
481                    let size = Evaluations::serialized_size(&evaluations, compress);
482                    let mut serialized = vec![0; size];
483                    Evaluations::serialize_with_mode(&evaluations, &mut serialized[..], compress).unwrap();
484                    let de =
485                        Evaluations::deserialize_with_mode(&batch_sizes, &serialized[..], compress, validate).unwrap();
486                    assert_eq!(evaluations, de);
487                }
488            }
489        }
490    }
491
492    #[test]
493    fn test_serializing_proof() {
494        let rng = &mut snarkvm_utilities::rand::TestRng::default();
495
496        for i in 1..11 {
497            for j in 1..11 {
498                let test_with_none = i * j % 2 == 0;
499                let batch_sizes = vec![j; i];
500                let commitments = rand_commitments(j, i, test_with_none);
501                let evaluations: Evaluations<Fr> = rand_evaluations(rng, i);
502                let third_msg = ThirdMessage::<Fr> { sums: vec![vec![rand_sums(rng); j]; i] };
503                let fourth_msg = FourthMessage::<Fr> { sums: vec![rand_sums(rng); i] };
504                let pc_proof =
505                    sonic_pc::BatchLCProof { proof: BatchProof(vec![rand_kzg_proof(rng, test_with_none); j]) };
506                let proof = Proof { batch_sizes, commitments, evaluations, third_msg, fourth_msg, pc_proof };
507                let combinations = modes();
508                for (compress, validate) in combinations {
509                    let size = Proof::serialized_size(&proof, compress);
510                    let mut serialized = vec![0; size];
511                    Proof::serialize_with_mode(&proof, &mut serialized[..], compress).unwrap();
512                    let de = Proof::deserialize_with_mode(&serialized[..], compress, validate).unwrap();
513                    assert_eq!(proof, de);
514                }
515            }
516        }
517    }
518}