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.

297 lines
9.1 KiB

  1. //! Demonstrates how to use Nova to produce a recursive proof of the correct execution of
  2. //! iterations of the MinRoot function, thereby realizing a Nova-based verifiable delay function (VDF).
  3. //! We execute a configurable number of iterations of the MinRoot function per step of Nova's recursion.
  4. type G1 = pasta_curves::pallas::Point;
  5. type G2 = pasta_curves::vesta::Point;
  6. use ::bellperson::{gadgets::num::AllocatedNum, ConstraintSystem, SynthesisError};
  7. use ff::PrimeField;
  8. use flate2::{write::ZlibEncoder, Compression};
  9. use nova_snark::{
  10. traits::{
  11. circuit::{StepCircuit, TrivialTestCircuit},
  12. Group,
  13. },
  14. CompressedSNARK, PublicParams, RecursiveSNARK,
  15. };
  16. use num_bigint::BigUint;
  17. use std::time::Instant;
  18. #[derive(Clone, Debug)]
  19. struct MinRootIteration<F: PrimeField> {
  20. x_i: F,
  21. y_i: F,
  22. x_i_plus_1: F,
  23. y_i_plus_1: F,
  24. }
  25. impl<F: PrimeField> MinRootIteration<F> {
  26. // produces a sample non-deterministic advice, executing one invocation of MinRoot per step
  27. fn new(num_iters: usize, x_0: &F, y_0: &F) -> (Vec<F>, Vec<Self>) {
  28. // although this code is written generically, it is tailored to Pallas' scalar field
  29. // (p - 3 / 5)
  30. let exp = BigUint::parse_bytes(
  31. b"23158417847463239084714197001737581570690445185553317903743794198714690358477",
  32. 10,
  33. )
  34. .unwrap();
  35. let mut res = Vec::new();
  36. let mut x_i = *x_0;
  37. let mut y_i = *y_0;
  38. for _i in 0..num_iters {
  39. let x_i_plus_1 = (x_i + y_i).pow_vartime(exp.to_u64_digits()); // computes the fifth root of x_i + y_i
  40. // sanity check
  41. let sq = x_i_plus_1 * x_i_plus_1;
  42. let quad = sq * sq;
  43. let fifth = quad * x_i_plus_1;
  44. debug_assert_eq!(fifth, x_i + y_i);
  45. let y_i_plus_1 = x_i;
  46. res.push(Self {
  47. x_i,
  48. y_i,
  49. x_i_plus_1,
  50. y_i_plus_1,
  51. });
  52. x_i = x_i_plus_1;
  53. y_i = y_i_plus_1;
  54. }
  55. let z0 = vec![*x_0, *y_0];
  56. (z0, res)
  57. }
  58. }
  59. #[derive(Clone, Debug)]
  60. struct MinRootCircuit<F: PrimeField> {
  61. seq: Vec<MinRootIteration<F>>,
  62. }
  63. impl<F> StepCircuit<F> for MinRootCircuit<F>
  64. where
  65. F: PrimeField,
  66. {
  67. fn arity(&self) -> usize {
  68. 2
  69. }
  70. fn synthesize<CS: ConstraintSystem<F>>(
  71. &self,
  72. cs: &mut CS,
  73. z: &[AllocatedNum<F>],
  74. ) -> Result<Vec<AllocatedNum<F>>, SynthesisError> {
  75. let mut z_out: Result<Vec<AllocatedNum<F>>, SynthesisError> =
  76. Err(SynthesisError::AssignmentMissing);
  77. // use the provided inputs
  78. let x_0 = z[0].clone();
  79. let y_0 = z[1].clone();
  80. // variables to hold running x_i and y_i
  81. let mut x_i = x_0;
  82. let mut y_i = y_0;
  83. for i in 0..self.seq.len() {
  84. // non deterministic advice
  85. let x_i_plus_1 =
  86. AllocatedNum::alloc(cs.namespace(|| format!("x_i_plus_1_iter_{i}")), || {
  87. Ok(self.seq[i].x_i_plus_1)
  88. })?;
  89. // check the following conditions hold:
  90. // (i) x_i_plus_1 = (x_i + y_i)^{1/5}, which can be more easily checked with x_i_plus_1^5 = x_i + y_i
  91. // (ii) y_i_plus_1 = x_i
  92. // (1) constraints for condition (i) are below
  93. // (2) constraints for condition (ii) is avoided because we just used x_i wherever y_i_plus_1 is used
  94. let x_i_plus_1_sq = x_i_plus_1.square(cs.namespace(|| format!("x_i_plus_1_sq_iter_{i}")))?;
  95. let x_i_plus_1_quad =
  96. x_i_plus_1_sq.square(cs.namespace(|| format!("x_i_plus_1_quad_{i}")))?;
  97. cs.enforce(
  98. || format!("x_i_plus_1_quad * x_i_plus_1 = x_i + y_i_iter_{i}"),
  99. |lc| lc + x_i_plus_1_quad.get_variable(),
  100. |lc| lc + x_i_plus_1.get_variable(),
  101. |lc| lc + x_i.get_variable() + y_i.get_variable(),
  102. );
  103. if i == self.seq.len() - 1 {
  104. z_out = Ok(vec![x_i_plus_1.clone(), x_i.clone()]);
  105. }
  106. // update x_i and y_i for the next iteration
  107. y_i = x_i;
  108. x_i = x_i_plus_1;
  109. }
  110. z_out
  111. }
  112. fn output(&self, z: &[F]) -> Vec<F> {
  113. // sanity check
  114. debug_assert_eq!(z[0], self.seq[0].x_i);
  115. debug_assert_eq!(z[1], self.seq[0].y_i);
  116. // compute output using advice
  117. vec![
  118. self.seq[self.seq.len() - 1].x_i_plus_1,
  119. self.seq[self.seq.len() - 1].y_i_plus_1,
  120. ]
  121. }
  122. }
  123. fn main() {
  124. println!("Nova-based VDF with MinRoot delay function");
  125. println!("=========================================================");
  126. let num_steps = 10;
  127. for num_iters_per_step in [1024, 2048, 4096, 8192, 16384, 32768, 65535] {
  128. // number of iterations of MinRoot per Nova's recursive step
  129. let circuit_primary = MinRootCircuit {
  130. seq: vec![
  131. MinRootIteration {
  132. x_i: <G1 as Group>::Scalar::zero(),
  133. y_i: <G1 as Group>::Scalar::zero(),
  134. x_i_plus_1: <G1 as Group>::Scalar::zero(),
  135. y_i_plus_1: <G1 as Group>::Scalar::zero(),
  136. };
  137. num_iters_per_step
  138. ],
  139. };
  140. let circuit_secondary = TrivialTestCircuit::default();
  141. println!("Proving {num_iters_per_step} iterations of MinRoot per step");
  142. // produce public parameters
  143. let start = Instant::now();
  144. println!("Producing public parameters...");
  145. let pp = PublicParams::<
  146. G1,
  147. G2,
  148. MinRootCircuit<<G1 as Group>::Scalar>,
  149. TrivialTestCircuit<<G2 as Group>::Scalar>,
  150. >::setup(circuit_primary.clone(), circuit_secondary.clone());
  151. println!("PublicParams::setup, took {:?} ", start.elapsed());
  152. println!(
  153. "Number of constraints per step (primary circuit): {}",
  154. pp.num_constraints().0
  155. );
  156. println!(
  157. "Number of constraints per step (secondary circuit): {}",
  158. pp.num_constraints().1
  159. );
  160. println!(
  161. "Number of variables per step (primary circuit): {}",
  162. pp.num_variables().0
  163. );
  164. println!(
  165. "Number of variables per step (secondary circuit): {}",
  166. pp.num_variables().1
  167. );
  168. // produce non-deterministic advice
  169. let (z0_primary, minroot_iterations) = MinRootIteration::new(
  170. num_iters_per_step * num_steps,
  171. &<G1 as Group>::Scalar::zero(),
  172. &<G1 as Group>::Scalar::one(),
  173. );
  174. let minroot_circuits = (0..num_steps)
  175. .map(|i| MinRootCircuit {
  176. seq: (0..num_iters_per_step)
  177. .map(|j| MinRootIteration {
  178. x_i: minroot_iterations[i * num_iters_per_step + j].x_i,
  179. y_i: minroot_iterations[i * num_iters_per_step + j].y_i,
  180. x_i_plus_1: minroot_iterations[i * num_iters_per_step + j].x_i_plus_1,
  181. y_i_plus_1: minroot_iterations[i * num_iters_per_step + j].y_i_plus_1,
  182. })
  183. .collect::<Vec<_>>(),
  184. })
  185. .collect::<Vec<_>>();
  186. let z0_secondary = vec![<G2 as Group>::Scalar::zero()];
  187. type C1 = MinRootCircuit<<G1 as Group>::Scalar>;
  188. type C2 = TrivialTestCircuit<<G2 as Group>::Scalar>;
  189. // produce a recursive SNARK
  190. println!("Generating a RecursiveSNARK...");
  191. let mut recursive_snark: RecursiveSNARK<G1, G2, C1, C2> = RecursiveSNARK::<G1, G2, C1, C2>::new(
  192. &pp,
  193. &minroot_circuits[0],
  194. &circuit_secondary,
  195. z0_primary.clone(),
  196. z0_secondary.clone(),
  197. );
  198. for (i, circuit_primary) in minroot_circuits.iter().take(num_steps).enumerate() {
  199. let start = Instant::now();
  200. let res = recursive_snark.prove_step(
  201. &pp,
  202. circuit_primary,
  203. &circuit_secondary,
  204. z0_primary.clone(),
  205. z0_secondary.clone(),
  206. );
  207. assert!(res.is_ok());
  208. println!(
  209. "RecursiveSNARK::prove_step {}: {:?}, took {:?} ",
  210. i,
  211. res.is_ok(),
  212. start.elapsed()
  213. );
  214. }
  215. // verify the recursive SNARK
  216. println!("Verifying a RecursiveSNARK...");
  217. let start = Instant::now();
  218. let res = recursive_snark.verify(&pp, num_steps, &z0_primary, &z0_secondary);
  219. println!(
  220. "RecursiveSNARK::verify: {:?}, took {:?}",
  221. res.is_ok(),
  222. start.elapsed()
  223. );
  224. assert!(res.is_ok());
  225. // produce a compressed SNARK
  226. println!("Generating a CompressedSNARK using Spartan with IPA-PC...");
  227. let (pk, vk) = CompressedSNARK::<_, _, _, _, S1, S2>::setup(&pp).unwrap();
  228. let start = Instant::now();
  229. type EE1 = nova_snark::provider::ipa_pc::EvaluationEngine<G1>;
  230. type EE2 = nova_snark::provider::ipa_pc::EvaluationEngine<G2>;
  231. type S1 = nova_snark::spartan::snark::RelaxedR1CSSNARK<G1, EE1>;
  232. type S2 = nova_snark::spartan::snark::RelaxedR1CSSNARK<G2, EE2>;
  233. let res = CompressedSNARK::<_, _, _, _, S1, S2>::prove(&pp, &pk, &recursive_snark);
  234. println!(
  235. "CompressedSNARK::prove: {:?}, took {:?}",
  236. res.is_ok(),
  237. start.elapsed()
  238. );
  239. assert!(res.is_ok());
  240. let compressed_snark = res.unwrap();
  241. let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default());
  242. bincode::serialize_into(&mut encoder, &compressed_snark).unwrap();
  243. let compressed_snark_encoded = encoder.finish().unwrap();
  244. println!(
  245. "CompressedSNARK::len {:?} bytes",
  246. compressed_snark_encoded.len()
  247. );
  248. // verify the compressed SNARK
  249. println!("Verifying a CompressedSNARK...");
  250. let start = Instant::now();
  251. let res = compressed_snark.verify(&vk, num_steps, z0_primary, z0_secondary);
  252. println!(
  253. "CompressedSNARK::verify: {:?}, took {:?}",
  254. res.is_ok(),
  255. start.elapsed()
  256. );
  257. assert!(res.is_ok());
  258. println!("=========================================================");
  259. }
  260. }