proof_of_sql/proof_primitive/dory/
public_parameters.rs

1use super::{G1Affine, G2Affine};
2use alloc::vec::Vec;
3use ark_ff::UniformRand;
4use ark_serialize::{
5    CanonicalDeserialize, CanonicalSerialize, Compress, SerializationError, Valid, Validate,
6};
7use ark_std::rand::{CryptoRng, Rng};
8use core::iter;
9#[cfg(feature = "std")]
10use std::{
11    fs::File,
12    io::{BufReader, BufWriter, Error, ErrorKind, Read, Write},
13    path::Path,
14};
15
16/// The public parameters for the Dory protocol. See section 5 of <https://eprint.iacr.org/2020/1274.pdf> for details.
17///
18/// Note: even though `H_1` and `H_2` are marked as blue, they are still needed.
19///
20/// Note: `Gamma_1_fin` is unused, so we leave it out.
21pub struct PublicParameters {
22    /// This is the vector of G1 elements that are used in the Dory protocol. That is, `Γ_1,0` in the Dory paper.
23    pub(super) Gamma_1: Vec<G1Affine>,
24    /// This is the vector of G2 elements that are used in the Dory protocol. That is, `Γ_2,0` in the Dory paper.
25    pub(super) Gamma_2: Vec<G2Affine>,
26    /// `H_1` = `H_1` in the Dory paper. This could be used for blinding, but is currently only used in the Fold-Scalars algorithm.
27    pub(super) H_1: G1Affine,
28    /// `H_2` = `H_2` in the Dory paper. This could be used for blinding, but is currently only used in the Fold-Scalars algorithm.
29    pub(super) H_2: G2Affine,
30    /// `Gamma_2_fin` = `Gamma_2,fin` in the Dory paper.
31    pub(super) Gamma_2_fin: G2Affine,
32    /// `max_nu` is the maximum nu that this setup will work for.
33    pub(super) max_nu: usize,
34}
35
36impl PublicParameters {
37    /// Generate cryptographically secure random public parameters.
38    pub fn rand<R: CryptoRng + Rng + ?Sized>(max_nu: usize, rng: &mut R) -> Self {
39        Self::rand_impl(max_nu, rng)
40    }
41    /// Generate random public parameters for testing.
42    pub fn test_rand<R: Rng + ?Sized>(max_nu: usize, rng: &mut R) -> Self {
43        Self::rand_impl(max_nu, rng)
44    }
45    fn rand_impl<R: Rng + ?Sized>(max_nu: usize, rng: &mut R) -> Self {
46        let (H_1, H_2) = (G1Affine::rand(rng), G2Affine::rand(rng));
47        let Gamma_2_fin = G2Affine::rand(rng);
48        let (Gamma_1, Gamma_2) = iter::repeat_with(|| (G1Affine::rand(rng), G2Affine::rand(rng)))
49            .take(1 << max_nu)
50            .unzip();
51
52        Self {
53            Gamma_1,
54            Gamma_2,
55            H_1,
56            H_2,
57            Gamma_2_fin,
58            max_nu,
59        }
60    }
61    #[cfg(feature = "std")]
62    /// Function to save `PublicParameters` to a file in binary form
63    pub fn save_to_file(&self, path: &Path) -> std::io::Result<()> {
64        // Create or open the file at the specified path
65        let file = File::create(path)?;
66        let mut writer = BufWriter::new(file);
67
68        // Serialize the PublicParameters struct into the file
69        let mut serialized_data = Vec::new();
70        self.serialize_with_mode(&mut serialized_data, Compress::No)
71            .map_err(|e| Error::new(ErrorKind::Other, format!("{e}")))?;
72
73        // Write serialized bytes to the file
74        writer.write_all(&serialized_data)?;
75        writer.flush()?;
76        Ok(())
77    }
78    #[cfg(feature = "std")]
79    /// Function to load `PublicParameters` from a file in binary form
80    pub fn load_from_file(path: &Path) -> std::io::Result<Self> {
81        // Open the file at the specified path
82        let file = File::open(path)?;
83        let mut reader = BufReader::new(file);
84
85        // Read the serialized data from the file
86        let mut serialized_data = Vec::new();
87        reader.read_to_end(&mut serialized_data)?;
88
89        // Deserialize the data into a PublicParameters instance
90        PublicParameters::deserialize_with_mode(
91            &mut &serialized_data[..],
92            Compress::No,
93            Validate::Yes,
94        )
95        .map_err(|e| Error::new(ErrorKind::Other, format!("{e}")))
96    }
97}
98
99impl CanonicalSerialize for PublicParameters {
100    fn serialize_with_mode<W: ark_serialize::Write>(
101        &self,
102        mut writer: W,
103        compress: ark_serialize::Compress,
104    ) -> Result<(), SerializationError> {
105        // Serialize max_nu (usize as u64)
106        (self.max_nu as u64).serialize_with_mode(&mut writer, compress)?;
107
108        // Serialize Gamma_1 (Vec<G1Affine>)
109        self.Gamma_1
110            .iter()
111            .try_for_each(|g1| g1.serialize_with_mode(&mut writer, compress))?;
112
113        // Serialize Gamma_2 (Vec<G2Affine>)
114        self.Gamma_2
115            .iter()
116            .try_for_each(|g2| g2.serialize_with_mode(&mut writer, compress))?;
117
118        // Serialize H_1 (G1Affine)
119        self.H_1.serialize_with_mode(&mut writer, compress)?;
120
121        // Serialize H_2 (G2Affine)
122        self.H_2.serialize_with_mode(&mut writer, compress)?;
123
124        // Serialize Gamma_2_fin (G2Affine)
125        self.Gamma_2_fin
126            .serialize_with_mode(&mut writer, compress)?;
127
128        Ok(())
129    }
130
131    // Update serialized_size accordingly
132    fn serialized_size(&self, compress: ark_serialize::Compress) -> usize {
133        // Size of max_nu (u64 is 8 bytes)
134        let max_nu_size = 8;
135
136        // Size of Gamma_1 (Vec<G1Affine>)
137        let gamma_1_size: usize = self
138            .Gamma_1
139            .iter()
140            .map(|g1| g1.serialized_size(compress))
141            .sum();
142
143        // Size of Gamma_2 (Vec<G2Affine>)
144        let gamma_2_size: usize = self
145            .Gamma_2
146            .iter()
147            .map(|g2| g2.serialized_size(compress))
148            .sum();
149
150        // Size of H_1 (G1Affine)
151        let h1_size = self.H_1.serialized_size(compress);
152
153        // Size of H_2 (G2Affine)
154        let h2_size = self.H_2.serialized_size(compress);
155
156        // Size of Gamma_2_fin (G2Affine)
157        let gamma_2_fin_size = self.Gamma_2_fin.serialized_size(compress);
158
159        // Sum everything to get the total size
160        max_nu_size + gamma_1_size + gamma_2_size + h1_size + h2_size + gamma_2_fin_size
161    }
162}
163
164impl CanonicalDeserialize for PublicParameters {
165    fn deserialize_with_mode<R: ark_serialize::Read>(
166        mut reader: R,
167        compress: ark_serialize::Compress,
168        validate: ark_serialize::Validate,
169    ) -> Result<Self, SerializationError> {
170        // Deserialize max_nu (u64)
171        let max_nu_u64 = u64::deserialize_with_mode(&mut reader, compress, validate)?;
172        let max_nu: usize = max_nu_u64
173            .try_into()
174            .map_err(|_| SerializationError::InvalidData)?;
175
176        // Deserialize Gamma_1 (Vec<G1Affine>)
177        let Gamma_1: Vec<G1Affine> = (0..(1 << max_nu))
178            .map(|_| G1Affine::deserialize_with_mode(&mut reader, compress, validate))
179            .collect::<Result<_, _>>()?;
180
181        // Deserialize Gamma_2 (Vec<G2Affine>)
182        let Gamma_2: Vec<G2Affine> = (0..(1 << max_nu))
183            .map(|_| G2Affine::deserialize_with_mode(&mut reader, compress, validate))
184            .collect::<Result<_, _>>()?;
185
186        // Deserialize H_1 (G1Affine)
187        let H_1 = G1Affine::deserialize_with_mode(&mut reader, compress, validate)?;
188
189        // Deserialize H_2 (G2Affine)
190        let H_2 = G2Affine::deserialize_with_mode(&mut reader, compress, validate)?;
191
192        // Deserialize Gamma_2_fin (G2Affine)
193        let Gamma_2_fin = G2Affine::deserialize_with_mode(&mut reader, compress, validate)?;
194
195        Ok(Self {
196            Gamma_1,
197            Gamma_2,
198            H_1,
199            H_2,
200            Gamma_2_fin,
201            max_nu,
202        })
203    }
204
205    // Remove unnecessary methods if they're not overridden
206}
207
208// Implement the Valid trait to perform validation on deserialized data
209impl Valid for PublicParameters {
210    fn check(&self) -> Result<(), SerializationError> {
211        // Check that all G1Affine and G2Affine elements are valid
212        self.Gamma_1
213            .iter()
214            .try_for_each(ark_serialize::Valid::check)?;
215        self.Gamma_2
216            .iter()
217            .try_for_each(ark_serialize::Valid::check)?;
218
219        self.H_1.check()?;
220        self.H_2.check()?;
221        self.Gamma_2_fin.check()?;
222
223        Ok(())
224    }
225}
226
227#[cfg(test)]
228#[cfg(feature = "std")]
229mod tests {
230    use super::*;
231    use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
232    use ark_std::rand::thread_rng;
233    use std::io::Cursor;
234
235    #[test]
236    fn we_can_serialize_and_deserialize_round_trip() {
237        // Create a random PublicParameters instance
238        let mut rng = thread_rng();
239        let original_params = PublicParameters::rand(2, &mut rng);
240
241        // Serialize the original parameters to a byte buffer
242        let mut serialized_data = Vec::new();
243        original_params
244            .serialize_with_mode(&mut serialized_data, ark_serialize::Compress::No)
245            .expect("Failed to serialize PublicParameters");
246
247        // Deserialize the byte buffer back into a PublicParameters instance
248        let mut reader = Cursor::new(serialized_data);
249        let deserialized_params = PublicParameters::deserialize_with_mode(
250            &mut reader,
251            ark_serialize::Compress::No,
252            ark_serialize::Validate::Yes,
253        )
254        .expect("Failed to deserialize PublicParameters");
255
256        // Check that the original and deserialized parameters are the same
257        assert_eq!(original_params.Gamma_1, deserialized_params.Gamma_1);
258        assert_eq!(original_params.Gamma_2, deserialized_params.Gamma_2);
259        assert_eq!(original_params.H_1, deserialized_params.H_1);
260        assert_eq!(original_params.H_2, deserialized_params.H_2);
261        assert_eq!(original_params.Gamma_2_fin, deserialized_params.Gamma_2_fin);
262        assert_eq!(original_params.max_nu, deserialized_params.max_nu);
263
264        // Validate the deserialized parameters to ensure correctness
265        deserialized_params
266            .check()
267            .expect("Deserialized parameters are not valid");
268    }
269
270    // 13th Gen Intel® Core™ i9-13900H × 20
271    // nu vs proof size & time:
272    // nu = 4  |  0.005 MB  | 287.972567ms
273    // nu = 10 |  0.282 MB  | 16.130250627s
274    // nu = 12 |  1.125 MB  | 64.036526973s
275    // nu = 14 |  4.500 MB  | 254.316791697s
276    // nu = 15 |  9.000 MB  | 504.351756724s
277    #[test]
278    fn we_can_read_and_write_a_file_round_trip() {
279        let nu_values = vec![1, 2, 4];
280
281        // Loop through each nu value
282        for &nu in &nu_values {
283            println!("\nTesting with nu = {nu}");
284
285            let start_time = std::time::Instant::now();
286
287            // Create a random PublicParameters instance with the current nu value
288            let mut rng = thread_rng();
289            let original_params = PublicParameters::rand(nu, &mut rng);
290
291            // File path in the current working directory
292            let file_name = format!("public_params_{nu}.bin");
293            let file_path = Path::new(&file_name);
294
295            original_params
296                .save_to_file(file_path)
297                .expect("Failed to save PublicParameters to file");
298
299            // Load the PublicParameters from the file
300            let loaded_params = PublicParameters::load_from_file(file_path)
301                .expect("Failed to load PublicParameters from file");
302
303            // Check that the original and loaded parameters are identical
304            assert_eq!(original_params.Gamma_1, loaded_params.Gamma_1);
305            assert_eq!(original_params.Gamma_2, loaded_params.Gamma_2);
306            assert_eq!(original_params.H_1, loaded_params.H_1);
307            assert_eq!(original_params.H_2, loaded_params.H_2);
308            assert_eq!(original_params.Gamma_2_fin, loaded_params.Gamma_2_fin);
309            assert_eq!(original_params.max_nu, loaded_params.max_nu);
310
311            // Record the file size in bytes
312            let metadata = std::fs::metadata(file_path).expect("Failed to get file metadata");
313            let file_size = metadata.len(); // Get the file size in bytes
314            println!("File size for nu = {nu}: {file_size} bytes");
315
316            // Record the time taken and print it
317            let elapsed_time = start_time.elapsed();
318            println!("Time taken for nu = {nu}: {elapsed_time:?}");
319
320            // Clean up the test file after the test runs
321            std::fs::remove_file(file_path).expect("Failed to remove test file");
322        }
323    }
324}