1
0
Fork 0
mirror of synced 2025-09-23 12:18:44 +00:00

Merge branch 'develop' of github.com:JacobEberhardt/ZoKrates into if-else-array

This commit is contained in:
schaeff 2019-01-04 14:36:14 +01:00
commit 38be2a4890
9 changed files with 274 additions and 35 deletions

View file

@ -380,21 +380,11 @@ fn main() {
})
.collect();
let witness_map = program_ast
.execute(arguments)
let witness = program_ast
.execute(&arguments)
.unwrap_or_else(|e| panic!(format!("Execution failed: {}", e)));
println!(
"\nWitness: \n\n{}",
witness_map
.iter()
.filter_map(|(variable, value)| match variable {
variable if variable.is_output() => Some(format!("{} {}", variable, value)),
_ => None,
})
.collect::<Vec<String>>()
.join("\n")
);
println!("\nWitness: \n\n{}", witness.format_outputs());
// write witness to file
let output_path = Path::new(sub_matches.value_of("output").unwrap());
@ -403,10 +393,7 @@ fn main() {
Err(why) => panic!("couldn't create {}: {}", output_path.display(), why),
};
let mut bw = BufWriter::new(output_file);
for (var, val) in &witness_map {
write!(&mut bw, "{} {}\n", var, val.to_dec_string())
.expect("Unable to write data to file.");
}
write!(&mut bw, "{}", witness).expect("Unable to write data to file.");
bw.flush().expect("Unable to flush buffer.");
}
#[cfg(feature = "libsnark")]
@ -656,7 +643,7 @@ mod tests {
let (..) = r1cs_program(program_flattened.clone());
let _ = program_flattened
.execute(vec![FieldPrime::from(0)])
.execute(&vec![FieldPrime::from(0)])
.unwrap();
}
}
@ -690,7 +677,7 @@ mod tests {
let result = std::panic::catch_unwind(|| {
let _ = program_flattened
.execute(vec![FieldPrime::from(0)])
.execute(&vec![FieldPrime::from(0)])
.unwrap();
});
assert!(result.is_err());

View file

@ -3,17 +3,57 @@ use ir::*;
use std::collections::BTreeMap;
use zokrates_field::field::Field;
pub type ExecutionResult<T> = Result<Witness<T>, Error>;
pub struct Witness<T: Field>(BTreeMap<FlatVariable, T>);
impl<T: Field> Witness<T> {
pub fn return_values(&self) -> Vec<T> {
self.0
.clone()
.into_iter()
.filter(|(k, _)| k.is_output())
.map(|(_, v)| v)
.collect()
}
pub fn format_outputs(&self) -> String {
self.0
.iter()
.filter_map(|(variable, value)| match variable {
variable if variable.is_output() => Some(format!("{} {}", variable, value)),
_ => None,
})
.collect::<Vec<String>>()
.join("\n")
}
}
impl<T: Field> fmt::Display for Witness<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}",
self.0
.iter()
.map(|(k, v)| format!("{} {}", k, v.to_dec_string()))
.collect::<Vec<_>>()
.join("\n")
)
}
}
impl<T: Field> Prog<T> {
pub fn execute(self, inputs: Vec<T>) -> Result<BTreeMap<FlatVariable, T>, Error<T>> {
let main = self.main;
assert_eq!(main.arguments.len(), inputs.len());
pub fn execute<U: Into<T> + Clone>(&self, inputs: &Vec<U>) -> ExecutionResult<T> {
let main = &self.main;
self.check_inputs(&inputs)?;
let mut witness = BTreeMap::new();
witness.insert(FlatVariable::one(), T::one());
for (arg, value) in main.arguments.iter().zip(inputs.iter()) {
witness.insert(arg.clone(), value.clone());
witness.insert(arg.clone(), value.clone().into());
}
for statement in main.statements {
for statement in &main.statements {
match statement {
Statement::Constraint(quad, lin) => match lin.is_assignee(&witness) {
true => {
@ -24,7 +64,10 @@ impl<T: Field> Prog<T> {
let lhs_value = quad.evaluate(&witness);
let rhs_value = lin.evaluate(&witness);
if lhs_value != rhs_value {
return Err(Error::Constraint(quad, lin, lhs_value, rhs_value));
return Err(Error::UnsatisfiedConstraint {
left: lhs_value.to_dec_string(),
right: rhs_value.to_dec_string(),
});
}
}
},
@ -44,7 +87,18 @@ impl<T: Field> Prog<T> {
}
}
Ok(witness)
Ok(Witness(witness))
}
fn check_inputs<U>(&self, inputs: &Vec<U>) -> Result<(), Error> {
if self.main.arguments.len() == inputs.len() {
Ok(())
} else {
Err(Error::WrongInputCount {
expected: self.main.arguments.len(),
received: inputs.len(),
})
}
}
}
@ -69,21 +123,35 @@ impl<T: Field> QuadComb<T> {
}
}
#[derive(PartialEq, Debug)]
pub enum Error<T: Field> {
Constraint(QuadComb<T>, LinComb<T>, T, T),
#[derive(PartialEq, Serialize, Deserialize)]
pub enum Error {
UnsatisfiedConstraint { left: String, right: String },
Solver,
WrongInputCount { expected: usize, received: usize },
}
impl<T: Field> fmt::Display for Error<T> {
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::Constraint(ref quad, ref lin, ref left_value, ref right_value) => write!(
f,
"Expected {} to equal {}, but {} != {}",
quad, lin, left_value, right_value
),
Error::UnsatisfiedConstraint {
ref left,
ref right,
} => write!(f, "Expected {} to equal {}", left, right),
Error::Solver => write!(f, ""),
Error::WrongInputCount { expected, received } => write!(
f,
"Program takes {} input{} but was passed {} value{}",
expected,
if expected == 1 { "" } else { "s" },
received,
if received == 1 { "" } else { "s" }
),
}
}
}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self)
}
}

