From 6e5cfe211feec9f0e612a47a8a19d31f37ea9071 Mon Sep 17 00:00:00 2001 From: Alex Vlasov Date: Thu, 17 Jan 2019 11:38:54 +0300 Subject: [PATCH] remove verbosity, migrate dependencies --- Cargo.toml | 4 +- src/demo/.gitignore | 2 - src/demo/Cargo.toml | 12 --- src/demo/README.md | 42 -------- src/demo/examples/xor.rs | 112 -------------------- src/demo/src/lib.rs | 9 -- src/demo/src/verifier_contract.rs | 164 ------------------------------ src/groth16/generator.rs | 41 ++------ src/multiexp.rs | 4 +- 9 files changed, 11 insertions(+), 379 deletions(-) delete mode 100644 src/demo/.gitignore delete mode 100644 src/demo/Cargo.toml delete mode 100644 src/demo/README.md delete mode 100644 src/demo/examples/xor.rs delete mode 100644 src/demo/src/lib.rs delete mode 100644 src/demo/src/verifier_contract.rs diff --git a/Cargo.toml b/Cargo.toml index 99bd4f8..29fb129 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ homepage = "https://github.com/matterinc/bellman" license = "MIT/Apache-2.0" name = "bellman" repository = "https://github.com/matterinc/bellman" -version = "0.1.1" +version = "0.1.2" [dependencies] rand = "0.4" @@ -17,7 +17,7 @@ num_cpus = "1" crossbeam = "0.3" pairing = { git = 'https://github.com/matterinc/pairing' } byteorder = "1" -ff = { version = "0.4", features = ["derive"] } +ff = { git = 'https://github.com/matterinc/ff', features = ["derive"] } pbr = "1.0.1" time = "0.1" diff --git a/src/demo/.gitignore b/src/demo/.gitignore deleted file mode 100644 index 53eaa21..0000000 --- a/src/demo/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/target -**/*.rs.bk diff --git a/src/demo/Cargo.toml b/src/demo/Cargo.toml deleted file mode 100644 index 15ad898..0000000 --- a/src/demo/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "bellman-demo" -version = "0.1.0" - -[dependencies] -rand = "0.4" -hex = "0.3.2" -time = "0.1" -num-bigint = "0.2" -ff = { version = "0.4", features = ["derive"] } -bellman = { path = "../.." } -pairing = { git = 'https://github.com/matterinc/pairing' } diff --git a/src/demo/README.md b/src/demo/README.md deleted file mode 100644 index 19e9926..0000000 --- a/src/demo/README.md +++ /dev/null @@ -1,42 +0,0 @@ -# Demo circuits - -This project contains usage demonstration for `bellman` zkSNARK proving framework. -We use elliptic curve BN256, for which pairings can be efficiently performed in Ethereum Virtual Machine. - -## Project structure - -``` -. -│ -├── examples -│ └── xor.rs: simple XOR circuit demo -└── src - └── lib.rs: demo contract rendering -``` - -## Usage: - -```$bash -cargo run --example xor -cargo run --bin circuit -``` - -## Verification in EVM contract: - -```$bash -cargo run --example xor > demo.sol -``` - -Now deploy `DemoVerifier` contract from `demo.sol` (e.g. in [remix](https://remix.ethereum.org)) and run method `verify()`. - -## Benchmarking - -```$bash -BELLMAN_VERBOSE=1 cargo run --release [num_constraints] -``` - -`num_constraints` is decimal: - -```$bash -BELLMAN_VERBOSE=1 cargo run --release 1000000 -``` \ No newline at end of file diff --git a/src/demo/examples/xor.rs b/src/demo/examples/xor.rs deleted file mode 100644 index b697ac4..0000000 --- a/src/demo/examples/xor.rs +++ /dev/null @@ -1,112 +0,0 @@ -extern crate bellman; -extern crate pairing; -extern crate rand; -extern crate ff; -extern crate bellman_demo; - -use bellman::{Circuit, ConstraintSystem, SynthesisError}; -use ff::{Field, PrimeField}; -use pairing::{Engine}; -use pairing::bn256::{Bn256, Fr}; - -trait OptionExt { - fn grab(&self) -> Result; -} - -impl OptionExt for Option { - fn grab(&self) -> Result { - self.ok_or(SynthesisError::AssignmentMissing) - } -} - -struct XorCircuit { - a: Option, - b: Option, - c: Option, -} - -// Implementation of our circuit: -// Given a bit `c`, prove that we know bits `a` and `b` such that `c = a xor b` -impl Circuit for XorCircuit { - fn synthesize>(self, cs: &mut CS) -> Result<(), SynthesisError> { - - // public input: c - // variables (witness): a, b - - // constraint system: - // a * a = a - // b * b = b - // 2a * b = a + b - c - - let a = cs.alloc(|| "a", || self.a.grab())?; - - // a * a = a - cs.enforce(|| "a is a boolean", |lc| lc + a, |lc| lc + a, |lc| lc + a); - - let b = cs.alloc(|| "b", || self.b.grab())?; - - // b * b = b - cs.enforce(|| "b is a boolean", |lc| lc + b, |lc| lc + b, |lc| lc + b); - - // c = a xor b - let c = cs.alloc_input(|| "c", || self.c.grab())?; - - // 2a * b = a + b - c - cs.enforce( - || "xor constraint", - |lc| lc + (E::Fr::from_str("2").unwrap(), a), - |lc| lc + b, - |lc| lc + a + b - c, - ); - Ok(()) - } -} - -// Create some parameters, create a proof, and verify the proof. -fn main() { - use rand::thread_rng; - - use bellman::groth16::{ - create_random_proof, generate_random_parameters, prepare_verifying_key, verify_proof - }; - - let rng = &mut thread_rng(); - - let params = { - let c = XorCircuit:: { - a: None, - b: None, - c: None, - }; - generate_random_parameters(c, rng).unwrap() - }; - - let pvk = prepare_verifying_key(¶ms.vk); - - // here we allocate actual variables - let c = XorCircuit { - a: Some(Fr::one()), - b: Some(Fr::zero()), - c: Some(Fr::one()), - }; - - // Create a groth16 proof with our parameters. - let proof = create_random_proof(c, ¶ms, rng).unwrap(); - - // `inputs` slice contains public parameters encoded as field elements Fr - - // incorrect input tests - let inputs = &[Fr::from_str("5").unwrap()]; - let success = verify_proof(&pvk, &proof, inputs).unwrap(); - assert!(!success); // fails, because 5 is not 1 or 0 - - let inputs = &[Fr::zero()]; - let success = verify_proof(&pvk, &proof, inputs).unwrap(); - assert!(!success); // fails because 0 != 0 xor 1 - - // correct input test - let inputs = &[Fr::one()]; - let success = verify_proof(&pvk, &proof, inputs).unwrap(); - assert!(success); - println!("{}", bellman_demo::verifier_contract::generate_demo_contract(¶ms.vk, &proof, inputs, "")); -} diff --git a/src/demo/src/lib.rs b/src/demo/src/lib.rs deleted file mode 100644 index bbdfec2..0000000 --- a/src/demo/src/lib.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![allow(unused_imports)] -#![allow(unused_variables)] -extern crate bellman; -extern crate pairing; -extern crate rand; -extern crate hex; -extern crate ff; - -pub mod verifier_contract; \ No newline at end of file diff --git a/src/demo/src/verifier_contract.rs b/src/demo/src/verifier_contract.rs deleted file mode 100644 index 374b42e..0000000 --- a/src/demo/src/verifier_contract.rs +++ /dev/null @@ -1,164 +0,0 @@ -// Library to generate a demo EVM verifier contract - -use bellman::{Circuit, ConstraintSystem, SynthesisError}; -use ff::{Field, PrimeField}; -use pairing::{Engine, CurveAffine, EncodedPoint}; -use bellman::groth16; -use pairing::bn256::{Bn256, Fr}; -use std::fmt; - -pub fn generate_demo_contract(vk: &groth16::VerifyingKey, proof: &groth16::Proof, inputs: &[E::Fr], inputs_extra: &str) -> String { - format!("{}{}", STANDARD_VERIFIER, demo_verifier(vk, proof, inputs, inputs_extra)) -} - -const STANDARD_VERIFIER: &str = -r#"pragma solidity ^0.4.24; - -// from https://github.com/HarryR/ethsnarks/blob/master/contracts/Verifier.sol -contract Verifier { - - function NegateY( uint256 Y ) internal pure returns (uint256) { - uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; - return q - (Y % q); - } - - function Verify ( uint256[14] in_vk, uint256[] vk_gammaABC, uint256[8] in_proof, uint256[] proof_inputs ) internal view returns (bool) { - require( ((vk_gammaABC.length / 2) - 1) == proof_inputs.length ); - - // Compute the linear combination vk_x - uint256[3] memory mul_input; - uint256[4] memory add_input; - bool success; - uint m = 2; - - // First two fields are used as the sum - add_input[0] = vk_gammaABC[0]; - add_input[1] = vk_gammaABC[1]; - - // Performs a sum of gammaABC[0] + sum[ gammaABC[i+1]^proof_inputs[i] ] - for (uint i = 0; i < proof_inputs.length; i++) { - mul_input[0] = vk_gammaABC[m++]; - mul_input[1] = vk_gammaABC[m++]; - mul_input[2] = proof_inputs[i]; - - assembly { - // ECMUL, output to last 2 elements of `add_input` - success := staticcall(sub(gas, 2000), 7, mul_input, 0x80, add(add_input, 0x40), 0x60) - } - require( success ); - - assembly { - // ECADD - success := staticcall(sub(gas, 2000), 6, add_input, 0xc0, add_input, 0x60) - } - require( success ); - } - - uint[24] memory input = [ - // (proof.A, proof.B) - in_proof[0], in_proof[1], // proof.A (G1) - in_proof[2], in_proof[3], in_proof[4], in_proof[5], // proof.B (G2) - - // (-vk.alpha, vk.beta) - in_vk[0], NegateY(in_vk[1]), // -vk.alpha (G1) - in_vk[2], in_vk[3], in_vk[4], in_vk[5], // vk.beta (G2) - - // (-vk_x, vk.gamma) - add_input[0], NegateY(add_input[1]), // -vk_x (G1) - in_vk[6], in_vk[7], in_vk[8], in_vk[9], // vk.gamma (G2) - - // (-proof.C, vk.delta) - in_proof[6], NegateY(in_proof[7]), // -proof.C (G1) - in_vk[10], in_vk[11], in_vk[12], in_vk[13] // vk.delta (G2) - ]; - - uint[1] memory out; - assembly { - success := staticcall(sub(gas, 2000), 8, input, 768, out, 0x20) - } - require(success); - return out[0] != 0; - } -} -"#; - -fn demo_verifier(vk: &groth16::VerifyingKey, proof: &groth16::Proof, inputs: &[E::Fr], inputs_extra: &str) -> String { - format!( -r#" -contract DemoVerifier is Verifier {{ - - function getVk() internal view returns (uint256[14] memory vk, uint256[] memory gammaABC) {{ - {vk} - }} - - function getProof() internal view returns (uint256[8] memory proof) {{ - {proof} - }} - - function getInputs() internal view returns (uint256[] memory inputs) {{ - {inputs} - {inputs_extra} - }} - - function verify( ) public view returns (bool) {{ - var (vk, gammaABC) = getVk(); - return Verify(vk, gammaABC, getProof(), getInputs()); - }} -}} -"#, - vk = hardcode_vk(vk), - proof = hardcode_proof(proof), - inputs = hardcode_inputs::(inputs), - inputs_extra = inputs_extra) -} - -fn unpack(t: &T) -> Vec -{ - t.into_uncompressed().as_ref().chunks(32).map(|c| "0x".to_owned() + &hex::encode(c)).collect() -} - -const SHIFT: &str = " "; - -fn render_array(name: &str, allocate: bool, values: &[Vec]) -> String { - let mut out = String::new(); - out.push('\n'); - let flattened: Vec<&String> = values.into_iter().flatten().collect(); - if allocate { - out.push_str(&format!("{}{} = new uint256[]({});\n", SHIFT, name, flattened.len())); - } - for (i, s) in flattened.iter().enumerate() { - out.push_str(&format!("{}{}[{}] = {};\n", SHIFT, name, i, s)); - } - out -} - -fn hardcode_vk(vk: &groth16::VerifyingKey) -> String { - let mut out = String::new(); - - let values = &[ - unpack(&vk.alpha_g1), - unpack(&vk.beta_g2), - unpack(&vk.gamma_g2), - unpack(&vk.delta_g2), - ]; - out.push_str(&render_array("vk", false, values)); - - let ic: Vec> = vk.ic.iter().map(unpack).collect(); - out.push_str(&render_array("gammaABC", true, ic.as_slice())); - - out -} - -fn hardcode_proof(proof: &groth16::Proof) -> String { - let values = &[ - unpack(&proof.a), - unpack(&proof.b), - unpack(&proof.c), - ]; - render_array("proof", false, values) -} - -fn hardcode_inputs(inputs: &[E::Fr]) -> String { - let values: Vec> = inputs.iter().map(|i| {vec!(format!("{}", inputs[0].into_repr()))}).collect(); - render_array("inputs", true, values.as_slice()) -} diff --git a/src/groth16/generator.rs b/src/groth16/generator.rs index 336608c..98a384c 100644 --- a/src/groth16/generator.rs +++ b/src/groth16/generator.rs @@ -1,12 +1,8 @@ extern crate time; -extern crate pbr; - use super::super::verbose_flag; use self::time::PreciseTime; -//use self::pbr::{MultiBar}; -use super::super::progress_bar::{MultiBar}; use rand::Rng; @@ -182,8 +178,6 @@ impl ConstraintSystem for KeypairAssembly { } } -const MIN_STEP: u64 = 1000; - /// Create parameters for a circuit, given some toxic waste. pub fn generate_parameters( circuit: C, @@ -227,12 +221,11 @@ pub fn generate_parameters( ); } + if verbose {eprintln!("Making {} powers of tau", assembly.num_constraints)}; // Create bases for blind evaluation of polynomials at tau let powers_of_tau = vec![Scalar::(E::Fr::zero()); assembly.num_constraints]; let mut powers_of_tau = EvaluationDomain::from_coeffs(powers_of_tau)?; - if verbose {eprintln!("assembly.num_constraints: {}", assembly.num_constraints)}; - // Compute G1 window table let mut g1_wnaf = Wnaf::new(); let g1_wnaf = g1_wnaf.base(g1, { @@ -268,7 +261,6 @@ pub fn generate_parameters( worker.scope(powers_of_tau.len(), |scope, chunk| { for (i, powers_of_tau) in powers_of_tau.chunks_mut(chunk).enumerate() { - //let mut progress_bar = mb.create_bar(a.len() as u64); scope.spawn(move || { let mut current_tau_power = tau.pow(&[(i*chunk) as u64]); @@ -290,14 +282,11 @@ pub fn generate_parameters( let start = PreciseTime::now(); // Compute the H query with multiple threads worker.scope(h.len(), |scope, chunk| { - let mut mb = if verbose {Some(MultiBar::new())} else {None}; for (h, p) in h.chunks_mut(chunk).zip(powers_of_tau.as_ref().chunks(chunk)) { let mut g1_wnaf = g1_wnaf.shared(); - let mut progress_bar = if let Some(mb) = mb.as_mut() {Some(mb.create_bar(h.len() as u64))} else {None}; scope.spawn(move || { // Set values of the H query to g1^{(tau^i * t(tau)) / delta} - let mut step: u64 = 0; for (h, p) in h.iter_mut().zip(p.iter()) { // Compute final exponent @@ -306,29 +295,23 @@ pub fn generate_parameters( // Exponentiate *h = g1_wnaf.scalar(exp.into_repr()); - if let Some(progress_bar) = progress_bar.as_mut() { - step += 1; - if step % MIN_STEP == 0 { - progress_bar.add(MIN_STEP); - }; - }; } // Batch normalize E::G1::batch_normalization(h); - if let Some(progress_bar) = progress_bar.as_mut() {progress_bar.finish();} }); } - if let Some(mb) = mb.as_mut() {mb.listen();} }); if verbose {eprintln!("computing the H query done in {} s", start.to(PreciseTime::now()).num_milliseconds() as f64 / 1000.0);}; } if verbose {eprintln!("using inverse FFT to convert powers of tau to Lagrange coefficients...")}; let start = PreciseTime::now(); + // Use inverse FFT to convert powers of tau to Lagrange coefficients powers_of_tau.ifft(&worker); let powers_of_tau = powers_of_tau.into_coeffs(); + if verbose {eprintln!("powers of tau stage 2 done in {} s", start.to(PreciseTime::now()).num_milliseconds() as f64 / 1000.0)}; let mut a = vec![E::G1::zero(); assembly.num_inputs + assembly.num_aux]; @@ -339,6 +322,7 @@ pub fn generate_parameters( if verbose {eprintln!("evaluating polynomials...")}; let start = PreciseTime::now(); + fn eval( // wNAF window tables g1_wnaf: &Wnaf>, @@ -368,9 +352,8 @@ pub fn generate_parameters( // Worker worker: &Worker ) - { - let verbose = verbose_flag(); + { // Sanity check assert_eq!(a.len(), at.len()); assert_eq!(a.len(), bt.len()); @@ -381,7 +364,6 @@ pub fn generate_parameters( // Evaluate polynomials in multiple threads worker.scope(a.len(), |scope, chunk| { - let mut mb = if verbose {Some(MultiBar::new())} else {None}; for ((((((a, b_g1), b_g2), ext), at), bt), ct) in a.chunks_mut(chunk) .zip(b_g1.chunks_mut(chunk)) .zip(b_g2.chunks_mut(chunk)) @@ -393,9 +375,7 @@ pub fn generate_parameters( let mut g1_wnaf = g1_wnaf.shared(); let mut g2_wnaf = g2_wnaf.shared(); - let mut progress_bar = if let Some(mb) = mb.as_mut() {Some(mb.create_bar(a.len() as u64))} else {None}; scope.spawn(move || { - let mut step: u64 = 0; for ((((((a, b_g1), b_g2), ext), at), bt), ct) in a.iter_mut() .zip(b_g1.iter_mut()) .zip(b_g2.iter_mut()) @@ -446,16 +426,8 @@ pub fn generate_parameters( e.mul_assign(inv); *ext = g1_wnaf.scalar(e.into_repr()); - if let Some(progress_bar) = progress_bar.as_mut() { - step += 1; - if step % MIN_STEP == 0 { - progress_bar.add(MIN_STEP); - }; - }; } - if let Some(progress_bar) = progress_bar.as_mut() {progress_bar.finish();} - // Batch normalize E::G1::batch_normalization(a); E::G1::batch_normalization(b_g1); @@ -463,7 +435,6 @@ pub fn generate_parameters( E::G1::batch_normalization(ext); }); }; - if let Some(mb) = mb.as_mut() {mb.listen();} }); } @@ -526,6 +497,8 @@ pub fn generate_parameters( ic: ic.into_iter().map(|e| e.into_affine()).collect() }; + println!("Has generated {} points", a.len()); + Ok(Parameters { vk: vk, h: Arc::new(h.into_iter().map(|e| e.into_affine()).collect()), diff --git a/src/multiexp.rs b/src/multiexp.rs index b46a8c8..b32327e 100644 --- a/src/multiexp.rs +++ b/src/multiexp.rs @@ -46,7 +46,7 @@ impl SourceBuilder for (Arc>, usize) { impl Source for (Arc>, usize) { fn add_assign_mixed(&mut self, to: &mut ::Projective) -> Result<(), SynthesisError> { if self.0.len() <= self.1 { - return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "expected more bases from source").into()); + return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "expected more bases when adding from source").into()); } if self.0[self.1].is_zero() { @@ -62,7 +62,7 @@ impl Source for (Arc>, usize) { fn skip(&mut self, amt: usize) -> Result<(), SynthesisError> { if self.0.len() <= self.1 { - return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "expected more bases from source").into()); + return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "expected more bases skipping from source").into()); } self.1 += amt;