From 276e00c9e4b16fcf4090708ee1883331fa414531 Mon Sep 17 00:00:00 2001 From: Brechtpd Date: Thu, 5 Dec 2019 23:17:06 +0100 Subject: [PATCH] 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)?;