From 29b4e1ddee5435001d3ffb610dd22c87ac9efd43 Mon Sep 17 00:00:00 2001 From: Brechtpd Date: Thu, 5 Dec 2019 18:30:09 +0100 Subject: [PATCH 1/2] Some misc small fixes + split up work in multiple programs --- bellman/src/groth16/mod.rs | 4 +- phase2/Cargo.toml | 5 + phase2/src/bin/beacon.rs | 92 +++++++++++ phase2/src/bin/contribute.rs | 72 +++++++++ phase2/src/bin/export_keys.rs | 217 ++++++++++++++++++++++++++ phase2/src/bin/new.rs | 29 ++++ phase2/src/bin/verify_contribution.rs | 37 +++++ phase2/src/lib.rs | 101 +++++++++++- phase2/tools/vk2ethsnarks.py | 48 ++++++ powersoftau/Cargo.lock | 4 +- powersoftau/src/bin/prepare_phase2.rs | 4 +- powersoftau/src/bin/verify.rs | 10 +- powersoftau/src/small_bn256/mod.rs | 2 +- 13 files changed, 612 insertions(+), 13 deletions(-) create mode 100644 phase2/src/bin/beacon.rs create mode 100644 phase2/src/bin/contribute.rs create mode 100644 phase2/src/bin/export_keys.rs create mode 100644 phase2/src/bin/new.rs create mode 100644 phase2/src/bin/verify_contribution.rs create mode 100644 phase2/tools/vk2ethsnarks.py diff --git a/bellman/src/groth16/mod.rs b/bellman/src/groth16/mod.rs index 8e70cc3..681bf7e 100644 --- a/bellman/src/groth16/mod.rs +++ b/bellman/src/groth16/mod.rs @@ -301,7 +301,7 @@ impl Parameters { .into_affine_unchecked() } .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - .and_then(|e| if e.is_zero() { + .and_then(|e| if /*e.is_zero()*/false { Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity")) } else { Ok(e) @@ -320,7 +320,7 @@ impl Parameters { .into_affine_unchecked() } .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - .and_then(|e| if e.is_zero() { + .and_then(|e| if /*e.is_zero()*/false { Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity")) } else { Ok(e) diff --git a/phase2/Cargo.toml b/phase2/Cargo.toml index d55bdce..9feda86 100644 --- a/phase2/Cargo.toml +++ b/phase2/Cargo.toml @@ -12,11 +12,16 @@ repository = "https://github.com/ebfull/phase2" rand = "0.4" bellman_ce = { path = "../bellman" } byteorder = "1" +exitcode = "1.1.2" num_cpus = "1" crossbeam = "0.3" blake2-rfc = "0.2" +blake2 = "0.6.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" memmap = "0.7" num-bigint = "0.2.3" num-traits = "0.2.8" +itertools = "0.8.1" +rust-crypto = "0.2" +hex-literal = "0.1" diff --git a/phase2/src/bin/beacon.rs b/phase2/src/bin/beacon.rs new file mode 100644 index 0000000..547362c --- /dev/null +++ b/phase2/src/bin/beacon.rs @@ -0,0 +1,92 @@ +extern crate rand; +extern crate phase2; +extern crate memmap; +extern crate num_bigint; +extern crate num_traits; +extern crate blake2; +extern crate byteorder; +extern crate exitcode; +extern crate itertools; +extern crate crypto; + +use itertools::Itertools; + +use std::fs::File; +use std::fs::OpenOptions; + +#[macro_use] +extern crate hex_literal; + +fn main() { + let args: Vec = std::env::args().collect(); + if args.len() != 3 { + println!("Usage: \n "); + std::process::exit(exitcode::USAGE); + } + let in_params_filename = &args[1]; + let out_params_filename = &args[2]; + + // Create an RNG based on the outcome of the random beacon + let mut rng = { + use byteorder::{ReadBytesExt, BigEndian}; + use rand::{SeedableRng}; + use rand::chacha::ChaChaRng; + use crypto::sha2::Sha256; + use crypto::digest::Digest; + + // Place block hash here (block number #564321) + let mut cur_hash: [u8; 32] = hex!("0000000000000000000a558a61ddc8ee4e488d647a747fe4dcc362fe2026c620"); + + // Performs 2^n hash iterations over it + const N: usize = 10; + + for i in 0..(1u64<().expect("digest is large enough for this to work"); + } + + ChaChaRng::from_seed(&seed) + }; + + println!("Done creating a beacon RNG"); + + let reader = OpenOptions::new() + .read(true) + .open(in_params_filename) + .expect("unable to open."); + let mut params = phase2::MPCParameters::read(reader, true).expect("unable to read params"); + + println!("Contributing to {}...", in_params_filename); + let hash = params.contribute(&mut rng); + println!("Contribution hash: 0x{:02x}", hash.iter().format("")); + + println!("Writing parameters to {}.", out_params_filename); + let mut f = File::create(out_params_filename).unwrap(); + params.write(&mut f).expect("failed to write updated parameters"); +} diff --git a/phase2/src/bin/contribute.rs b/phase2/src/bin/contribute.rs new file mode 100644 index 0000000..3a9087b --- /dev/null +++ b/phase2/src/bin/contribute.rs @@ -0,0 +1,72 @@ +extern crate rand; +extern crate phase2; +extern crate memmap; +extern crate num_bigint; +extern crate num_traits; +extern crate blake2; +extern crate byteorder; +extern crate exitcode; +extern crate itertools; + +use itertools::Itertools; + +use std::fs::File; +use std::fs::OpenOptions; + +fn main() { + let args: Vec = std::env::args().collect(); + if args.len() != 4 { + println!("Usage: \n "); + std::process::exit(exitcode::USAGE); + } + let in_params_filename = &args[1]; + let entropy = &args[2]; + let out_params_filename = &args[3]; + + // Create an RNG based on a mixture of system randomness and user provided randomness + let mut rng = { + use byteorder::{ReadBytesExt, BigEndian}; + use blake2::{Blake2b, Digest}; + use rand::{SeedableRng, Rng, OsRng}; + use rand::chacha::ChaChaRng; + + let h = { + let mut system_rng = OsRng::new().unwrap(); + let mut h = Blake2b::default(); + + // Gather 1024 bytes of entropy from the system + for _ in 0..1024 { + let r: u8 = system_rng.gen(); + h.input(&[r]); + } + + // Hash it all up to make a seed + h.input(&entropy.as_bytes()); + h.result() + }; + + let mut digest = &h[..]; + + // Interpret the first 32 bytes of the digest as 8 32-bit words + let mut seed = [0u32; 8]; + for i in 0..8 { + seed[i] = digest.read_u32::().expect("digest is large enough for this to work"); + } + + ChaChaRng::from_seed(&seed) + }; + + let reader = OpenOptions::new() + .read(true) + .open(in_params_filename) + .expect("unable to open."); + let mut params = phase2::MPCParameters::read(reader, true).expect("unable to read params"); + + println!("Contributing to {}...", in_params_filename); + let hash = params.contribute(&mut rng); + println!("Contribution hash: 0x{:02x}", hash.iter().format("")); + + println!("Writing parameters to {}.", out_params_filename); + let mut f = File::create(out_params_filename).unwrap(); + params.write(&mut f).expect("failed to write updated parameters"); +} diff --git a/phase2/src/bin/export_keys.rs b/phase2/src/bin/export_keys.rs new file mode 100644 index 0000000..0934127 --- /dev/null +++ b/phase2/src/bin/export_keys.rs @@ -0,0 +1,217 @@ +extern crate bellman_ce; +extern crate rand; +extern crate phase2; +extern crate memmap; +extern crate num_bigint; +extern crate num_traits; +extern crate exitcode; + +extern crate serde; +extern crate serde_json; + +use serde::{Deserialize, Serialize}; +use num_bigint::BigUint; +use num_traits::Num; + +use std::fs::OpenOptions; +use std::io::Write; +use std::ops::DerefMut; + +#[derive(Serialize, Deserialize)] +struct ProvingKeyJson { + #[serde(rename = "A")] + pub a: Vec>, + #[serde(rename = "B1")] + pub b1: Vec>, + #[serde(rename = "B2")] + pub b2: Vec>>, + #[serde(rename = "C")] + pub c: Vec>>, + pub vk_alfa_1: Vec, + pub vk_beta_1: Vec, + pub vk_delta_1: Vec, + pub vk_beta_2: Vec>, + pub vk_delta_2: Vec>, + #[serde(rename = "hExps")] + pub h: Vec>, +} + +#[derive(Serialize, Deserialize)] +struct VerifyingKeyJson { + #[serde(rename = "IC")] + pub ic: Vec>, + pub vk_alfa_1: Vec, + pub vk_beta_2: Vec>, + pub vk_gamma_2: Vec>, + pub vk_delta_2: Vec>, +} + +// Bring in some tools for using pairing-friendly curves +use bellman_ce::pairing::{ + Engine, + CurveAffine, + ff::PrimeField, +}; + +// We're going to use the BLS12-381 pairing-friendly elliptic curve. +use bellman_ce::pairing::bn256::{ + Bn256, +}; + +use std::collections::BTreeMap; + +#[derive(Serialize, Deserialize)] +struct CircuitJson { + pub constraints: Vec>>, + #[serde(rename = "nPubInputs")] + pub num_inputs: usize, + #[serde(rename = "nOutputs")] + pub num_outputs: usize, + #[serde(rename = "nVars")] + pub num_variables: usize, +} + +fn main() { + let args: Vec = std::env::args().collect(); + if args.len() != 4 { + println!("Usage: \n "); + std::process::exit(exitcode::USAGE); + } + let params_filename = &args[1]; + let vk_filename = &args[2]; + let pk_filename = &args[3]; + + println!("Exporting {}...", params_filename); + + let reader = OpenOptions::new() + .read(true) + .open(params_filename) + .expect("unable to open."); + let params = phase2::MPCParameters::read(reader, true).expect("unable to read params"); + let params = params.get_params(); + + let mut proving_key = ProvingKeyJson { + a: vec![], + b1: vec![], + b2: vec![], + c: vec![], + vk_alfa_1: vec![], + vk_beta_1: vec![], + vk_delta_1: vec![], + vk_beta_2: vec![], + vk_delta_2: vec![], + h: vec![], + }; + let repr_to_big = |r| { + BigUint::from_str_radix(&format!("{}", r)[2..], 16).unwrap().to_str_radix(10) + }; + + let p1_to_vec = |p : &::G1Affine| { + let mut v = vec![]; + //println!("test: {}", p.get_x().into_repr()); + let x = repr_to_big(p.get_x().into_repr()); + v.push(x); + let y = repr_to_big(p.get_y().into_repr()); + v.push(y); + if p.is_zero() { + v.push("0".to_string()); + } else { + v.push("1".to_string()); + } + v + }; + let p2_to_vec = |p : &::G2Affine| { + let mut v = vec![]; + let x = p.get_x(); + let mut x_v = vec![]; + x_v.push(repr_to_big(x.c0.into_repr())); + x_v.push(repr_to_big(x.c1.into_repr())); + v.push(x_v); + + let y = p.get_y(); + let mut y_v = vec![]; + y_v.push(repr_to_big(y.c0.into_repr())); + y_v.push(repr_to_big(y.c1.into_repr())); + v.push(y_v); + + if p.is_zero() { + v.push(["0".to_string(), "0".to_string()].to_vec()); + } else { + v.push(["1".to_string(), "0".to_string()].to_vec()); + } + + v + }; + let a = params.a.clone(); + for e in a.iter() { + proving_key.a.push(p1_to_vec(e)); + } + let b1 = params.b_g1.clone(); + for e in b1.iter() { + proving_key.b1.push(p1_to_vec(e)); + } + let b2 = params.b_g2.clone(); + for e in b2.iter() { + proving_key.b2.push(p2_to_vec(e)); + } + let c = params.l.clone(); + for _ in 0..params.vk.ic.len() { + proving_key.c.push(None); + } + for e in c.iter() { + proving_key.c.push(Some(p1_to_vec(e))); + } + + let vk_alfa_1 = params.vk.alpha_g1.clone(); + proving_key.vk_alfa_1 = p1_to_vec(&vk_alfa_1); + + let vk_beta_1 = params.vk.beta_g1.clone(); + proving_key.vk_beta_1 = p1_to_vec(&vk_beta_1); + + let vk_delta_1 = params.vk.delta_g1.clone(); + proving_key.vk_delta_1 = p1_to_vec(&vk_delta_1); + + let vk_beta_2 = params.vk.beta_g2.clone(); + proving_key.vk_beta_2 = p2_to_vec(&vk_beta_2); + + let vk_delta_2 = params.vk.delta_g2.clone(); + proving_key.vk_delta_2 = p2_to_vec(&vk_delta_2); + + let h = params.h.clone(); + for e in h.iter() { + proving_key.h.push(p1_to_vec(e)); + } + + let mut verification_key = VerifyingKeyJson { + ic: vec![], + vk_alfa_1: vec![], + vk_beta_2: vec![], + vk_gamma_2: vec![], + vk_delta_2: vec![], + }; + + let ic = params.vk.ic.clone(); + for e in ic.iter() { + verification_key.ic.push(p1_to_vec(e)); + } + + verification_key.vk_alfa_1 = p1_to_vec(&vk_alfa_1); + verification_key.vk_beta_2 = p2_to_vec(&vk_beta_2); + let vk_gamma_2 = params.vk.gamma_g2.clone(); + verification_key.vk_gamma_2 = p2_to_vec(&vk_gamma_2); + verification_key.vk_delta_2 = p2_to_vec(&vk_delta_2); + + let pk_file = OpenOptions::new().read(true).write(true).create_new(true).open(pk_filename).unwrap(); + let pk_json = serde_json::to_string(&proving_key).unwrap(); + pk_file.set_len(pk_json.len() as u64).expect("unable to write pk file"); + let mut mmap = unsafe { memmap::Mmap::map(&pk_file) }.unwrap().make_mut().unwrap(); + mmap.deref_mut().write_all(pk_json.as_bytes()).unwrap(); + + let vk_file = OpenOptions::new().read(true).write(true).create_new(true).open(vk_filename).unwrap(); + let vk_json = serde_json::to_string(&verification_key).unwrap(); + vk_file.set_len(vk_json.len() as u64).expect("unable to write vk file"); + let mut mmap = unsafe { memmap::Mmap::map(&vk_file) }.unwrap().make_mut().unwrap(); + mmap.deref_mut().write_all(vk_json.as_bytes()).unwrap(); + + println!("Created {} and {}.", pk_filename, vk_filename); +} diff --git a/phase2/src/bin/new.rs b/phase2/src/bin/new.rs new file mode 100644 index 0000000..d8b17a0 --- /dev/null +++ b/phase2/src/bin/new.rs @@ -0,0 +1,29 @@ +extern crate rand; +extern crate phase2; +extern crate exitcode; + +use std::fs::File; + +fn main() { + let args: Vec = std::env::args().collect(); + if args.len() != 3 { + println!("Usage: \n "); + std::process::exit(exitcode::USAGE); + } + let circuit_filename = &args[1]; + let params_filename = &args[2]; + + // Import the circuit and create the initial parameters using phase 1 + println!("Creating initial parameters for {}...", circuit_filename); + let should_filter_points_at_infinity = false; + let params = { + let c = phase2::CircomCircuit { + file_name: &circuit_filename, + }; + phase2::MPCParameters::new(c, should_filter_points_at_infinity).unwrap() + }; + + println!("Writing initial parameters to {}.", params_filename); + let mut f = File::create(params_filename).unwrap(); + params.write(&mut f).expect("unable to write params"); +} diff --git a/phase2/src/bin/verify_contribution.rs b/phase2/src/bin/verify_contribution.rs new file mode 100644 index 0000000..1b96fee --- /dev/null +++ b/phase2/src/bin/verify_contribution.rs @@ -0,0 +1,37 @@ +extern crate phase2; +extern crate exitcode; + +use std::fs::OpenOptions; + +fn main() { + let args: Vec = std::env::args().collect(); + if args.len() != 4 { + println!("Usage: \n "); + std::process::exit(exitcode::USAGE); + } + let circuit_filename = &args[1]; + let old_params_filename = &args[2]; + let new_params_filename = &args[3]; + + let old_reader = OpenOptions::new() + .read(true) + .open(old_params_filename) + .expect("unable to open old params"); + let old_params = phase2::MPCParameters::read(old_reader, true).expect("unable to read old params"); + + let new_reader = OpenOptions::new() + .read(true) + .open(new_params_filename) + .expect("unable to open new params"); + let new_params = phase2::MPCParameters::read(new_reader, true).expect("unable to read new params"); + + println!("Checking contribution {}...", new_params_filename); + let contribution = phase2::verify_contribution(&old_params, &new_params).expect("should verify"); + + let should_filter_points_at_infinity = false; + let verification_result = new_params.verify(phase2::CircomCircuit { + file_name: &circuit_filename, + }, should_filter_points_at_infinity).unwrap(); + assert!(phase2::contains_contribution(&verification_result, &contribution)); + println!("Contribution {} verified.", new_params_filename); +} diff --git a/phase2/src/lib.rs b/phase2/src/lib.rs index 6b9ac52..51fe3bf 100644 --- a/phase2/src/lib.rs +++ b/phase2/src/lib.rs @@ -269,6 +269,14 @@ use rand::{ SeedableRng }; +use std::collections::BTreeMap; + +use std::str; + +#[macro_use] +extern crate serde; +extern crate serde_json; + /// This is our assembly structure that we'll use to synthesize the /// circuit into a QAP. struct KeypairAssembly { @@ -438,8 +446,8 @@ impl MPCParameters { m *= 2; exp += 1; - // Powers of Tau ceremony can't support more than 2^21 - if exp > 21 { + // Powers of Tau ceremony can't support more than 2^28 + if exp > 28 { return Err(SynthesisError::PolynomialDegreeTooLarge) } } @@ -511,8 +519,8 @@ impl MPCParameters { let alpha_coeffs_g1 = Arc::new(alpha_coeffs_g1); let beta_coeffs_g1 = Arc::new(beta_coeffs_g1); - let mut h = Vec::with_capacity(m); - for i in 0..m { + let mut h = Vec::with_capacity(m-1); + for _ in 0..m-1 { h.push(read_g1(f)?); } @@ -1399,3 +1407,88 @@ pub fn contains_contribution( return false } + +#[derive(Serialize, Deserialize)] +struct CircuitJson { + pub constraints: Vec>>, + #[serde(rename = "nPubInputs")] + pub num_inputs: usize, + #[serde(rename = "nOutputs")] + pub num_outputs: usize, + #[serde(rename = "nVars")] + pub num_variables: usize, +} + +pub struct CircomCircuit<'a> { + pub file_name: &'a str, +} + +/// 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 for CircomCircuit<'a> { + fn synthesize>( + self, + cs: &mut CS + ) -> Result<(), SynthesisError> + { + let mmap = unsafe { memmap::Mmap::map(&File::open(self.file_name)?) }?; + let content = str::from_utf8(&mmap).unwrap(); + let circuit_json: CircuitJson = serde_json::from_str(&content).unwrap(); + let num_public_inputs = circuit_json.num_inputs + circuit_json.num_outputs + 1; + //println!("num public inputs: {}", num_public_inputs); + for i in 1..circuit_json.num_variables { + if i < num_public_inputs { + //println!("allocating public input {}", i); + cs.alloc_input(|| format!("variable {}", i), || { + //println!("variable {}: {}", i, &self.witness[i]); + Ok(E::Fr::from_str("1").unwrap()) + }); + } else { + //println!("allocating private input {}", i); + cs.alloc(|| format!("variable {}", i), || { + //println!("variable {}: {}", i, &self.witness[i]); + Ok(E::Fr::from_str("1").unwrap()) + }); + } + } + let mut constrained: BTreeMap = BTreeMap::new(); + let mut constraint_num = 0; + for (i, constraint) in circuit_json.constraints.iter().enumerate() { + let mut lcs = vec![]; + for lc_description in constraint { + let mut lc = LinearCombination::::zero(); + //println!("lc_description: {:?}, i: {}, len: {}", lc_description, i, constraint.len()); + for (var_index_str, coefficient_str) in lc_description { + //println!("var_index_str: {}, coefficient_str: {}", var_index_str, coefficient_str); + let var_index_num: usize = var_index_str.parse().unwrap(); + let var_index = if var_index_num < num_public_inputs { + Index::Input(var_index_num) + } else { + Index::Aux(var_index_num - num_public_inputs) + }; + constrained.insert(var_index_num, true); + if i == 2 { + lc = lc + (E::Fr::from_str(coefficient_str).unwrap(), Variable::new_unchecked(var_index)); + } else { + lc = lc + (E::Fr::from_str(coefficient_str).unwrap(), Variable::new_unchecked(var_index)); + } + } + lcs.push(lc); + } + cs.enforce(|| format!("constraint {}", constraint_num), |_| lcs[0].clone(), |_| lcs[1].clone(), |_| lcs[2].clone()); + constraint_num += 1; + } + println!("constraints: {}", circuit_json.constraints.len()); + let mut unconstrained: BTreeMap = BTreeMap::new(); + for i in 0..circuit_json.num_variables { + if !constrained.contains_key(&i) { + unconstrained.insert(i, true); + } + } + for (i, _) in unconstrained { + println!("variable {} is unconstrained", i); + } + Ok(()) + } +} \ No newline at end of file diff --git a/phase2/tools/vk2ethsnarks.py b/phase2/tools/vk2ethsnarks.py new file mode 100644 index 0000000..7e4a40e --- /dev/null +++ b/phase2/tools/vk2ethsnarks.py @@ -0,0 +1,48 @@ +import sys +import json + +def to_hex(d): + return hex(int(d)).rstrip('L') + return d + +class vk_ethsnarks(object): + def to_json(self): + return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True, indent=4) + +if len(sys.argv) != 3: + print("Usage: ") + print(" ") + +f = json.load(open(sys.argv[1])) + +vk = vk_ethsnarks() +# alpha +vk.alpha = [] +for i in range(2): + vk.alpha.append(to_hex(f["vk_alfa_1"][i])) +# beta +vk.beta = [[], []] +for i in range(2): + for j in range(2): + vk.beta[i].append(to_hex(f["vk_beta_2"][i][1-j])) +# gamma +vk.gamma = [[], []] +for i in range(2): + for j in range(2): + vk.gamma[i].append(to_hex(f["vk_gamma_2"][i][1-j])) +# delta +vk.delta = [[], []] +for i in range(2): + for j in range(2): + vk.delta[i].append(to_hex(f["vk_delta_2"][i][1-j])) +# gammaABC +vk.gammaABC = [[], []] +for i in range(2): + for j in range(2): + vk.gammaABC[i].append(to_hex(f["IC"][i][j])) + +f3 = open(sys.argv[2], 'w') +f3.write(vk.to_json()) +f3.close() + +print("vk file created: " + str(sys.argv[2])) diff --git a/powersoftau/Cargo.lock b/powersoftau/Cargo.lock index 807f1eb..59d43bd 100644 --- a/powersoftau/Cargo.lock +++ b/powersoftau/Cargo.lock @@ -19,7 +19,7 @@ dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "pairing_ce 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pairing_ce 0.18.0", "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -296,7 +296,6 @@ dependencies = [ [[package]] name = "pairing_ce" version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ff_ce 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -511,7 +510,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" "checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba" -"checksum pairing_ce 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f075a9c570e2026111cb6dddf6a320e5163c42aa32500b315ec34acbcf7c9b36" "checksum proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c725b36c99df7af7bf9324e9c999b9e37d92c8f8caf106d82e1d7953218d2d8" "checksum proc-macro-hack-impl 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2b753ad9ed99dd8efeaa7d2fb8453c8f6bc3e54b97966d35f1bc77ca6865254a" "checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915" diff --git a/powersoftau/src/bin/prepare_phase2.rs b/powersoftau/src/bin/prepare_phase2.rs index ec71991..c910a9a 100644 --- a/powersoftau/src/bin/prepare_phase2.rs +++ b/powersoftau/src/bin/prepare_phase2.rs @@ -29,7 +29,7 @@ fn log_2(x: u64) -> u32 { } fn main() { - // Try to load `./transcript` from disk. + // Try to load `./response` from disk. let reader = OpenOptions::new() .read(true) .open("response") @@ -47,7 +47,7 @@ fn main() { // Create the parameters for various 2^m circuit depths. let max_degree = log_2(current_accumulator.tau_powers_g2.len() as u64); - for m in 0..max_degree { + for m in 0..max_degree+1 { let paramname = format!("phase1radix2m{}", m); println!("Creating {}", paramname); diff --git a/powersoftau/src/bin/verify.rs b/powersoftau/src/bin/verify.rs index 73dbd24..e1016d3 100644 --- a/powersoftau/src/bin/verify.rs +++ b/powersoftau/src/bin/verify.rs @@ -25,6 +25,13 @@ use std::io::{self, Read, BufWriter, Write}; use memmap::*; +const fn num_bits() -> usize { std::mem::size_of::() * 8 } + +fn log_2(x: u64) -> u32 { + assert!(x > 0); + num_bits::() as u32 - x.leading_zeros() - 1 +} + // Computes the hash of the challenge file for the player, // given the current state of the accumulator and the last // response file hash. @@ -268,7 +275,8 @@ fn main() { let worker = &Worker::new(); // Create the parameters for various 2^m circuit depths. - for m in 0..22 { + let max_degree = log_2(current_accumulator.tau_powers_g2.len() as u64); + for m in 0..max_degree+1 { let paramname = format!("phase1radix2m{}", m); println!("Creating {}", paramname); diff --git a/powersoftau/src/small_bn256/mod.rs b/powersoftau/src/small_bn256/mod.rs index d7cf89d..17565e6 100644 --- a/powersoftau/src/small_bn256/mod.rs +++ b/powersoftau/src/small_bn256/mod.rs @@ -30,7 +30,7 @@ pub struct Bn256CeremonyParameters { } impl PowersOfTauParameters for Bn256CeremonyParameters { - const REQUIRED_POWER: usize = 12; // generate to have roughly 2 million constraints + const REQUIRED_POWER: usize = 28; // This ceremony is based on the BN256 elliptic curve construction. const G1_UNCOMPRESSED_BYTE_SIZE: usize = 64; From 276e00c9e4b16fcf4090708ee1883331fa414531 Mon Sep 17 00:00:00 2001 From: Brechtpd Date: Thu, 5 Dec 2019 23:17:06 +0100 Subject: [PATCH 2/2] Points at infinity checking can be toggled + beacon cli arguments --- bellman/src/groth16/mod.rs | 5 +- phase2/Cargo.toml | 2 +- phase2/src/bin/beacon.rs | 26 +- phase2/src/bin/circom.rs | 409 -------------------------- phase2/src/bin/contribute.rs | 4 +- phase2/src/bin/export_keys.rs | 4 +- phase2/src/bin/new.rs | 3 +- phase2/src/bin/verify_contribution.rs | 6 +- phase2/src/lib.rs | 3 +- 9 files changed, 32 insertions(+), 430 deletions(-) delete mode 100644 phase2/src/bin/circom.rs diff --git a/bellman/src/groth16/mod.rs b/bellman/src/groth16/mod.rs index 681bf7e..2108a32 100644 --- a/bellman/src/groth16/mod.rs +++ b/bellman/src/groth16/mod.rs @@ -286,6 +286,7 @@ impl Parameters { pub fn read( mut reader: R, + disallow_points_at_infinity: bool, checked: bool ) -> io::Result { @@ -301,7 +302,7 @@ impl Parameters { .into_affine_unchecked() } .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - .and_then(|e| if /*e.is_zero()*/false { + .and_then(|e| if disallow_points_at_infinity && e.is_zero() { Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity")) } else { Ok(e) @@ -320,7 +321,7 @@ impl Parameters { .into_affine_unchecked() } .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - .and_then(|e| if /*e.is_zero()*/false { + .and_then(|e| if disallow_points_at_infinity && e.is_zero() { Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity")) } else { Ok(e) diff --git a/phase2/Cargo.toml b/phase2/Cargo.toml index 9feda86..400ab2a 100644 --- a/phase2/Cargo.toml +++ b/phase2/Cargo.toml @@ -24,4 +24,4 @@ num-bigint = "0.2.3" num-traits = "0.2.8" itertools = "0.8.1" rust-crypto = "0.2" -hex-literal = "0.1" +hex = "0.4.0" diff --git a/phase2/src/bin/beacon.rs b/phase2/src/bin/beacon.rs index 547362c..04676d6 100644 --- a/phase2/src/bin/beacon.rs +++ b/phase2/src/bin/beacon.rs @@ -8,23 +8,26 @@ extern crate byteorder; extern crate exitcode; extern crate itertools; extern crate crypto; +extern crate hex; use itertools::Itertools; use std::fs::File; use std::fs::OpenOptions; -#[macro_use] -extern crate hex_literal; fn main() { let args: Vec = std::env::args().collect(); - if args.len() != 3 { - println!("Usage: \n "); + if args.len() != 5 { + println!("Usage: \n "); std::process::exit(exitcode::USAGE); } let in_params_filename = &args[1]; - let out_params_filename = &args[2]; + let beacon_hash = &args[2]; + let num_iterations_exp = &args[3].parse::().unwrap(); + let out_params_filename = &args[4]; + + let disallow_points_at_infinity = false; // Create an RNG based on the outcome of the random beacon let mut rng = { @@ -34,18 +37,17 @@ fn main() { use crypto::sha2::Sha256; use crypto::digest::Digest; - // Place block hash here (block number #564321) - let mut cur_hash: [u8; 32] = hex!("0000000000000000000a558a61ddc8ee4e488d647a747fe4dcc362fe2026c620"); - + // The hash used for the beacon + let mut cur_hash = hex::decode(beacon_hash).unwrap(); // Performs 2^n hash iterations over it - const N: usize = 10; + let n: usize = *num_iterations_exp; - for i in 0..(1u64<>, - #[serde(rename = "B1")] - pub b1: Vec>, - #[serde(rename = "B2")] - pub b2: Vec>>, - #[serde(rename = "C")] - pub c: Vec>>, - pub vk_alfa_1: Vec, - pub vk_beta_1: Vec, - pub vk_delta_1: Vec, - pub vk_beta_2: Vec>, - pub vk_delta_2: Vec>, - #[serde(rename = "hExps")] - pub h: Vec>, -} - -#[derive(Serialize, Deserialize)] -struct VerifyingKeyJson { - #[serde(rename = "IC")] - pub ic: Vec>, - pub vk_alfa_1: Vec, - pub vk_beta_2: Vec>, - pub vk_gamma_2: Vec>, - pub vk_delta_2: Vec>, -} - -// Bring in some tools for using pairing-friendly curves -use bellman_ce::pairing::{ - Engine, - CurveAffine, - ff::{Field, PrimeField}, -}; - -// We're going to use the BLS12-381 pairing-friendly elliptic curve. -use bellman_ce::pairing::bn256::{ - Bn256, -}; - -// We'll use these interfaces to construct our circuit. -use bellman_ce::{ - Circuit, - Variable, - Index, - LinearCombination, - ConstraintSystem, - SynthesisError -}; - -// We're going to use the Groth16 proving system. -use bellman_ce::groth16::{ - Proof, - prepare_verifying_key, - create_random_proof, - verify_proof, -}; - -use std::collections::BTreeMap; - -#[derive(Serialize, Deserialize)] -struct CircuitJson { - pub constraints: Vec>>, - #[serde(rename = "nPubInputs")] - pub num_inputs: usize, - #[serde(rename = "nOutputs")] - pub num_outputs: usize, - #[serde(rename = "nVars")] - pub num_variables: usize, -} - -struct CircomCircuit<'a> { - pub file_name: &'a str, - pub witness: Vec, -} - -/// 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 for CircomCircuit<'a> { - fn synthesize>( - self, - cs: &mut CS - ) -> Result<(), SynthesisError> - { - let mmap = unsafe { memmap::Mmap::map(&File::open(self.file_name)?) }?; - let content = str::from_utf8(&mmap).unwrap(); - let circuit_json: CircuitJson = serde_json::from_str(&content).unwrap(); - let num_public_inputs = circuit_json.num_inputs + circuit_json.num_outputs + 1; - println!("num public inputs: {}", num_public_inputs); - for i in 1..circuit_json.num_variables { - if i < num_public_inputs { - //println!("allocating public input {}", i); - cs.alloc_input(|| format!("variable {}", i), || { - println!("variable {}: {}", i, &self.witness[i]); - Ok(E::Fr::from_str(&self.witness[i]).unwrap()) - }); - } else { - //println!("allocating private input {}", i); - cs.alloc(|| format!("variable {}", i), || { - println!("variable {}: {}", i, &self.witness[i]); - Ok(E::Fr::from_str(&self.witness[i]).unwrap()) - }); - } - } - let mut constrained: BTreeMap = BTreeMap::new(); - let mut constraint_num = 0; - for (i, constraint) in circuit_json.constraints.iter().enumerate() { - let mut lcs = vec![]; - for lc_description in constraint { - let mut lc = LinearCombination::::zero(); - //println!("lc_description: {:?}, i: {}, len: {}", lc_description, i, constraint.len()); - for (var_index_str, coefficient_str) in lc_description { - //println!("var_index_str: {}, coefficient_str: {}", var_index_str, coefficient_str); - let var_index_num: usize = var_index_str.parse().unwrap(); - let var_index = if var_index_num < num_public_inputs { - Index::Input(var_index_num) - } else { - Index::Aux(var_index_num - num_public_inputs) - }; - constrained.insert(var_index_num, true); - if i == 2 { - lc = lc + (E::Fr::from_str(coefficient_str).unwrap(), Variable::new_unchecked(var_index)); - } else { - lc = lc + (E::Fr::from_str(coefficient_str).unwrap(), Variable::new_unchecked(var_index)); - } - } - lcs.push(lc); - } - cs.enforce(|| format!("constraint {}", constraint_num), |_| lcs[0].clone(), |_| lcs[1].clone(), |_| lcs[2].clone()); - constraint_num += 1; - } - println!("contraints: {}", circuit_json.constraints.len()); - let mut unconstrained: BTreeMap = BTreeMap::new(); - for i in 0..circuit_json.num_variables { - if !constrained.contains_key(&i) { - unconstrained.insert(i, true); - } - } - for (i, _) in unconstrained { - println!("variable {} is unconstrained", i); - } - Ok(()) - } -} - -fn main() { - // This may not be cryptographically safe, use - // `OsRng` (for example) in production software. - //let rng = &mut thread_rng(); - let mut rng = ChaChaRng::new_unseeded(); - rng.set_counter(0u64, 1234567890u64); - let rng = &mut rng; - - - println!("Creating parameters..."); - - let should_filter_points_at_infinity = false; - - let file_name = "circuit.json"; - - let mmap = unsafe { memmap::Mmap::map(&File::open("witness.json").unwrap()) }.unwrap(); - let content = str::from_utf8(&mmap).unwrap(); - - let witness: Vec = serde_json::from_str(&content).unwrap(); - // Create parameters for our circuit - let mut params = { - let c = CircomCircuit { - file_name, - witness: witness.clone(), - }; - - phase2::MPCParameters::new(c, should_filter_points_at_infinity).unwrap() - }; - - let old_params = params.clone(); - params.contribute(rng); - - let first_contrib = phase2::verify_contribution(&old_params, ¶ms).expect("should verify"); - - let old_params = params.clone(); - params.contribute(rng); - - let second_contrib = phase2::verify_contribution(&old_params, ¶ms).expect("should verify"); - - let verification_result = params.verify(CircomCircuit { - file_name, - witness: witness.clone(), - }, should_filter_points_at_infinity).unwrap(); - - assert!(phase2::contains_contribution(&verification_result, &first_contrib)); - assert!(phase2::contains_contribution(&verification_result, &second_contrib)); - - let params = params.get_params(); - - let mut f = File::create("circom.params").unwrap(); - params.write(&mut f); - - let mut proving_key = ProvingKeyJson { - a: vec![], - b1: vec![], - b2: vec![], - c: vec![], - vk_alfa_1: vec![], - vk_beta_1: vec![], - vk_delta_1: vec![], - vk_beta_2: vec![], - vk_delta_2: vec![], - h: vec![], - }; - let repr_to_big = |r| { - BigUint::from_str_radix(&format!("{}", r)[2..], 16).unwrap().to_str_radix(10) - }; - - let p1_to_vec = |p : &::G1Affine| { - let mut v = vec![]; - let x = repr_to_big(p.get_x().into_repr()); - v.push(x); - let y = repr_to_big(p.get_y().into_repr()); - v.push(y); - if p.is_zero() { - v.push("0".to_string()); - } else { - v.push("1".to_string()); - } - v - }; - let p2_to_vec = |p : &::G2Affine| { - let mut v = vec![]; - let x = p.get_x(); - let mut x_v = vec![]; - x_v.push(repr_to_big(x.c0.into_repr())); - x_v.push(repr_to_big(x.c1.into_repr())); - v.push(x_v); - - let y = p.get_y(); - let mut y_v = vec![]; - y_v.push(repr_to_big(y.c0.into_repr())); - y_v.push(repr_to_big(y.c1.into_repr())); - v.push(y_v); - - if p.is_zero() { - v.push(["0".to_string(), "0".to_string()].to_vec()); - } else { - v.push(["1".to_string(), "0".to_string()].to_vec()); - } - - v - }; - let a = params.a.clone(); - for e in a.iter() { - proving_key.a.push(p1_to_vec(e)); - } - let b1 = params.b_g1.clone(); - for e in b1.iter() { - proving_key.b1.push(p1_to_vec(e)); - } - let b2 = params.b_g2.clone(); - for e in b2.iter() { - proving_key.b2.push(p2_to_vec(e)); - } - let c = params.l.clone(); - for _ in 0..params.vk.ic.len() { - proving_key.c.push(None); - } - for e in c.iter() { - proving_key.c.push(Some(p1_to_vec(e))); - } - - let vk_alfa_1 = params.vk.alpha_g1.clone(); - proving_key.vk_alfa_1 = p1_to_vec(&vk_alfa_1); - - let vk_beta_1 = params.vk.beta_g1.clone(); - proving_key.vk_beta_1 = p1_to_vec(&vk_beta_1); - - let vk_delta_1 = params.vk.delta_g1.clone(); - proving_key.vk_delta_1 = p1_to_vec(&vk_delta_1); - - let vk_beta_2 = params.vk.beta_g2.clone(); - proving_key.vk_beta_2 = p2_to_vec(&vk_beta_2); - - let vk_delta_2 = params.vk.delta_g2.clone(); - proving_key.vk_delta_2 = p2_to_vec(&vk_delta_2); - - let h = params.h.clone(); - for e in h.iter() { - proving_key.h.push(p1_to_vec(e)); - } - - - let mut verification_key = VerifyingKeyJson { - ic: vec![], - vk_alfa_1: vec![], - vk_beta_2: vec![], - vk_gamma_2: vec![], - vk_delta_2: vec![], - }; - - let ic = params.vk.ic.clone(); - for e in ic.iter() { - verification_key.ic.push(p1_to_vec(e)); - } - - verification_key.vk_alfa_1 = p1_to_vec(&vk_alfa_1); - verification_key.vk_beta_2 = p2_to_vec(&vk_beta_2); - //let vk_alfabeta_12 = vk_alfa_1.pairing_with(&vk_beta_2); - //println!("vk_alfabeta_12: {}", vk_alfabeta_12); - let vk_gamma_2 = params.vk.gamma_g2.clone(); - verification_key.vk_gamma_2 = p2_to_vec(&vk_gamma_2); - verification_key.vk_delta_2 = p2_to_vec(&vk_delta_2); - - let mut pk_file = OpenOptions::new().read(true).write(true).create_new(true).open("pk.json").unwrap(); - let pk_json = serde_json::to_string(&proving_key).unwrap(); - pk_file.set_len(pk_json.len() as u64); - let mut mmap = unsafe { memmap::Mmap::map(&pk_file) }.unwrap().make_mut().unwrap(); - mmap.deref_mut().write_all(pk_json.as_bytes()).unwrap(); - - let mut vk_file = OpenOptions::new().read(true).write(true).create_new(true).open("vk.json").unwrap(); - let vk_json = serde_json::to_string(&verification_key).unwrap(); - vk_file.set_len(vk_json.len() as u64); - let mut mmap = unsafe { memmap::Mmap::map(&vk_file) }.unwrap().make_mut().unwrap(); - mmap.deref_mut().write_all(vk_json.as_bytes()).unwrap(); - - /* - // Prepare the verification key (for proof verification) - let pvk = prepare_verifying_key(¶ms.vk); - - println!("Creating proofs..."); - - // Let's benchmark stuff! - const SAMPLES: u32 = 1; - 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 { - proof_vec.truncate(0); - - let start = Instant::now(); - { - // Create an instance of our circuit (with the - // witness) - let c = CircomCircuit { - file_name, - witness: witness.clone(), - }; - - // Create a groth16 proof with our parameters. - let proof = create_random_proof(c, params, rng).unwrap(); - println!("proof: {:?}", proof); - - 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, - &[] - ).unwrap()); - 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); - */ -} diff --git a/phase2/src/bin/contribute.rs b/phase2/src/bin/contribute.rs index 3a9087b..d53f3db 100644 --- a/phase2/src/bin/contribute.rs +++ b/phase2/src/bin/contribute.rs @@ -23,6 +23,8 @@ fn main() { let entropy = &args[2]; let out_params_filename = &args[3]; + let disallow_points_at_infinity = false; + // Create an RNG based on a mixture of system randomness and user provided randomness let mut rng = { use byteorder::{ReadBytesExt, BigEndian}; @@ -60,7 +62,7 @@ fn main() { .read(true) .open(in_params_filename) .expect("unable to open."); - let mut params = phase2::MPCParameters::read(reader, true).expect("unable to read params"); + let mut params = phase2::MPCParameters::read(reader, disallow_points_at_infinity, true).expect("unable to read params"); println!("Contributing to {}...", in_params_filename); let hash = params.contribute(&mut rng); diff --git a/phase2/src/bin/export_keys.rs b/phase2/src/bin/export_keys.rs index 0934127..79b6332 100644 --- a/phase2/src/bin/export_keys.rs +++ b/phase2/src/bin/export_keys.rs @@ -81,13 +81,15 @@ fn main() { let vk_filename = &args[2]; let pk_filename = &args[3]; + let disallow_points_at_infinity = false; + println!("Exporting {}...", params_filename); let reader = OpenOptions::new() .read(true) .open(params_filename) .expect("unable to open."); - let params = phase2::MPCParameters::read(reader, true).expect("unable to read params"); + let params = phase2::MPCParameters::read(reader, disallow_points_at_infinity, true).expect("unable to read params"); let params = params.get_params(); let mut proving_key = ProvingKeyJson { diff --git a/phase2/src/bin/new.rs b/phase2/src/bin/new.rs index d8b17a0..fb9f4cf 100644 --- a/phase2/src/bin/new.rs +++ b/phase2/src/bin/new.rs @@ -13,9 +13,10 @@ fn main() { let circuit_filename = &args[1]; let params_filename = &args[2]; + let should_filter_points_at_infinity = false; + // Import the circuit and create the initial parameters using phase 1 println!("Creating initial parameters for {}...", circuit_filename); - let should_filter_points_at_infinity = false; let params = { let c = phase2::CircomCircuit { file_name: &circuit_filename, diff --git a/phase2/src/bin/verify_contribution.rs b/phase2/src/bin/verify_contribution.rs index 1b96fee..89afdf1 100644 --- a/phase2/src/bin/verify_contribution.rs +++ b/phase2/src/bin/verify_contribution.rs @@ -13,17 +13,19 @@ fn main() { let old_params_filename = &args[2]; let new_params_filename = &args[3]; + let disallow_points_at_infinity = false; + let old_reader = OpenOptions::new() .read(true) .open(old_params_filename) .expect("unable to open old params"); - let old_params = phase2::MPCParameters::read(old_reader, true).expect("unable to read old params"); + let old_params = phase2::MPCParameters::read(old_reader, disallow_points_at_infinity, true).expect("unable to read old params"); let new_reader = OpenOptions::new() .read(true) .open(new_params_filename) .expect("unable to open new params"); - let new_params = phase2::MPCParameters::read(new_reader, true).expect("unable to read new params"); + let new_params = phase2::MPCParameters::read(new_reader, disallow_points_at_infinity, true).expect("unable to read new params"); println!("Checking contribution {}...", new_params_filename); let contribution = phase2::verify_contribution(&old_params, &new_params).expect("should verify"); diff --git a/phase2/src/lib.rs b/phase2/src/lib.rs index 51fe3bf..d630747 100644 --- a/phase2/src/lib.rs +++ b/phase2/src/lib.rs @@ -955,10 +955,11 @@ impl MPCParameters { /// checks. pub fn read( mut reader: R, + disallow_points_at_infinity: bool, checked: bool ) -> io::Result { - let params = Parameters::read(&mut reader, checked)?; + let params = Parameters::read(&mut reader, disallow_points_at_infinity, checked)?; let mut cs_hash = [0u8; 64]; reader.read_exact(&mut cs_hash)?;