Skip to main content

snarkvm_algorithms/snark/varuna/data_structures/
circuit_verifying_key.rs

1// Copyright (c) 2019-2026 Provable Inc.
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::{polycommit::sonic_pc, snark::varuna::ahp::indexer::*};
17use snarkvm_curves::PairingEngine;
18use snarkvm_utilities::{FromBytes, FromBytesDeserializer, ToBytes, ToBytesSerializer, into_io_error, serialize::*};
19
20use anyhow::Result;
21use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
22use std::{
23    cmp::Ordering,
24    fmt,
25    io::{self, Read, Write},
26    str::FromStr,
27    string::String,
28};
29
30/// Verification key for a specific index (i.e., R1CS matrices).
31#[derive(Debug, Clone, PartialEq, Eq, CanonicalSerialize)]
32pub struct CircuitVerifyingKey<E: PairingEngine> {
33    /// Stores information about the size of the circuit, as well as its defined
34    /// field.
35    pub circuit_info: CircuitInfo,
36    /// Commitments to the indexed polynomials.
37    pub circuit_commitments: Vec<sonic_pc::Commitment<E>>,
38    pub id: CircuitId,
39}
40
41impl<E: PairingEngine> Valid for CircuitVerifyingKey<E> {
42    fn check(&self) -> Result<(), SerializationError> {
43        self.circuit_info.check()?;
44        sonic_pc::Commitment::<E>::batch_check(self.circuit_commitments.iter())?;
45        self.id.check()
46    }
47
48    fn batch_check<'a>(batch: impl Iterator<Item = &'a Self> + Send) -> Result<(), SerializationError>
49    where
50        Self: 'a,
51    {
52        #[cfg(not(feature = "serial"))]
53        {
54            use rayon::{iter::ParallelBridge, prelude::ParallelIterator};
55            batch.par_bridge().try_for_each(|e| e.check())?;
56        }
57        #[cfg(feature = "serial")]
58        {
59            for item in batch {
60                item.check()?;
61            }
62        }
63        Ok(())
64    }
65}
66
67impl<E: PairingEngine> CanonicalDeserialize for CircuitVerifyingKey<E> {
68    fn deserialize_with_mode<R: Read>(
69        mut reader: R,
70        compress: Compress,
71        validate: Validate,
72    ) -> Result<Self, SerializationError> {
73        // Deserialize circuit_info
74        let circuit_info = CircuitInfo::deserialize_with_mode(&mut reader, compress, validate)?;
75
76        // Deserialize the length of circuit_commitments
77        let len = u64::deserialize_with_mode(&mut reader, compress, validate)?;
78
79        // Bound check: Maximum of 12 commitments (3 matrices × 4 polynomials each)
80        const MAX_CIRCUIT_COMMITMENTS: u64 = 12;
81        if len > MAX_CIRCUIT_COMMITMENTS {
82            return Err(SerializationError::InvalidData);
83        }
84
85        // Deserialize circuit_commitments
86        let mut circuit_commitments = Vec::with_capacity(len as usize);
87        for _ in 0..len {
88            circuit_commitments.push(sonic_pc::Commitment::deserialize_with_mode(&mut reader, compress, Validate::No)?);
89        }
90
91        if let Validate::Yes = validate {
92            sonic_pc::Commitment::<E>::batch_check(circuit_commitments.iter())?;
93        }
94
95        // Deserialize id
96        let id = CircuitId::deserialize_with_mode(&mut reader, compress, validate)?;
97
98        Ok(CircuitVerifyingKey { circuit_info, circuit_commitments, id })
99    }
100}
101
102impl<E: PairingEngine> FromBytes for CircuitVerifyingKey<E> {
103    fn read_le<R: Read>(r: R) -> io::Result<Self> {
104        Self::deserialize_compressed(r)
105            .map_err(|err| into_io_error(anyhow::Error::from(err).context("could not deserialize CircuitVerifyingKey")))
106    }
107
108    fn read_le_unchecked<R: Read>(r: R) -> io::Result<Self> {
109        Self::deserialize_compressed_unchecked(r)
110            .map_err(|err| into_io_error(anyhow::Error::from(err).context("could not deserialize CircuitVerifyingKey")))
111    }
112}
113
114impl<E: PairingEngine> ToBytes for CircuitVerifyingKey<E> {
115    fn write_le<W: Write>(&self, w: W) -> io::Result<()> {
116        self.serialize_compressed(w)
117            .map_err(|err| into_io_error(anyhow::Error::from(err).context("could not serialize CircuitVerifyingKey")))
118    }
119}
120
121impl<E: PairingEngine> CircuitVerifyingKey<E> {
122    /// Iterate over the commitments to indexed polynomials in `self`.
123    pub fn iter(&self) -> impl Iterator<Item = &sonic_pc::Commitment<E>> {
124        self.circuit_commitments.iter()
125    }
126}
127
128impl<E: PairingEngine> FromStr for CircuitVerifyingKey<E> {
129    type Err = anyhow::Error;
130
131    #[inline]
132    fn from_str(vk_hex: &str) -> Result<Self, Self::Err> {
133        Self::from_bytes_le(&hex::decode(vk_hex)?)
134    }
135}
136
137impl<E: PairingEngine> fmt::Display for CircuitVerifyingKey<E> {
138    #[inline]
139    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
140        let vk_hex = hex::encode(self.to_bytes_le().expect("Failed to convert verifying key to bytes"));
141        write!(f, "{vk_hex}")
142    }
143}
144
145impl<E: PairingEngine> Serialize for CircuitVerifyingKey<E> {
146    #[inline]
147    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
148        match serializer.is_human_readable() {
149            true => serializer.collect_str(self),
150            false => ToBytesSerializer::serialize_with_size_encoding(self, serializer),
151        }
152    }
153}
154
155impl<'de, E: PairingEngine> Deserialize<'de> for CircuitVerifyingKey<E> {
156    #[inline]
157    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
158        match deserializer.is_human_readable() {
159            true => {
160                let s: String = Deserialize::deserialize(deserializer)?;
161                FromStr::from_str(&s).map_err(de::Error::custom)
162            }
163            false => FromBytesDeserializer::<Self>::deserialize_with_size_encoding(deserializer, "verifying key"),
164        }
165    }
166}
167
168impl<E: PairingEngine> Ord for CircuitVerifyingKey<E> {
169    fn cmp(&self, other: &Self) -> Ordering {
170        self.id.cmp(&other.id)
171    }
172}
173
174impl<E: PairingEngine> PartialOrd for CircuitVerifyingKey<E> {
175    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
176        Some(self.cmp(other))
177    }
178}