Generate proof

This commit is contained in:
poma 2020-01-16 21:45:47 +07:00
parent 8f7f1f44f8
commit d770eb36c6
No known key found for this signature in database
GPG Key ID: BA20CB01FE165657
3 changed files with 151 additions and 43 deletions

64
phase2/src/bin/prove.rs Normal file

@ -0,0 +1,64 @@
#![allow(unused_imports)]
extern crate phase2;
extern crate bellman_ce;
use phase2::circom_circuit::CircomCircuit;
use std::fs::OpenOptions;
use phase2::parameters::MPCParameters;
use bellman_ce::groth16::{Proof, generate_random_parameters, prepare_verifying_key, create_random_proof, verify_proof};
use std::sync::Arc;
use bellman_ce::pairing::bn256::{
Bn256,
};
use bellman_ce::pairing::{
Engine,
CurveAffine,
ff::{
Field,
PrimeField,
},
};
use bellman_ce::{
Circuit,
SynthesisError,
Variable,
Index,
ConstraintSystem,
LinearCombination,
};
fn main() {
let should_filter_points_at_infinity = false;
let rng = &mut rand::XorShiftRng::new_unseeded(); // TODO: change this unsafe unseeded random (!)
let mut c = CircomCircuit::from_json("circuit.json");
c.load_witness_json("witness.json");
let input = c.inputs.to_vec();
let reader = OpenOptions::new()
.read(true)
.open("circom4.params")
.expect("unable to open.");
let mut params = MPCParameters::read(reader, should_filter_points_at_infinity, true).expect("unable to read params");
params.filter_params();
let params = params.get_params();
println!("Proving...");
let proof = create_random_proof(c, &*params, rng).unwrap();
println!("Checking proof");
let pvk = prepare_verifying_key(&params.vk);
let result = verify_proof(
&pvk,
&proof,
&input[1..]
).unwrap();
assert!(result, "Proof is correct");
println!("Done!")
}

