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_dir() -> Option<PathBuf> {
209 dirs::cache_dir().map(|mut path| {
210 path.push("dory");
211 path
212 })
213}
214
215#[cfg(feature = "disk-persistence")]
217fn get_storage_path(max_log_n: usize) -> Option<PathBuf> {
218 get_storage_dir().map(|mut path| {
219 path.push(format!("dory_{}.urs", max_log_n));
220 path
221 })
222}
223
224#[cfg(feature = "disk-persistence")]
236pub fn save_setup<E: PairingCurve>(
237 prover: &ProverSetup<E>,
238 verifier: &VerifierSetup<E>,
239 max_log_n: usize,
240) where
241 ProverSetup<E>: DorySerialize,
242 VerifierSetup<E>: DorySerialize,
243{
244 let storage_path = get_storage_path(max_log_n).expect("Failed to determine storage directory");
245
246 if let Some(parent) = storage_path.parent() {
247 fs::create_dir_all(parent)
248 .unwrap_or_else(|e| panic!("Failed to create storage directory: {}", e));
249 }
250
251 tracing::info!("Saving setup to {}", storage_path.display());
252
253 let file = File::create(&storage_path)
254 .unwrap_or_else(|e| panic!("Failed to create setup file: {}", e));
255
256 let mut writer = BufWriter::new(file);
257
258 DorySerialize::serialize_compressed(prover, &mut writer)
259 .unwrap_or_else(|e| panic!("Failed to serialize prover setup: {}", e));
260
261 DorySerialize::serialize_compressed(verifier, &mut writer)
262 .unwrap_or_else(|e| panic!("Failed to serialize verifier setup: {}", e));
263
264 tracing::info!("Successfully saved setup to disk");
265}
266
267#[cfg(feature = "disk-persistence")]
278pub fn load_setup<E: PairingCurve>(
279 max_log_n: usize,
280) -> Result<(ProverSetup<E>, VerifierSetup<E>), crate::DoryError>
281where
282 ProverSetup<E>: DoryDeserialize,
283 VerifierSetup<E>: DoryDeserialize,
284{
285 let storage_path = get_storage_path(max_log_n).ok_or_else(|| {
286 crate::DoryError::InvalidURS("Failed to determine storage directory".to_string())
287 })?;
288
289 if !storage_path.exists() {
290 return Err(crate::DoryError::InvalidURS(format!(
291 "Setup file not found at {}",
292 storage_path.display()
293 )));
294 }
295
296 tracing::info!("Looking for saved setup at {}", storage_path.display());
297
298 let file = File::open(&storage_path)
299 .map_err(|e| crate::DoryError::InvalidURS(format!("Failed to open setup file: {}", e)))?;
300
301 let mut reader = BufReader::new(file);
302
303 let prover = DoryDeserialize::deserialize_compressed(&mut reader).map_err(|e| {
304 crate::DoryError::InvalidURS(format!("Failed to deserialize prover setup: {}", e))
305 })?;
306
307 let verifier = DoryDeserialize::deserialize_compressed(&mut reader).map_err(|e| {
308 crate::DoryError::InvalidURS(format!("Failed to deserialize verifier setup: {}", e))
309 })?;
310
311 tracing::info!("Loaded setup for max_log_n={}", max_log_n);
312
313 Ok((prover, verifier))
314}