View file

@ -13,6 +13,9 @@ mod interpreter;
use self::expression::LinComb;
use self::expression::QuadComb;
pub use self::interpreter::Error;
pub use self::interpreter::ExecutionResult;
#[derive(Debug, Serialize, Deserialize, Clone)]
pub enum Statement<T: Field> {
Constraint(QuadComb<T>, LinComb<T>),

View file

@ -0,0 +1,2 @@
def main(field a, field b) -> (field):
return a + b

View file

@ -0,0 +1,27 @@
{
"tests": [
{
"input": {
"values": ["1", "2"]
},
"output": {
"Ok": {
"values": ["3"]
}
}
},
{
"input": {
"values": ["1", "2", "42"]
},
"output": {
"Err": {
"WrongInputCount": {
"expected": 2,
"received": 3
}
}
}
}
]
}

View file

@ -0,0 +1,3 @@
def main(field a) -> (field):
a == 1
return 1

View file

@ -0,0 +1,17 @@
{
"tests": [
{
"input": {
"values": ["0"]
},
"output": {
"Err": {
"UnsatisfiedConstraint": {
"left": "1",
"right": "0"
}
}
}
}
]
}

View file

@ -0,0 +1,12 @@
extern crate serde_json;
extern crate zokrates_core;
#[macro_use]
extern crate serde_derive;
#[macro_use]
mod utils;
zokrates_test! {
add,
assert_one,
}

View file

@ -0,0 +1,120 @@
extern crate serde_json;
use std::io;
use zokrates_core::compile::{compile as generic_compile, CompileError};
use zokrates_core::field::{Field, FieldPrime};
use zokrates_core::ir;
#[derive(Serialize, Deserialize)]
pub struct Tests {
pub tests: Vec<Test>,
}
#[derive(Serialize, Deserialize)]
pub struct Input {
pub values: Vec<Val>,
}
#[derive(Serialize, Deserialize)]
pub struct Test {
pub input: Input,
pub output: TestResult,
}
pub type TestResult = Result<Output, ir::Error>;
#[derive(PartialEq, Debug)]
pub struct ComparableResult(Result<Vec<FieldPrime>, ir::Error>);
#[derive(Serialize, Deserialize)]
pub struct Output {
values: Vec<Val>,
}
type Val = String;
impl From<ir::ExecutionResult<FieldPrime>> for ComparableResult {
fn from(r: ir::ExecutionResult<FieldPrime>) -> ComparableResult {
ComparableResult(r.map(|v| v.return_values()))
}
}
impl From<TestResult> for ComparableResult {
fn from(r: TestResult) -> ComparableResult {
ComparableResult(r.map(|v| {
v.values
.into_iter()
.map(|v| FieldPrime::from_dec_string(v))
.collect()
}))
}
}
pub fn compare(
result: ir::ExecutionResult<FieldPrime>,
expected: TestResult,
) -> Result<(), String> {
// extract outputs from result
let result = ComparableResult::from(result);
// deserialize expected result
let expected = ComparableResult::from(expected);
if result != expected {
return Err(format!(
"Expected {:?} but found {:?}",
expected.0, result.0
));
}
Ok(())
}
pub fn read_file(path: &str) -> String {
use std::fs::File;
use std::io::Read;
let mut file = File::open(format!("./tests/bench/{}", path)).expect("Unable to open the file");
let mut contents = String::new();
file.read_to_string(&mut contents)
.expect("Unable to read the file");
contents
}
pub fn compile(code: &str) -> Result<ir::Prog<FieldPrime>, CompileError<FieldPrime>> {
generic_compile::<FieldPrime, &[u8], &[u8], io::Error>(&mut code.as_bytes(), None, None)
}
macro_rules! zokrates_test {
($($name:ident,)*) => {
$(
#[test]
fn $name() {
use zokrates_core::field::{FieldPrime, Field};
let code_string = $crate::utils::read_file(&format!("./{}.code", stringify!($name)));
let test_string = $crate::utils::read_file(&format!("./{}.json", stringify!($name)));
let bin = $crate::utils::compile(&code_string).unwrap();
let t: $crate::utils::Tests = serde_json::from_str(&test_string).unwrap();
for test in t.tests.into_iter() {
let input = &test.input.values;
let output = bin.execute(&input.iter().map(|v| FieldPrime::from_dec_string(v.clone())).collect());
let context = format!("
{}
Called with input ({})
", code_string, input.iter().map(|i| format!("{}", i)).collect::<Vec<_>>().join(", "));
match $crate::utils::compare(output, test.output) {
Err(e) => panic!("{}{}", context, e),
Ok(..) => {}
};
}
}
)*
};
}