Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[package]
name = "phase2"
version = "0.2.2"
version = "0.3.0"
edition = "2021"
authors = ["Sean Bowe <ewillbefull@gmail.com>"]
description = "Library for performing MPCs for creating zk-SNARK public parameters"
documentation = "https://docs.rs/phase2"
Expand All @@ -9,9 +10,13 @@ license = "MIT/Apache-2.0"
repository = "https://github.com/ebfull/phase2"

[dependencies]
pairing = "0.14"
rand = "0.4"
bellman = "0.1"
pairing = "0.23.0"
rand = "0.8.5"
bellman = "0.14.0"
bls12_381 = "0.8.0"
ff = { version = "0.13" }
group = "0.13.0"
rand_chacha = "0.3.1"
byteorder = "1"
num_cpus = "1"
crossbeam = "0.3"
Expand Down
163 changes: 77 additions & 86 deletions examples/mimc.rs
Original file line number Diff line number Diff line change
@@ -1,45 +1,34 @@
extern crate bellman;
extern crate pairing;
extern crate rand;
extern crate phase2;
extern crate rand;

// For randomness (during paramgen and proof generation)
use rand::{thread_rng, Rng};
use rand::thread_rng;

// For benchmarking
use std::time::{Duration, Instant};

// Bring in some tools for using pairing-friendly curves
use pairing::{
Engine,
Field,
};
use ff::{Field, PrimeField};
use pairing::Engine;

// We're going to use the BLS12-381 pairing-friendly elliptic curve.
use pairing::bls12_381::{
Bls12
};
use bls12_381::Bls12;

// We'll use these interfaces to construct our circuit.
use bellman::{
Circuit,
ConstraintSystem,
SynthesisError
};
use bellman::{Circuit, ConstraintSystem, SynthesisError};

// We're going to use the Groth16 proving system.
use bellman::groth16::{
Proof,
prepare_verifying_key,
create_random_proof,
verify_proof,
};
use bellman::groth16::{create_random_proof, prepare_verifying_key, verify_proof, Proof};

use std::ops::{AddAssign, MulAssign};

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
/// See http://eprint.iacr.org/2016/492 for more
/// information about this construction.
///
/// ```
Expand All @@ -50,19 +39,14 @@ const MIMC_ROUNDS: usize = 322;
/// return xL
/// }
/// ```
fn mimc<E: Engine>(
mut xl: E::Fr,
mut xr: E::Fr,
constants: &[E::Fr]
) -> E::Fr
{
fn mimc<E: Engine>(mut xl: E::Fr, mut xr: E::Fr, constants: &[E::Fr]) -> E::Fr {
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;
tmp2.square();
tmp2 = tmp2.square();
tmp2.mul_assign(&tmp1);
tmp2.add_assign(&xr);
xr = xl;
Expand All @@ -74,83 +58,84 @@ fn mimc<E: Engine>(

/// This is our demo circuit for proving knowledge of the
/// preimage of a MiMC hash invocation.
struct MiMCDemo<'a, E: Engine> {
xl: Option<E::Fr>,
xr: Option<E::Fr>,
constants: &'a [E::Fr]
struct MiMCDemo<'a, S: PrimeField> {
xl: Option<S>,
xr: Option<S>,
constants: &'a [S],
}

/// Our demo circuit implements this `Circuit` trait which
/// is used during paramgen and proving in order to
/// synthesize the constraint system.
impl<'a, E: Engine> Circuit<E> for MiMCDemo<'a, E> {
fn synthesize<CS: ConstraintSystem<E>>(
self,
cs: &mut CS
) -> Result<(), SynthesisError>
{
impl<'a, S: PrimeField> Circuit<S> for MiMCDemo<'a, S> {
fn synthesize<CS: ConstraintSystem<S>>(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)
})?;
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)
})?;
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 mut tmp_value = xl_value.map(|mut e| {
let tmp_value = xl_value.map(|mut e| {
e.add_assign(&self.constants[i]);
e.square();
e = e.square();
e
});
let mut tmp = cs.alloc(|| "tmp", || {
tmp_value.ok_or(SynthesisError::AssignmentMissing)
})?;
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
|lc| lc + tmp,
);

// new_xL = xR + (xL + Ci)^3
// new_xL = xR + tmp * (xL + Ci)
// new_xL - xR = tmp * (xL + Ci)
let mut new_xl_value = xl_value.map(|mut e| {
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 mut new_xl = if i == (MIMC_ROUNDS-1) {
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)
})?
cs.alloc_input(
|| "image",
|| new_xl_value.ok_or(SynthesisError::AssignmentMissing),
)?
} else {
cs.alloc(|| "new_xl", || {
new_xl_value.ok_or(SynthesisError::AssignmentMissing)
})?
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
|lc| lc + new_xl - xr,
);

