openvm_native_recursion/halo2/
utils.rs

1use std::{
2    collections::HashMap,
3    env::var,
4    io::BufReader,
5    path::{Path, PathBuf},
6    sync::{Arc, Mutex},
7};
8
9use lazy_static::lazy_static;
10use once_cell::sync::Lazy;
11use rand::{prelude::StdRng, SeedableRng};
12use snark_verifier_sdk::{
13    halo2::{PoseidonTranscript, POSEIDON_SPEC},
14    snark_verifier::{
15        halo2_base::{
16            halo2_proofs::{
17                halo2curves::bn256::{Bn256, G1Affine},
18                poly::{
19                    commitment::{CommitmentScheme, Params},
20                    kzg::commitment::{KZGCommitmentScheme, ParamsKZG},
21                },
22            },
23            utils::fs::read_params as read_params_impl,
24        },
25        pcs::kzg::KzgDecidingKey,
26        verifier::{plonk::PlonkProof, SnarkVerifier},
27    },
28    NativeLoader, PlonkVerifier, Snark, SHPLONK,
29};
30
31use crate::halo2::Halo2Params;
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
94#[derive(Clone)]
95pub struct CacheHalo2ParamsReader {
96    params_dir: PathBuf,
97    cached_params: Arc<Mutex<HashMap<usize, Arc<Halo2Params>>>>,
98}
99
100impl Halo2ParamsReader for CacheHalo2ParamsReader {
101    fn read_params(&self, k: usize) -> Arc<Halo2Params> {
102        self.cached_params
103            .lock()
104            .unwrap()
105            .entry(k)
106            .or_insert_with(|| Arc::new(self.read_params_from_folder(k)))
107            .clone()
108    }
109}
110impl CacheHalo2ParamsReader {
111    pub fn new(params_dir: impl AsRef<Path>) -> Self {
112        Self {
113            params_dir: params_dir.as_ref().to_path_buf(),
114            cached_params: Default::default(),
115        }
116    }
117    pub fn new_with_default_params_dir() -> Self {
118        let default_params_dir = PathBuf::from(var("HOME").unwrap())
119            .join(".openvm")
120            .join("params");
121        CacheHalo2ParamsReader::new(default_params_dir)
122    }
123    fn read_params_from_folder(&self, k: usize) -> Halo2Params {
124        let file_path = self.params_dir.as_path().join(format!("kzg_bn254_{k}.srs"));
125        ParamsKZG::<Bn256>::read(&mut BufReader::new(
126            std::fs::File::open(&file_path)
127                .unwrap_or_else(|e| panic!("Params file {:?} does not exist: {e:?}", file_path)),
128        ))
129        .unwrap()
130    }
131}
132
133/// When `RANDOM_SRS` is set, this function will return a random params which should only be used
134/// for testing purpose.
135fn read_params(k: u32) -> Arc<Halo2Params> {
136    if std::env::var("RANDOM_SRS").is_ok() {
137        let mut ret = TESTING_KZG_PARAMS_23.clone();
138        ret.downsize(k);
139        Arc::new(ret)
140    } else {
141        Arc::new(read_params_impl(k))
142    }
143}