1use crate::primitives::arithmetic::{Group, PairingCurve};
8use crate::primitives::serialization::{DoryDeserialize, DorySerialize};
9
10#[cfg(all(feature = "disk-persistence", not(target_arch = "wasm32")))]
11use std::fs::{self, File};
12#[cfg(all(feature = "disk-persistence", not(target_arch = "wasm32")))]
13use std::io::{BufReader, BufWriter};
14#[cfg(all(feature = "disk-persistence", not(target_arch = "wasm32")))]
15use std::path::PathBuf;
16
17#[derive(Clone, Debug, DorySerialize, DoryDeserialize)]
25pub struct ProverSetup<E: PairingCurve> {
26 pub g1_vec: Vec<E::G1>,
28
29 pub g2_vec: Vec<E::G2>,
31
32 pub h1: E::G1,
34
35 pub h2: E::G2,
37
38 pub ht: E::GT,
40}
41
42#[derive(Clone, Debug, DorySerialize, DoryDeserialize)]
47pub struct VerifierSetup<E: PairingCurve> {
48 pub delta_1l: Vec<E::GT>,
50
51 pub delta_1r: Vec<E::GT>,
53
54 pub delta_2l: Vec<E::GT>,
56
57 pub delta_2r: Vec<E::GT>,
59
60 pub chi: Vec<E::GT>,
62
63 pub g1_0: E::G1,
65
66 pub g2_0: E::G2,
68
69 pub h1: E::G1,
71
72 pub h2: E::G2,
74
75 pub ht: E::GT,
77
78 pub max_log_n: usize,
80}
81
82impl<E: PairingCurve> ProverSetup<E> {
83 pub fn new(max_log_n: usize) -> Self {
94 let n = 1 << max_log_n.div_ceil(2);
96 let g1_vec: Vec<E::G1> = (0..n).map(|_| E::G1::random()).collect();
98 let g2_vec: Vec<E::G2> = (0..n).map(|_| E::G2::random()).collect();
100
101 let h1 = E::G1::random();
103 let h2 = E::G2::random();
104
105 let ht = E::pair(&h1, &h2);
107
108 Self {
109 g1_vec,
110 g2_vec,
111 h1,
112 h2,
113 ht,
114 }
115 }
116
117 pub fn to_verifier_setup(&self) -> VerifierSetup<E> {
122 let max_num_rounds = self.g1_vec.len().trailing_zeros() as usize;
123
124 let mut delta_1l = Vec::with_capacity(max_num_rounds + 1);
125 let mut delta_1r = Vec::with_capacity(max_num_rounds + 1);
126 let mut delta_2r = Vec::with_capacity(max_num_rounds + 1);
127 let mut chi = Vec::with_capacity(max_num_rounds + 1);
128
129 for k in 0..=max_num_rounds {
130 if k == 0 {
131 delta_1l.push(E::GT::identity());
133 delta_1r.push(E::GT::identity());
134 delta_2r.push(E::GT::identity());
135 chi.push(E::pair(&self.g1_vec[0], &self.g2_vec[0]));
136 } else {
137 let half_len = 1 << (k - 1);
138 let full_len = 1 << k;
139
140 let g1_first_half = &self.g1_vec[..half_len];
141 let g1_second_half = &self.g1_vec[half_len..full_len];
142 let g2_first_half = &self.g2_vec[..half_len];
143 let g2_second_half = &self.g2_vec[half_len..full_len];
144
145 delta_1l.push(chi[k - 1]);
147
148 delta_1r.push(E::multi_pair(g1_second_half, g2_first_half));
150
151 delta_2r.push(E::multi_pair(g1_first_half, g2_second_half));
153
154 chi.push(chi[k - 1].add(&E::multi_pair(g1_second_half, g2_second_half)));
156 }
157 }
158
159 VerifierSetup {
160 delta_1l: delta_1l.clone(),
161 delta_1r,
162 delta_2l: delta_1l, delta_2r,
164 chi,
165 g1_0: self.g1_vec[0],
166 g2_0: self.g2_vec[0],
167 h1: self.h1,
168 h2: self.h2,
169 ht: self.ht,
170 max_log_n: max_num_rounds * 2, }
172 }
173
174 #[inline]
176 pub fn max_nu(&self) -> usize {
177 self.g1_vec.len().trailing_zeros() as usize
178 }
179
180 #[inline]
184 pub fn max_sigma(&self) -> usize {
185 self.max_nu()
186 }
187
188 #[inline]
192 pub fn max_log_n(&self) -> usize {
193 self.max_nu() * 2
194 }
195}
196
197#[cfg(all(feature = "disk-persistence", not(target_arch = "wasm32")))]
206fn get_storage_path(max_log_n: usize) -> Option<PathBuf> {
207 let cache_directory = {
208 if let Ok(local_app_data) = std::env::var("LOCALAPPDATA") {
210 Some(PathBuf::from(local_app_data))
211 } else if let Ok(home) = std::env::var("HOME") {
212 let mut path = PathBuf::from(&home);
213
214 let macos_cache = {
216 let mut test_path = PathBuf::from(&home);
217 test_path.push("Library");
218 test_path.push("Caches");
219 test_path.exists()
220 };
221
222 if macos_cache {
223 path.push("Library");
224 path.push("Caches");
225 } else {
226 path.push(".cache");
228 }
229 Some(path)
230 } else {
231 None
232 }
233 };
234
235 cache_directory.map(|mut path| {
236 path.push("dory");
237 path.push(format!("dory_{max_log_n}.urs"));
238 path
239 })
240}
241
242#[cfg(all(feature = "disk-persistence", not(target_arch = "wasm32")))]
254pub fn save_setup<E: PairingCurve>(
255 prover: &ProverSetup<E>,
256 verifier: &VerifierSetup<E>,
257 max_log_n: usize,
258) where
259 ProverSetup<E>: DorySerialize,
260 VerifierSetup<E>: DorySerialize,
261{
262 let storage_path = get_storage_path(max_log_n).expect("Failed to determine storage directory");
263
264 if let Some(parent) = storage_path.parent() {
265 fs::create_dir_all(parent)
266 .unwrap_or_else(|e| panic!("Failed to create storage directory: {e}"));
267 }
268
269 tracing::info!("Saving setup to {}", storage_path.display());
270
271 let file =
272 File::create(&storage_path).unwrap_or_else(|e| panic!("Failed to create setup file: {e}"));
273
274 let mut writer = BufWriter::new(file);
275
276 DorySerialize::serialize_compressed(prover, &mut writer)
277 .unwrap_or_else(|e| panic!("Failed to serialize prover setup: {e}"));
278
279 DorySerialize::serialize_compressed(verifier, &mut writer)
280 .unwrap_or_else(|e| panic!("Failed to serialize verifier setup: {e}"));
281
282 tracing::info!("Successfully saved setup to disk");
283}
284
285#[cfg(all(feature = "disk-persistence", not(target_arch = "wasm32")))]
296pub fn load_setup<E: PairingCurve>(
297 max_log_n: usize,
298) -> Result<(ProverSetup<E>, VerifierSetup<E>), crate::DoryError>
299where
300 ProverSetup<E>: DoryDeserialize,
301 VerifierSetup<E>: DoryDeserialize,
302{
303 let storage_path = get_storage_path(max_log_n).ok_or_else(|| {
304 crate::DoryError::InvalidURS("Failed to determine storage directory".to_string())
305 })?;
306
307 if !storage_path.exists() {
308 return Err(crate::DoryError::InvalidURS(format!(
309 "Setup file not found at {}",
310 storage_path.display()
311 )));
312 }
313
314 tracing::info!("Looking for saved setup at {}", storage_path.display());
315
316 let file = File::open(&storage_path)
317 .map_err(|e| crate::DoryError::InvalidURS(format!("Failed to open setup file: {e}")))?;
318
319 let mut reader = BufReader::new(file);
320
321 let prover = DoryDeserialize::deserialize_compressed(&mut reader).map_err(|e| {
322 crate::DoryError::InvalidURS(format!("Failed to deserialize prover setup: {e}"))
323 })?;
324
325 let verifier = DoryDeserialize::deserialize_compressed(&mut reader).map_err(|e| {
326 crate::DoryError::InvalidURS(format!("Failed to deserialize verifier setup: {e}"))
327 })?;
328
329 tracing::info!("Loaded setup for max_log_n={}", max_log_n);
330
331 Ok((prover, verifier))
332}