snark_verifier_sdk/
lib.rs

1#![feature(associated_type_defaults)]
2#![feature(trait_alias)]
3#[cfg(feature = "display")]
4use ark_std::{end_timer, start_timer};
5use halo2_base::halo2_proofs::{self};
6use halo2_proofs::{
7    halo2curves::{
8        bn256::{Bn256, Fr, G1Affine},
9        group::ff::Field,
10    },
11    plonk::{keygen_pk, keygen_vk, Circuit, ProvingKey, Selector},
12    poly::kzg::commitment::ParamsKZG,
13    SerdeFormat,
14};
15use itertools::Itertools;
16use serde::{Deserialize, Serialize};
17pub use snark_verifier::loader::native::NativeLoader;
18use snark_verifier::{
19    pcs::kzg::{Bdfg21, Gwc19, KzgAs, LimbsEncoding},
20    verifier::{self, plonk::PlonkProtocol},
21};
22use std::{
23    fs::{self, File},
24    io::{self, BufReader, BufWriter},
25    path::Path,
26};
27
28pub use snark_verifier;
29
30#[cfg(feature = "loader_evm")]
31pub mod evm;
32#[cfg(feature = "loader_halo2")]
33pub mod halo2;
34
35pub const LIMBS: usize = 3;
36pub const BITS: usize = 88;
37
38const BUFFER_SIZE: usize = 1024 * 1024; // 1MB
39
40/// AS stands for accumulation scheme.
41/// AS can be either `Kzg<Bn256, Gwc19>` (the original PLONK KZG multi-open) or `Kzg<Bn256, Bdfg21>` (SHPLONK)
42pub type PlonkVerifier<AS> = verifier::plonk::PlonkVerifier<AS, LimbsEncoding<LIMBS, BITS>>;
43pub type PlonkSuccinctVerifier<AS> =
44    verifier::plonk::PlonkSuccinctVerifier<AS, LimbsEncoding<LIMBS, BITS>>;
45pub type SHPLONK = KzgAs<Bn256, Bdfg21>;
46pub type GWC = KzgAs<Bn256, Gwc19>;
47
48#[derive(Clone, Debug)]
49#[cfg_attr(feature = "halo2-axiom", derive(Serialize, Deserialize))]
50pub struct Snark {
51    pub protocol: PlonkProtocol<G1Affine>,
52    pub instances: Vec<Vec<Fr>>,
53    pub proof: Vec<u8>,
54}
55
56impl Snark {
57    pub fn new(protocol: PlonkProtocol<G1Affine>, instances: Vec<Vec<Fr>>, proof: Vec<u8>) -> Self {
58        Self { protocol, instances, proof }
59    }
60
61    pub fn proof(&self) -> &[u8] {
62        &self.proof[..]
63    }
64}
65
66pub trait CircuitExt<F: Field>: Circuit<F> {
67    /// Return the number of instances of the circuit.
68    /// This may depend on extra circuit parameters but NOT on private witnesses.
69    fn num_instance(&self) -> Vec<usize>;
70
71    fn instances(&self) -> Vec<Vec<F>>;
72
73    fn accumulator_indices() -> Option<Vec<(usize, usize)>> {
74        None
75    }
76
77    /// Output the simple selector columns (before selector compression) of the circuit
78    fn selectors(_: &Self::Config) -> Vec<Selector> {
79        vec![]
80    }
81}
82
83pub fn read_pk<C: Circuit<Fr>>(path: &Path, params: C::Params) -> io::Result<ProvingKey<G1Affine>> {
84    read_pk_with_capacity::<C>(BUFFER_SIZE, path, params)
85}
86
87pub fn read_pk_with_capacity<C: Circuit<Fr>>(
88    capacity: usize,
89    path: impl AsRef<Path>,
90    params: C::Params,
91) -> io::Result<ProvingKey<G1Affine>> {
92    let f = File::open(path.as_ref())?;
93    #[cfg(feature = "display")]
94    let read_time = start_timer!(|| format!("Reading pkey from {:?}", path.as_ref()));
95
96    // BufReader is indeed MUCH faster than Read
97    let mut bufreader = BufReader::with_capacity(capacity, f);
98    // But it's even faster to load the whole file into memory first and then process,
99    // HOWEVER this requires twice as much memory to initialize
100    // let initial_buffer_size = f.metadata().map(|m| m.len() as usize + 1).unwrap_or(0);
101    // let mut bufreader = Vec::with_capacity(initial_buffer_size);
102    // f.read_to_end(&mut bufreader)?;
103    let pk =
104        ProvingKey::read::<_, C>(&mut bufreader, SerdeFormat::RawBytesUnchecked, params).unwrap();
105
106    #[cfg(feature = "display")]
107    end_timer!(read_time);
108
109    Ok(pk)
110}
111
112#[allow(clippy::let_and_return)]
113pub fn gen_pk<C: Circuit<Fr>>(
114    params: &ParamsKZG<Bn256>, // TODO: read pk without params
115    circuit: &C,
116    path: Option<&Path>,
117) -> ProvingKey<G1Affine> {
118    if let Some(path) = path {
119        if let Ok(pk) = read_pk::<C>(path, circuit.params()) {
120            return pk;
121        }
122    }
123    #[cfg(feature = "display")]
124    let pk_time = start_timer!(|| "Generating vkey & pkey");
125
126    let vk = keygen_vk(params, circuit).unwrap();
127    let pk = keygen_pk(params, vk, circuit).unwrap();
128
129    #[cfg(feature = "display")]
130    end_timer!(pk_time);
131
132    if let Some(path) = path {
133        #[cfg(feature = "display")]
134        let write_time = start_timer!(|| format!("Writing pkey to {path:?}"));
135
136        path.parent().and_then(|dir| fs::create_dir_all(dir).ok()).unwrap();
137        let mut f = BufWriter::with_capacity(BUFFER_SIZE, File::create(path).unwrap());
138        pk.write(&mut f, SerdeFormat::RawBytesUnchecked).unwrap();
139
140        #[cfg(feature = "display")]
141        end_timer!(write_time);
142    }
143    pk
144}
145
146pub fn read_instances(path: impl AsRef<Path>) -> Result<Vec<Vec<Fr>>, bincode::Error> {
147    let f = File::open(path)?;
148    let reader = BufReader::new(f);
149    let instances: Vec<Vec<[u8; 32]>> = bincode::deserialize_from(reader)?;
150    instances
151        .into_iter()
152        .map(|instance_column| {
153            instance_column
154                .iter()
155                .map(|bytes| {
156                    Option::from(Fr::from_bytes(bytes)).ok_or(Box::new(bincode::ErrorKind::Custom(
157                        "Invalid finite field point".to_owned(),
158                    )))
159                })
160                .collect::<Result<Vec<_>, _>>()
161        })
162        .collect()
163}
164
165pub fn write_instances(instances: &[&[Fr]], path: impl AsRef<Path>) {
166    let instances: Vec<Vec<[u8; 32]>> = instances
167        .iter()
168        .map(|instance_column| instance_column.iter().map(|x| x.to_bytes()).collect_vec())
169        .collect_vec();
170    let f = BufWriter::new(File::create(path).unwrap());
171    bincode::serialize_into(f, &instances).unwrap();
172}
173
174#[cfg(feature = "zkevm")]
175mod zkevm {
176    use super::CircuitExt;
177    use eth_types::Field;
178    use zkevm_circuits::{evm_circuit::EvmCircuit, state_circuit::StateCircuit};
179
180    impl<F: Field> CircuitExt<F> for EvmCircuit<F> {
181        fn instances(&self) -> Vec<Vec<F>> {
182            vec![]
183        }
184        fn num_instance(&self) -> Vec<usize> {
185            vec![]
186        }
187    }
188
189    impl<F: Field> CircuitExt<F> for StateCircuit<F> {
190        fn instances(&self) -> Vec<Vec<F>> {
191            vec![]
192        }
193        fn num_instance(&self) -> Vec<usize> {
194            vec![]
195        }
196    }
197}