openvm_native_recursion/halo2/
utils.rs

1use std::{
2    collections::HashMap,
3    io::BufReader,
4    path::{Path, PathBuf},
5    sync::{Arc, Mutex},
6};
7
8use lazy_static::lazy_static;
9use once_cell::sync::Lazy;
10use rand::{prelude::StdRng, SeedableRng};
11use snark_verifier_sdk::{
12    halo2::{PoseidonTranscript, POSEIDON_SPEC},
13    snark_verifier::{
14        halo2_base::{
15            halo2_proofs::{
16                halo2curves::bn256::{Bn256, G1Affine},
17                poly::{
18                    commitment::{CommitmentScheme, Params},
19                    kzg::commitment::{KZGCommitmentScheme, ParamsKZG},
20                },
21            },
22            utils::fs::read_params as read_params_impl,
23        },
24        pcs::kzg::KzgDecidingKey,
25        verifier::{plonk::PlonkProof, SnarkVerifier},
26    },
27    NativeLoader, PlonkVerifier, Snark, SHPLONK,
28};
29
30use crate::halo2::Halo2Params;
31pub const DEFAULT_PARAMS_DIR: &str = "./params";
32static TESTING_KZG_PARAMS_23: Lazy<Halo2Params> = Lazy::new(|| gen_kzg_params(23));
33
34pub(crate) fn gen_kzg_params(k: u32) -> Halo2Params {
35    let mut rng = StdRng::seed_from_u64(42);
36    ParamsKZG::setup(k, &mut rng)
37}
38
39lazy_static! {
40    static ref SVK: G1Affine =
41        serde_json::from_str("\"0100000000000000000000000000000000000000000000000000000000000000\"")
42            .unwrap();
43
44    /// This is also stored in the pinning jsons. We should read it from the pinning if possible.
45    /// This commits to the trusted setup used to generate all proving keys.
46    /// This MUST be updated whenever the trusted setup is changed.
47    pub static ref DK: KzgDecidingKey<Bn256> = serde_json::from_str(r#"
48          {
49            "_marker": null,
50            "g2": "edf692d95cbdde46ddda5ef7d422436779445c5e66006a42761e1f12efde0018c212f3aeb785e49712e7a9353349aaf1255dfb31b7bf60723a480d9293938e19",
51            "s_g2": "0016e2a0605f771222637bae45148c8faebb4598ee98f30f20f790a0c3c8e02a7bf78bf67c4aac19dcc690b9ca0abef445d9a576c92ad6041e6ef1413ca92a17",
52            "svk": {
53              "g": "0100000000000000000000000000000000000000000000000000000000000000"
54            }
55          }
56       "#).unwrap();
57    /// Hacking because of bad interface. This is to construct a fake KZG params to pass Svk(which only requires ParamsKZG.g[0]) to AggregationCircuit.
58    static ref FAKE_KZG_PARAMS: Halo2Params = KZGCommitmentScheme::new_params(1);
59}
60
61pub static KZG_PARAMS_FOR_SVK: Lazy<Halo2Params> = Lazy::new(|| {
62    if std::env::var("RANDOM_SRS").is_ok() {
63        read_params(1).as_ref().clone()
64    } else {
65        build_kzg_params_for_svk(*SVK)
66    }
67});
68
69fn build_kzg_params_for_svk(g: G1Affine) -> Halo2Params {
70    FAKE_KZG_PARAMS.from_parts(
71        1,
72        vec![g],
73        Some(vec![g]),
74        Default::default(),
75        Default::default(),
76    )
77}
78
79#[allow(dead_code)]
80pub(crate) fn verify_snark(dk: &KzgDecidingKey<Bn256>, snark: &Snark) {
81    let mut transcript =
82        PoseidonTranscript::<NativeLoader, &[u8]>::from_spec(snark.proof(), POSEIDON_SPEC.clone());
83    let proof: PlonkProof<_, _, SHPLONK> =
84        PlonkVerifier::read_proof(dk, &snark.protocol, &snark.instances, &mut transcript)
85            .expect("Failed to read PlonkProof");
86    PlonkVerifier::verify(dk, &snark.protocol, &snark.instances, &proof)
87        .expect("PlonkVerifier failed");
88}
89
90pub trait Halo2ParamsReader {
91    fn read_params(&self, k: usize) -> Arc<Halo2Params>;
92}
93
94pub struct CacheHalo2ParamsReader {
95    params_dir: PathBuf,
96    cached_params: Arc<Mutex<HashMap<usize, Arc<Halo2Params>>>>,
97}
98
99impl Halo2ParamsReader for CacheHalo2ParamsReader {
100    fn read_params(&self, k: usize) -> Arc<Halo2Params> {
101        self.cached_params
102            .lock()
103            .unwrap()
104            .entry(k)
105            .or_insert_with(|| Arc::new(self.read_params_from_folder(k)))
106            .clone()
107    }
108}
109impl CacheHalo2ParamsReader {
110    pub fn new(params_dir: impl AsRef<Path>) -> Self {
111        Self {
112            params_dir: params_dir.as_ref().to_path_buf(),
113            cached_params: Default::default(),
114        }
115    }
116    pub fn new_with_default_params_dir() -> Self {
117        Self {
118            params_dir: PathBuf::from(DEFAULT_PARAMS_DIR),
119            cached_params: Default::default(),
120        }
121    }
122    fn read_params_from_folder(&self, k: usize) -> Halo2Params {
123        let file_path = self.params_dir.as_path().join(format!("kzg_bn254_{k}.srs"));
124        ParamsKZG::<Bn256>::read(&mut BufReader::new(
125            std::fs::File::open(&file_path)
126                .unwrap_or_else(|e| panic!("Params file {:?} does not exist: {e:?}", file_path)),
127        ))
128        .unwrap()
129    }
130}
131
132/// When `RANDOM_SRS` is set, this function will return a random params which should only be used
133/// for testing purpose.
134fn read_params(k: u32) -> Arc<Halo2Params> {
135    if std::env::var("RANDOM_SRS").is_ok() {
136        let mut ret = TESTING_KZG_PARAMS_23.clone();
137        ret.downsize(k);
138        Arc::new(ret)
139    } else {
140        Arc::new(read_params_impl(k))
141    }
142}