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