/ algorithms / src / snark / varuna / tests.rs
tests.rs
  1  // Copyright (c) 2019-2025 Alpha-Delta Network Inc.
  2  // This file is part of the deltavm library.
  3  
  4  // Licensed under the Apache License, Version 2.0 (the "License");
  5  // you may not use this file except in compliance with the License.
  6  // You may obtain a copy of the License at:
  7  
  8  // http://www.apache.org/licenses/LICENSE-2.0
  9  
 10  // Unless required by applicable law or agreed to in writing, software
 11  // distributed under the License is distributed on an "AS IS" BASIS,
 12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  // See the License for the specific language governing permissions and
 14  // limitations under the License.
 15  
 16  #[cfg(any(test, feature = "test"))]
 17  mod varuna {
 18      use crate::{
 19          snark::varuna::{
 20              AHPForR1CS,
 21              CircuitVerifyingKey,
 22              VarunaHidingMode,
 23              VarunaNonHidingMode,
 24              VarunaSNARK,
 25              VarunaVersion,
 26              mode::SNARKMode,
 27              proof::proof_size,
 28              test_circuit::TestCircuit,
 29          },
 30          traits::{AlgebraicSponge, SNARK},
 31      };
 32  
 33      use std::collections::BTreeMap;
 34  
 35      use deltavm_curves::bls12_377::{Bls12_377, Fq, Fr};
 36      use deltavm_utilities::{
 37          CanonicalSerialize,
 38          ToBytes,
 39          rand::{TestRng, Uniform},
 40      };
 41  
 42      type FS = crate::crypto_hash::PoseidonSponge<Fq, 2, 1>;
 43  
 44      type VarunaSonicInst = VarunaSNARK<Bls12_377, FS, VarunaHidingMode>;
 45      type VarunaSonicPoSWInst = VarunaSNARK<Bls12_377, FS, VarunaNonHidingMode>;
 46  
 47      macro_rules! impl_varuna_test {
 48          ($test_struct: ident, $snark_inst: tt, $snark_mode: tt) => {
 49              struct $test_struct {}
 50              impl $test_struct {
 51                  pub(crate) fn test_circuit(num_constraints: usize, num_variables: usize, pk_size_expectation: usize, varuna_version: VarunaVersion, rng: &mut deltavm_utilities::rand::TestRng) {
 52                      let random = Fr::rand(rng);
 53  
 54                      let max_degree = AHPForR1CS::<Fr, $snark_mode>::max_degree(100, 25, 300).unwrap();
 55                      let universal_srs = $snark_inst::universal_setup(max_degree).unwrap();
 56                      let universal_prover = &universal_srs.to_universal_prover().unwrap();
 57                      let universal_verifier = &universal_srs.to_universal_verifier().unwrap();
 58                      let fs_parameters = FS::sample_parameters();
 59  
 60                      let wrong_varuna_version = match varuna_version {
 61                          VarunaVersion::V1 => VarunaVersion::V2,
 62                          VarunaVersion::V2 => VarunaVersion::V1,
 63                      };
 64  
 65                      for i in 0..5 {
 66                          let mul_depth = 1;
 67                          println!("running test with SM::ZK: {}, mul_depth: {}, num_constraints: {}, num_variables: {}, varuna_version: {:?}", $snark_mode::ZK, mul_depth + i, num_constraints + i, num_variables + i, varuna_version);
 68                          let (circ, public_inputs) = TestCircuit::gen_rand(mul_depth + i, num_constraints + i, num_variables + i, rng);
 69                          let mut fake_inputs = public_inputs.clone();
 70                          fake_inputs[public_inputs.len() - 1] = random;
 71  
 72                          let (index_pk, index_vk) = $snark_inst::circuit_setup(&universal_srs, &circ).unwrap();
 73                          println!("Called circuit setup");
 74  
 75                          let certificate = $snark_inst::prove_vk(universal_prover, &fs_parameters, &index_vk, &index_pk).unwrap();
 76                          assert!($snark_inst::verify_vk(universal_verifier, &fs_parameters, &circ, &index_vk, &certificate).unwrap());
 77                          println!("verified vk");
 78  
 79                          if i == 0 {
 80                              assert_eq!(pk_size_expectation, index_pk.to_bytes_le().unwrap().len(), "Update me if serialization has changed");
 81                          }
 82                          assert_eq!(664, index_vk.to_bytes_le().unwrap().len(), "Update me if serialization has changed");
 83  
 84                          let proof = $snark_inst::prove(universal_prover, &fs_parameters, &index_pk, varuna_version, &circ, rng).unwrap();
 85                          println!("Called prover");
 86  
 87                          assert!($snark_inst::verify(universal_verifier, &fs_parameters, &index_vk, varuna_version, public_inputs.clone(), &proof).unwrap());
 88                          println!("Called verifier");
 89                          eprintln!("\nShould not verify with fake inputs (i.e. verifier messages should print below):");
 90                          assert!(!$snark_inst::verify(universal_verifier, &fs_parameters, &index_vk, varuna_version, fake_inputs, &proof).unwrap());
 91                          eprintln!("\nShould not verify with wrong varuna version (i.e. verifier messages should print below):");
 92                          assert!(!$snark_inst::verify(universal_verifier, &fs_parameters, &index_vk, wrong_varuna_version, public_inputs, &proof).unwrap());
 93                      }
 94  
 95                      for circuit_batch_size in (0..4).map(|i| 2usize.pow(i)) {
 96                          for instance_batch_size in (0..4).map(|i| 2usize.pow(i)) {
 97                              println!("running test with circuit_batch_size: {circuit_batch_size} and instance_batch_size: {instance_batch_size}");
 98                              let mut constraints = BTreeMap::new();
 99                              let mut inputs = BTreeMap::new();
100  
101                              for i in 0..circuit_batch_size {
102                                  let (circuit_batch, input_batch): (Vec<_>, Vec<_>) = (0..instance_batch_size)
103                                  .map(|_| {
104                                      let mul_depth = 2 + i;
105                                      let (circ, inputs) = TestCircuit::gen_rand(mul_depth, num_constraints + 100*i, num_variables, rng);
106                                      (circ, inputs)
107                                  })
108                                  .unzip();
109                                  let circuit_id = AHPForR1CS::<Fr, $snark_mode>::index(&circuit_batch[0]).unwrap().id;
110                                  constraints.insert(circuit_id, circuit_batch);
111                                  inputs.insert(circuit_id, input_batch);
112                              }
113                              let unique_instances = constraints.values().map(|instances| &instances[0]).collect::<Vec<_>>();
114  
115                              let index_keys =
116                                  $snark_inst::batch_circuit_setup(&universal_srs, unique_instances.as_slice()).unwrap();
117                              println!("Called circuit setup");
118  
119                              let mut pks_to_constraints = BTreeMap::new();
120                              let mut vks_to_inputs = BTreeMap::new();
121  
122                              for (index_pk, index_vk) in index_keys.iter() {
123                                  let certificate = $snark_inst::prove_vk(universal_prover, &fs_parameters, &index_vk, &index_pk).unwrap();
124                                  let circuits = constraints[&index_pk.circuit.id].as_slice();
125                                  assert!($snark_inst::verify_vk(universal_verifier, &fs_parameters, &circuits[0], &index_vk, &certificate).unwrap());
126                                  pks_to_constraints.insert(index_pk, circuits);
127                                  vks_to_inputs.insert(index_vk, inputs[&index_pk.circuit.id].as_slice());
128                              }
129                              println!("verified vks");
130  
131                              let proof =
132                                  $snark_inst::prove_batch(universal_prover, &fs_parameters, varuna_version, &pks_to_constraints, rng).unwrap();
133                              println!("Called prover");
134  
135                              if varuna_version == VarunaVersion::V2 {
136                                  let batch_sizes = proof.batch_sizes();
137                                  let mut proof_bytes = vec![];
138                                  proof.serialize_compressed(&mut proof_bytes).unwrap();
139                                  let actual_size = proof_size::<Bls12_377>(&batch_sizes, VarunaVersion::V2, $snark_mode::ZK).unwrap();
140                                  assert_eq!(proof_bytes.len(), actual_size);
141                                  println!("Compressed size is as expected ({actual_size} B)");
142                              }
143  
144                              assert!(
145                                  $snark_inst::verify_batch(universal_verifier, &fs_parameters, varuna_version, &vks_to_inputs, &proof).unwrap(),
146                                  "Batch verification failed with {instance_batch_size} instances and {circuit_batch_size} circuits for circuits: {constraints:?}"
147                              );
148                              println!("Called verifier");
149                              eprintln!("\nShould not verify with wrong inputs (i.e. verifier messages should print below):");
150                              let mut fake_instance_inputs = Vec::with_capacity(vks_to_inputs.len());
151                              for instance_input in vks_to_inputs.values() {
152                                  let mut fake_instance_input = Vec::with_capacity(instance_input.len());
153                                  for input in instance_input.iter() {
154                                      let mut fake_input = input.clone();
155                                      fake_input[input.len() - 1] = Fr::rand(rng);
156                                      fake_instance_input.push(fake_input);
157                                  }
158                                  fake_instance_inputs.push(fake_instance_input);
159                              }
160                              let mut vks_to_fake_inputs = BTreeMap::new();
161                              for (i, vk) in vks_to_inputs.keys().enumerate() {
162                                  vks_to_fake_inputs.insert(*vk, fake_instance_inputs[i].as_slice());
163                              }
164                              assert!(
165                                  !$snark_inst::verify_batch(
166                                      universal_verifier,
167                                      &fs_parameters,
168                                      varuna_version,
169                                      &vks_to_fake_inputs,
170                                      &proof,
171                                  )
172                                  .unwrap()
173                              );
174                              eprintln!("\nShould not verify with wrong varuna version (i.e. verifier messages should print below):");
175                              assert!(
176                                  !$snark_inst::verify_batch(
177                                      universal_verifier,
178                                      &fs_parameters,
179                                      wrong_varuna_version,
180                                      &vks_to_inputs,
181                                      &proof,
182                                  )
183                                  .unwrap()
184                              );
185                          }
186                      }
187                  }
188  
189                  pub(crate) fn test_serde_json(num_constraints: usize, num_variables: usize, rng: &mut TestRng) {
190                      use std::str::FromStr;
191  
192                      let max_degree = AHPForR1CS::<Fr, $snark_mode>::max_degree(100, 25, 300).unwrap();
193                      let universal_srs = $snark_inst::universal_setup(max_degree).unwrap();
194  
195                      let mul_depth = 1;
196                      let (circ, _) = TestCircuit::gen_rand(mul_depth, num_constraints, num_variables, rng);
197  
198                      let (_index_pk, index_vk) = $snark_inst::circuit_setup(&universal_srs, &circ).unwrap();
199                      println!("Called circuit setup");
200  
201                      // Serialize
202                      let expected_string = index_vk.to_string();
203                      let candidate_string = serde_json::to_string(&index_vk).unwrap();
204                      assert_eq!(
205                          expected_string,
206                          serde_json::Value::from_str(&candidate_string).unwrap().as_str().unwrap()
207                      );
208  
209                      // Deserialize
210                      assert_eq!(index_vk, CircuitVerifyingKey::from_str(&expected_string).unwrap());
211                      assert_eq!(index_vk, serde_json::from_str(&candidate_string).unwrap());
212                  }
213  
214                  pub(crate) fn test_bincode(num_constraints: usize, num_variables: usize, rng: &mut TestRng) {
215                      use deltavm_utilities::{FromBytes, ToBytes};
216  
217                      let max_degree = AHPForR1CS::<Fr, $snark_mode>::max_degree(100, 25, 300).unwrap();
218                      let universal_srs = $snark_inst::universal_setup(max_degree).unwrap();
219  
220                      let mul_depth = 1;
221                      let (circ, _) = TestCircuit::gen_rand(mul_depth, num_constraints, num_variables, rng);
222  
223                      let (_index_pk, index_vk) = $snark_inst::circuit_setup(&universal_srs, &circ).unwrap();
224                      println!("Called circuit setup");
225  
226                      // Serialize
227                      let expected_bytes = index_vk.to_bytes_le().unwrap();
228                      let candidate_bytes = bincode::serialize(&index_vk).unwrap();
229                      // TODO (howardwu): Serialization - Handle the inconsistency between ToBytes and Serialize (off by a length encoding).
230                      assert_eq!(&expected_bytes[..], &candidate_bytes[8..]);
231  
232                      // Deserialize
233                      assert_eq!(index_vk, CircuitVerifyingKey::read_le(&expected_bytes[..]).unwrap());
234                      assert_eq!(index_vk, bincode::deserialize(&candidate_bytes[..]).unwrap());
235                  }
236              }
237          };
238      }
239  
240      impl_varuna_test!(SonicPCTest, VarunaSonicInst, VarunaHidingMode);
241      impl_varuna_test!(SonicPCPoswTest, VarunaSonicPoSWInst, VarunaNonHidingMode);
242  
243      #[test]
244      fn prove_and_verify_with_tall_matrix_big() {
245          let num_constraints = 100;
246          let num_variables = 25;
247          let pk_size_zk = 91971;
248          let pk_size_posw = 91633;
249          let mut rng = TestRng::default();
250  
251          SonicPCTest::test_circuit(num_constraints, num_variables, pk_size_zk, VarunaVersion::V1, &mut rng);
252          SonicPCPoswTest::test_circuit(num_constraints, num_variables, pk_size_posw, VarunaVersion::V1, &mut rng);
253  
254          SonicPCTest::test_circuit(num_constraints, num_variables, pk_size_zk, VarunaVersion::V2, &mut rng);
255          SonicPCPoswTest::test_circuit(num_constraints, num_variables, pk_size_posw, VarunaVersion::V2, &mut rng);
256  
257          SonicPCTest::test_serde_json(num_constraints, num_variables, &mut rng);
258          SonicPCPoswTest::test_serde_json(num_constraints, num_variables, &mut rng);
259  
260          SonicPCTest::test_bincode(num_constraints, num_variables, &mut rng);
261          SonicPCPoswTest::test_bincode(num_constraints, num_variables, &mut rng);
262      }
263  
264      #[test]
265      fn prove_and_verify_with_tall_matrix_small() {
266          let num_constraints = 26;
267          let num_variables = 25;
268          let pk_size_zk = 25428;
269          let pk_size_posw = 25090;
270          let mut rng = TestRng::default();
271  
272          SonicPCTest::test_circuit(num_constraints, num_variables, pk_size_zk, VarunaVersion::V1, &mut rng);
273          SonicPCPoswTest::test_circuit(num_constraints, num_variables, pk_size_posw, VarunaVersion::V1, &mut rng);
274  
275          SonicPCTest::test_circuit(num_constraints, num_variables, pk_size_zk, VarunaVersion::V2, &mut rng);
276          SonicPCPoswTest::test_circuit(num_constraints, num_variables, pk_size_posw, VarunaVersion::V2, &mut rng);
277  
278          SonicPCTest::test_serde_json(num_constraints, num_variables, &mut rng);
279          SonicPCPoswTest::test_serde_json(num_constraints, num_variables, &mut rng);
280  
281          SonicPCTest::test_bincode(num_constraints, num_variables, &mut rng);
282          SonicPCPoswTest::test_bincode(num_constraints, num_variables, &mut rng);
283      }
284  
285      #[test]
286      fn prove_and_verify_with_squat_matrix_big() {
287          let num_constraints = 25;
288          let num_variables = 100;
289          let pk_size_zk = 53523;
290          let pk_size_posw = 53185;
291          let mut rng = TestRng::default();
292  
293          SonicPCTest::test_circuit(num_constraints, num_variables, pk_size_zk, VarunaVersion::V1, &mut rng);
294          SonicPCPoswTest::test_circuit(num_constraints, num_variables, pk_size_posw, VarunaVersion::V1, &mut rng);
295  
296          SonicPCTest::test_circuit(num_constraints, num_variables, pk_size_zk, VarunaVersion::V2, &mut rng);
297          SonicPCPoswTest::test_circuit(num_constraints, num_variables, pk_size_posw, VarunaVersion::V2, &mut rng);
298  
299          SonicPCTest::test_serde_json(num_constraints, num_variables, &mut rng);
300          SonicPCPoswTest::test_serde_json(num_constraints, num_variables, &mut rng);
301  
302          SonicPCTest::test_bincode(num_constraints, num_variables, &mut rng);
303          SonicPCPoswTest::test_bincode(num_constraints, num_variables, &mut rng);
304      }
305  
306      #[test]
307      fn prove_and_verify_with_squat_matrix_small() {
308          let num_constraints = 25;
309          let num_variables = 26;
310          let pk_size_zk = 25284;
311          let pk_size_posw = 24946;
312          let mut rng = TestRng::default();
313  
314          SonicPCTest::test_circuit(num_constraints, num_variables, pk_size_zk, VarunaVersion::V1, &mut rng);
315          SonicPCPoswTest::test_circuit(num_constraints, num_variables, pk_size_posw, VarunaVersion::V1, &mut rng);
316  
317          SonicPCTest::test_circuit(num_constraints, num_variables, pk_size_zk, VarunaVersion::V2, &mut rng);
318          SonicPCPoswTest::test_circuit(num_constraints, num_variables, pk_size_posw, VarunaVersion::V2, &mut rng);
319  
320          SonicPCTest::test_serde_json(num_constraints, num_variables, &mut rng);
321          SonicPCPoswTest::test_serde_json(num_constraints, num_variables, &mut rng);
322  
323          SonicPCTest::test_bincode(num_constraints, num_variables, &mut rng);
324          SonicPCPoswTest::test_bincode(num_constraints, num_variables, &mut rng);
325      }
326  
327      #[test]
328      fn prove_and_verify_with_square_matrix() {
329          let num_constraints = 25;
330          let num_variables = 25;
331          let pk_size_zk = 25284;
332          let pk_size_posw = 24946;
333          let mut rng = TestRng::default();
334  
335          SonicPCTest::test_circuit(num_constraints, num_variables, pk_size_zk, VarunaVersion::V1, &mut rng);
336          SonicPCPoswTest::test_circuit(num_constraints, num_variables, pk_size_posw, VarunaVersion::V1, &mut rng);
337  
338          SonicPCTest::test_circuit(num_constraints, num_variables, pk_size_zk, VarunaVersion::V2, &mut rng);
339          SonicPCPoswTest::test_circuit(num_constraints, num_variables, pk_size_posw, VarunaVersion::V2, &mut rng);
340  
341          SonicPCTest::test_serde_json(num_constraints, num_variables, &mut rng);
342          SonicPCPoswTest::test_serde_json(num_constraints, num_variables, &mut rng);
343  
344          SonicPCTest::test_bincode(num_constraints, num_variables, &mut rng);
345          SonicPCPoswTest::test_bincode(num_constraints, num_variables, &mut rng);
346      }
347  }
348  
349  #[cfg(any(test, feature = "test"))]
350  mod varuna_hiding {
351      use crate::{
352          crypto_hash::PoseidonSponge,
353          snark::varuna::{
354              CircuitVerifyingKey,
355              VarunaHidingMode,
356              VarunaSNARK,
357              VarunaVersion,
358              ahp::AHPForR1CS,
359              test_circuit::TestCircuit,
360          },
361          traits::{AlgebraicSponge, SNARK},
362      };
363      use deltavm_curves::bls12_377::{Bls12_377, Fq, Fr};
364      use deltavm_utilities::{
365          FromBytes,
366          ToBytes,
367          rand::{TestRng, Uniform},
368      };
369  
370      use std::str::FromStr;
371  
372      type VarunaInst = VarunaSNARK<Bls12_377, FS, VarunaHidingMode>;
373      type FS = PoseidonSponge<Fq, 2, 1>;
374  
375      fn test_circuit_n_times(
376          num_constraints: usize,
377          num_variables: usize,
378          num_times: usize,
379          varuna_version: VarunaVersion,
380          rng: &mut TestRng,
381      ) {
382          let max_degree = AHPForR1CS::<Fr, VarunaHidingMode>::max_degree(100, 25, 300).unwrap();
383          let universal_srs = VarunaInst::universal_setup(max_degree).unwrap();
384          let universal_prover = &universal_srs.to_universal_prover().unwrap();
385          let universal_verifier = &universal_srs.to_universal_verifier().unwrap();
386          let fs_parameters = FS::sample_parameters();
387  
388          let wrong_varuna_version = match varuna_version {
389              VarunaVersion::V1 => VarunaVersion::V2,
390              VarunaVersion::V2 => VarunaVersion::V1,
391          };
392  
393          for _ in 0..num_times {
394              let mul_depth = 2;
395              let (circuit, public_inputs) = TestCircuit::gen_rand(mul_depth, num_constraints, num_variables, rng);
396              let mut fake_inputs = public_inputs.clone();
397              fake_inputs[public_inputs.len() - 1] = Fr::rand(rng);
398  
399              let (index_pk, index_vk) = VarunaInst::circuit_setup(&universal_srs, &circuit).unwrap();
400              println!("Called circuit setup");
401  
402              let proof =
403                  VarunaInst::prove(universal_prover, &fs_parameters, &index_pk, varuna_version, &circuit, rng).unwrap();
404              println!("Called prover");
405  
406              assert!(
407                  VarunaInst::verify(
408                      universal_verifier,
409                      &fs_parameters,
410                      &index_vk,
411                      varuna_version,
412                      public_inputs.clone(),
413                      &proof,
414                  )
415                  .unwrap()
416              );
417              println!("Called verifier");
418              eprintln!("\nShould not verify with fake inputs (i.e. verifier messages should print below):");
419              assert!(
420                  !VarunaInst::verify(
421                      universal_verifier,
422                      &fs_parameters,
423                      &index_vk,
424                      varuna_version,
425                      fake_inputs.clone(),
426                      &proof
427                  )
428                  .unwrap()
429              );
430              eprintln!("\nShould not verify with wrong varuna version (i.e. verifier messages should print below):");
431              assert!(
432                  !VarunaInst::verify(
433                      universal_verifier,
434                      &fs_parameters,
435                      &index_vk,
436                      wrong_varuna_version,
437                      public_inputs.clone(),
438                      &proof,
439                  )
440                  .unwrap()
441              );
442          }
443      }
444  
445      fn test_circuit(num_constraints: usize, num_variables: usize, varuna_version: VarunaVersion, rng: &mut TestRng) {
446          test_circuit_n_times(num_constraints, num_variables, 100, varuna_version, rng)
447      }
448  
449      fn test_serde_json(num_constraints: usize, num_variables: usize, rng: &mut TestRng) {
450          let max_degree = AHPForR1CS::<Fr, VarunaHidingMode>::max_degree(100, 25, 300).unwrap();
451          let universal_srs = VarunaInst::universal_setup(max_degree).unwrap();
452  
453          let mul_depth = 1;
454          let (circuit, _) = TestCircuit::gen_rand(mul_depth, num_constraints, num_variables, rng);
455  
456          let (_index_pk, index_vk) = VarunaInst::circuit_setup(&universal_srs, &circuit).unwrap();
457          println!("Called circuit setup");
458  
459          // Serialize
460          let expected_string = index_vk.to_string();
461          let candidate_string = serde_json::to_string(&index_vk).unwrap();
462          assert_eq!(expected_string, serde_json::Value::from_str(&candidate_string).unwrap().as_str().unwrap());
463  
464          // Deserialize
465          assert_eq!(index_vk, CircuitVerifyingKey::from_str(&expected_string).unwrap());
466          assert_eq!(index_vk, serde_json::from_str(&candidate_string).unwrap());
467      }
468  
469      fn test_bincode(num_constraints: usize, num_variables: usize, rng: &mut TestRng) {
470          let max_degree = AHPForR1CS::<Fr, VarunaHidingMode>::max_degree(100, 25, 300).unwrap();
471          let universal_srs = VarunaInst::universal_setup(max_degree).unwrap();
472  
473          let mul_depth = 1;
474          let (circuit, _) = TestCircuit::gen_rand(mul_depth, num_constraints, num_variables, rng);
475  
476          let (_index_pk, index_vk) = VarunaInst::circuit_setup(&universal_srs, &circuit).unwrap();
477          println!("Called circuit setup");
478  
479          // Serialize
480          let expected_bytes = index_vk.to_bytes_le().unwrap();
481          let candidate_bytes = bincode::serialize(&index_vk).unwrap();
482          // TODO (howardwu): Serialization - Handle the inconsistency between ToBytes and
483          // Serialize (off by a length encoding).
484          assert_eq!(&expected_bytes[..], &candidate_bytes[8..]);
485  
486          // Deserialize
487          assert_eq!(index_vk, CircuitVerifyingKey::read_le(&expected_bytes[..]).unwrap());
488          assert_eq!(index_vk, bincode::deserialize(&candidate_bytes[..]).unwrap());
489      }
490  
491      #[test]
492      fn prove_and_verify_with_tall_matrix_big() {
493          let num_constraints = 100;
494          let num_variables = 25;
495          let mut rng = TestRng::default();
496  
497          test_circuit(num_constraints, num_variables, VarunaVersion::V1, &mut rng);
498          test_circuit(num_constraints, num_variables, VarunaVersion::V2, &mut rng);
499          test_serde_json(num_constraints, num_variables, &mut rng);
500          test_bincode(num_constraints, num_variables, &mut rng);
501      }
502  
503      #[test]
504      fn prove_and_verify_with_tall_matrix_small() {
505          let num_constraints = 26;
506          let num_variables = 25;
507          let mut rng = TestRng::default();
508  
509          test_circuit(num_constraints, num_variables, VarunaVersion::V1, &mut rng);
510          test_circuit(num_constraints, num_variables, VarunaVersion::V2, &mut rng);
511          test_serde_json(num_constraints, num_variables, &mut rng);
512          test_bincode(num_constraints, num_variables, &mut rng);
513      }
514  
515      #[test]
516      fn prove_and_verify_with_squat_matrix_big() {
517          let num_constraints = 25;
518          let num_variables = 100;
519          let mut rng = TestRng::default();
520  
521          test_circuit(num_constraints, num_variables, VarunaVersion::V1, &mut rng);
522          test_circuit(num_constraints, num_variables, VarunaVersion::V2, &mut rng);
523          test_serde_json(num_constraints, num_variables, &mut rng);
524          test_bincode(num_constraints, num_variables, &mut rng);
525      }
526  
527      #[test]
528      fn prove_and_verify_with_squat_matrix_small() {
529          let num_constraints = 25;
530          let num_variables = 26;
531          let mut rng = TestRng::default();
532  
533          test_circuit(num_constraints, num_variables, VarunaVersion::V1, &mut rng);
534          test_circuit(num_constraints, num_variables, VarunaVersion::V2, &mut rng);
535          test_serde_json(num_constraints, num_variables, &mut rng);
536          test_bincode(num_constraints, num_variables, &mut rng);
537      }
538  
539      #[test]
540      fn prove_and_verify_with_square_matrix() {
541          let num_constraints = 25;
542          let num_variables = 25;
543          let mut rng = TestRng::default();
544  
545          test_circuit(num_constraints, num_variables, VarunaVersion::V1, &mut rng);
546          test_circuit(num_constraints, num_variables, VarunaVersion::V2, &mut rng);
547          test_serde_json(num_constraints, num_variables, &mut rng);
548          test_bincode(num_constraints, num_variables, &mut rng);
549      }
550  
551      #[test]
552      fn prove_and_verify_with_large_matrix() {
553          let num_constraints = 1 << 16;
554          let num_variables = 1 << 16;
555          let mut rng = TestRng::default();
556  
557          test_circuit_n_times(num_constraints, num_variables, 1, VarunaVersion::V1, &mut rng);
558          test_circuit_n_times(num_constraints, num_variables, 1, VarunaVersion::V2, &mut rng);
559      }
560  
561      #[test]
562      fn check_indexing() {
563          let rng = &mut TestRng::default();
564          let mul_depth = 2;
565          let num_constraints = 1 << 13;
566          let num_variables = 1 << 13;
567          let (circuit, public_inputs) = TestCircuit::gen_rand(mul_depth, num_constraints, num_variables, rng);
568  
569          let max_degree = AHPForR1CS::<Fr, VarunaHidingMode>::max_degree(100, 25, 300).unwrap();
570          let universal_srs = VarunaInst::universal_setup(max_degree).unwrap();
571          let universal_prover = &universal_srs.to_universal_prover().unwrap();
572          let universal_verifier = &universal_srs.to_universal_verifier().unwrap();
573          let fs_parameters = FS::sample_parameters();
574          for varuna_version in [VarunaVersion::V1, VarunaVersion::V2] {
575              let wrong_varuna_version = match varuna_version {
576                  VarunaVersion::V1 => VarunaVersion::V2,
577                  VarunaVersion::V2 => VarunaVersion::V1,
578              };
579              let (index_pk, index_vk) = VarunaInst::circuit_setup(&universal_srs, &circuit).unwrap();
580              println!("Called circuit setup");
581  
582              let proof =
583                  VarunaInst::prove(universal_prover, &fs_parameters, &index_pk, varuna_version, &circuit, rng).unwrap();
584              println!("Called prover");
585  
586              universal_srs.download_powers_for(0..2usize.pow(18)).unwrap();
587              let (new_pk, new_vk) = VarunaInst::circuit_setup(&universal_srs, &circuit).unwrap();
588              assert_eq!(index_pk, new_pk);
589              assert_eq!(index_vk, new_vk);
590              assert!(
591                  VarunaInst::verify(
592                      universal_verifier,
593                      &fs_parameters,
594                      &index_vk,
595                      varuna_version,
596                      public_inputs.clone(),
597                      &proof,
598                  )
599                  .unwrap()
600              );
601              assert!(
602                  VarunaInst::verify(
603                      universal_verifier,
604                      &fs_parameters,
605                      &new_vk,
606                      varuna_version,
607                      public_inputs.clone(),
608                      &proof
609                  )
610                  .unwrap()
611              );
612              assert!(
613                  !VarunaInst::verify(
614                      universal_verifier,
615                      &fs_parameters,
616                      &index_vk,
617                      wrong_varuna_version,
618                      public_inputs.clone(),
619                      &proof,
620                  )
621                  .unwrap()
622              );
623          }
624      }
625  
626      #[test]
627      fn test_srs_downloads() {
628          let rng = &mut TestRng::default();
629  
630          let max_degree = AHPForR1CS::<Fr, VarunaHidingMode>::max_degree(100, 25, 300).unwrap();
631          let universal_srs = VarunaInst::universal_setup(max_degree).unwrap();
632          let universal_prover = &universal_srs.to_universal_prover().unwrap();
633          let universal_verifier = &universal_srs.to_universal_verifier().unwrap();
634          let fs_parameters = FS::sample_parameters();
635          let varuna_version = VarunaVersion::V2;
636  
637          // Indexing, proving, and verifying for a circuit with 1 << 15 constraints and 1
638          // << 15 variables.
639          let mul_depth = 2;
640          let num_constraints = 2usize.pow(15) - 10;
641          let num_variables = 2usize.pow(15) - 10;
642          let (circuit1, public_inputs1) = TestCircuit::gen_rand(mul_depth, num_constraints, num_variables, rng);
643          let (pk1, vk1) = VarunaInst::circuit_setup(&universal_srs, &circuit1).unwrap();
644          println!("Called circuit setup");
645  
646          let proof1 = VarunaInst::prove(universal_prover, &fs_parameters, &pk1, varuna_version, &circuit1, rng).unwrap();
647          println!("Called prover");
648          assert!(
649              VarunaInst::verify(
650                  universal_verifier,
651                  &fs_parameters,
652                  &vk1,
653                  varuna_version,
654                  public_inputs1.clone(),
655                  &proof1
656              )
657              .unwrap()
658          );
659  
660          /***************************************************************************
661           * * */
662  
663          // Indexing, proving, and verifying for a circuit with 1 << 19 constraints and 1
664          // << 19 variables.
665          let mul_depth = 2;
666          let num_constraints = 2usize.pow(19) - 10;
667          let num_variables = 2usize.pow(19) - 10;
668          let (circuit2, public_inputs2) = TestCircuit::gen_rand(mul_depth, num_constraints, num_variables, rng);
669          let (pk2, vk2) = VarunaInst::circuit_setup(&universal_srs, &circuit2).unwrap();
670          println!("Called circuit setup");
671  
672          let proof2 = VarunaInst::prove(universal_prover, &fs_parameters, &pk2, varuna_version, &circuit2, rng).unwrap();
673          println!("Called prover");
674          assert!(
675              VarunaInst::verify(universal_verifier, &fs_parameters, &vk2, varuna_version, public_inputs2, &proof2)
676                  .unwrap()
677          );
678          /***************************************************************************
679           * * */
680          assert!(
681              VarunaInst::verify(universal_verifier, &fs_parameters, &vk1, varuna_version, public_inputs1, &proof1)
682                  .unwrap()
683          );
684      }
685  }
686  
687  mod varuna_test_vectors {
688      use crate::{
689          fft::EvaluationDomain,
690          snark::varuna::{AHPForR1CS, TestCircuit, VarunaNonHidingMode, VarunaSNARK, VarunaVersion, ahp::verifier},
691          traits::snark::SNARK,
692      };
693      use deltavm_curves::bls12_377::{Bls12_377, Fq, Fr};
694      use deltavm_fields::One;
695      use std::{collections::BTreeMap, fs, ops::Deref, path::PathBuf, str::FromStr, sync::Arc};
696  
697      type FS = crate::crypto_hash::PoseidonSponge<Fq, 2, 1>;
698      type MM = VarunaNonHidingMode;
699      type VarunaSonicInst = VarunaSNARK<Bls12_377, FS, MM>;
700  
701      // Create the path for the `resources` folder.
702      fn resources_path(create_dir: bool) -> PathBuf {
703          let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
704          path.push("src");
705          path.push("snark");
706          path.push("varuna");
707          path.push("resources");
708  
709          // Create the `resources` folder, if it does not exist.
710          if !path.exists() {
711              if create_dir {
712                  fs::create_dir(&path).unwrap_or_else(|_| panic!("Failed to create resources folder: {path:?}"));
713              } else {
714                  panic!("Resources folder does not exist: {path:?}");
715              }
716          }
717  
718          path
719      }
720  
721      // Create the file path.
722      fn test_vector_path(folder: &str, file: &str, circuit: &str, create_dir: bool) -> PathBuf {
723          let mut path = resources_path(create_dir);
724  
725          // Construct the path where the test data lives.
726          path.push(circuit);
727          path.push(folder);
728  
729          // Create the test folder if it does not exist if specified, otherwise panic.
730          if !path.exists() {
731              if create_dir {
732                  fs::create_dir(&path).unwrap_or_else(|_| panic!("Failed to create resources folder: {path:?}"));
733              } else {
734                  panic!("Resources folder does not exist: {path:?}");
735              }
736          }
737  
738          // Construct the path for the test file.
739          path.push(file);
740          path.set_extension("txt");
741  
742          path
743      }
744  
745      // Loads the given `test_folder/test_file` and asserts the given `candidate`
746      // matches the expected values.
747      #[track_caller]
748      fn assert_test_vector_equality(test_folder: &str, test_file: &str, candidate: &str, circuit: &str) {
749          // Get the path to the test file.
750          let path = test_vector_path(test_folder, test_file, circuit, false);
751  
752          // Assert the test file is equal to the expected value.
753          expect_test::expect_file![path].assert_eq(candidate);
754      }
755  
756      // Create a test vector from a trusted revision of Varuna.
757      fn create_test_vector(folder: &str, file: &str, data: &str, circuit: &str) {
758          // Get the path to the test file.
759          let path = test_vector_path(folder, file, circuit, true);
760  
761          // Write the test vector to file.
762          fs::write(&path, data).unwrap_or_else(|_| panic!("Failed to write to file: {path:?}"));
763      }
764  
765      // Tests varuna against the test vectors in all circuits in the resources
766      // folder.
767      fn test_varuna_with_all_circuits(create_test_vectors: bool) {
768          let entries = fs::read_dir(resources_path(create_test_vectors)).expect("Failed to read resources folder");
769          entries.into_iter().for_each(|entry| {
770              let path = entry.unwrap().path();
771              if path.is_dir() {
772                  let circuit = path.file_name().unwrap().to_str().unwrap();
773                  test_circuit_with_test_vectors(create_test_vectors, circuit);
774              }
775          });
776      }
777  
778      // Test Varuna against test vectors for a specific circuit.
779      fn test_circuit_with_test_vectors(create_test_vectors: bool, circuit: &str) {
780          // Initialize the parts of the witness used in the multiplicative constraints.
781          let witness_path = format!("src/snark/varuna/resources/{circuit}/witness.input");
782          let instance_file = fs::read_to_string(witness_path).expect("Could not read the file");
783          let witness: Vec<u128> = serde_json::from_str(instance_file.lines().next().unwrap()).unwrap();
784          let (a, b) = (witness[0], witness[1]);
785  
786          // Initialize challenges from file.
787          let challenges_path = format!("src/snark/varuna/resources/{circuit}/challenges.input");
788          let challenges_file = fs::read_to_string(challenges_path).expect("Could not read the file");
789          let mut challenges = Vec::new();
790          for line in challenges_file.lines() {
791              challenges.push(line)
792          }
793          let (alpha, _eta_a, eta_b, eta_c, beta, delta_a, delta_b, delta_c, _gamma) = (
794              Fr::from_str(challenges[0]).unwrap(),
795              Fr::from_str(challenges[1]).unwrap(),
796              Fr::from_str(challenges[2]).unwrap(),
797              Fr::from_str(challenges[3]).unwrap(),
798              Fr::from_str(challenges[4]).unwrap(),
799              vec![Fr::from_str(challenges[5]).unwrap()],
800              vec![Fr::from_str(challenges[6]).unwrap()],
801              vec![Fr::from_str(challenges[7]).unwrap()],
802              Fr::from_str(challenges[8]).unwrap(),
803          );
804  
805          let circuit_combiner = Fr::one();
806          let instance_combiners = vec![Fr::one()];
807  
808          // Create sample circuit which corresponds to instance.input file.
809          let mul_depth = 3;
810          let num_constraints = 7;
811          let num_variables = 7;
812  
813          // Create a fixed seed rng that matches those the test vectors were generated
814          // with.
815          let rng = &mut deltavm_utilities::rand::TestRng::fixed(4730);
816          let max_degree =
817              AHPForR1CS::<Fr, MM>::max_degree(num_constraints, num_variables, num_variables * num_constraints).unwrap();
818          let universal_srs = VarunaSonicInst::universal_setup(max_degree).unwrap();
819          let (circ, _) =
820              TestCircuit::generate_circuit_with_fixed_witness(a, b, mul_depth, num_constraints, num_variables);
821          println!("Circuit: {circ:?}");
822          let (index_pk, _index_vk) = VarunaSonicInst::circuit_setup(&universal_srs, &circ).unwrap();
823          let mut keys_to_constraints = BTreeMap::new();
824          keys_to_constraints.insert(index_pk.circuit.deref(), std::slice::from_ref(&circ));
825  
826          // Begin the Varuna protocol execution.
827          let prover_state = AHPForR1CS::<_, MM>::init_prover(&keys_to_constraints, rng).unwrap();
828          let mut prover_state = AHPForR1CS::<_, MM>::prover_first_round(prover_state, rng).unwrap();
829          let first_round_oracles = Arc::new(prover_state.first_round_oracles.as_ref().unwrap());
830  
831          // Get private witness polynomial coefficients.
832          let (_, w_poly) = first_round_oracles.batches.iter().next().unwrap();
833          let w_lde = format!("{:?}", w_poly[0].0.coeffs().map(|(_, coeff)| coeff).collect::<Vec<_>>());
834          if create_test_vectors {
835              create_test_vector("polynomials", "w_lde", &w_lde, circuit);
836          }
837  
838          // Generate test vectors from assignments.
839          let assignments = AHPForR1CS::<_, MM>::calculate_assignments(&mut prover_state).unwrap();
840  
841          // Get full witness polynomial coefficients.
842          let (_, z_poly) = assignments.iter().next().unwrap();
843          let z_lde = format!("{:?}", z_poly[0].coeffs().iter().collect::<Vec<_>>());
844          if create_test_vectors {
845              create_test_vector("polynomials", "z_lde", &z_lde, circuit);
846          }
847  
848          let combiners = verifier::BatchCombiners::<Fr> { circuit_combiner, instance_combiners };
849          let first_round_batch_combiners = BTreeMap::from_iter([(index_pk.circuit.id, combiners)]);
850          let verifier_first_msg = verifier::FirstMessage::<Fr> { first_round_batch_combiners };
851  
852          let (second_oracles, prover_state) =
853              AHPForR1CS::<_, MM>::prover_second_round::<_>(&verifier_first_msg, prover_state, rng).unwrap();
854  
855          // Get round 2 rowcheck polynomial oracle coefficients.
856          let h_0 = format!("{:?}", second_oracles.h_0.coeffs().map(|(_, coeff)| coeff).collect::<Vec<_>>());
857          if create_test_vectors {
858              create_test_vector("polynomials", "h_0", &h_0, circuit);
859          }
860  
861          let verifier_second_msg = verifier::SecondMessage::<Fr> { alpha, eta_b: Some(eta_b), eta_c: Some(eta_c) };
862          let (_prover_third_message, third_oracles, prover_state) = AHPForR1CS::<_, MM>::prover_third_round(
863              &verifier_first_msg,
864              &verifier_second_msg,
865              &None,
866              prover_state,
867              rng,
868              VarunaVersion::V1,
869          )
870          .unwrap();
871  
872          // Get coefficients round 3 univariate rowcheck polynomial oracles.
873          let g_1 = format!("{:?}", third_oracles.g_1.coeffs().map(|(_, coeff)| coeff).collect::<Vec<_>>());
874          if create_test_vectors {
875              create_test_vector("polynomials", "g_1", &g_1, circuit);
876          }
877          let h_1 = format!("{:?}", third_oracles.h_1.coeffs().map(|(_, coeff)| coeff).collect::<Vec<_>>());
878          if create_test_vectors {
879              create_test_vector("polynomials", "h_1", &h_1, circuit);
880          }
881  
882          let verifier_third_msg = verifier::ThirdMessage::<Fr> { beta };
883          let (_prover_fourth_message, fourth_oracles, prover_state) =
884              AHPForR1CS::<_, MM>::prover_fourth_round(&verifier_second_msg, &verifier_third_msg, prover_state, rng)
885                  .unwrap();
886  
887          // Create round 4 rational sumcheck oracle polynomials.
888          let (_, gm_polys) = fourth_oracles.gs.iter().next().unwrap();
889          let g_a = format!("{:?}", gm_polys.g_a.coeffs().map(|(_, coeff)| coeff).collect::<Vec<_>>());
890          let g_b = format!("{:?}", gm_polys.g_b.coeffs().map(|(_, coeff)| coeff).collect::<Vec<_>>());
891          let g_c = format!("{:?}", gm_polys.g_b.coeffs().map(|(_, coeff)| coeff).collect::<Vec<_>>());
892          if create_test_vectors {
893              create_test_vector("polynomials", "g_a", &g_a, circuit);
894              create_test_vector("polynomials", "g_b", &g_b, circuit);
895              create_test_vector("polynomials", "g_c", &g_c, circuit);
896          }
897  
898          // Create the verifier's fourth message.
899          let verifier_fourth_msg = verifier::FourthMessage::<Fr> { delta_a, delta_b, delta_c };
900  
901          let mut public_inputs = BTreeMap::new();
902          let public_input = prover_state.public_inputs(&index_pk.circuit).unwrap();
903          public_inputs.insert(index_pk.circuit.id, public_input);
904          let non_zero_a_domain = EvaluationDomain::<Fr>::new(index_pk.circuit.index_info.num_non_zero_a).unwrap();
905          let non_zero_b_domain = EvaluationDomain::<Fr>::new(index_pk.circuit.index_info.num_non_zero_b).unwrap();
906          let non_zero_c_domain = EvaluationDomain::<Fr>::new(index_pk.circuit.index_info.num_non_zero_c).unwrap();
907          let variable_domain =
908              EvaluationDomain::<Fr>::new(index_pk.circuit.index_info.num_public_and_private_variables).unwrap();
909          let constraint_domain = EvaluationDomain::<Fr>::new(index_pk.circuit.index_info.num_constraints).unwrap();
910          let input_domain = EvaluationDomain::<Fr>::new(index_pk.circuit.index_info.num_public_inputs).unwrap();
911  
912          // Get constraint domain elements.
913          let mut constraint_domain_elements = Vec::with_capacity(constraint_domain.size());
914          for el in constraint_domain.elements() {
915              constraint_domain_elements.push(el);
916          }
917          if create_test_vectors {
918              create_test_vector("domain", "R", &format!("{constraint_domain_elements:?}"), circuit);
919          }
920  
921          // Get non_zero_domain elements.
922          let non_zero_domain = *[&non_zero_a_domain, &non_zero_b_domain, &non_zero_c_domain]
923              .iter()
924              .max_by_key(|domain| domain.size)
925              .unwrap();
926          let mut non_zero_domain_elements = Vec::with_capacity(non_zero_domain.size());
927          for el in non_zero_domain.elements() {
928              non_zero_domain_elements.push(el);
929          }
930          if create_test_vectors {
931              create_test_vector("domain", "K", &format!("{non_zero_domain_elements:?}"), circuit);
932          }
933  
934          // Get variable domain elements.
935          let mut variable_domain_elements = Vec::with_capacity(input_domain.size());
936          for el in variable_domain.elements() {
937              variable_domain_elements.push(el);
938          }
939          if create_test_vectors {
940              create_test_vector("domain", "C", &format!("{variable_domain_elements:?}"), circuit);
941          }
942  
943          let fifth_oracles = AHPForR1CS::<_, MM>::prover_fifth_round(verifier_fourth_msg, prover_state, rng).unwrap();
944  
945          // Get coefficients of final oracle polynomial from round 5.
946          let h_2 = format!("{:?}", fifth_oracles.h_2.coeffs().map(|(_, coeff)| coeff).collect::<Vec<_>>());
947          if create_test_vectors {
948              create_test_vector("polynomials", "h_2", &h_2, circuit);
949          }
950  
951          // Check the intermediate oracle polynomials against the test vectors.
952          assert_test_vector_equality("polynomials", "w_lde", &w_lde, circuit);
953          assert_test_vector_equality("polynomials", "z_lde", &z_lde, circuit);
954          assert_test_vector_equality("polynomials", "h_0", &h_0, circuit);
955          assert_test_vector_equality("polynomials", "h_1", &h_1, circuit);
956          assert_test_vector_equality("polynomials", "g_1", &g_1, circuit);
957          assert_test_vector_equality("polynomials", "h_2", &h_2, circuit);
958          assert_test_vector_equality("polynomials", "g_a", &g_a, circuit);
959          assert_test_vector_equality("polynomials", "g_b", &g_b, circuit);
960          assert_test_vector_equality("polynomials", "g_c", &g_c, circuit);
961  
962          // Check that the domains match the test vectors.
963          assert_test_vector_equality("domain", "R", &format!("{constraint_domain_elements:?}"), circuit);
964          assert_test_vector_equality("domain", "K", &format!("{non_zero_domain_elements:?}"), circuit);
965          assert_test_vector_equality("domain", "C", &format!("{variable_domain_elements:?}"), circuit);
966      }
967  
968      #[test]
969      fn test_varuna_with_prover_test_vectors() {
970          test_varuna_with_all_circuits(false);
971      }
972  }