1use crate::primitives::arithmetic::{Group, PairingCurve};
8use crate::primitives::serialization::{DoryDeserialize, DorySerialize};
9use rand_core::RngCore;
10
11#[cfg(feature = "disk-persistence")]
12use std::fs::{self, File};
13#[cfg(feature = "disk-persistence")]
14use std::io::{BufReader, BufWriter};
15#[cfg(feature = "disk-persistence")]
16use std::path::PathBuf;
17
18#[derive(Clone, Debug, DorySerialize, DoryDeserialize)]
26pub struct ProverSetup<E: PairingCurve> {
27 pub g1_vec: Vec<E::G1>,
29
30 pub g2_vec: Vec<E::G2>,
32
33 pub h1: E::G1,
35
36 pub h2: E::G2,
38
39 pub ht: E::GT,
41}
42
43#[derive(Clone, Debug, DorySerialize, DoryDeserialize)]
48pub struct VerifierSetup<E: PairingCurve> {
49 pub delta_1l: Vec<E::GT>,
51
52 pub delta_1r: Vec<E::GT>,
54
55 pub delta_2l: Vec<E::GT>,
57
58 pub delta_2r: Vec<E::GT>,
60
61 pub chi: Vec<E::GT>,
63
64 pub g1_0: E::G1,
66
67 pub g2_0: E::G2,
69
70 pub h1: E::G1,
72
73 pub h2: E::G2,
75
76 pub ht: E::GT,
78
79 pub max_log_n: usize,
81}
82
83impl<E: PairingCurve> ProverSetup<E> {
84 pub fn new<R: RngCore>(rng: &mut R, max_log_n: usize) -> Self {
96 let n = 1 << max_log_n.div_ceil(2);
98 let g1_vec: Vec<E::G1> = (0..n).map(|_| E::G1::random(rng)).collect();
100 let g2_vec: Vec<E::G2> = (0..n).map(|_| E::G2::random(rng)).collect();
102
103 let h1 = E::G1::random(rng);
105 let h2 = E::G2::random(rng);
106
107 let ht = E::pair(&h1, &h2);
109
110 Self {
111 g1_vec,
112 g2_vec,
113 h1,
114 h2,
115 ht,
116 }
117 }
118
119 pub fn to_verifier_setup(&self) -> VerifierSetup<E> {
124 let max_num_rounds = self.g1_vec.len().trailing_zeros() as usize;
125
126 let mut delta_1l = Vec::with_capacity(max_num_rounds + 1);
127 let mut delta_1r = Vec::with_capacity(max_num_rounds + 1);
128 let mut delta_2r = Vec::with_capacity(max_num_rounds + 1);
129 let mut chi = Vec::with_capacity(max_num_rounds + 1);
130
131 for k in 0..=max_num_rounds {
132 if k == 0 {
133 delta_1l.push(E::GT::identity());
135 delta_1r.push(E::GT::identity());
136 delta_2r.push(E::GT::identity());
137 chi.push(E::pair(&self.g1_vec[0], &self.g2_vec[0]));
138 } else {
139 let half_len = 1 << (k - 1);
140 let full_len = 1 << k;
141
142 let g1_first_half = &self.g1_vec[..half_len];
143 let g1_second_half = &self.g1_vec[half_len..full_len];
144 let g2_first_half = &self.g2_vec[..half_len];
145 let g2_second_half = &self.g2_vec[half_len..full_len];
146
147 delta_1l.push(chi[k - 1]);
149
150 delta_1r.push(E::multi_pair(g1_second_half, g2_first_half));
152
153 delta_2r.push(E::multi_pair(g1_first_half, g2_second_half));
155
156 chi.push(chi[k - 1].add(&E::multi_pair(g1_second_half, g2_second_half)));
158 }
159 }
160
161 VerifierSetup {
162 delta_1l: delta_1l.clone(),
163 delta_1r,
164 delta_2l: delta_1l, delta_2r,
166 chi,
167 g1_0: self.g1_vec[0],
168 g2_0: self.g2_vec[0],
169 h1: self.h1,
170 h2: self.h2,
171 ht: self.ht,
172 max_log_n: max_num_rounds * 2, }
174 }
175
176 #[inline]
178 pub fn max_nu(&self) -> usize {
179 self.g1_vec.len().trailing_zeros() as usize
180 }
181
182 #[inline]
186 pub fn max_sigma(&self) -> usize {
187 self.max_nu()
188 }
189
190 #[inline]
194 pub fn max_log_n(&self) -> usize {
195 self.max_nu() * 2
196 }
197}
198
199#[cfg(feature = "disk-persistence")]
208fn get_storage_path(max_log_n: usize) -> Option<PathBuf> {
209 let cache_directory = {
210 if let Ok(local_app_data) = std::env::var("LOCALAPPDATA") {
212 Some(PathBuf::from(local_app_data))
213 } else if let Ok(home) = std::env::var("HOME") {
214 let mut path = PathBuf::from(&home);
215
216 let macos_cache = {
218 let mut test_path = PathBuf::from(&home);
219 test_path.push("Library");
220 test_path.push("Caches");
221 test_path.exists()
222 };
223
224 if macos_cache {
225 path.push("Library");
226 path.push("Caches");
227 } else {
228 path.push(".cache");
230 }
231 Some(path)
232 } else {
233 None
234 }
235 };
236
237 cache_directory.map(|mut path| {
238 path.push("dory");
239 path.push(format!("dory_{max_log_n}.urs"));
240 path
241 })
242}
243
244#[cfg(feature = "disk-persistence")]
256pub fn save_setup<E: PairingCurve>(
257 prover: &ProverSetup<E>,
258 verifier: &VerifierSetup<E>,
259 max_log_n: usize,
260) where
261 ProverSetup<E>: DorySerialize,
262 VerifierSetup<E>: DorySerialize,
263{
264 let storage_path = get_storage_path(max_log_n).expect("Failed to determine storage directory");
265
266 if let Some(parent) = storage_path.parent() {
267 fs::create_dir_all(parent)
268 .unwrap_or_else(|e| panic!("Failed to create storage directory: {e}"));
269 }
270
271 tracing::info!("Saving setup to {}", storage_path.display());
272
273 let file =
274 File::create(&storage_path).unwrap_or_else(|e| panic!("Failed to create setup file: {e}"));
275
276 let mut writer = BufWriter::new(file);
277
278 DorySerialize::serialize_compressed(prover, &mut writer)
279 .unwrap_or_else(|e| panic!("Failed to serialize prover setup: {e}"));
280
281 DorySerialize::serialize_compressed(verifier, &mut writer)
282 .unwrap_or_else(|e| panic!("Failed to serialize verifier setup: {e}"));
283
284 tracing::info!("Successfully saved setup to disk");
285}
286
287#[cfg(feature = "disk-persistence")]
298pub fn load_setup<E: PairingCurve>(
299 max_log_n: usize,
300) -> Result<(ProverSetup<E>, VerifierSetup<E>), crate::DoryError>
301where
302 ProverSetup<E>: DoryDeserialize,
303 VerifierSetup<E>: DoryDeserialize,
304{
305 let storage_path = get_storage_path(max_log_n).ok_or_else(|| {
306 crate::DoryError::InvalidURS("Failed to determine storage directory".to_string())
307 })?;
308
309 if !storage_path.exists() {
310 return Err(crate::DoryError::InvalidURS(format!(
311 "Setup file not found at {}",
312 storage_path.display()
313 )));
314 }
315
316 tracing::info!("Looking for saved setup at {}", storage_path.display());
317
318 let file = File::open(&storage_path)
319 .map_err(|e| crate::DoryError::InvalidURS(format!("Failed to open setup file: {e}")))?;
320
321 let mut reader = BufReader::new(file);
322
323 let prover = DoryDeserialize::deserialize_compressed(&mut reader).map_err(|e| {
324 crate::DoryError::InvalidURS(format!("Failed to deserialize prover setup: {e}"))
325 })?;
326
327 let verifier = DoryDeserialize::deserialize_compressed(&mut reader).map_err(|e| {
328 crate::DoryError::InvalidURS(format!("Failed to deserialize verifier setup: {e}"))
329 })?;
330
331 tracing::info!("Loaded setup for max_log_n={}", max_log_n);
332
333 Ok((prover, verifier))
334}