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