@ -34,63 +34,99 @@ struct CircuitJson {
pub num_variables: usize, pub num_variables: usize,
} }
pub struct CircomCircuit<'a> { #[derive(Clone)]
pub file_name: &'a str, pub struct CircomCircuit<E: Engine> {
pub num_inputs: usize,
pub num_aux: usize,
pub num_constraints: usize,
pub inputs: Vec<E::Fr>,
pub aux: Vec<E::Fr>,
pub constraints: Vec<(
Vec<(usize, E::Fr)>,
Vec<(usize, E::Fr)>,
Vec<(usize, E::Fr)>,
)>,
}
impl<'a, E: Engine> CircomCircuit<E> {
pub fn load_witness_json(&mut self, filename: &str) {
let witness: Vec<String> = serde_json::from_str(&fs::read_to_string(filename).unwrap()).unwrap();
let witness = witness.into_iter().map(|x| E::Fr::from_str(&x).unwrap()).collect::<Vec<E::Fr>>();
self.inputs = witness[..self.num_inputs].to_vec();
self.aux = witness[self.num_inputs..].to_vec();
}
pub fn from_json(filename: &str) -> CircomCircuit::<E> {
let circuit_json: CircuitJson = serde_json::from_str(&fs::read_to_string(filename).unwrap()).unwrap();
let num_inputs = circuit_json.num_inputs + circuit_json.num_outputs + 1;
let num_aux = circuit_json.num_variables - num_inputs;
fn convert_constraint<EE: Engine>(lc: &BTreeMap<String, String>) -> Vec<(usize, EE::Fr)> {
let mut coeffs = vec![];
for (var_index_str, coefficient_str) in lc {
coeffs.push((var_index_str.parse().unwrap(), EE::Fr::from_str(coefficient_str).unwrap()));
}
return coeffs;
}
let mut constraints = vec![];
for constraint in circuit_json.constraints.iter() {
constraints.push((convert_constraint::<E>(&constraint[0]), convert_constraint::<E>(&constraint[1]), convert_constraint::<E>(&constraint[2])));
}
return CircomCircuit {
num_inputs: num_inputs,
num_aux: num_aux,
num_constraints: circuit_json.num_variables,
inputs: vec![],
aux: vec![],
constraints: constraints,
};
}
} }
/// Our demo circuit implements this `Circuit` trait which /// Our demo circuit implements this `Circuit` trait which
/// is used during paramgen and proving in order to /// is used during paramgen and proving in order to
/// synthesize the constraint system. /// synthesize the constraint system.
impl<'a, E: Engine> Circuit<E> for CircomCircuit<'a> { impl<'a, E: Engine> Circuit<E> for CircomCircuit<E> {
fn synthesize<CS: ConstraintSystem<E>>( fn synthesize<CS: ConstraintSystem<E>>(
self, self,
cs: &mut CS cs: &mut CS
) -> Result<(), SynthesisError> ) -> Result<(), SynthesisError>
{ {
let content = fs::read_to_string(self.file_name)?; for i in 1..self.num_inputs {
let circuit_json: CircuitJson = serde_json::from_str(&content).unwrap(); cs.alloc_input(|| format!("variable {}", i),
let num_public_inputs = circuit_json.num_inputs + circuit_json.num_outputs + 1; || {
for i in 1..circuit_json.num_variables { Ok(if self.inputs.len() > 0 { self.inputs[i] } else { E::Fr::from_str("1").unwrap() })
if i < num_public_inputs { })?;
cs.alloc_input(|| format!("variable {}", i), || {
Ok(E::Fr::from_str("1").unwrap())
})?;
} else {
cs.alloc(|| format!("variable {}", i), || {
Ok(E::Fr::from_str("1").unwrap())
})?;
}
} }
let mut constrained: BTreeMap<usize, bool> = BTreeMap::new();
let mut constraint_num = 0; for i in 0..self.num_aux {
for (_i, constraint) in circuit_json.constraints.iter().enumerate() { cs.alloc(|| format!("aux {}", i),
let mut lcs = vec![]; || {
for lc_description in constraint { Ok(if self.aux.len() > 0 { self.aux[i] } else { E::Fr::from_str("1").unwrap() })
let mut lc = LinearCombination::<E>::zero(); })?;
for (var_index_str, coefficient_str) in lc_description {
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);
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<usize, bool> = BTreeMap::new(); fn make_lc<E: Engine>(lc_data: Vec<(usize, E::Fr)>, num_inputs: usize) -> LinearCombination<E> {
for i in 0..circuit_json.num_variables { let mut lc = LinearCombination::<E>::zero();
if !constrained.contains_key(&i) { for (index, coeff) in lc_data {
unconstrained.insert(i, true); let var_index = if index < num_inputs {
Index::Input(index)
} else {
Index::Aux(index - num_inputs)
};
lc = lc + (coeff, Variable::new_unchecked(var_index))
} }
return lc;
} }
for (i, _) in unconstrained { for (i, constraint) in self.constraints.iter().enumerate() {
println!("variable {} is unconstrained", i); cs.enforce(|| format!("constraint {}", i),
|_| make_lc(constraint.0.clone(), self.num_inputs),
|_| make_lc(constraint.1.clone(), self.num_inputs),
|_| make_lc(constraint.2.clone(), self.num_inputs),
);
} }
Ok(()) Ok(())
} }

@ -401,6 +401,14 @@ impl MPCParameters {
&self.params &self.params
} }
pub fn filter_params(&mut self) {
self.params.vk.ic = self.params.vk.ic.clone().into_iter().filter(|x| !x.is_zero()).collect::<Vec<_>>();
self.params.h = Arc::new((*self.params.h).clone().into_iter().filter(|x| !x.is_zero()).collect::<Vec<_>>());
self.params.a = Arc::new((*self.params.a).clone().into_iter().filter(|x| !x.is_zero()).collect::<Vec<_>>());
self.params.b_g1 = Arc::new((*self.params.b_g1).clone().into_iter().filter(|x| !x.is_zero()).collect::<Vec<_>>());
self.params.b_g2 = Arc::new((*self.params.b_g2).clone().into_iter().filter(|x| !x.is_zero()).collect::<Vec<_>>());
}
/// Contributes some randomness to the parameters. Only one /// Contributes some randomness to the parameters. Only one
/// contributor needs to be honest for the parameters to be /// contributor needs to be honest for the parameters to be
/// secure. /// secure.