remove verbosity, migrate dependencies

This commit is contained in:
Alex Vlasov 2019-01-17 11:38:54 +03:00
parent d87d815037
commit 6e5cfe211f
9 changed files with 11 additions and 379 deletions

@ -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"

2
src/demo/.gitignore vendored

@ -1,2 +0,0 @@
/target
**/*.rs.bk

@ -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' }

@ -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
```

@ -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<T> {
fn grab(&self) -> Result<T, SynthesisError>;
}
impl<T: Copy> OptionExt<T> for Option<T> {
fn grab(&self) -> Result<T, SynthesisError> {
self.ok_or(SynthesisError::AssignmentMissing)
}
}
struct XorCircuit<E: Engine> {
a: Option<E::Fr>,
b: Option<E::Fr>,
c: Option<E::Fr>,
}
// Implementation of our circuit:
// Given a bit `c`, prove that we know bits `a` and `b` such that `c = a xor b`
impl<E: Engine> Circuit<E> for XorCircuit<E> {
fn synthesize<CS: ConstraintSystem<E>>(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::<Bn256> {
a: None,
b: None,
c: None,
};
generate_random_parameters(c, rng).unwrap()
};
let pvk = prepare_verifying_key(&params.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, &params, 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(&params.vk, &proof, inputs, ""));
}

@ -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;

@ -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<E: Engine>(vk: &groth16::VerifyingKey<E>, proof: &groth16::Proof<E>, 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<E: Engine>(vk: &groth16::VerifyingKey<E>, proof: &groth16::Proof<E>, 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::<E>(inputs),
inputs_extra = inputs_extra)
}
fn unpack<T: CurveAffine>(t: &T) -> Vec<String>
{
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>]) -> 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<E: Engine>(vk: &groth16::VerifyingKey<E>) -> 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<Vec<String>> = vk.ic.iter().map(unpack).collect();
out.push_str(&render_array("gammaABC", true, ic.as_slice()));
out
}
fn hardcode_proof<E: Engine>(proof: &groth16::Proof<E>) -> String {
let values = &[
unpack(&proof.a),
unpack(&proof.b),
unpack(&proof.c),
];
render_array("proof", false, values)
}
fn hardcode_inputs<E: Engine>(inputs: &[E::Fr]) -> String {
let values: Vec<Vec<String>> = inputs.iter().map(|i| {vec!(format!("{}", inputs[0].into_repr()))}).collect();
render_array("inputs", true, values.as_slice())
}

@ -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<E: Engine> ConstraintSystem<E> for KeypairAssembly<E> {
}
}
const MIN_STEP: u64 = 1000;
/// Create parameters for a circuit, given some toxic waste.
pub fn generate_parameters<E, C>(
circuit: C,
@ -227,12 +221,11 @@ pub fn generate_parameters<E, C>(
);
}
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>(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<E, C>(
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<E, C>(
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<E, C>(
// 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<E, C>(
if verbose {eprintln!("evaluating polynomials...")};
let start = PreciseTime::now();
fn eval<E: Engine>(
// wNAF window tables
g1_wnaf: &Wnaf<usize, &[E::G1], &mut Vec<i64>>,
@ -368,9 +352,8 @@ pub fn generate_parameters<E, C>(
// 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<E, C>(
// 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<E, C>(
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, C>(
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, C>(
E::G1::batch_normalization(ext);
});
};
if let Some(mb) = mb.as_mut() {mb.listen();}
});
}
@ -526,6 +497,8 @@ pub fn generate_parameters<E, C>(
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()),

@ -46,7 +46,7 @@ impl<G: CurveAffine> SourceBuilder<G> for (Arc<Vec<G>>, usize) {
impl<G: CurveAffine> Source<G> for (Arc<Vec<G>>, usize) {
fn add_assign_mixed(&mut self, to: &mut <G as CurveAffine>::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<G: CurveAffine> Source<G> for (Arc<Vec<G>>, 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;