mimc.rs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. // For randomness (during paramgen and proof generation)
  2. //use rand::thread_rng;
  3. // For benchmarking
  4. use std::time::{Duration, Instant};
  5. // from string scalar
  6. use drk::bls_extensions::BlsStringConversion;
  7. // Bring in some tools for using finite fiels
  8. use ff::PrimeField;
  9. // mimc constants
  10. //mod mimc_constants;
  11. //use mimc_constants::mimc_constants;
  12. // We're going to use the BLS12-381 pairing-friendly elliptic curve.
  13. use bls12_381::Bls12;
  14. // We'll use these interfaces to construct our circuit.
  15. use bellman::{Circuit, ConstraintSystem, SynthesisError};
  16. // We're going to use the Groth16 proving system.
  17. use bellman::groth16::{
  18. create_random_proof, generate_random_parameters, prepare_verifying_key, verify_proof, Proof,
  19. };
  20. const MIMC_ROUNDS: usize = 322;
  21. /// This is an implementation of MiMC, specifically a
  22. /// variant named `LongsightF322p3` for BLS12-381.
  23. /// See http://eprint.iacr.org/2016/492 for more
  24. /// information about this construction.
  25. ///
  26. /// ```
  27. /// function LongsightF322p3(xL ⦂ Fp, xR ⦂ Fp) {
  28. /// for i from 0 up to 321 {
  29. /// xL, xR := xR + (xL + Ci)^3, xL
  30. /// }
  31. /// return xL
  32. /// }
  33. /// ```
  34. fn mimc<Scalar: PrimeField>(mut xl: Scalar, mut xr: Scalar, constants: &[Scalar]) -> Scalar {
  35. assert_eq!(constants.len(), MIMC_ROUNDS);
  36. for i in 0..MIMC_ROUNDS {
  37. let mut tmp1 = xl;
  38. tmp1.add_assign(&constants[i]);
  39. let mut tmp2 = tmp1.square();
  40. tmp2.mul_assign(&tmp1);
  41. tmp2.add_assign(&xr);
  42. xr = xl;
  43. xl = tmp2;
  44. }
  45. xl
  46. }
  47. //macro_rules! from_slice {
  48. // ($data:expr, $len:literal) => {{
  49. // let mut array = [0; $len];
  50. // // panics if not enough data
  51. // let bytes = &$data[..array.len()];
  52. // assert_eq!(bytes.len(), array.len());
  53. // for (a, b) in array.iter_mut().rev().zip(bytes.iter()) {
  54. // *a = *b;
  55. // }
  56. // //array.copy_from_slice(bytes.iter().rev());
  57. // array
  58. // }};
  59. //}
  60. /// This is our demo circuit for proving knowledge of the
  61. /// preimage of a MiMC hash invocation.
  62. struct MiMCDemo<'a, Scalar: PrimeField> {
  63. xl: Option<Scalar>,
  64. xr: Option<Scalar>,
  65. constants: &'a [Scalar],
  66. }
  67. /// Our demo circuit implements this `Circuit` trait which
  68. /// is used during paramgen and proving in order to
  69. /// synthesize the constraint system.
  70. impl<'a, Scalar: PrimeField> Circuit<Scalar> for MiMCDemo<'a, Scalar> {
  71. fn synthesize<CS: ConstraintSystem<Scalar>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
  72. assert_eq!(self.constants.len(), MIMC_ROUNDS);
  73. // Allocate the first component of the preimage.
  74. let mut xl_value = self.xl;
  75. let mut xl = cs.alloc(
  76. || "preimage xl",
  77. || xl_value.ok_or(SynthesisError::AssignmentMissing),
  78. )?;
  79. // Allocate the second component of the preimage.
  80. let mut xr_value = self.xr;
  81. let mut xr = cs.alloc(
  82. || "preimage xr",
  83. || xr_value.ok_or(SynthesisError::AssignmentMissing),
  84. )?;
  85. for i in 0..MIMC_ROUNDS {
  86. // xL, xR := xR + (xL + Ci)^3, xL
  87. let cs = &mut cs.namespace(|| format!("round {}", i));
  88. // tmp = (xL + Ci)^2
  89. let tmp_value = xl_value.map(|mut e| {
  90. println!("{:?}", e);
  91. e.add_assign(&self.constants[i]);
  92. e.square()
  93. });
  94. // println!("tmp_value {:?} {:?}", self.constants[i], tmp_value);
  95. let tmp = cs.alloc(
  96. || "tmp",
  97. || tmp_value.ok_or(SynthesisError::AssignmentMissing),
  98. )?;
  99. cs.enforce(
  100. || "tmp = (xL + Ci)^2",
  101. |lc| lc + xl + (self.constants[i], CS::one()),
  102. |lc| lc + xl + (self.constants[i], CS::one()),
  103. |lc| lc + tmp,
  104. );
  105. // new_xL = xR + (xL + Ci)^3
  106. // new_xL = xR + tmp * (xL + Ci)
  107. // new_xL - xR = tmp * (xL + Ci)
  108. let new_xl_value = xl_value.map(|mut e| {
  109. e.add_assign(&self.constants[i]);
  110. e.mul_assign(&tmp_value.unwrap());
  111. e.add_assign(&xr_value.unwrap());
  112. e
  113. });
  114. let new_xl = if i == (MIMC_ROUNDS - 1) {
  115. // This is the last round, xL is our image and so
  116. // we allocate a public input.
  117. cs.alloc_input(
  118. || "image",
  119. || new_xl_value.ok_or(SynthesisError::AssignmentMissing),
  120. )?
  121. } else {
  122. cs.alloc(
  123. || "new_xl",
  124. || new_xl_value.ok_or(SynthesisError::AssignmentMissing),
  125. )?
  126. };
  127. cs.enforce(
  128. || "new_xL = xR + (xL + Ci)^3",
  129. |lc| lc + tmp,
  130. |lc| lc + xl + (self.constants[i], CS::one()),
  131. |lc| lc + new_xl - xr,
  132. );
  133. println!("{:?}", i);
  134. println!("{:?} {:?}", xl_value, xr_value);
  135. println!("{:?}", new_xl_value);
  136. // xR = xL
  137. xr = xl;
  138. xr_value = xl_value;
  139. // xL = new_xL
  140. xl = new_xl;
  141. xl_value = new_xl_value;
  142. }
  143. Ok(())
  144. }
  145. }
  146. fn main() {
  147. use rand::rngs::OsRng;
  148. // // Generate the MiMC round constants
  149. // let constants = (0..MIMC_ROUNDS)
  150. // .map(|_| Scalar::random(&mut OsRng))
  151. // .collect::<Vec<_>>();
  152. let constants = Vec::new();
  153. /*
  154. for const_str in mimc_constants() {
  155. let bytes = from_slice!(&hex::decode(const_str).unwrap(), 32);
  156. assert_eq!(bytes.len(), 32);
  157. let constant = Scalar::from_bytes(&bytes).unwrap();
  158. constants.push(constant);
  159. }
  160. */
  161. println!("Creating parameters...");
  162. // Create parameters for our circuit
  163. let params = {
  164. let c = MiMCDemo {
  165. xl: None,
  166. xr: None,
  167. constants: &constants,
  168. };
  169. generate_random_parameters::<Bls12, _, _>(c, &mut OsRng).unwrap()
  170. };
  171. // Prepare the verification key (for proof verification)
  172. let pvk = prepare_verifying_key(&params.vk);
  173. println!("Creating proofs...");
  174. // Let's benchmark stuff!
  175. const SAMPLES: u32 = 1;
  176. let mut total_proving = Duration::new(0, 0);
  177. let mut total_verifying = Duration::new(0, 0);
  178. // Just a place to put the proof data, so we can
  179. // benchmark deserialization.
  180. let mut proof_vec = vec![];
  181. for _ in 0..SAMPLES {
  182. // Generate a random preimage and compute the image
  183. // let xl = Scalar::random(&mut OsRng);
  184. // let xr = Scalar::random(&mut OsRng);
  185. let xl = bls12_381::Scalar::from_string(
  186. "15a36d1f0f390d8852a35a8c1908dd87a361ee3fd48fdf77b9819dc82d90607e",
  187. );
  188. let xr = bls12_381::Scalar::from_string(
  189. "015d8c7f5b43fe33f7891142c001d9251f3abeeb98fad3e87b0dc53c4ebf1891",
  190. );
  191. let image = mimc(xl, xr, &constants);
  192. proof_vec.truncate(0);
  193. let start = Instant::now();
  194. {
  195. // Create an instance of our circuit (with the
  196. // witness)
  197. let c = MiMCDemo {
  198. xl: Some(xl),
  199. xr: Some(xr),
  200. constants: &constants,
  201. };
  202. // Create a groth16 proof with our parameters.
  203. let proof = create_random_proof(c, &params, &mut OsRng).unwrap();
  204. proof.write(&mut proof_vec).unwrap();
  205. }
  206. total_proving += start.elapsed();
  207. let start = Instant::now();
  208. let proof = Proof::read(&proof_vec[..]).unwrap();
  209. // Check the proof
  210. assert!(verify_proof(&pvk, &proof, &[image]).is_ok());
  211. total_verifying += start.elapsed();
  212. }
  213. let proving_avg = total_proving / SAMPLES;
  214. //let proving_avg =
  215. // proving_avg.subsec_nanos() as f64 / 1_000_000_000f64 +
  216. // (proving_avg.as_secs() as f64);
  217. let verifying_avg = total_verifying / SAMPLES;
  218. //let verifying_avg =
  219. // verifying_avg.subsec_nanos() as f64 / 1_000_000_000f64 +
  220. // (verifying_avg.as_secs() as f64);
  221. println!("Average proving time: {:?} seconds", proving_avg);
  222. println!("Average verifying time: {:?} seconds", verifying_avg);
  223. }