poly_commitment/
precomputed_srs.rs1use crate::{hash_map_cache::HashMapCache, ipa::SRS, CommitmentCurve, PolyComm};
13use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
14use mina_curves::named::NamedCurve;
15use serde::{Deserialize, Serialize};
16use serde_with::serde_as;
17use std::{collections::HashMap, fs::File, io::BufReader, path::PathBuf};
18
19#[derive(Clone, Copy, PartialEq, Eq)]
22pub enum StoredSRSType {
23 Test,
24 Prod,
25}
26
27#[serde_as]
34#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
35#[serde(bound = "G: CanonicalDeserialize + CanonicalSerialize")]
36pub struct TestSRS<G> {
37 #[serde_as(as = "Vec<o1_utils::serialization::SerdeAsUnchecked>")]
40 pub g: Vec<G>,
41
42 #[serde_as(as = "o1_utils::serialization::SerdeAsUnchecked")]
44 pub h: G,
45
46 #[serde_as(as = "HashMap<_,Vec<PolyComm<o1_utils::serialization::SerdeAsUnchecked>>>")]
48 pub lagrange_bases: HashMap<usize, Vec<PolyComm<G>>>,
49}
50
51impl<G: Clone> From<SRS<G>> for TestSRS<G> {
52 fn from(value: SRS<G>) -> Self {
53 TestSRS {
54 g: value.g,
55 h: value.h,
56 lagrange_bases: value.lagrange_bases.into(),
57 }
58 }
59}
60
61impl<G> From<TestSRS<G>> for SRS<G> {
62 fn from(value: TestSRS<G>) -> Self {
63 SRS {
64 g: value.g,
65 h: value.h,
66 lagrange_bases: HashMapCache::new_from_hashmap(value.lagrange_bases),
67 }
68 }
69}
70
71pub const SERIALIZED_SRS_SIZE: u32 = 16;
73
74fn get_srs_path<G: NamedCurve>(srs_type: StoredSRSType) -> PathBuf {
76 let test_prefix: String = (match srs_type {
77 StoredSRSType::Test => "test_",
78 StoredSRSType::Prod => "",
79 })
80 .to_owned();
81 let base_path = env!("CARGO_MANIFEST_DIR");
82 PathBuf::from(base_path)
83 .join("../srs")
84 .join(test_prefix + &format!("{}.srs", G::NAME))
85}
86
87pub fn get_srs_generic<G>(srs_type: StoredSRSType) -> SRS<G>
89where
90 G: NamedCurve + CommitmentCurve,
91{
92 let srs_path = get_srs_path::<G>(srs_type);
93 let file =
94 File::open(srs_path.clone()).unwrap_or_else(|_| panic!("missing SRS file: {srs_path:?}"));
95 let reader = BufReader::new(file);
96 match srs_type {
97 StoredSRSType::Test => {
98 let test_srs: TestSRS<G> = rmp_serde::from_read(reader).unwrap();
99 From::from(test_srs)
100 }
101 StoredSRSType::Prod => rmp_serde::from_read(reader).unwrap(),
102 }
103}
104
105pub fn get_srs<G>() -> SRS<G>
108where
109 G: NamedCurve + CommitmentCurve,
110{
111 get_srs_generic(StoredSRSType::Prod)
112}
113
114pub fn get_srs_test<G>() -> SRS<G>
117where
118 G: NamedCurve + CommitmentCurve,
119{
120 get_srs_generic(StoredSRSType::Test)
121}
122
123#[cfg(test)]
124mod tests {
125 use super::*;
126
127 use crate::{hash_map_cache::HashMapCache, SRS as _};
128 use ark_ec::AffineRepr;
129 use ark_ff::PrimeField;
130 use ark_poly::{EvaluationDomain, Radix2EvaluationDomain};
131 use ark_serialize::Write;
132 use hex;
133 use mina_curves::pasta::{Pallas, Vesta};
134
135 fn test_regression_serialization_srs_with_generators<G: AffineRepr>(exp_output: String) {
136 let h = G::generator();
137 let g = vec![h];
138 let lagrange_bases = HashMapCache::new();
139 let srs = SRS::<G> {
140 g,
141 h,
142 lagrange_bases,
143 };
144 let srs_bytes = rmp_serde::to_vec(&srs).unwrap();
145 let output = hex::encode(srs_bytes.clone());
146 assert_eq!(output, exp_output)
147 }
148
149 #[test]
150 fn test_regression_serialization_srs_with_generators_vesta() {
151 let exp_output = "9291c421010000000000000000000000000000000000000000000000000000000000000000c421010000000000000000000000000000000000000000000000000000000000000000";
154 test_regression_serialization_srs_with_generators::<Vesta>(exp_output.to_string())
155 }
156
157 #[test]
158 fn test_regression_serialization_srs_with_generators_pallas() {
159 let exp_output = "9291c421010000000000000000000000000000000000000000000000000000000000000000c421010000000000000000000000000000000000000000000000000000000000000000";
162 test_regression_serialization_srs_with_generators::<Pallas>(exp_output.to_string())
163 }
164
165 fn create_or_check_srs<G>(log2_size: u32, srs_type: StoredSRSType)
166 where
167 G: NamedCurve + CommitmentCurve,
168 G::BaseField: PrimeField,
169 {
170 let domain_size = 1 << log2_size;
172 let srs = SRS::<G>::create(domain_size);
173
174 if srs_type == StoredSRSType::Test {
176 for sub_domain_size in 1..=domain_size {
178 let domain = Radix2EvaluationDomain::new(sub_domain_size).unwrap();
179 srs.get_lagrange_basis(domain);
180 }
181 }
182
183 let srs_path = get_srs_path::<G>(srs_type);
185 if std::env::var("SRS_OVERWRITE").is_ok() {
186 let mut file = std::fs::OpenOptions::new()
187 .create(true)
188 .truncate(true)
189 .write(true)
190 .open(srs_path)
191 .expect("failed to open SRS file");
192
193 let srs_bytes = match srs_type {
194 StoredSRSType::Test => {
195 let srs: TestSRS<G> = From::from(srs.clone());
196 rmp_serde::to_vec(&srs).unwrap()
197 }
198 StoredSRSType::Prod => rmp_serde::to_vec(&srs).unwrap(),
199 };
200
201 file.write_all(&srs_bytes).expect("failed to write file");
202 file.flush().expect("failed to flush file");
203 }
204
205 let srs_on_disk: SRS<G> = get_srs_generic::<G>(srs_type);
207
208 assert_eq!(srs, srs_on_disk);
210 }
211
212 #[test]
214 pub fn heavy_check_get_srs_prod_pallas() {
215 get_srs::<Pallas>();
216 }
217
218 #[test]
220 pub fn heavy_check_get_srs_prod_vesta() {
221 get_srs::<Vesta>();
222 }
223
224 #[test]
226 pub fn check_get_srs_test_pallas() {
227 get_srs_test::<Pallas>();
228 }
229
230 #[test]
232 pub fn check_get_srs_test_vesta() {
233 get_srs_test::<Vesta>();
234 }
235
236 #[test]
238 pub fn heavy_test_srs_serialization() {
239 create_or_check_srs::<Vesta>(SERIALIZED_SRS_SIZE, StoredSRSType::Prod);
240 create_or_check_srs::<Pallas>(SERIALIZED_SRS_SIZE, StoredSRSType::Prod);
241 create_or_check_srs::<Vesta>(SERIALIZED_SRS_SIZE, StoredSRSType::Test);
242 create_or_check_srs::<Pallas>(SERIALIZED_SRS_SIZE, StoredSRSType::Test);
243 }
244}