Skip to main content

kimchi_msm/
precomputed_srs.rs

1//! Clone of kimchi/precomputed_srs.rs but for MSM project with BN254
2
3use crate::{Fp, BN254, DOMAIN_SIZE};
4use ark_ec::pairing::Pairing;
5use ark_ff::UniformRand;
6use ark_serialize::Write;
7use kimchi::circuits::domains::EvaluationDomains;
8use poly_commitment::{kzg::PairingSRS, precomputed_srs::TestSRS, SRS as _};
9use rand::{rngs::StdRng, SeedableRng};
10use serde::{Deserialize, Serialize};
11use std::{fs::File, io::BufReader, path::PathBuf};
12use zeroize::Zeroize;
13
14/// A clone of the `PairingSRS` that is serialized in a test-optimised way.
15#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
16pub struct TestPairingSRS<Pair: Pairing> {
17    pub full_srs: TestSRS<Pair::G1Affine>,
18    pub verifier_srs: TestSRS<Pair::G2Affine>,
19}
20
21impl<Pair: Pairing> From<PairingSRS<Pair>> for TestPairingSRS<Pair> {
22    fn from(value: PairingSRS<Pair>) -> Self {
23        TestPairingSRS {
24            full_srs: From::from(value.full_srs),
25            verifier_srs: From::from(value.verifier_srs),
26        }
27    }
28}
29
30impl<Pair: Pairing> From<TestPairingSRS<Pair>> for PairingSRS<Pair> {
31    fn from(value: TestPairingSRS<Pair>) -> Self {
32        PairingSRS {
33            full_srs: From::from(value.full_srs),
34            verifier_srs: From::from(value.verifier_srs),
35        }
36    }
37}
38
39/// Obtains an SRS for a specific curve from disk, or generates it if absent.
40pub fn get_bn254_srs(domain: EvaluationDomains<Fp>) -> PairingSRS<BN254> {
41    let srs = if domain.d1.size as usize == DOMAIN_SIZE {
42        read_bn254_srs_from_disk(get_bn254_srs_path())
43    } else {
44        PairingSRS::create(domain.d1.size as usize)
45    };
46    srs.full_srs.get_lagrange_basis(domain.d1); // not added if already present.
47    srs
48}
49
50/// The path of the serialized BN254 SRS, inside this repo.
51pub fn get_bn254_srs_path() -> PathBuf {
52    let base_path = env!("CARGO_MANIFEST_DIR");
53    if base_path.is_empty() {
54        println!("WARNING: BN254 precomputation: CARGO_MANIFEST_DIR is absent, can't determine working directory. It is sometimes absent in release mode.");
55    }
56    PathBuf::from(base_path).join("../srs/test_bn254.srs")
57}
58
59/// Tries to read the SRS from disk, otherwise panics. Returns the
60/// value without Lagrange basis.
61fn read_bn254_srs_from_disk(srs_path: PathBuf) -> PairingSRS<BN254> {
62    let file =
63        File::open(srs_path.clone()).unwrap_or_else(|_| panic!("missing SRS file: {srs_path:?}"));
64    let reader = BufReader::new(file);
65    let srs: TestPairingSRS<BN254> = rmp_serde::from_read(reader).unwrap();
66    From::from(srs)
67}
68
69/// Creates a BN254 SRS. If the `overwrite_srs` flag is on, or
70/// `SRS_OVERWRITE` env variable is ON, also writes it into the file.
71fn create_and_store_srs_with_path(
72    force_overwrite: bool,
73    domain_size: usize,
74    srs_path: PathBuf,
75) -> PairingSRS<BN254> {
76    // We generate with a fixed-seed RNG, only used for testing.
77    let mut rng = &mut StdRng::from_seed([42u8; 32]);
78    let mut trapdoor = Fp::rand(&mut rng);
79    let srs = PairingSRS::create_trusted_setup_with_toxic_waste(trapdoor, domain_size);
80    trapdoor.zeroize();
81
82    for sub_domain_size in 1..=domain_size {
83        let domain = EvaluationDomains::<Fp>::create(sub_domain_size).unwrap();
84        srs.full_srs.get_lagrange_basis(domain.d1);
85    }
86
87    // overwrite SRS if the env var is set
88    if force_overwrite || std::env::var("SRS_OVERWRITE").is_ok() {
89        // Create parent directories
90        std::fs::create_dir_all(srs_path.parent().unwrap()).unwrap();
91        // Open/create the file
92        let mut file = std::fs::OpenOptions::new()
93            .create(true)
94            .truncate(true)
95            .write(true)
96            .open(srs_path.clone())
97            .expect("failed to open SRS file");
98
99        let test_srs: TestPairingSRS<BN254> = From::from(srs.clone());
100        let srs_bytes = rmp_serde::to_vec(&test_srs).unwrap();
101        file.write_all(&srs_bytes).expect("failed to write file");
102        file.flush().expect("failed to flush file");
103    }
104
105    // get SRS from disk
106    let srs_on_disk = read_bn254_srs_from_disk(srs_path);
107
108    // check that it matches what we just generated
109    assert_eq!(srs, srs_on_disk);
110
111    srs
112}
113
114/// Creates and writes the SRS into `get_bn254_srs_path()`.
115pub fn create_and_store_srs(force_overwrite: bool, domain_size: usize) -> PairingSRS<BN254> {
116    let srs_path = get_bn254_srs_path();
117    create_and_store_srs_with_path(force_overwrite, domain_size, srs_path)
118}
119
120#[cfg(test)]
121mod tests {
122    use super::*;
123
124    #[test]
125    /// Creates or checks the real full-sized SRS. Only overwrites
126    /// with the ENV flag.
127    pub fn heavy_test_create_or_check_srs() {
128        let domain_size = DOMAIN_SIZE;
129        create_and_store_srs_with_path(false, domain_size, get_bn254_srs_path());
130    }
131
132    #[test]
133    /// Fast test for a small-sized SRS. Always writes & reads.
134    pub fn check_bn256_srs_serialization() {
135        let domain_size = 1 << 8;
136        let test_srs_path = PathBuf::from("/tmp/test_bn254.srs");
137        create_and_store_srs_with_path(true, domain_size, test_srs_path);
138    }
139
140    #[test]
141    /// Checks if `get_bn254_srs` does not fail. Can be used for
142    /// time-profiling.
143    pub fn check_get_bn254_srs() {
144        let domain_size = DOMAIN_SIZE;
145        let domain = EvaluationDomains::<Fp>::create(domain_size).unwrap();
146        get_bn254_srs(domain);
147    }
148}