// xR = xL
Expand All @@ -169,42 +154,52 @@ impl<'a, E: Engine> Circuit<E> for MiMCDemo<'a, E> {
fn main() {
// This may not be cryptographically safe, use
// `OsRng` (for example) in production software.
let rng = &mut thread_rng();
let mut rng = thread_rng();

// Generate the MiMC round constants
let constants = (0..MIMC_ROUNDS).map(|_| rng.gen()).collect::<Vec<_>>();
let constants = (0..MIMC_ROUNDS)
.map(|_| bls12_381::Scalar::random(&mut rng))
.collect::<Vec<_>>();

println!("Creating parameters...");

// Create parameters for our circuit
let mut params = {
let c = MiMCDemo::<Bls12> {
let c = MiMCDemo::<bls12_381::Scalar> {
xl: None,
xr: None,
constants: &constants
constants: &constants,
};

phase2::MPCParameters::new(c).unwrap()
};

let old_params = params.clone();
params.contribute(rng);
params.contribute(&mut rng);

let first_contrib = phase2::verify_contribution(&old_params, &params).expect("should verify");

let old_params = params.clone();
params.contribute(rng);
params.contribute(&mut rng);

let second_contrib = phase2::verify_contribution(&old_params, &params).expect("should verify");

let verification_result = params.verify(MiMCDemo::<Bls12> {
xl: None,
xr: None,
constants: &constants
}).unwrap();

assert!(phase2::contains_contribution(&verification_result, &first_contrib));
assert!(phase2::contains_contribution(&verification_result, &second_contrib));
let verification_result = params
.verify(MiMCDemo::<bls12_381::Scalar> {
xl: None,
xr: None,
constants: &constants,
})
.unwrap();

assert!(phase2::contains_contribution(
&verification_result,
&first_contrib
));
assert!(phase2::contains_contribution(
&verification_result,
&second_contrib
));

let params = params.get_params();

Expand All @@ -224,8 +219,8 @@ fn main() {

for _ in 0..SAMPLES {
// Generate a random preimage and compute the image
let xl = rng.gen();
let xr = rng.gen();
let xl = bls12_381::Scalar::random(&mut rng);
let xr = bls12_381::Scalar::random(&mut rng);
let image = mimc::<Bls12>(xl, xr, &constants);

proof_vec.truncate(0);
Expand All @@ -237,11 +232,11 @@ fn main() {
let c = MiMCDemo {
xl: Some(xl),
xr: Some(xr),
constants: &constants
constants: &constants,
};

// Create a groth16 proof with our parameters.
let proof = create_random_proof(c, params, rng).unwrap();
let proof = create_random_proof(c, params, &mut rng).unwrap();

proof.write(&mut proof_vec).unwrap();
}
Expand All @@ -251,20 +246,16 @@ fn main() {
let start = Instant::now();
let proof = Proof::read(&proof_vec[..]).unwrap();
// Check the proof
assert!(verify_proof(
&pvk,
&proof,
&[image]
).unwrap());
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 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);
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);
Expand Down
Loading