You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

154 lines
4.0 KiB

  1. #![allow(non_snake_case)]
  2. use bellperson::{gadgets::num::AllocatedNum, ConstraintSystem, SynthesisError};
  3. use core::marker::PhantomData;
  4. use criterion::*;
  5. use ff::PrimeField;
  6. use nova_snark::{
  7. traits::{
  8. circuit::{StepCircuit, TrivialTestCircuit},
  9. Group,
  10. },
  11. CompressedSNARK, PublicParams, RecursiveSNARK,
  12. };
  13. use std::time::Duration;
  14. type G1 = pasta_curves::pallas::Point;
  15. type G2 = pasta_curves::vesta::Point;
  16. type S1 = nova_snark::spartan_with_ipa_pc::RelaxedR1CSSNARK<G1>;
  17. type S2 = nova_snark::spartan_with_ipa_pc::RelaxedR1CSSNARK<G2>;
  18. type C1 = NonTrivialTestCircuit<<G1 as Group>::Scalar>;
  19. type C2 = TrivialTestCircuit<<G2 as Group>::Scalar>;
  20. criterion_group! {
  21. name = compressed_snark;
  22. config = Criterion::default().warm_up_time(Duration::from_millis(3000));
  23. targets = bench_compressed_snark
  24. }
  25. criterion_main!(compressed_snark);
  26. fn bench_compressed_snark(c: &mut Criterion) {
  27. let num_samples = 10;
  28. // we vary the number of constraints in the step circuit
  29. for &log_num_cons_in_step_circuit in [0, 14, 15, 16, 17, 18, 19, 20].iter() {
  30. let num_cons = 1 << log_num_cons_in_step_circuit;
  31. let mut group = c.benchmark_group(format!("CompressedSNARK-StepCircuitSize-{}", num_cons));
  32. group.sample_size(num_samples);
  33. // Produce public parameters
  34. let pp = PublicParams::<G1, G2, C1, C2>::setup(
  35. NonTrivialTestCircuit::new(num_cons),
  36. TrivialTestCircuit::default(),
  37. );
  38. // produce a recursive SNARK
  39. let num_steps = 3;
  40. let mut recursive_snark: Option<RecursiveSNARK<G1, G2, C1, C2>> = None;
  41. for i in 0..num_steps {
  42. let res = RecursiveSNARK::prove_step(
  43. &pp,
  44. recursive_snark,
  45. NonTrivialTestCircuit::new(num_cons),
  46. TrivialTestCircuit::default(),
  47. <G1 as Group>::Scalar::one(),
  48. <G2 as Group>::Scalar::one(),
  49. );
  50. assert!(res.is_ok());
  51. let recursive_snark_unwrapped = res.unwrap();
  52. // verify the recursive snark at each step of recursion
  53. let res = recursive_snark_unwrapped.verify(
  54. &pp,
  55. i + 1,
  56. <G1 as Group>::Scalar::one(),
  57. <G2 as Group>::Scalar::one(),
  58. );
  59. assert!(res.is_ok());
  60. // set the running variable for the next iteration
  61. recursive_snark = Some(recursive_snark_unwrapped);
  62. }
  63. // Bench time to produce a compressed SNARK
  64. let recursive_snark = recursive_snark.unwrap();
  65. group.bench_function("Prove", |b| {
  66. b.iter(|| {
  67. assert!(CompressedSNARK::<_, _, _, _, S1, S2>::prove(
  68. black_box(&pp),
  69. black_box(&recursive_snark)
  70. )
  71. .is_ok());
  72. })
  73. });
  74. let res = CompressedSNARK::<_, _, _, _, S1, S2>::prove(&pp, &recursive_snark);
  75. assert!(res.is_ok());
  76. let compressed_snark = res.unwrap();
  77. // Benchmark the verification time
  78. group.bench_function("Verify", |b| {
  79. b.iter(|| {
  80. assert!(black_box(&compressed_snark)
  81. .verify(
  82. black_box(&pp),
  83. black_box(num_steps),
  84. black_box(<G1 as Group>::Scalar::one()),
  85. black_box(<G2 as Group>::Scalar::one()),
  86. )
  87. .is_ok());
  88. })
  89. });
  90. group.finish();
  91. }
  92. }
  93. #[derive(Clone, Debug, Default)]
  94. struct NonTrivialTestCircuit<F: PrimeField> {
  95. num_cons: usize,
  96. _p: PhantomData<F>,
  97. }
  98. impl<F> NonTrivialTestCircuit<F>
  99. where
  100. F: PrimeField,
  101. {
  102. pub fn new(num_cons: usize) -> Self {
  103. Self {
  104. num_cons,
  105. _p: Default::default(),
  106. }
  107. }
  108. }
  109. impl<F> StepCircuit<F> for NonTrivialTestCircuit<F>
  110. where
  111. F: PrimeField,
  112. {
  113. fn synthesize<CS: ConstraintSystem<F>>(
  114. &self,
  115. cs: &mut CS,
  116. z: AllocatedNum<F>,
  117. ) -> Result<AllocatedNum<F>, SynthesisError> {
  118. // Consider a an equation: `x^2 = y`, where `x` and `y` are respectively the input and output.
  119. let mut x = z;
  120. let mut y = x.clone();
  121. for i in 0..self.num_cons {
  122. y = x.square(cs.namespace(|| format!("x_sq_{}", i)))?;
  123. x = y.clone();
  124. }
  125. Ok(y)
  126. }
  127. fn compute(&self, z: &F) -> F {
  128. let mut x = *z;
  129. let mut y = x;
  130. for _i in 0..self.num_cons {
  131. y = x * x;
  132. x = y;
  133. }
  134. y
  135. }
  136. }