snark_verifier_sdk/
lib.rs1#![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; pub 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 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 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 let mut bufreader = BufReader::with_capacity(capacity, f);
98 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>, 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}