Explorar el Código

add mimc code

narodnik hace 6 años
padre
commit
c6e28002fd
Se han modificado 4 ficheros con 239 adiciones y 0 borrados
  1. 7 0
      Cargo.toml
  2. 7 0
      README.md
  3. 225 0
      src/mimc.rs
  4. 0 0
      src/sha256.rs

+ 7 - 0
Cargo.toml

@@ -17,3 +17,10 @@ bellman = { git = "https://github.com/zcash/librustzcash" }
 rand = "0.7.3"
 sha2 = "0.9.1"
 
+[[bin]]
+name = "sha256"
+path = "src/sha256.rs"
+
+[[bin]]
+name = "mimc"
+path = "src/mimc.rs"

+ 7 - 0
README.md

@@ -0,0 +1,7 @@
+```
+cargo run --bin sha256
+```
+
+```
+cargo run --bin mimc
+```

+ 225 - 0
src/mimc.rs

@@ -0,0 +1,225 @@
+// For randomness (during paramgen and proof generation)
+use rand::thread_rng;
+
+// For benchmarking
+use std::time::{Duration, Instant};
+
+// Bring in some tools for using finite fiels
+use ff::{Field, PrimeField};
+
+// We're going to use the BLS12-381 pairing-friendly elliptic curve.
+use pairing::bls12_381::{Bls12, Fr};
+
+// We'll use these interfaces to construct our circuit.
+use bellman::{Circuit, ConstraintSystem, SynthesisError};
+
+// We're going to use the Groth16 proving system.
+use bellman::groth16::{
+    create_random_proof, generate_random_parameters, prepare_verifying_key, verify_proof, Proof,
+};
+
+const MIMC_ROUNDS: usize = 322;
+
+/// This is an implementation of MiMC, specifically a
+/// variant named `LongsightF322p3` for BLS12-381.
+/// See http://eprint.iacr.org/2016/492 for more
+/// information about this construction.
+///
+/// ```
+/// function LongsightF322p3(xL ⦂ Fp, xR ⦂ Fp) {
+///     for i from 0 up to 321 {
+///         xL, xR := xR + (xL + Ci)^3, xL
+///     }
+///     return xL
+/// }
+/// ```
+fn mimc<Scalar: PrimeField>(mut xl: Scalar, mut xr: Scalar, constants: &[Scalar]) -> Scalar {
+    assert_eq!(constants.len(), MIMC_ROUNDS);
+
+    for i in 0..MIMC_ROUNDS {
+        let mut tmp1 = xl;
+        tmp1.add_assign(&constants[i]);
+        let mut tmp2 = tmp1.square();
+        tmp2.mul_assign(&tmp1);
+        tmp2.add_assign(&xr);
+        xr = xl;
+        xl = tmp2;
+    }
+
+    xl
+}
+
+/// This is our demo circuit for proving knowledge of the
+/// preimage of a MiMC hash invocation.
+struct MiMCDemo<'a, Scalar: PrimeField> {
+    xl: Option<Scalar>,
+    xr: Option<Scalar>,
+    constants: &'a [Scalar],
+}
+
+/// Our demo circuit implements this `Circuit` trait which
+/// is used during paramgen and proving in order to
+/// synthesize the constraint system.
+impl<'a, Scalar: PrimeField> Circuit<Scalar> for MiMCDemo<'a, Scalar> {
+    fn synthesize<CS: ConstraintSystem<Scalar>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
+        assert_eq!(self.constants.len(), MIMC_ROUNDS);
+
+        // Allocate the first component of the preimage.
+        let mut xl_value = self.xl;
+        let mut xl = cs.alloc(
+            || "preimage xl",
+            || xl_value.ok_or(SynthesisError::AssignmentMissing),
+        )?;
+
+        // Allocate the second component of the preimage.
+        let mut xr_value = self.xr;
+        let mut xr = cs.alloc(
+            || "preimage xr",
+            || xr_value.ok_or(SynthesisError::AssignmentMissing),
+        )?;
+
+        for i in 0..MIMC_ROUNDS {
+            // xL, xR := xR + (xL + Ci)^3, xL
+            let cs = &mut cs.namespace(|| format!("round {}", i));
+
+            // tmp = (xL + Ci)^2
+            let tmp_value = xl_value.map(|mut e| {
+                e.add_assign(&self.constants[i]);
+                e.square()
+            });
+            let tmp = cs.alloc(
+                || "tmp",
+                || tmp_value.ok_or(SynthesisError::AssignmentMissing),
+            )?;
+
+            cs.enforce(
+                || "tmp = (xL + Ci)^2",
+                |lc| lc + xl + (self.constants[i], CS::one()),
+                |lc| lc + xl + (self.constants[i], CS::one()),
+                |lc| lc + tmp,
+            );
+
+            // new_xL = xR + (xL + Ci)^3
+            // new_xL = xR + tmp * (xL + Ci)
+            // new_xL - xR = tmp * (xL + Ci)
+            let new_xl_value = xl_value.map(|mut e| {
+                e.add_assign(&self.constants[i]);
+                e.mul_assign(&tmp_value.unwrap());
+                e.add_assign(&xr_value.unwrap());
+                e
+            });
+
+            let new_xl = if i == (MIMC_ROUNDS - 1) {
+                // This is the last round, xL is our image and so
+                // we allocate a public input.
+                cs.alloc_input(
+                    || "image",
+                    || new_xl_value.ok_or(SynthesisError::AssignmentMissing),
+                )?
+            } else {
+                cs.alloc(
+                    || "new_xl",
+                    || new_xl_value.ok_or(SynthesisError::AssignmentMissing),
+                )?
+            };
+
+            cs.enforce(
+                || "new_xL = xR + (xL + Ci)^3",
+                |lc| lc + tmp,
+                |lc| lc + xl + (self.constants[i], CS::one()),
+                |lc| lc + new_xl - xr,
+            );
+
+            // xR = xL
+            xr = xl;
+            xr_value = xl_value;
+
+            // xL = new_xL
+            xl = new_xl;
+            xl_value = new_xl_value;
+        }
+
+        Ok(())
+    }
+}
+
+fn main() {
+    // This may not be cryptographically safe, use
+    // `OsRng` (for example) in production software.
+    let rng = &mut thread_rng();
+
+    // Generate the MiMC round constants
+    let constants = (0..MIMC_ROUNDS)
+        .map(|_| Fr::random(rng))
+        .collect::<Vec<_>>();
+
+    println!("Creating parameters...");
+
+    // Create parameters for our circuit
+    let params = {
+        let c = MiMCDemo {
+            xl: None,
+            xr: None,
+            constants: &constants,
+        };
+
+        generate_random_parameters::<Bls12, _, _>(c, rng).unwrap()
+    };
+
+    // Prepare the verification key (for proof verification)
+    let pvk = prepare_verifying_key(&params.vk);
+
+    println!("Creating proofs...");
+
+    // Let's benchmark stuff!
+    const SAMPLES: u32 = 50;
+    let mut total_proving = Duration::new(0, 0);
+    let mut total_verifying = Duration::new(0, 0);
+
+    // Just a place to put the proof data, so we can
+    // benchmark deserialization.
+    let mut proof_vec = vec![];
+
+    for _ in 0..SAMPLES {
+        // Generate a random preimage and compute the image
+        let xl = Fr::random(rng);
+        let xr = Fr::random(rng);
+        let image = mimc(xl, xr, &constants);
+
+        proof_vec.truncate(0);
+
+        let start = Instant::now();
+        {
+            // Create an instance of our circuit (with the
+            // witness)
+            let c = MiMCDemo {
+                xl: Some(xl),
+                xr: Some(xr),
+                constants: &constants,
+            };
+
+            // Create a groth16 proof with our parameters.
+            let proof = create_random_proof(c, &params, rng).unwrap();
+
+            proof.write(&mut proof_vec).unwrap();
+        }
+
+        total_proving += start.elapsed();
+
+        let start = Instant::now();
+        let proof = Proof::read(&proof_vec[..]).unwrap();
+        // Check the proof
+        assert!(verify_proof(&pvk, &proof, &[image]).is_ok());
+        total_verifying += start.elapsed();
+    }
+    let proving_avg = total_proving / SAMPLES;
+    let proving_avg =
+        proving_avg.subsec_nanos() as f64 / 1_000_000_000f64 + (proving_avg.as_secs() as f64);
+
+    let verifying_avg = total_verifying / SAMPLES;
+    let verifying_avg =
+        verifying_avg.subsec_nanos() as f64 / 1_000_000_000f64 + (verifying_avg.as_secs() as f64);
+
+    println!("Average proving time: {:?} seconds", proving_avg);
+    println!("Average verifying time: {:?} seconds", verifying_avg);
+}

+ 0 - 0
src/main.rs → src/sha256.rs