spawn_zk_snarks/
groth16.rs

1// Copyright (c) 2023 spawn-zk-snarks developers
2//
3// Licensed under the MIT License
4// <LICENSE-MIT or http://opensource.org/licenses/MIT>
5
6use ark_bn254::{Bn254, Fr};
7use ark_groth16::{
8    PreparedVerifyingKey, Proof as ArkProof, ProvingKey, VerifyingKey,
9};
10use ark_snark::SNARK;
11use ark_groth16::Groth16;
12use ark_ec::pairing::Pairing;
13use ark_serialize::CanonicalSerialize;
14use ark_std::rand::thread_rng;
15use thiserror::Error;
16use crate::circuits::{CircuitError, ArithmeticCircuit};
17
18/// Represents all possible errors that can occur during Groth16 operations.
19/// 
20/// This enum provides a comprehensive set of errors that might occur during
21/// setup, proving, verification, and other related operations.
22#[derive(Error, Debug)]
23pub enum Groth16Error {
24    /// Occurs when the setup phase fails, typically due to invalid parameters
25    /// or insufficient randomness.
26    #[error("Setup failed")]
27    SetupError,
28
29    /// Occurs when proof generation fails, usually due to invalid witness
30    /// or constraint system issues.
31    #[error("Proving failed")]
32    ProvingError,
33
34    /// Occurs when proof verification fails, indicating either an invalid proof
35    /// or mismatched public inputs.
36    #[error("Verification failed")]
37    VerificationError,
38
39    /// Wraps an error from the underlying circuit implementation.
40    /// This can occur during constraint generation or witness computation.
41    #[error("Circuit error: {0}")]
42    CircuitError(#[from] CircuitError),
43
44    /// Occurs when serialization or deserialization of proofs, keys,
45    /// or other data structures fails.
46    #[error("Serialization error")]
47    SerializationError,
48}
49
50/// Contains all necessary parameters for the Groth16 proving system.
51/// 
52/// This structure holds the proving key, verifying key, and prepared verifying key
53/// needed for generating and verifying zero-knowledge proofs.
54#[derive(Debug)]
55pub struct Groth16Setup<E: Pairing> {
56    /// The proving key used to generate proofs. This contains the secret parameters
57    /// and should be kept private in some applications.
58    pub proving_key: ProvingKey<E>,
59
60    /// The verification key used to verify proofs. This can be made public
61    /// and distributed to verifiers.
62    pub verifying_key: VerifyingKey<E>,
63
64    /// A preprocessed version of the verification key that allows for
65    /// more efficient proof verification.
66    pub prepared_verifying_key: PreparedVerifyingKey<E>,
67}
68
69impl Groth16Setup<Bn254> {
70    /// Creates a new Groth16 setup for a circuit with the specified parameters.
71    /// 
72    /// This function generates the proving and verification keys necessary for
73    /// creating and verifying zero-knowledge proofs.
74    /// 
75    /// # Arguments
76    /// * `num_constraints` - Number of constraints in the arithmetic circuit
77    /// * `num_variables` - Number of variables used in the circuit
78    /// 
79    /// # Returns
80    /// * `Result<Self, Groth16Error>` - The setup parameters or an error
81    /// 
82    /// # Example
83    /// ```
84    /// # use spawn_zk_snarks::Groth16Setup;
85    /// let setup = Groth16Setup::new(3, 2)?;
86    /// ```
87    pub fn new(num_constraints: usize, num_variables: usize) -> Result<Self, Groth16Error> {
88        let circuit: ArithmeticCircuit<Fr> = ArithmeticCircuit::new(num_constraints, num_variables, 1);
89        let rng = &mut thread_rng();
90        
91        let (pk, vk) = Groth16::<Bn254>::circuit_specific_setup(
92            circuit,
93            rng,
94        ).map_err(|_| Groth16Error::SetupError)?;
95
96        let pvk = match Groth16::<Bn254>::process_vk(&vk) {
97            Ok(pvk) => pvk,
98            Err(_) => return Err(Groth16Error::SetupError),
99        };
100
101        Ok(Self {
102            proving_key: pk,
103            verifying_key: vk,
104            prepared_verifying_key: pvk,
105        })
106    }
107
108    /// Generates a zero-knowledge proof using the provided inputs and witness.
109    /// 
110    /// # Arguments
111    /// * `inputs` - Public inputs to the circuit
112    /// * `witness` - Private witness values
113    /// 
114    /// # Returns
115    /// * `Result<ArkProof<Bn254>, Groth16Error>` - The generated proof or an error
116    /// 
117    /// # Example
118    /// ```
119    /// # use spawn_zk_snarks::{Groth16Setup, Fr};
120    /// # let setup = Groth16Setup::new(3, 2)?;
121    /// let proof = setup.prove(&inputs, &witness)?;
122    /// ```
123    pub fn prove(&self, inputs: &[Fr], witness: &[Fr]) -> Result<ArkProof<Bn254>, Groth16Error> {
124        let rng = &mut thread_rng();
125        
126        let circuit = ArithmeticCircuit {
127            num_constraints: inputs.len(),
128            num_variables: witness.len(),
129            num_inputs: 1,
130            witness: witness.to_vec(),
131        };
132
133        Groth16::<Bn254>::create_random_proof_with_reduction(
134            circuit,
135            &self.proving_key,
136            rng,
137        ).map_err(|_| Groth16Error::ProvingError)
138    }
139
140    /// Verifies a zero-knowledge proof against the provided public inputs.
141    /// 
142    /// # Arguments
143    /// * `proof` - The proof to verify
144    /// * `public_inputs` - Public inputs used in the proof
145    /// 
146    /// # Returns
147    /// * `Result<bool, Groth16Error>` - Whether the proof is valid
148    /// 
149    /// # Example
150    /// ```
151    /// # use spawn_zk_snarks::Groth16Setup;
152    /// # let setup = Groth16Setup::new(3, 2)?;
153    /// let is_valid = setup.verify(&proof, &public_inputs)?;
154    /// assert!(is_valid);
155    /// ```
156    pub fn verify(
157        &self,
158        proof: &ArkProof<Bn254>,
159        public_inputs: &[Fr],
160    ) -> Result<bool, Groth16Error> {
161        <Groth16<Bn254> as SNARK<Fr>>::verify_with_processed_vk(
162            &self.prepared_verifying_key,
163            public_inputs,
164            proof,
165        ).map_err(|_| Groth16Error::VerificationError)
166    }
167
168    /// Converts a proof to EVM-compatible format for on-chain verification.
169    /// 
170    /// # Arguments
171    /// * `proof` - The proof to convert
172    /// 
173    /// # Returns
174    /// * `Result<Vec<u8>, Groth16Error>` - The serialized proof bytes
175    pub fn proof_to_evm_format(proof: &ArkProof<Bn254>) -> Result<Vec<u8>, Groth16Error> {
176        let mut bytes = Vec::new();
177        proof.serialize_compressed(&mut bytes)
178            .map_err(|_| Groth16Error::SerializationError)?;
179        Ok(bytes)
180    }
181
182    /// Estimates the gas cost for verifying a proof on Ethereum.
183    /// 
184    /// # Arguments
185    /// * `proof_size` - Size of the proof in bytes
186    /// * `num_inputs` - Number of public inputs
187    /// 
188    /// # Returns
189    /// * `u64` - Estimated gas cost in units
190    pub fn estimate_verification_gas(proof_size: usize, num_inputs: usize) -> u64 {
191        let base_cost = 150_000;
192        let input_cost = num_inputs as u64 * 1_000;
193        let data_cost = proof_size as u64 * 16;
194        base_cost + input_cost + data_cost
195    }
196}