1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
//! To prover and verify proofs you need a [Structured Reference String](https://www.cryptologie.net/article/560/zk-faq-whats-a-trusted-setup-whats-a-structured-reference-string-whats-toxic-waste/) (SRS).
//! The generation of this SRS is quite expensive, so we provide a pre-generated SRS in this repo.
//! Specifically, two of them, one for each pasta curve.
//!
//! We generate the SRS within the test in this module.
//! If you modify the SRS, you will need to regenerate the SRS by passing the `SRS_OVERWRITE` env var.

use std::{fs::File, io::BufReader, path::PathBuf};

use poly_commitment::srs::SRS;

use crate::curve::KimchiCurve;

/// The size of the SRS that we serialize.
pub const SERIALIZED_SRS_SIZE: u32 = 16;

/// The path of the serialized SRS.
fn get_srs_path<G: KimchiCurve>() -> PathBuf {
    let base_path = env!("CARGO_MANIFEST_DIR");
    PathBuf::from(base_path)
        .join("../srs")
        .join(format!("{}.srs", G::NAME))
}

/// Obtains an SRS for a specific curve from disk.
/// Panics if the SRS does not exists.
pub fn get_srs<G>() -> SRS<G>
where
    G: KimchiCurve,
{
    let srs_path = get_srs_path::<G>();
    let file =
        File::open(srs_path.clone()).unwrap_or_else(|_| panic!("missing SRS file: {srs_path:?}"));
    let reader = BufReader::new(file);
    rmp_serde::from_read(reader).unwrap()
}

#[cfg(test)]
mod tests {
    use super::*;

    use ark_ec::AffineCurve;
    use ark_ff::PrimeField;
    use ark_serialize::Write;
    use hex;
    use mina_curves::pasta::{Pallas, Vesta};
    use std::collections::HashMap;

    fn test_regression_serialization_srs_with_generators<G: AffineCurve>(exp_output: String) {
        let h = G::prime_subgroup_generator();
        let g = vec![h];
        let lagrange_bases = HashMap::new();
        let srs = SRS::<G> {
            g,
            h,
            lagrange_bases,
        };
        let srs_bytes = rmp_serde::to_vec(&srs).unwrap();
        let output = hex::encode(srs_bytes.clone());
        assert_eq!(output, exp_output)
    }

    #[test]
    fn test_regression_serialization_srs_with_generators_vesta() {
        // This is the same as Pallas as we encode the coordinate x only.
        // Generated with commit 4c69a4defdb109b94f1124fe93283e728f1d8758
        let exp_output = "9291c421010000000000000000000000000000000000000000000000000000000000000000c421010000000000000000000000000000000000000000000000000000000000000000";
        test_regression_serialization_srs_with_generators::<Vesta>(exp_output.to_string())
    }

    #[test]
    fn test_regression_serialization_srs_with_generators_pallas() {
        // This is the same as Vesta as we encode the coordinate x only.
        // Generated with commit 4c69a4defdb109b94f1124fe93283e728f1d8758
        let exp_output = "9291c421010000000000000000000000000000000000000000000000000000000000000000c421010000000000000000000000000000000000000000000000000000000000000000";
        test_regression_serialization_srs_with_generators::<Pallas>(exp_output.to_string())
    }

    fn create_or_check_srs<G>(log2_size: u32)
    where
        G: KimchiCurve,
        G::BaseField: PrimeField,
    {
        // generate SRS
        let srs = SRS::<G>::create(1 << log2_size);

        // overwrite SRS if the env var is set
        let srs_path = get_srs_path::<G>();
        if std::env::var("SRS_OVERWRITE").is_ok() {
            let mut file = std::fs::OpenOptions::new()
                .create(true)
                .write(true)
                .open(srs_path)
                .expect("failed to open SRS file");

            let srs_bytes = rmp_serde::to_vec(&srs).unwrap();
            file.write_all(&srs_bytes).expect("failed to write file");
            file.flush().expect("failed to flush file");
        }

        // get SRS from disk
        let srs_on_disk = get_srs::<G>();

        // check that it matches what we just generated
        assert_eq!(srs, srs_on_disk);
    }

    /// This test checks that the two serialized SRS on disk are correct.
    #[test]
    pub fn test_srs_serialization() {
        create_or_check_srs::<Vesta>(SERIALIZED_SRS_SIZE);
        create_or_check_srs::<Pallas>(SERIALIZED_SRS_SIZE);
    }
}