merge develop, resolve conflicts
This commit is contained in:
commit
101bbb17f4
29 changed files with 1837 additions and 615 deletions
1
zokrates_cli/tests/code/if_else_false.arguments.json
Normal file
1
zokrates_cli/tests/code/if_else_false.arguments.json
Normal file
|
@ -0,0 +1 @@
|
|||
[0]
|
2
zokrates_cli/tests/code/if_else_false.code
Normal file
2
zokrates_cli/tests/code/if_else_false.code
Normal file
|
@ -0,0 +1,2 @@
|
|||
def main(a):
|
||||
return if a == 1 then 1 else 0 fi
|
1
zokrates_cli/tests/code/if_else_false.expected.witness
Normal file
1
zokrates_cli/tests/code/if_else_false.expected.witness
Normal file
|
@ -0,0 +1 @@
|
|||
~out_0 0
|
1
zokrates_cli/tests/code/if_else_true.arguments.json
Normal file
1
zokrates_cli/tests/code/if_else_true.arguments.json
Normal file
|
@ -0,0 +1 @@
|
|||
[1]
|
2
zokrates_cli/tests/code/if_else_true.code
Normal file
2
zokrates_cli/tests/code/if_else_true.code
Normal file
|
@ -0,0 +1,2 @@
|
|||
def main(a):
|
||||
return if a == 1 then 1 else 0 fi
|
1
zokrates_cli/tests/code/if_else_true.expected.witness
Normal file
1
zokrates_cli/tests/code/if_else_true.expected.witness
Normal file
|
@ -0,0 +1 @@
|
|||
~out_0 1
|
|
@ -70,6 +70,10 @@ mod integration {
|
|||
if program_name.contains("sha_libsnark") {
|
||||
compile.push("--gadgets");
|
||||
compile.push("--optimized");
|
||||
|
||||
// we don't want to test libsnark integrations if libsnark is not available
|
||||
#[cfg(feature = "nolibsnark")]
|
||||
return
|
||||
}
|
||||
|
||||
// compile
|
||||
|
@ -77,63 +81,65 @@ mod integration {
|
|||
.succeeds()
|
||||
.unwrap();
|
||||
|
||||
// SETUP
|
||||
assert_cli::Assert::command(&["../target/debug/zokrates-cli", "setup",
|
||||
"-i", flattened_path.to_str().unwrap(),
|
||||
"-p", proving_key_path.to_str().unwrap(),
|
||||
"-v", verification_key_path.to_str().unwrap(),
|
||||
"-m", variable_information_path.to_str().unwrap()])
|
||||
.succeeds()
|
||||
.unwrap();
|
||||
#[cfg(not(feature = "nolibsnark"))]
|
||||
{
|
||||
// SETUP
|
||||
assert_cli::Assert::command(&["../target/debug/zokrates-cli", "setup",
|
||||
"-i", flattened_path.to_str().unwrap(),
|
||||
"-p", proving_key_path.to_str().unwrap(),
|
||||
"-v", verification_key_path.to_str().unwrap(),
|
||||
"-m", variable_information_path.to_str().unwrap()])
|
||||
.succeeds()
|
||||
.unwrap();
|
||||
|
||||
// EXPORT-VERIFIER
|
||||
assert_cli::Assert::command(&["../target/debug/zokrates-cli", "export-verifier",
|
||||
"-i", verification_key_path.to_str().unwrap(),
|
||||
"-o", verification_contract_path.to_str().unwrap()])
|
||||
.succeeds()
|
||||
.unwrap();
|
||||
// EXPORT-VERIFIER
|
||||
assert_cli::Assert::command(&["../target/debug/zokrates-cli", "export-verifier",
|
||||
"-i", verification_key_path.to_str().unwrap(),
|
||||
"-o", verification_contract_path.to_str().unwrap()])
|
||||
.succeeds()
|
||||
.unwrap();
|
||||
|
||||
// COMPUTE_WITNESS
|
||||
let arguments: Value = serde_json::from_reader(File::open(arguments_path).unwrap()).unwrap();
|
||||
// COMPUTE_WITNESS
|
||||
let arguments: Value = serde_json::from_reader(File::open(arguments_path).unwrap()).unwrap();
|
||||
|
||||
let arguments_str_list: Vec<String> = arguments.as_array().unwrap().iter().map(|i| match *i {
|
||||
Value::Number(ref n) => n.to_string(),
|
||||
_ => panic!(format!("Cannot read arguments. Check {}", arguments_path.to_str().unwrap()))
|
||||
}).collect();
|
||||
let arguments_str_list: Vec<String> = arguments.as_array().unwrap().iter().map(|i| match *i {
|
||||
Value::Number(ref n) => n.to_string(),
|
||||
_ => panic!(format!("Cannot read arguments. Check {}", arguments_path.to_str().unwrap()))
|
||||
}).collect();
|
||||
|
||||
let mut compute = vec!["../target/debug/zokrates-cli", "compute-witness",
|
||||
"-i", flattened_path.to_str().unwrap(),
|
||||
"-o", witness_path.to_str().unwrap(),
|
||||
"-a"];
|
||||
let mut compute = vec!["../target/debug/zokrates-cli", "compute-witness",
|
||||
"-i", flattened_path.to_str().unwrap(),
|
||||
"-o", witness_path.to_str().unwrap(),
|
||||
"-a"];
|
||||
|
||||
for arg in arguments_str_list.iter() {
|
||||
compute.push(arg);
|
||||
for arg in arguments_str_list.iter() {
|
||||
compute.push(arg);
|
||||
}
|
||||
|
||||
assert_cli::Assert::command(&compute)
|
||||
.succeeds()
|
||||
.unwrap();
|
||||
|
||||
// load the expected witness
|
||||
let mut expected_witness_file = File::open(&expected_witness_path).unwrap();
|
||||
let mut expected_witness = String::new();
|
||||
expected_witness_file.read_to_string(&mut expected_witness).unwrap();
|
||||
|
||||
// load the actual witness
|
||||
let mut witness_file = File::open(&witness_path).unwrap();
|
||||
let mut witness = String::new();
|
||||
witness_file.read_to_string(&mut witness).unwrap();
|
||||
|
||||
for line in expected_witness.as_str().split("\n") {
|
||||
assert!(witness.contains(line), "Witness generation failed for {}\n\nLine \"{}\" not found in witness", program_path.to_str().unwrap(), line);
|
||||
}
|
||||
// GENERATE-PROOF
|
||||
assert_cli::Assert::command(&["../target/debug/zokrates-cli", "generate-proof",
|
||||
"-w", witness_path.to_str().unwrap(),
|
||||
"-p", proving_key_path.to_str().unwrap(),
|
||||
"-i", variable_information_path.to_str().unwrap()])
|
||||
.succeeds()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
assert_cli::Assert::command(&compute)
|
||||
.succeeds()
|
||||
.unwrap();
|
||||
|
||||
// load the expected witness
|
||||
let mut expected_witness_file = File::open(&expected_witness_path).unwrap();
|
||||
let mut expected_witness = String::new();
|
||||
expected_witness_file.read_to_string(&mut expected_witness).unwrap();
|
||||
|
||||
// load the actual witness
|
||||
let mut witness_file = File::open(&witness_path).unwrap();
|
||||
let mut witness = String::new();
|
||||
witness_file.read_to_string(&mut witness).unwrap();
|
||||
|
||||
for line in expected_witness.as_str().split("\n") {
|
||||
assert!(witness.contains(line), "Witness generation failed for {}\n\nLine \"{}\" not found in witness", program_path.to_str().unwrap(), line);
|
||||
}
|
||||
// GENERATE-PROOF
|
||||
assert_cli::Assert::command(&["../target/debug/zokrates-cli", "generate-proof",
|
||||
"-w", witness_path.to_str().unwrap(),
|
||||
"-p", proving_key_path.to_str().unwrap(),
|
||||
"-i", variable_information_path.to_str().unwrap()])
|
||||
.succeeds()
|
||||
.unwrap();
|
||||
|
||||
}
|
||||
}
|
6
zokrates_core/examples/argument_reassign.code
Normal file
6
zokrates_core/examples/argument_reassign.code
Normal file
|
@ -0,0 +1,6 @@
|
|||
def sub(a):
|
||||
a = a + 3
|
||||
return a
|
||||
|
||||
def main():
|
||||
return sub(4)
|
|
@ -5,11 +5,16 @@
|
|||
//! @author Jacob Eberhardt <jacob.eberhardt@tu-berlin.de>
|
||||
//! @date 2017
|
||||
|
||||
pub mod parameter;
|
||||
pub mod variable;
|
||||
|
||||
use types::signature::Signature;
|
||||
use absy::parameter::Parameter;
|
||||
use absy::variable::Variable;
|
||||
|
||||
use std::fmt;
|
||||
use substitution::Substitution;
|
||||
use field::Field;
|
||||
use imports::Import;
|
||||
use parameter::Parameter;
|
||||
use flat_absy::*;
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, PartialEq)]
|
||||
|
@ -75,8 +80,8 @@ pub struct Function<T: Field> {
|
|||
pub arguments: Vec<Parameter>,
|
||||
/// Vector of statements that are executed when running the function
|
||||
pub statements: Vec<Statement<T>>,
|
||||
/// number of returns
|
||||
pub return_count: usize,
|
||||
/// function signature
|
||||
pub signature: Signature,
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Display for Function<T> {
|
||||
|
@ -118,10 +123,10 @@ impl<T: Field> fmt::Debug for Function<T> {
|
|||
#[derive(Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum Statement<T: Field> {
|
||||
Return(ExpressionList<T>),
|
||||
Definition(String, Expression<T>),
|
||||
Definition(Variable, Expression<T>),
|
||||
Condition(Expression<T>, Expression<T>),
|
||||
For(String, T, T, Vec<Statement<T>>),
|
||||
MultipleDefinition(Vec<String>, Expression<T>),
|
||||
For(Variable, T, T, Vec<Statement<T>>),
|
||||
MultipleDefinition(Vec<Variable>, Expression<T>),
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Display for Statement<T> {
|
||||
|
@ -185,72 +190,6 @@ pub enum Expression<T: Field> {
|
|||
FunctionCall(String, Vec<Expression<T>>),
|
||||
}
|
||||
|
||||
impl<T: Field> Expression<T> {
|
||||
pub fn apply_substitution(&self, substitution: &Substitution) -> Expression<T> {
|
||||
match *self {
|
||||
ref e @ Expression::Number(_) => e.clone(),
|
||||
Expression::Identifier(ref v) => {
|
||||
let mut new_name = v.to_string();
|
||||
loop {
|
||||
match substitution.get(&new_name) {
|
||||
Some(x) => new_name = x.to_string(),
|
||||
None => return Expression::Identifier(new_name),
|
||||
}
|
||||
}
|
||||
}
|
||||
Expression::Add(ref e1, ref e2) => Expression::Add(
|
||||
box e1.apply_substitution(substitution),
|
||||
box e2.apply_substitution(substitution),
|
||||
),
|
||||
Expression::Sub(ref e1, ref e2) => Expression::Sub(
|
||||
box e1.apply_substitution(substitution),
|
||||
box e2.apply_substitution(substitution),
|
||||
),
|
||||
Expression::Mult(ref e1, ref e2) => Expression::Mult(
|
||||
box e1.apply_substitution(substitution),
|
||||
box e2.apply_substitution(substitution),
|
||||
),
|
||||
Expression::Div(ref e1, ref e2) => Expression::Div(
|
||||
box e1.apply_substitution(substitution),
|
||||
box e2.apply_substitution(substitution),
|
||||
),
|
||||
Expression::Pow(ref e1, ref e2) => Expression::Pow(
|
||||
box e1.apply_substitution(substitution),
|
||||
box e2.apply_substitution(substitution),
|
||||
),
|
||||
Expression::IfElse(ref c, ref e1, ref e2) => Expression::IfElse(
|
||||
box c.apply_substitution(substitution),
|
||||
box e1.apply_substitution(substitution),
|
||||
box e2.apply_substitution(substitution),
|
||||
),
|
||||
Expression::FunctionCall(ref i, ref p) => {
|
||||
for param in p {
|
||||
param.apply_substitution(substitution);
|
||||
}
|
||||
Expression::FunctionCall(i.clone(), p.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_linear(&self) -> bool {
|
||||
match *self {
|
||||
Expression::Number(_) | Expression::Identifier(_) => true,
|
||||
Expression::Add(ref x, ref y) | Expression::Sub(ref x, ref y) => {
|
||||
x.is_linear() && y.is_linear()
|
||||
}
|
||||
Expression::Mult(ref x, ref y) | Expression::Div(ref x, ref y) => {
|
||||
match (x.clone(), y.clone()) {
|
||||
(box Expression::Number(_), box Expression::Number(_)) |
|
||||
(box Expression::Number(_), box Expression::Identifier(_)) |
|
||||
(box Expression::Identifier(_), box Expression::Number(_)) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Display for Expression<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
|
@ -277,7 +216,7 @@ impl<T: Field> fmt::Display for Expression<T> {
|
|||
}
|
||||
}
|
||||
write!(f, ")")
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -303,7 +242,7 @@ impl<T: Field> fmt::Debug for Expression<T> {
|
|||
try!(write!(f, "FunctionCall({:?}, (", i));
|
||||
try!(f.debug_list().entries(p.iter()).finish());
|
||||
write!(f, ")")
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -319,13 +258,6 @@ impl<T: Field> ExpressionList<T> {
|
|||
expressions: vec![]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn apply_substitution(&self, substitution: &Substitution) -> ExpressionList<T> {
|
||||
let expressions: Vec<Expression<T>> = self.expressions.iter().map(|e| e.apply_substitution(substitution)).collect();
|
||||
ExpressionList {
|
||||
expressions: expressions
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Display for ExpressionList<T> {
|
||||
|
@ -355,33 +287,6 @@ pub enum Condition<T: Field> {
|
|||
Gt(Expression<T>, Expression<T>),
|
||||
}
|
||||
|
||||
impl<T: Field> Condition<T> {
|
||||
fn apply_substitution(&self, substitution: &Substitution) -> Condition<T> {
|
||||
match *self {
|
||||
Condition::Lt(ref lhs, ref rhs) => Condition::Lt(
|
||||
lhs.apply_substitution(substitution),
|
||||
rhs.apply_substitution(substitution),
|
||||
),
|
||||
Condition::Le(ref lhs, ref rhs) => Condition::Le(
|
||||
lhs.apply_substitution(substitution),
|
||||
rhs.apply_substitution(substitution),
|
||||
),
|
||||
Condition::Eq(ref lhs, ref rhs) => Condition::Eq(
|
||||
lhs.apply_substitution(substitution),
|
||||
rhs.apply_substitution(substitution),
|
||||
),
|
||||
Condition::Ge(ref lhs, ref rhs) => Condition::Ge(
|
||||
lhs.apply_substitution(substitution),
|
||||
rhs.apply_substitution(substitution),
|
||||
),
|
||||
Condition::Gt(ref lhs, ref rhs) => Condition::Gt(
|
||||
lhs.apply_substitution(substitution),
|
||||
rhs.apply_substitution(substitution),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Display for Condition<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
21
zokrates_core/src/absy/parameter.rs
Normal file
21
zokrates_core/src/absy/parameter.rs
Normal file
|
@ -0,0 +1,21 @@
|
|||
use std::fmt;
|
||||
use absy::Variable;
|
||||
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Parameter {
|
||||
pub id: Variable,
|
||||
pub private: bool,
|
||||
}
|
||||
|
||||
impl fmt::Display for Parameter {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let visibility = if self.private { "private " } else { "" };
|
||||
write!(f, "{}{} {}", visibility, self.id._type, self.id.id)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Parameter {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Parameter(variable: {:?})", self.id)
|
||||
}
|
||||
}
|
45
zokrates_core/src/absy/variable.rs
Normal file
45
zokrates_core/src/absy/variable.rs
Normal file
|
@ -0,0 +1,45 @@
|
|||
use std::fmt;
|
||||
use types::Type;
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, PartialEq, Hash, Eq)]
|
||||
pub struct Variable {
|
||||
pub id: String,
|
||||
pub _type: Type
|
||||
}
|
||||
|
||||
impl Variable {
|
||||
pub fn get_type(&self) -> Type {
|
||||
self._type.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Into<String>> From<S> for Variable {
|
||||
fn from(s: S) -> Self {
|
||||
Variable {
|
||||
id: s.into(),
|
||||
_type: Type::FieldElement
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Variable {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{} {}",
|
||||
self._type,
|
||||
self.id,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Variable {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"Variable(type: {:?}, id: {:?})",
|
||||
self._type,
|
||||
self.id,
|
||||
)
|
||||
}
|
||||
}
|
|
@ -15,8 +15,6 @@ use semantics::{self, Checker};
|
|||
use optimizer::{Optimizer};
|
||||
use flatten::Flattener;
|
||||
use std::io::{self};
|
||||
use serde_json;
|
||||
use standard;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CompileError<T: Field> {
|
||||
|
@ -106,10 +104,12 @@ fn compile_aux<T: Field, R: BufRead, S: BufRead, E: Into<imports::Error>>(reader
|
|||
#[cfg(feature = "libsnark")]
|
||||
{
|
||||
use libsnark::{get_sha256_constraints};
|
||||
use standard::R1CS;
|
||||
use serde_json::from_str;
|
||||
|
||||
if should_include_gadgets {
|
||||
// inject globals
|
||||
let r1cs: standard::R1CS = serde_json::from_str(&get_sha256_constraints()).unwrap();
|
||||
let r1cs: R1CS = from_str(&get_sha256_constraints()).unwrap();
|
||||
|
||||
compiled_imports.push((FlatProg::from(r1cs), "sha256libsnark".to_string()));
|
||||
}
|
||||
|
@ -118,11 +118,11 @@ fn compile_aux<T: Field, R: BufRead, S: BufRead, E: Into<imports::Error>>(reader
|
|||
let program_ast = Importer::new().apply_imports(compiled_imports, program_ast_without_imports);
|
||||
|
||||
// check semantics
|
||||
Checker::new().check_program(program_ast.clone())?;
|
||||
let typed_ast = Checker::new().check_program(program_ast)?;
|
||||
|
||||
// flatten input program
|
||||
let program_flattened =
|
||||
Flattener::new(T::get_required_bits()).flatten_program(program_ast);
|
||||
Flattener::new(T::get_required_bits()).flatten_program(typed_ast);
|
||||
|
||||
Ok(program_flattened)
|
||||
}
|
||||
|
|
|
@ -2,27 +2,27 @@ use std::fmt;
|
|||
use substitution::Substitution;
|
||||
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Parameter {
|
||||
pub struct FlatParameter {
|
||||
pub id: String,
|
||||
pub private: bool,
|
||||
}
|
||||
|
||||
impl fmt::Display for Parameter {
|
||||
impl fmt::Display for FlatParameter {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let visibility = if self.private { "private " } else { "" };
|
||||
write!(f, "{}{}", visibility, self.id)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Parameter {
|
||||
impl fmt::Debug for FlatParameter {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Parameter(id: {:?})", self.id)
|
||||
write!(f, "FlatParameter(id: {:?})", self.id)
|
||||
}
|
||||
}
|
||||
|
||||
impl Parameter {
|
||||
pub fn apply_substitution(&self, substitution: &Substitution) -> Parameter {
|
||||
Parameter {
|
||||
impl FlatParameter {
|
||||
pub fn apply_substitution(&self, substitution: &Substitution) -> FlatParameter {
|
||||
FlatParameter {
|
||||
id: substitution.get(&self.id).unwrap().to_string(),
|
||||
private: self.private
|
||||
}
|
|
@ -5,12 +5,14 @@
|
|||
//! @author Jacob Eberhardt <jacob.eberhardt@tu-berlin.de>
|
||||
//! @date 2017
|
||||
|
||||
pub mod flat_parameter;
|
||||
|
||||
const BINARY_SEPARATOR: &str = "_b";
|
||||
|
||||
use self::flat_parameter::FlatParameter;
|
||||
use std::fmt;
|
||||
use std::collections::{BTreeMap};
|
||||
use field::Field;
|
||||
use parameter::Parameter;
|
||||
use substitution::Substitution;
|
||||
use standard;
|
||||
use helpers::{DirectiveStatement, Executable};
|
||||
|
@ -73,7 +75,7 @@ pub struct FlatFunction<T: Field> {
|
|||
/// Name of the program
|
||||
pub id: String,
|
||||
/// Arguments of the function
|
||||
pub arguments: Vec<Parameter>,
|
||||
pub arguments: Vec<FlatParameter>,
|
||||
/// Vector of statements that are executed when running the function
|
||||
pub statements: Vec<FlatStatement<T>>,
|
||||
/// number of returns
|
||||
|
@ -89,6 +91,7 @@ impl<T: Field> FlatFunction<T> {
|
|||
witness.insert(arg.id.to_string(), inputs[i].clone());
|
||||
}
|
||||
for statement in &self.statements {
|
||||
println!("{}", statement);
|
||||
match *statement {
|
||||
FlatStatement::Return(ref list) => {
|
||||
for (i, val) in list.expressions.iter().enumerate() {
|
File diff suppressed because it is too large
Load diff
|
@ -161,6 +161,7 @@ mod tests {
|
|||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[cfg(not(feature = "nolibsnark"))]
|
||||
fn execute() {
|
||||
let sha = LibsnarkGadgetHelper::Sha256Compress;
|
||||
// second vector here https://homes.esat.kuleuven.be/~nsmart/MPC/sha-256-test.txt
|
||||
|
|
|
@ -11,17 +11,16 @@ extern crate serde_derive;
|
|||
extern crate bincode;
|
||||
extern crate regex;
|
||||
|
||||
mod parameter;
|
||||
mod parser;
|
||||
mod imports;
|
||||
mod semantics;
|
||||
mod substitution;
|
||||
mod prefixed_substitution;
|
||||
mod direct_substitution;
|
||||
mod flatten;
|
||||
mod optimizer;
|
||||
mod standard;
|
||||
mod helpers;
|
||||
mod types;
|
||||
mod typed_absy;
|
||||
|
||||
pub mod absy;
|
||||
pub mod flat_absy;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
//! @author Jacob Eberhardt <jacob.eberhardt@tu-berlin.de>
|
||||
//! @date 2017
|
||||
|
||||
use prefixed_substitution::PrefixedSubstitution;
|
||||
use substitution::prefixed_substitution::PrefixedSubstitution;
|
||||
use substitution::Substitution;
|
||||
use flat_absy::*;
|
||||
use field::Field;
|
||||
|
@ -123,13 +123,13 @@ impl Optimizer {
|
|||
mod tests {
|
||||
use super::*;
|
||||
use field::FieldPrime;
|
||||
use parameter::Parameter;
|
||||
use flat_absy::flat_parameter::FlatParameter;
|
||||
|
||||
#[test]
|
||||
fn remove_synonyms() {
|
||||
let f: FlatFunction<FieldPrime> = FlatFunction {
|
||||
id: "foo".to_string(),
|
||||
arguments: vec![Parameter {id: "a".to_string(), private: false}],
|
||||
arguments: vec![FlatParameter {id: "a".to_string(), private: false}],
|
||||
statements: vec![
|
||||
FlatStatement::Definition("b".to_string(), FlatExpression::Identifier("a".to_string())),
|
||||
FlatStatement::Definition("c".to_string(), FlatExpression::Identifier("b".to_string())),
|
||||
|
@ -142,7 +142,7 @@ mod tests {
|
|||
|
||||
let optimized: FlatFunction<FieldPrime> = FlatFunction {
|
||||
id: "foo".to_string(),
|
||||
arguments: vec![Parameter {id: "_0".to_string(), private: false}],
|
||||
arguments: vec![FlatParameter {id: "_0".to_string(), private: false}],
|
||||
statements: vec![
|
||||
FlatStatement::Return(FlatExpressionList {
|
||||
expressions: vec![FlatExpression::Identifier("_0".to_string())]
|
||||
|
@ -160,7 +160,7 @@ mod tests {
|
|||
fn remove_multiple_synonyms() {
|
||||
let f: FlatFunction<FieldPrime> = FlatFunction {
|
||||
id: "foo".to_string(),
|
||||
arguments: vec![Parameter {id: "a".to_string(), private: false}],
|
||||
arguments: vec![FlatParameter {id: "a".to_string(), private: false}],
|
||||
statements: vec![
|
||||
FlatStatement::Definition("b".to_string(), FlatExpression::Identifier("a".to_string())),
|
||||
FlatStatement::Definition("d".to_string(), FlatExpression::Number(FieldPrime::from(1))),
|
||||
|
@ -175,7 +175,7 @@ mod tests {
|
|||
|
||||
let optimized: FlatFunction<FieldPrime> = FlatFunction {
|
||||
id: "foo".to_string(),
|
||||
arguments: vec![Parameter {id: "_0".to_string(), private: false}],
|
||||
arguments: vec![FlatParameter {id: "_0".to_string(), private: false}],
|
||||
statements: vec![
|
||||
FlatStatement::Definition("_1".to_string(), FlatExpression::Number(FieldPrime::from(1))),
|
||||
FlatStatement::Return(FlatExpressionList {
|
||||
|
|
|
@ -9,8 +9,11 @@ use std::io::{Lines};
|
|||
use std::io::prelude::*;
|
||||
use field::{Field};
|
||||
use absy::*;
|
||||
use absy::variable::Variable;
|
||||
use imports::*;
|
||||
use parameter::Parameter;
|
||||
use absy::parameter::Parameter;
|
||||
use types::Type;
|
||||
use types::signature::Signature;
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
struct Position {
|
||||
|
@ -768,9 +771,9 @@ fn parse_identifier_list1<T: Field>(
|
|||
head: String,
|
||||
input: String,
|
||||
pos: Position,
|
||||
) -> Result<(Vec<String>, String, Position), Error<T>> {
|
||||
) -> Result<(Vec<Variable>, String, Position), Error<T>> {
|
||||
let mut res = Vec::new();
|
||||
res.push(head);
|
||||
res.push(Variable::from(head));
|
||||
parse_comma_separated_identifier_list_rec(input, pos, &mut res)
|
||||
}
|
||||
|
||||
|
@ -833,11 +836,11 @@ fn parse_statement1<T: Field>(
|
|||
Ok((e2, s2, p2)) => match next_token(&s2, &p2) {
|
||||
(Token::InlineComment(_), ref s3, _) => {
|
||||
assert_eq!(s3, "");
|
||||
Ok((Statement::Definition(ide, e2), s2, p2))
|
||||
Ok((Statement::Definition(Variable::from(ide), e2), s2, p2))
|
||||
}
|
||||
(Token::Unknown(ref t3), ref s3, _) if t3 == "" => {
|
||||
assert_eq!(s3, "");
|
||||
Ok((Statement::Definition(ide, e2), s2, p2))
|
||||
Ok((Statement::Definition(Variable::from(ide), e2), s2, p2))
|
||||
}
|
||||
(t3, _, p3) => {
|
||||
Err(Error {
|
||||
|
@ -1004,11 +1007,11 @@ fn parse_statement<T: Field, R: BufRead>(
|
|||
match next_token(&s8, &p8) {
|
||||
(Token::InlineComment(_), ref s9, _) => {
|
||||
assert_eq!(s9, "");
|
||||
return Ok((Statement::For(x2, x4, x6, statements), s8, p8))
|
||||
return Ok((Statement::For(Variable::from(x2), x4, x6, statements), s8, p8))
|
||||
}
|
||||
(Token::Unknown(ref t9), ref s9, _) if t9 == "" => {
|
||||
assert_eq!(s9, "");
|
||||
return Ok((Statement::For(x2, x4, x6, statements), s8, p8))
|
||||
return Ok((Statement::For(Variable::from(x2), x4, x6, statements), s8, p8))
|
||||
},
|
||||
(t9, _, p9) => return Err(Error { expected: vec![Token::Unknown("1432567iuhgvfc".to_string())], got: t9 , pos: p9 }),
|
||||
}
|
||||
|
@ -1128,7 +1131,7 @@ fn parse_function<T: Field, R: BufRead>(
|
|||
(Token::Private, s4, p4) => {
|
||||
match next_token(&s4, &p4) {
|
||||
(Token::Ide(x), s5, p5) => {
|
||||
args.push(Parameter { id: x, private: true });
|
||||
args.push(Parameter { id: Variable::from(x), private: true });
|
||||
match next_token(&s5, &p5) {
|
||||
(Token::Comma, s6, p6) => {
|
||||
s = s6;
|
||||
|
@ -1173,7 +1176,7 @@ fn parse_function<T: Field, R: BufRead>(
|
|||
}
|
||||
}
|
||||
(Token::Ide(x), s4, p4) => {
|
||||
args.push(Parameter { id: x, private: false });
|
||||
args.push(Parameter { id: Variable::from(x), private: false });
|
||||
match next_token(&s4, &p4) {
|
||||
(Token::Comma, s5, p5) => {
|
||||
s = s5;
|
||||
|
@ -1296,12 +1299,18 @@ fn parse_function<T: Field, R: BufRead>(
|
|||
Some(x) => panic!("Last function statement not Return: {}", x),
|
||||
None => panic!("Error while checking last function statement"),
|
||||
}
|
||||
|
||||
let input_count = args.len();
|
||||
|
||||
Ok((
|
||||
Function {
|
||||
id: id,
|
||||
arguments: args,
|
||||
statements: stats,
|
||||
return_count: return_count
|
||||
signature: Signature {
|
||||
inputs: vec![Type::FieldElement; input_count],
|
||||
outputs: vec![Type::FieldElement; return_count]
|
||||
}
|
||||
},
|
||||
Position {
|
||||
line: current_line,
|
||||
|
@ -1463,11 +1472,11 @@ fn parse_comma_separated_expression_list_rec<T: Field>(
|
|||
fn parse_comma_separated_identifier_list_rec<T: Field>(
|
||||
input: String,
|
||||
pos: Position,
|
||||
mut acc: &mut Vec<String>
|
||||
) -> Result<(Vec<String>, String, Position), Error<T>> {
|
||||
mut acc: &mut Vec<Variable>
|
||||
) -> Result<(Vec<Variable>, String, Position), Error<T>> {
|
||||
match next_token(&input, &pos) {
|
||||
(Token::Ide(id), s1, p1) => {
|
||||
acc.push(id);
|
||||
acc.push(Variable::from(id));
|
||||
match next_token::<T>(&s1, &p1) {
|
||||
(Token::Comma, s2, p2) => parse_comma_separated_identifier_list_rec(s2, p2, &mut acc),
|
||||
(..) => Ok((acc.to_vec(), s1, p1)),
|
||||
|
|
|
@ -10,6 +10,11 @@ use std::collections::HashSet;
|
|||
use absy::*;
|
||||
use field::Field;
|
||||
use std::fmt;
|
||||
use types::signature::Signature;
|
||||
use absy::variable::Variable;
|
||||
use typed_absy::*;
|
||||
|
||||
use types::Type;
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub struct Error {
|
||||
|
@ -23,21 +28,20 @@ impl fmt::Display for Error {
|
|||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub struct Symbol {
|
||||
id: String,
|
||||
pub struct ScopedVariable {
|
||||
id: Variable,
|
||||
level: usize
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub struct FunctionDeclaration {
|
||||
id: String,
|
||||
return_count: usize,
|
||||
arg_count: usize,
|
||||
signature: Signature
|
||||
}
|
||||
|
||||
// Checker, checks the semantics of a program.
|
||||
pub struct Checker {
|
||||
scope: HashSet<Symbol>,
|
||||
scope: HashSet<ScopedVariable>,
|
||||
functions: HashSet<FunctionDeclaration>,
|
||||
level: usize
|
||||
}
|
||||
|
@ -51,25 +55,33 @@ impl Checker {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn check_program<T: Field>(&mut self, prog: Prog<T>) -> Result<(), Error> {
|
||||
for func in prog.imported_functions {
|
||||
pub fn check_program<T: Field>(&mut self, prog: Prog<T>) -> Result<TypedProg<T>, Error> {
|
||||
for func in &prog.imported_functions {
|
||||
self.functions.insert(FunctionDeclaration {
|
||||
id: func.id,
|
||||
return_count: func.return_count,
|
||||
arg_count: func.arguments.len()
|
||||
id: func.id.clone(),
|
||||
signature: Signature { // a bit hacky
|
||||
inputs: vec![Type::FieldElement; func.arguments.len()],
|
||||
outputs: vec![Type::FieldElement; func.return_count]
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let mut checked_functions = vec![];
|
||||
|
||||
for func in prog.functions {
|
||||
self.check_function(&func)?;
|
||||
let checked_func = self.check_function(&func)?;
|
||||
checked_functions.push(checked_func);
|
||||
self.functions.insert(FunctionDeclaration {
|
||||
id: func.id,
|
||||
return_count: func.return_count,
|
||||
arg_count: func.arguments.len()
|
||||
signature: func.signature
|
||||
});
|
||||
}
|
||||
self.check_single_main()?;
|
||||
Ok(())
|
||||
Ok(TypedProg {
|
||||
functions: checked_functions,
|
||||
imported_functions: prog.imported_functions,
|
||||
imports: prog.imports
|
||||
})
|
||||
}
|
||||
|
||||
fn check_single_main(&mut self) -> Result<(), Error> {
|
||||
|
@ -80,8 +92,10 @@ impl Checker {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_function<T: Field>(&mut self, funct: &Function<T>) -> Result<(), Error> {
|
||||
match self.find_function(&funct.id, funct.arguments.len()) {
|
||||
fn check_function<T: Field>(&mut self, funct: &Function<T>) -> Result<TypedFunction<T>, Error> {
|
||||
assert_eq!(funct.arguments.len(), funct.signature.inputs.len());
|
||||
|
||||
match self.find_function(&funct.id, &funct.arguments.iter().map(|a| a.clone().id._type).collect()) {
|
||||
Some(_) => {
|
||||
return Err(Error { message: format!("Duplicate definition for function {} with {} arguments", funct.id, funct.arguments.len()) })
|
||||
},
|
||||
|
@ -90,15 +104,21 @@ impl Checker {
|
|||
}
|
||||
}
|
||||
self.level += 1;
|
||||
|
||||
for arg in funct.arguments.clone() {
|
||||
self.scope.insert(Symbol {
|
||||
id: arg.id.to_string(),
|
||||
self.scope.insert(ScopedVariable {
|
||||
id: arg.id,
|
||||
level: self.level
|
||||
});
|
||||
}
|
||||
|
||||
let mut statements_checked = vec![];
|
||||
|
||||
for stat in funct.statements.clone() {
|
||||
self.check_statement(stat)?;
|
||||
let checked_stat = self.check_statement(stat)?;
|
||||
statements_checked.push(checked_stat);
|
||||
}
|
||||
|
||||
let current_level = self.level.clone();
|
||||
let current_scope = self.scope.clone();
|
||||
let to_remove = current_scope.iter().filter(|symbol| symbol.level == current_level);
|
||||
|
@ -106,69 +126,102 @@ impl Checker {
|
|||
self.scope.remove(symbol);
|
||||
}
|
||||
self.level -= 1;
|
||||
Ok(())
|
||||
Ok(TypedFunction {
|
||||
id: funct.id.clone(),
|
||||
arguments: funct.arguments.clone(),
|
||||
statements: statements_checked,
|
||||
signature: funct.signature.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn check_statement<T: Field>(&mut self, stat: Statement<T>) -> Result<(), Error> {
|
||||
fn check_statement<T: Field>(&mut self, stat: Statement<T>) -> Result<TypedStatement<T>, Error> {
|
||||
match stat {
|
||||
Statement::Return(list) => {
|
||||
self.check_expression_list(list)?;
|
||||
Ok(())
|
||||
Statement::Return(ref list) => {
|
||||
let mut expression_list_checked = vec![];
|
||||
for e in list.expressions.clone() {
|
||||
let e_checked = self.check_expression(e)?;
|
||||
expression_list_checked.push(e_checked);
|
||||
}
|
||||
Ok(TypedStatement::Return(expression_list_checked))
|
||||
}
|
||||
Statement::Definition(id, expr) => {
|
||||
self.check_expression(expr)?;
|
||||
self.scope.insert(Symbol {
|
||||
id: id.to_string(),
|
||||
Statement::Definition(var, expr) => {
|
||||
let checked_expr = self.check_expression(expr)?;
|
||||
|
||||
let expression_type = checked_expr.get_type();
|
||||
|
||||
if expression_type != var._type {
|
||||
return Err( Error { message: format!("cannot assign {:?} to {:?}", expression_type, var._type) });
|
||||
}
|
||||
|
||||
self.scope.insert(ScopedVariable {
|
||||
id: var.clone(),
|
||||
level: self.level
|
||||
});
|
||||
Ok(())
|
||||
|
||||
Ok(TypedStatement::Definition(var, checked_expr))
|
||||
}
|
||||
Statement::Condition(lhs, rhs) => {
|
||||
self.check_expression(lhs)?;
|
||||
self.check_expression(rhs)?;
|
||||
Ok(())
|
||||
let checked_lhs = self.check_expression(lhs)?;
|
||||
let checked_rhs = self.check_expression(rhs)?;
|
||||
|
||||
match (checked_lhs.clone(), checked_rhs.clone()) {
|
||||
(TypedExpression::FieldElement(_), TypedExpression::FieldElement(_)) => Ok(TypedStatement::Condition(checked_lhs, checked_rhs)),
|
||||
(e1, e2) => Err( Error { message: format!("cannot compare {:?} to {:?}", e1.get_type(), e2.get_type()) })
|
||||
}
|
||||
}
|
||||
Statement::For(id, _, _, statements) => {
|
||||
Statement::For(var, from, to, statements) => {
|
||||
self.level += 1;
|
||||
let index = Symbol {
|
||||
id: id.to_string(),
|
||||
let index = ScopedVariable {
|
||||
id: var.clone(),
|
||||
level: self.level
|
||||
};
|
||||
self.scope.insert(index.clone());
|
||||
|
||||
let mut checked_statements = vec![];
|
||||
|
||||
for stat in statements {
|
||||
self.check_statement(stat)?;
|
||||
let checked_stat = self.check_statement(stat)?;
|
||||
checked_statements.push(checked_stat);
|
||||
}
|
||||
self.scope.remove(&index);
|
||||
self.level -= 1;
|
||||
Ok(())
|
||||
Ok(TypedStatement::For(var, from, to, checked_statements))
|
||||
},
|
||||
Statement::MultipleDefinition(ids, rhs) => {
|
||||
Statement::MultipleDefinition(vars, rhs) => {
|
||||
let vars_types: Vec<Type> = vars.iter().map(|var| var.clone()._type).collect();
|
||||
|
||||
// All elements of the left side have to be identifiers
|
||||
match rhs {
|
||||
// Right side has to be a function call
|
||||
Expression::FunctionCall(ref fun_id, ref arguments) => {
|
||||
match self.find_function(fun_id, arguments.len()) {
|
||||
// check the arguments
|
||||
let mut arguments_checked = vec![];
|
||||
for arg in arguments {
|
||||
let arg_checked = self.check_expression(arg.clone())?;
|
||||
arguments_checked.push(arg_checked);
|
||||
}
|
||||
|
||||
|
||||
let mut arguments_types = vec![];
|
||||
for arg in arguments_checked.iter() {
|
||||
arguments_types.push(arg.get_type());
|
||||
}
|
||||
|
||||
match self.find_function(fun_id, &arguments_types) {
|
||||
// the function has to be defined
|
||||
Some(f) => {
|
||||
// the return count has to match the left side
|
||||
if f.return_count == ids.len() {
|
||||
// check the arguments
|
||||
for arg in arguments {
|
||||
self.check_expression(arg.clone())?;
|
||||
}
|
||||
|
||||
for id in ids {
|
||||
self.scope.insert(Symbol {
|
||||
id: id.to_string(),
|
||||
if f.signature.outputs == vars_types {
|
||||
for var in &vars {
|
||||
self.scope.insert(ScopedVariable {
|
||||
id: var.clone(),
|
||||
level: self.level
|
||||
});
|
||||
}
|
||||
return Ok(())
|
||||
return Ok(TypedStatement::MultipleDefinition(vars, TypedExpressionList::FunctionCall(f.id, arguments_checked, f.signature.outputs)))
|
||||
}
|
||||
Err(Error { message: format!("{} returns {} values but left side is of size {}", f.id, f.return_count, ids.len()) })
|
||||
Err(Error { message: format!("{} returns {} values but left side is of size {}", f.id, f.signature.outputs.len(), vars.len()) })
|
||||
},
|
||||
None => Err(Error { message: format!("Function definition for function {} with {} argument(s) not found.", fun_id, arguments.len()) })
|
||||
None => Err(Error { message: format!("Function definition for function {} with arguments {:?} not found.", fun_id, arguments_types) })
|
||||
}
|
||||
},
|
||||
_ => Err(Error { message: format!("{} should be a FunctionCall", rhs) })
|
||||
|
@ -177,69 +230,177 @@ impl Checker {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_expression<T: Field>(&mut self, expr: Expression<T>) -> Result<(), Error> {
|
||||
fn check_expression<T: Field>(&mut self, expr: Expression<T>) -> Result<TypedExpression<T>, Error> {
|
||||
match expr {
|
||||
Expression::Identifier(id) => {
|
||||
Expression::Identifier(variable) => {
|
||||
// check that `id` is defined in the scope
|
||||
match self.scope.iter().find(|symbol| symbol.id == id.to_string()) {
|
||||
Some(_) => Ok(()),
|
||||
None => Err(Error { message: format!("{} is undefined", id.to_string()) }),
|
||||
}
|
||||
}
|
||||
Expression::Add(box e1, box e2) | Expression::Sub(box e1, box e2) | Expression::Mult(box e1, box e2) |
|
||||
Expression::Div(box e1, box e2) | Expression::Pow(box e1, box e2) => {
|
||||
self.check_expression(e1)?;
|
||||
self.check_expression(e2)?;
|
||||
Ok(())
|
||||
}
|
||||
Expression::IfElse(box condition, box consequence, box alternative) => {
|
||||
self.check_condition(condition)?;
|
||||
self.check_expression(consequence)?;
|
||||
self.check_expression(alternative)?;
|
||||
Ok(())
|
||||
}
|
||||
Expression::FunctionCall(ref fun_id, ref arguments) => {
|
||||
match self.find_function(fun_id, arguments.len()) {
|
||||
// the function has to be defined
|
||||
Some(f) => {
|
||||
if f.return_count == 1 { // Functions must return a single value when not in a MultipleDefinition
|
||||
for expr in arguments {
|
||||
self.check_expression(expr.clone())?;
|
||||
}
|
||||
return Ok(())
|
||||
}
|
||||
Err(Error { message: format!("{} returns {} values but is called outside of a definition", fun_id, f.return_count) })
|
||||
match self.scope.iter().find(|v| v.id.id == variable) {
|
||||
Some(v) => match v.clone().id._type {
|
||||
Type::Boolean => Ok(BooleanExpression::Identifier(variable).into()),
|
||||
Type::FieldElement => Ok(FieldElementExpression::Identifier(variable).into()),
|
||||
},
|
||||
None => Err(Error { message: format!("Function definition for function {} with {} argument(s) not found.", fun_id, arguments.len()) })
|
||||
None => Err(Error { message: format!("{} is undefined", variable.to_string()) }),
|
||||
}
|
||||
},
|
||||
Expression::Add(box e1, box e2) => {
|
||||
let e1_checked = self.check_expression(e1)?;
|
||||
let e2_checked = self.check_expression(e2)?;
|
||||
|
||||
match (e1_checked, e2_checked) {
|
||||
(TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => {
|
||||
Ok(FieldElementExpression::Add(box e1, box e2).into())
|
||||
}
|
||||
(t1, t2) => Err(Error { message: format!("Expected only field elements, found {:?}, {:?}", t1.get_type(), t2.get_type()) }),
|
||||
}
|
||||
},
|
||||
Expression::Sub(box e1, box e2) => {
|
||||
let e1_checked = self.check_expression(e1)?;
|
||||
let e2_checked = self.check_expression(e2)?;
|
||||
|
||||
match (e1_checked, e2_checked) {
|
||||
(TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => {
|
||||
Ok(FieldElementExpression::Sub(box e1, box e2).into())
|
||||
}
|
||||
(t1, t2) => Err(Error { message: format!("Expected only field elements, found {:?}, {:?}", t1.get_type(), t2.get_type()) }),
|
||||
}
|
||||
},
|
||||
Expression::Mult(box e1, box e2) => {
|
||||
let e1_checked = self.check_expression(e1)?;
|
||||
let e2_checked = self.check_expression(e2)?;
|
||||
|
||||
match (e1_checked, e2_checked) {
|
||||
(TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => {
|
||||
Ok(FieldElementExpression::Mult(box e1, box e2).into())
|
||||
}
|
||||
(t1, t2) => Err(Error { message: format!("Expected only field elements, found {:?}, {:?}", t1.get_type(), t2.get_type()) }),
|
||||
}
|
||||
},
|
||||
Expression::Div(box e1, box e2) => {
|
||||
let e1_checked = self.check_expression(e1)?;
|
||||
let e2_checked = self.check_expression(e2)?;
|
||||
|
||||
match (e1_checked, e2_checked) {
|
||||
(TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => {
|
||||
Ok(FieldElementExpression::Div(box e1, box e2).into())
|
||||
}
|
||||
(t1, t2) => Err(Error { message: format!("Expected only field elements, found {:?}, {:?}", t1.get_type(), t2.get_type()) }),
|
||||
}
|
||||
},
|
||||
Expression::Pow(box e1, box e2) => {
|
||||
let e1_checked = self.check_expression(e1)?;
|
||||
let e2_checked = self.check_expression(e2)?;
|
||||
|
||||
match (e1_checked, e2_checked) {
|
||||
(TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => {
|
||||
Ok(TypedExpression::FieldElement(FieldElementExpression::Pow(box e1, box e2)))
|
||||
}
|
||||
(t1, t2) => Err(Error { message: format!("Expected only field elements, found {:?}, {:?}", t1.get_type(), t2.get_type()) }),
|
||||
}
|
||||
},
|
||||
Expression::IfElse(box condition, box consequence, box alternative) => {
|
||||
let condition_checked = self.check_condition(&condition)?;
|
||||
let consequence_checked = self.check_expression(consequence)?;
|
||||
let alternative_checked = self.check_expression(alternative)?;
|
||||
|
||||
match (condition_checked, consequence_checked, alternative_checked) {
|
||||
(condition, TypedExpression::FieldElement(consequence), TypedExpression::FieldElement(alternative)) => {
|
||||
Ok(FieldElementExpression::IfElse(box condition, box consequence, box alternative).into())
|
||||
},
|
||||
_ => panic!("id else only for bool fe fe")
|
||||
}
|
||||
},
|
||||
Expression::Number(n) => Ok(FieldElementExpression::Number(n).into()),
|
||||
Expression::FunctionCall(ref fun_id, ref arguments) => {
|
||||
// check the arguments
|
||||
let mut arguments_checked = vec![];
|
||||
for arg in arguments {
|
||||
let arg_checked = self.check_expression(arg.clone())?;
|
||||
arguments_checked.push(arg_checked);
|
||||
}
|
||||
|
||||
|
||||
let mut arguments_types = vec![];
|
||||
for arg in arguments_checked.iter() {
|
||||
arguments_types.push(arg.get_type());
|
||||
}
|
||||
|
||||
match self.find_function(fun_id, &arguments_types) {
|
||||
// the function has to be defined
|
||||
Some(f) => {
|
||||
// the return count has to be 1
|
||||
if f.signature.outputs.len() == 1 {
|
||||
match f.signature.outputs[0] {
|
||||
Type::FieldElement => return Ok(FieldElementExpression::FunctionCall(f.id, arguments_checked).into()),
|
||||
_ => panic!("cannot return booleans")
|
||||
}
|
||||
}
|
||||
Err(Error { message: format!("{} returns {} values but is called outside of a definition", f.id, f.signature.outputs.len()) })
|
||||
},
|
||||
None => Err(Error { message: format!("Function definition for function {} with arguments {:?} not found.", fun_id, arguments_types) })
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn check_condition<T: Field>(&mut self, cond: &Condition<T>) -> Result<BooleanExpression<T>, Error> {
|
||||
match cond.clone() {
|
||||
Condition::Lt(e1, e2) => {
|
||||
let e1_checked = self.check_expression(e1)?;
|
||||
let e2_checked = self.check_expression(e2)?;
|
||||
match (e1_checked, e2_checked) {
|
||||
(TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => {
|
||||
Ok(BooleanExpression::Lt(box e1, box e2))
|
||||
},
|
||||
(e1, e2) => Err(Error { message: format!("cannot compare {} to {}", e1.get_type(), e2.get_type()) })
|
||||
}
|
||||
},
|
||||
Condition::Le(e1, e2) => {
|
||||
let e1_checked = self.check_expression(e1)?;
|
||||
let e2_checked = self.check_expression(e2)?;
|
||||
match (e1_checked, e2_checked) {
|
||||
(TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => {
|
||||
Ok(BooleanExpression::Le(box e1, box e2))
|
||||
},
|
||||
(e1, e2) => Err(Error { message: format!("cannot compare {} to {}", e1.get_type(), e2.get_type()) })
|
||||
}
|
||||
},
|
||||
Condition::Eq(e1, e2) => {
|
||||
let e1_checked = self.check_expression(e1)?;
|
||||
let e2_checked = self.check_expression(e2)?;
|
||||
match (e1_checked, e2_checked) {
|
||||
(TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => {
|
||||
Ok(BooleanExpression::Eq(box e1, box e2))
|
||||
},
|
||||
(e1, e2) => Err(Error { message: format!("cannot compare {} to {}", e1.get_type(), e2.get_type()) })
|
||||
}
|
||||
},
|
||||
Condition::Ge(e1, e2) => {
|
||||
let e1_checked = self.check_expression(e1)?;
|
||||
let e2_checked = self.check_expression(e2)?;
|
||||
match (e1_checked, e2_checked) {
|
||||
(TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => {
|
||||
Ok(BooleanExpression::Ge(box e1, box e2))
|
||||
},
|
||||
(e1, e2) => Err(Error { message: format!("cannot compare {} to {}", e1.get_type(), e2.get_type()) })
|
||||
}
|
||||
},
|
||||
Condition::Gt(e1, e2) => {
|
||||
let e1_checked = self.check_expression(e1)?;
|
||||
let e2_checked = self.check_expression(e2)?;
|
||||
match (e1_checked, e2_checked) {
|
||||
(TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => {
|
||||
Ok(BooleanExpression::Gt(box e1, box e2))
|
||||
},
|
||||
(e1, e2) => Err(Error { message: format!("cannot compare {} to {}", e1.get_type(), e2.get_type()) })
|
||||
}
|
||||
}
|
||||
Expression::Number(_) => Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn check_expression_list<T: Field>(&mut self, list: ExpressionList<T>) -> Result<(), Error> {
|
||||
for expr in list.expressions { // implement Iterator trait?
|
||||
self.check_expression(expr)?
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_condition<T: Field>(&mut self, cond: Condition<T>) -> Result<(), Error> {
|
||||
match cond {
|
||||
Condition::Lt(e1, e2) |
|
||||
Condition::Le(e1, e2) |
|
||||
Condition::Eq(e1, e2) |
|
||||
Condition::Ge(e1, e2) |
|
||||
Condition::Gt(e1, e2) => {
|
||||
self.check_expression(e1)?;
|
||||
self.check_expression(e2)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn find_function(&mut self, id: &str, arg_count: usize) -> Option<FunctionDeclaration> {
|
||||
self.functions.clone().into_iter().find(|fun| fun.id == id && fun.arg_count == arg_count)
|
||||
fn find_function(&mut self, id: &str, arg_types: &Vec<Type>) -> Option<FunctionDeclaration> {
|
||||
self.functions.clone().into_iter().find(|fun| {
|
||||
fun.id == id && fun.signature.inputs.len() == arg_types.len()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -247,9 +408,9 @@ impl Checker {
|
|||
mod tests {
|
||||
use super::*;
|
||||
use field::FieldPrime;
|
||||
use parameter::Parameter;
|
||||
use absy::parameter::Parameter;
|
||||
|
||||
pub fn new_with_args(scope: HashSet<Symbol>, level: usize, functions: HashSet<FunctionDeclaration>) -> Checker {
|
||||
pub fn new_with_args(scope: HashSet<ScopedVariable>, level: usize, functions: HashSet<FunctionDeclaration>) -> Checker {
|
||||
Checker {
|
||||
scope: scope,
|
||||
functions: functions,
|
||||
|
@ -262,7 +423,7 @@ mod tests {
|
|||
// a = b
|
||||
// b undefined
|
||||
let statement: Statement<FieldPrime> = Statement::Definition(
|
||||
String::from("a"),
|
||||
Variable::from("a"),
|
||||
Expression::Identifier(String::from("b"))
|
||||
);
|
||||
let mut checker = Checker::new();
|
||||
|
@ -274,16 +435,23 @@ mod tests {
|
|||
// a = b
|
||||
// b defined
|
||||
let statement: Statement<FieldPrime> = Statement::Definition(
|
||||
String::from("a"),
|
||||
Variable::from("a"),
|
||||
Expression::Identifier(String::from("b"))
|
||||
);
|
||||
let mut scope = HashSet::new();
|
||||
scope.insert(Symbol {
|
||||
id: String::from("b"),
|
||||
scope.insert(ScopedVariable {
|
||||
id: Variable::from("b"),
|
||||
level: 0
|
||||
});
|
||||
let mut checker = new_with_args(scope, 1, HashSet::new());
|
||||
assert_eq!(checker.check_statement(statement), Ok(()));
|
||||
assert_eq!(checker.check_statement(statement),
|
||||
Ok(
|
||||
TypedStatement::Definition(
|
||||
Variable::from("a"),
|
||||
FieldElementExpression::Identifier(String::from("b")).into()
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -296,14 +464,17 @@ mod tests {
|
|||
let foo_args = Vec::<Parameter>::new();
|
||||
let mut foo_statements = Vec::<Statement<FieldPrime>>::new();
|
||||
foo_statements.push(Statement::Definition(
|
||||
String::from("a"),
|
||||
Variable::from("a"),
|
||||
Expression::Number(FieldPrime::from(1)))
|
||||
);
|
||||
let foo = Function {
|
||||
id: "foo".to_string(),
|
||||
arguments: foo_args,
|
||||
statements: foo_statements,
|
||||
return_count: 1,
|
||||
signature: Signature {
|
||||
inputs: vec![],
|
||||
outputs: vec![Type::FieldElement]
|
||||
}
|
||||
};
|
||||
|
||||
let bar_args = Vec::<Parameter>::new();
|
||||
|
@ -317,7 +488,10 @@ mod tests {
|
|||
id: "bar".to_string(),
|
||||
arguments: bar_args,
|
||||
statements: bar_statements,
|
||||
return_count: 1,
|
||||
signature: Signature {
|
||||
inputs: vec![],
|
||||
outputs: vec![Type::FieldElement]
|
||||
}
|
||||
};
|
||||
|
||||
let mut funcs = Vec::<Function<FieldPrime>>::new();
|
||||
|
@ -343,49 +517,61 @@ mod tests {
|
|||
// def main():
|
||||
// return 1
|
||||
// should pass
|
||||
let foo_args = Vec::<Parameter>::new();
|
||||
let mut foo_statements = Vec::<Statement<FieldPrime>>::new();
|
||||
foo_statements.push(Statement::Definition(
|
||||
String::from("a"),
|
||||
Expression::Number(FieldPrime::from(1)))
|
||||
);
|
||||
let foo_args = vec![];
|
||||
let foo_statements = vec![
|
||||
Statement::Definition(
|
||||
Variable::from("a"),
|
||||
Expression::Number(FieldPrime::from(1)))
|
||||
];
|
||||
|
||||
let foo = Function {
|
||||
id: "foo".to_string(),
|
||||
arguments: foo_args,
|
||||
statements: foo_statements,
|
||||
return_count: 1,
|
||||
signature: Signature {
|
||||
inputs: vec![],
|
||||
outputs: vec![Type::FieldElement]
|
||||
}
|
||||
};
|
||||
|
||||
let bar_args = Vec::<Parameter>::new();
|
||||
let mut bar_statements = Vec::<Statement<FieldPrime>>::new();
|
||||
bar_statements.push(Statement::Definition(
|
||||
String::from("a"),
|
||||
Expression::Number(FieldPrime::from(2))
|
||||
));
|
||||
bar_statements.push(Statement::Return(
|
||||
ExpressionList {
|
||||
expressions: vec![Expression::Identifier(String::from("a"))]
|
||||
}
|
||||
));
|
||||
let bar_statements = vec![
|
||||
Statement::Definition(
|
||||
Variable::from("a"),
|
||||
Expression::Number(FieldPrime::from(2))
|
||||
),
|
||||
Statement::Return(
|
||||
ExpressionList {
|
||||
expressions: vec![Expression::Identifier(String::from("a"))]
|
||||
}
|
||||
)
|
||||
];
|
||||
let bar = Function {
|
||||
id: "bar".to_string(),
|
||||
arguments: bar_args,
|
||||
statements: bar_statements,
|
||||
return_count: 1,
|
||||
signature: Signature {
|
||||
inputs: vec![],
|
||||
outputs: vec![Type::FieldElement]
|
||||
}
|
||||
};
|
||||
|
||||
let main_args = Vec::<Parameter>::new();
|
||||
let mut main_statements = Vec::<Statement<FieldPrime>>::new();
|
||||
main_statements.push(Statement::Return(
|
||||
ExpressionList {
|
||||
expressions: vec![Expression::Number(FieldPrime::from(1))]
|
||||
})
|
||||
);
|
||||
let main_args = vec![];
|
||||
let main_statements = vec![
|
||||
Statement::Return(
|
||||
ExpressionList {
|
||||
expressions: vec![Expression::Number(FieldPrime::from(1))]
|
||||
})
|
||||
];
|
||||
|
||||
let main = Function {
|
||||
id: "main".to_string(),
|
||||
arguments: main_args,
|
||||
statements: main_statements,
|
||||
return_count: 1,
|
||||
signature: Signature {
|
||||
inputs: vec![],
|
||||
outputs: vec![Type::FieldElement]
|
||||
}
|
||||
};
|
||||
|
||||
let mut funcs = Vec::<Function<FieldPrime>>::new();
|
||||
|
@ -399,7 +585,7 @@ mod tests {
|
|||
};
|
||||
|
||||
let mut checker = Checker::new();
|
||||
assert_eq!(checker.check_program(prog), Ok(()));
|
||||
assert!(checker.check_program(prog).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -411,7 +597,7 @@ mod tests {
|
|||
// should fail
|
||||
let mut foo_statements = Vec::<Statement<FieldPrime>>::new();
|
||||
foo_statements.push(Statement::For(
|
||||
String::from("i"),
|
||||
Variable::from("i"),
|
||||
FieldPrime::from(0),
|
||||
FieldPrime::from(10),
|
||||
Vec::<Statement<FieldPrime>>::new())
|
||||
|
@ -425,7 +611,10 @@ mod tests {
|
|||
id: "foo".to_string(),
|
||||
arguments: Vec::<Parameter>::new(),
|
||||
statements: foo_statements,
|
||||
return_count: 1,
|
||||
signature: Signature {
|
||||
inputs: vec![],
|
||||
outputs: vec![Type::FieldElement]
|
||||
}
|
||||
};
|
||||
|
||||
let mut checker = Checker::new();
|
||||
|
@ -442,24 +631,54 @@ mod tests {
|
|||
let mut foo_statements = Vec::<Statement<FieldPrime>>::new();
|
||||
let mut for_statements = Vec::<Statement<FieldPrime>>::new();
|
||||
for_statements.push(Statement::Definition(
|
||||
String::from("a"),
|
||||
Variable::from("a"),
|
||||
Expression::Identifier(String::from("i"))
|
||||
));
|
||||
foo_statements.push(Statement::For(
|
||||
String::from("i"),
|
||||
Variable::from("i"),
|
||||
FieldPrime::from(0),
|
||||
FieldPrime::from(10),
|
||||
for_statements
|
||||
));
|
||||
|
||||
let mut foo_statements_checked = Vec::<TypedStatement<FieldPrime>>::new();
|
||||
let mut for_statements_checked = Vec::<TypedStatement<FieldPrime>>::new();
|
||||
|
||||
for_statements_checked.push(TypedStatement::Definition(
|
||||
Variable::from("a"),
|
||||
FieldElementExpression::Identifier(String::from("i")).into()
|
||||
));
|
||||
|
||||
foo_statements_checked.push(TypedStatement::For(
|
||||
Variable::from("i"),
|
||||
FieldPrime::from(0),
|
||||
FieldPrime::from(10),
|
||||
for_statements_checked
|
||||
));
|
||||
|
||||
|
||||
let foo = Function {
|
||||
id: "foo".to_string(),
|
||||
arguments: Vec::<Parameter>::new(),
|
||||
statements: foo_statements,
|
||||
return_count: 1,
|
||||
signature: Signature {
|
||||
inputs: vec![],
|
||||
outputs: vec![Type::FieldElement]
|
||||
}
|
||||
};
|
||||
|
||||
let foo_checked = TypedFunction {
|
||||
id: "foo".to_string(),
|
||||
arguments: Vec::<Parameter>::new(),
|
||||
statements: foo_statements_checked,
|
||||
signature: Signature {
|
||||
inputs: vec![],
|
||||
outputs: vec![Type::FieldElement]
|
||||
}
|
||||
};
|
||||
|
||||
let mut checker = Checker::new();
|
||||
assert_eq!(checker.check_function(&foo), Ok(()));
|
||||
assert_eq!(checker.check_function(&foo), Ok(foo_checked));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -470,14 +689,16 @@ mod tests {
|
|||
// c = foo()
|
||||
// should fail
|
||||
let bar_statements: Vec<Statement<FieldPrime>> = vec![Statement::MultipleDefinition(
|
||||
vec!["c".to_string()],
|
||||
vec![Variable::from("a")],
|
||||
Expression::FunctionCall("foo".to_string(), vec![])
|
||||
)];
|
||||
|
||||
let foo = FunctionDeclaration {
|
||||
id: "foo".to_string(),
|
||||
arg_count: 0,
|
||||
return_count: 2,
|
||||
signature: Signature {
|
||||
inputs: vec![],
|
||||
outputs: vec![Type::FieldElement, Type::FieldElement]
|
||||
}
|
||||
};
|
||||
|
||||
let mut functions = HashSet::new();
|
||||
|
@ -487,8 +708,11 @@ mod tests {
|
|||
id: "bar".to_string(),
|
||||
arguments: vec![],
|
||||
statements: bar_statements,
|
||||
return_count: 1
|
||||
};
|
||||
signature: Signature {
|
||||
inputs: vec![],
|
||||
outputs: vec![Type::FieldElement]
|
||||
}
|
||||
};
|
||||
|
||||
let mut checker = new_with_args(HashSet::new(), 0, functions);
|
||||
assert_eq!(checker.check_function(&bar), Err(Error { message: "foo returns 2 values but left side is of size 1".to_string() }));
|
||||
|
@ -508,8 +732,10 @@ mod tests {
|
|||
|
||||
let foo = FunctionDeclaration {
|
||||
id: "foo".to_string(),
|
||||
arg_count: 0,
|
||||
return_count: 2,
|
||||
signature: Signature {
|
||||
inputs: vec![],
|
||||
outputs: vec![Type::FieldElement, Type::FieldElement]
|
||||
}
|
||||
};
|
||||
|
||||
let mut functions = HashSet::new();
|
||||
|
@ -519,7 +745,10 @@ mod tests {
|
|||
id: "bar".to_string(),
|
||||
arguments: vec![],
|
||||
statements: bar_statements,
|
||||
return_count: 1
|
||||
signature: Signature {
|
||||
inputs: vec![],
|
||||
outputs: vec![Type::FieldElement]
|
||||
}
|
||||
};
|
||||
|
||||
let mut checker = new_with_args(HashSet::new(), 0, functions);
|
||||
|
@ -532,7 +761,7 @@ mod tests {
|
|||
// c = foo()
|
||||
// should fail
|
||||
let bar_statements: Vec<Statement<FieldPrime>> = vec![Statement::MultipleDefinition(
|
||||
vec!["c".to_string()],
|
||||
vec![Variable::from("a")],
|
||||
Expression::FunctionCall("foo".to_string(), vec![])
|
||||
)];
|
||||
|
||||
|
@ -540,11 +769,14 @@ mod tests {
|
|||
id: "bar".to_string(),
|
||||
arguments: vec![],
|
||||
statements: bar_statements,
|
||||
return_count: 1
|
||||
signature: Signature {
|
||||
inputs: vec![],
|
||||
outputs: vec![Type::FieldElement]
|
||||
}
|
||||
};
|
||||
|
||||
let mut checker = new_with_args(HashSet::new(), 0, HashSet::new());
|
||||
assert_eq!(checker.check_function(&bar), Err(Error { message: "Function definition for function foo with 0 argument(s) not found.".to_string() }));
|
||||
assert_eq!(checker.check_function(&bar), Err(Error { message: "Function definition for function foo with arguments [] not found.".to_string() }));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -567,14 +799,17 @@ mod tests {
|
|||
|
||||
let foo = Function {
|
||||
id: "foo".to_string(),
|
||||
arguments: vec![Parameter { id: "x".to_string(), private: false}],
|
||||
arguments: vec![Parameter { id: Variable::from("x"), private: false}],
|
||||
statements: foo_statements,
|
||||
return_count: 2
|
||||
signature: Signature {
|
||||
inputs: vec![Type::FieldElement],
|
||||
outputs: vec![Type::FieldElement, Type::FieldElement]
|
||||
}
|
||||
};
|
||||
|
||||
let main_statements: Vec<Statement<FieldPrime>> = vec![
|
||||
Statement::MultipleDefinition(
|
||||
vec!["a".to_string(), "b".to_string()],
|
||||
vec![Variable::from("a"), Variable::from("b")],
|
||||
Expression::FunctionCall("foo".to_string(), vec![
|
||||
Expression::Identifier("x".to_string())
|
||||
])
|
||||
|
@ -590,7 +825,10 @@ mod tests {
|
|||
id: "main".to_string(),
|
||||
arguments: vec![],
|
||||
statements: main_statements,
|
||||
return_count: 1
|
||||
signature: Signature {
|
||||
inputs: vec![],
|
||||
outputs: vec![Type::FieldElement, Type::FieldElement]
|
||||
}
|
||||
};
|
||||
|
||||
let program = Prog {
|
||||
|
@ -617,11 +855,14 @@ mod tests {
|
|||
id: "bar".to_string(),
|
||||
arguments: vec![],
|
||||
statements: bar_statements,
|
||||
return_count: 1
|
||||
signature: Signature {
|
||||
inputs: vec![],
|
||||
outputs: vec![Type::FieldElement]
|
||||
}
|
||||
};
|
||||
|
||||
let mut checker = new_with_args(HashSet::new(), 0, HashSet::new());
|
||||
assert_eq!(checker.check_function(&bar), Err(Error { message: "Function definition for function foo with 0 argument(s) not found.".to_string() }));
|
||||
assert_eq!(checker.check_function(&bar), Err(Error { message: "Function definition for function foo with arguments [] not found.".to_string() }));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -640,7 +881,10 @@ mod tests {
|
|||
id: "bar".to_string(),
|
||||
arguments: vec![],
|
||||
statements: bar_statements,
|
||||
return_count: 2
|
||||
signature: Signature {
|
||||
inputs: vec![],
|
||||
outputs: vec![Type::FieldElement, Type::FieldElement]
|
||||
}
|
||||
};
|
||||
|
||||
let mut checker = new_with_args(HashSet::new(), 0, HashSet::new());
|
||||
|
@ -658,7 +902,7 @@ mod tests {
|
|||
// should pass
|
||||
let bar_statements: Vec<Statement<FieldPrime>> = vec![
|
||||
Statement::MultipleDefinition(
|
||||
vec!["a".to_string(), "b".to_string()],
|
||||
vec![Variable::from("a"), Variable::from("b")],
|
||||
Expression::FunctionCall("foo".to_string(), vec![])
|
||||
),
|
||||
Statement::Return(
|
||||
|
@ -671,10 +915,25 @@ mod tests {
|
|||
)
|
||||
];
|
||||
|
||||
let bar_statements_checked: Vec<TypedStatement<FieldPrime>> = vec![
|
||||
TypedStatement::MultipleDefinition(
|
||||
vec![Variable::from("a"), Variable::from("b")],
|
||||
TypedExpressionList::FunctionCall("foo".to_string(), vec![], vec![Type::FieldElement, Type::FieldElement])
|
||||
),
|
||||
TypedStatement::Return(vec![
|
||||
FieldElementExpression::Add(
|
||||
box FieldElementExpression::Identifier("a".to_string()),
|
||||
box FieldElementExpression::Identifier("b".to_string())
|
||||
).into()]
|
||||
)
|
||||
];
|
||||
|
||||
let foo = FunctionDeclaration {
|
||||
id: "foo".to_string(),
|
||||
arg_count: 0,
|
||||
return_count: 2,
|
||||
signature: Signature {
|
||||
inputs: vec![],
|
||||
outputs: vec![Type::FieldElement, Type::FieldElement]
|
||||
}
|
||||
};
|
||||
|
||||
let mut functions = HashSet::new();
|
||||
|
@ -684,11 +943,24 @@ mod tests {
|
|||
id: "bar".to_string(),
|
||||
arguments: vec![],
|
||||
statements: bar_statements,
|
||||
return_count: 1
|
||||
signature: Signature {
|
||||
inputs: vec![],
|
||||
outputs: vec![Type::FieldElement]
|
||||
}
|
||||
};
|
||||
|
||||
let bar_checked = TypedFunction {
|
||||
id: "bar".to_string(),
|
||||
arguments: vec![],
|
||||
statements: bar_statements_checked,
|
||||
signature: Signature {
|
||||
inputs: vec![],
|
||||
outputs: vec![Type::FieldElement]
|
||||
}
|
||||
};
|
||||
|
||||
let mut checker = new_with_args(HashSet::new(), 0, functions);
|
||||
assert_eq!(checker.check_function(&bar), Ok(()));
|
||||
assert_eq!(checker.check_function(&bar), Ok(bar_checked));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -710,14 +982,16 @@ mod tests {
|
|||
];
|
||||
|
||||
let foo2_arguments = vec![
|
||||
Parameter { id: 'c'.to_string(), private: true },
|
||||
Parameter { id: 'd'.to_string(), private: true }
|
||||
Parameter { id: Variable::from("a"), private: true },
|
||||
Parameter { id: Variable::from("b"), private: true }
|
||||
];
|
||||
|
||||
let foo1 = FunctionDeclaration {
|
||||
id: "foo".to_string(),
|
||||
arg_count: 2,
|
||||
return_count: 1,
|
||||
signature: Signature {
|
||||
inputs: vec![Type::FieldElement, Type::FieldElement],
|
||||
outputs: vec![Type::FieldElement]
|
||||
}
|
||||
};
|
||||
|
||||
let mut functions = HashSet::new();
|
||||
|
@ -727,7 +1001,10 @@ mod tests {
|
|||
id: "foo".to_string(),
|
||||
arguments: foo2_arguments,
|
||||
statements: foo2_statements,
|
||||
return_count: 1
|
||||
signature: Signature {
|
||||
inputs: vec![Type::FieldElement, Type::FieldElement],
|
||||
outputs: vec![Type::FieldElement]
|
||||
}
|
||||
};
|
||||
|
||||
let mut checker = new_with_args(HashSet::new(), 0, functions);
|
||||
|
@ -752,7 +1029,7 @@ mod tests {
|
|||
)
|
||||
];
|
||||
|
||||
let main1_arguments = vec![Parameter { id: 'a'.to_string(), private: false }];
|
||||
let main1_arguments = vec![Parameter { id: Variable::from("a"), private: false }];
|
||||
|
||||
let main2_statements: Vec<Statement<FieldPrime>> = vec![
|
||||
Statement::Return(
|
||||
|
@ -770,14 +1047,20 @@ mod tests {
|
|||
id: "main".to_string(),
|
||||
arguments: main1_arguments,
|
||||
statements: main1_statements,
|
||||
return_count: 1,
|
||||
signature: Signature {
|
||||
inputs: vec![Type::FieldElement],
|
||||
outputs: vec![Type::FieldElement]
|
||||
}
|
||||
};
|
||||
|
||||
let main2 = Function {
|
||||
id: "main".to_string(),
|
||||
arguments: main2_arguments,
|
||||
statements: main2_statements,
|
||||
return_count: 1,
|
||||
signature: Signature {
|
||||
inputs: vec![],
|
||||
outputs: vec![Type::FieldElement]
|
||||
}
|
||||
};
|
||||
|
||||
let prog = Prog {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
use std::collections::{BTreeMap, HashSet};
|
||||
use flat_absy::{FlatStatement, FlatExpression, FlatFunction, FlatExpressionList};
|
||||
use field::Field;
|
||||
use parameter::Parameter;
|
||||
use flat_absy::flat_parameter::FlatParameter;
|
||||
use reduce::Reduce;
|
||||
use helpers::{DirectiveStatement, Helper, LibsnarkGadgetHelper};
|
||||
|
||||
|
@ -94,7 +94,7 @@ impl<T: Field> Into<FlatFunction<T>> for R1CS {
|
|||
|
||||
// define the inputs with dummy variables: arguments to the function and to the directive
|
||||
let inputs: Vec<String> = vec![0; self.input_count].iter().enumerate().map(|(i, _)| format!("input{}", i)).collect();
|
||||
let input_parameters = inputs.iter().map(|i| Parameter { id: i.clone(), private: true }).collect();
|
||||
let input_parameters = inputs.iter().map(|i| FlatParameter { id: i.clone(), private: true }).collect();
|
||||
|
||||
// define which subset of the witness is returned
|
||||
let outputs: Vec<FlatExpression<T>> = self.outputs.iter()
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
pub mod direct_substitution;
|
||||
pub mod prefixed_substitution;
|
||||
|
||||
pub trait Substitution {
|
||||
fn new() -> Self where Self: Sized;
|
||||
fn insert(&mut self, key: String, element: String) -> Option<String>;
|
|
@ -57,7 +57,7 @@ impl Substitution for PrefixedSubstitution {
|
|||
|
||||
impl PrefixedSubstitution {
|
||||
fn split_key<'a>(&self, key: &'a str) -> (&'a str, Option<&'a str>) {
|
||||
match self.regex.find(key) {
|
||||
match self.regex.find_iter(key).last() {
|
||||
Some(candidate) => (&key[0..candidate.start()], Some(&key[candidate.start()..])),
|
||||
None => (key, None)
|
||||
}
|
522
zokrates_core/src/typed_absy/mod.rs
Normal file
522
zokrates_core/src/typed_absy/mod.rs
Normal file
|
@ -0,0 +1,522 @@
|
|||
//! Module containing structs and enums to represent a program.
|
||||
//!
|
||||
//! @file absy.rs
|
||||
//! @author Dennis Kuhnert <dennis.kuhnert@campus.tu-berlin.de>
|
||||
//! @author Jacob Eberhardt <jacob.eberhardt@tu-berlin.de>
|
||||
//! @date 2017
|
||||
|
||||
use types::signature::Signature;
|
||||
use absy::parameter::Parameter;
|
||||
use absy::variable::Variable;
|
||||
|
||||
use std::fmt;
|
||||
use substitution::Substitution;
|
||||
use field::Field;
|
||||
use imports::Import;
|
||||
use flat_absy::*;
|
||||
use types::Type;
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, PartialEq)]
|
||||
pub struct TypedProg<T: Field> {
|
||||
/// Functions of the program
|
||||
pub functions: Vec<TypedFunction<T>>,
|
||||
pub imports: Vec<Import>,
|
||||
pub imported_functions: Vec<FlatFunction<T>>
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Display for TypedProg<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut res = vec![];
|
||||
res.extend(self.imports
|
||||
.iter()
|
||||
.map(|x| format!("{}", x))
|
||||
.collect::<Vec<_>>());
|
||||
res.extend(self.imported_functions
|
||||
.iter()
|
||||
.map(|x| format!("{}", x))
|
||||
.collect::<Vec<_>>());
|
||||
res.extend(self.functions
|
||||
.iter()
|
||||
.map(|x| format!("{}", x))
|
||||
.collect::<Vec<_>>());
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
res.join("\n")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Debug for TypedProg<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"program(\n\timports:\n\t\t{}\n\tfunctions:\n\t\t{}{}\n)",
|
||||
self.imports
|
||||
.iter()
|
||||
.map(|x| format!("{:?}", x))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n\t\t"),
|
||||
self.imported_functions
|
||||
.iter()
|
||||
.map(|x| format!("{}", x))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n\t\t"),
|
||||
self.functions
|
||||
.iter()
|
||||
.map(|x| format!("{:?}", x))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n\t\t")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, PartialEq)]
|
||||
pub struct TypedFunction<T: Field> {
|
||||
/// Name of the program
|
||||
pub id: String,
|
||||
/// Arguments of the function
|
||||
pub arguments: Vec<Parameter>,
|
||||
/// Vector of statements that are executed when running the function
|
||||
pub statements: Vec<TypedStatement<T>>,
|
||||
/// function signature
|
||||
pub signature: Signature,
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Display for TypedFunction<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"def {}({}):\n{}",
|
||||
self.id,
|
||||
self.arguments
|
||||
.iter()
|
||||
.map(|x| format!("{}", x))
|
||||
.collect::<Vec<_>>()
|
||||
.join(","),
|
||||
self.statements
|
||||
.iter()
|
||||
.map(|x| format!("\t{}", x))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Debug for TypedFunction<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"TypedFunction(id: {:?}, arguments: {:?}, ...):\n{}",
|
||||
self.id,
|
||||
self.arguments,
|
||||
self.statements
|
||||
.iter()
|
||||
.map(|x| format!("\t{:?}", x))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum TypedStatement<T: Field> {
|
||||
Return(Vec<TypedExpression<T>>),
|
||||
Definition(Variable, TypedExpression<T>),
|
||||
Condition(TypedExpression<T>, TypedExpression<T>),
|
||||
For(Variable, T, T, Vec<TypedStatement<T>>),
|
||||
MultipleDefinition(Vec<Variable>, TypedExpressionList<T>),
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Debug for TypedStatement<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
TypedStatement::Return(ref exprs) => {
|
||||
try!(write!(f, "Return("));
|
||||
for (i, expr) in exprs.iter().enumerate() {
|
||||
try!(write!(f, "{}", expr));
|
||||
if i < exprs.len() - 1 {
|
||||
try!(write!(f, ", "));
|
||||
}
|
||||
}
|
||||
write!(f, ")")
|
||||
},
|
||||
TypedStatement::Definition(ref lhs, ref rhs) => {
|
||||
write!(f, "Definition({:?}, {:?})", lhs, rhs)
|
||||
}
|
||||
TypedStatement::Condition(ref lhs, ref rhs) => write!(f, "Condition({:?}, {:?})", lhs, rhs),
|
||||
TypedStatement::For(ref var, ref start, ref stop, ref list) => {
|
||||
try!(write!(f, "for {:?} in {:?}..{:?} do\n", var, start, stop));
|
||||
for l in list {
|
||||
try!(write!(f, "\t\t{:?}\n", l));
|
||||
}
|
||||
write!(f, "\tendfor")
|
||||
}
|
||||
TypedStatement::MultipleDefinition(ref lhs, ref rhs) => {
|
||||
write!(f, "MultipleDefinition({:?}, {:?})", lhs, rhs)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<T: Field> fmt::Display for TypedStatement<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
TypedStatement::Return(ref exprs) => {
|
||||
try!(write!(f, "return "));
|
||||
for (i, expr) in exprs.iter().enumerate() {
|
||||
try!(write!(f, "{}", expr));
|
||||
if i < exprs.len() - 1 {
|
||||
try!(write!(f, ", "));
|
||||
}
|
||||
}
|
||||
write!(f, "")
|
||||
},
|
||||
TypedStatement::Definition(ref lhs, ref rhs) => write!(f, "{} = {}", lhs, rhs),
|
||||
TypedStatement::Condition(ref lhs, ref rhs) => write!(f, "{} == {}", lhs, rhs),
|
||||
TypedStatement::For(ref var, ref start, ref stop, ref list) => {
|
||||
try!(write!(f, "for {} in {}..{} do\n", var, start, stop));
|
||||
for l in list {
|
||||
try!(write!(f, "\t\t{}\n", l));
|
||||
}
|
||||
write!(f, "\tendfor")
|
||||
}
|
||||
TypedStatement::MultipleDefinition(ref ids, ref rhs) => {
|
||||
for (i, id) in ids.iter().enumerate() {
|
||||
try!(write!(f, "{}", id));
|
||||
if i < ids.len() - 1 {
|
||||
try!(write!(f, ", "));
|
||||
}
|
||||
}
|
||||
write!(f, " = {}", rhs)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Typed
|
||||
{
|
||||
fn get_type(&self) -> Type;
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum TypedExpression<T: Field> {
|
||||
Boolean(BooleanExpression<T>),
|
||||
FieldElement(FieldElementExpression<T>),
|
||||
}
|
||||
|
||||
impl<T: Field> From<BooleanExpression<T>> for TypedExpression<T> {
|
||||
fn from(e: BooleanExpression<T>) -> TypedExpression<T> {
|
||||
TypedExpression::Boolean(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> From<FieldElementExpression<T>> for TypedExpression<T> {
|
||||
fn from(e: FieldElementExpression<T>) -> TypedExpression<T> {
|
||||
TypedExpression::FieldElement(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Display for TypedExpression<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
TypedExpression::Boolean(ref e) => {
|
||||
write!(f, "{}", e)
|
||||
},
|
||||
TypedExpression::FieldElement(ref e) => {
|
||||
write!(f, "{}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Debug for TypedExpression<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
TypedExpression::Boolean(ref e) => {
|
||||
write!(f, "{:?}", e)
|
||||
},
|
||||
TypedExpression::FieldElement(ref e) => {
|
||||
write!(f, "{:?}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> Typed for TypedExpression<T> {
|
||||
fn get_type(&self) -> Type {
|
||||
match self {
|
||||
TypedExpression::Boolean(_) => Type::Boolean,
|
||||
TypedExpression::FieldElement(_) => Type::FieldElement
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait MultiTyped
|
||||
{
|
||||
fn get_types(&self) -> &Vec<Type>;
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum TypedExpressionList<T: Field> {
|
||||
FunctionCall(String, Vec<TypedExpression<T>>, Vec<Type>)
|
||||
}
|
||||
|
||||
impl<T: Field> MultiTyped for TypedExpressionList<T> {
|
||||
fn get_types(&self) -> &Vec<Type> {
|
||||
match *self {
|
||||
TypedExpressionList::FunctionCall(_, _, ref types) => types
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum FieldElementExpression<T: Field> {
|
||||
Number(T),
|
||||
Identifier(String),
|
||||
Add(Box<FieldElementExpression<T>>, Box<FieldElementExpression<T>>),
|
||||
Sub(Box<FieldElementExpression<T>>, Box<FieldElementExpression<T>>),
|
||||
Mult(Box<FieldElementExpression<T>>, Box<FieldElementExpression<T>>),
|
||||
Div(Box<FieldElementExpression<T>>, Box<FieldElementExpression<T>>),
|
||||
Pow(Box<FieldElementExpression<T>>, Box<FieldElementExpression<T>>),
|
||||
IfElse(Box<BooleanExpression<T>>, Box<FieldElementExpression<T>>, Box<FieldElementExpression<T>>),
|
||||
FunctionCall(String, Vec<TypedExpression<T>>),
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum BooleanExpression<T: Field> {
|
||||
Identifier(String),
|
||||
Lt(Box<FieldElementExpression<T>>, Box<FieldElementExpression<T>>),
|
||||
Le(Box<FieldElementExpression<T>>, Box<FieldElementExpression<T>>),
|
||||
Eq(Box<FieldElementExpression<T>>, Box<FieldElementExpression<T>>),
|
||||
Ge(Box<FieldElementExpression<T>>, Box<FieldElementExpression<T>>),
|
||||
Gt(Box<FieldElementExpression<T>>, Box<FieldElementExpression<T>>),
|
||||
}
|
||||
|
||||
impl<T: Field> BooleanExpression<T> {
|
||||
fn apply_substitution(&self, substitution: &Substitution) -> BooleanExpression<T> {
|
||||
match *self {
|
||||
BooleanExpression::Identifier(ref id) => {
|
||||
let mut new_name = id.clone();
|
||||
loop {
|
||||
match substitution.get(&new_name) {
|
||||
Some(x) => new_name = x.to_string(),
|
||||
None => return BooleanExpression::Identifier(new_name),
|
||||
}
|
||||
}
|
||||
},
|
||||
BooleanExpression::Lt(ref lhs, ref rhs) => BooleanExpression::Lt(
|
||||
box lhs.apply_substitution(substitution),
|
||||
box rhs.apply_substitution(substitution),
|
||||
),
|
||||
BooleanExpression::Le(ref lhs, ref rhs) => BooleanExpression::Le(
|
||||
box lhs.apply_substitution(substitution),
|
||||
box rhs.apply_substitution(substitution),
|
||||
),
|
||||
BooleanExpression::Eq(ref lhs, ref rhs) => BooleanExpression::Eq(
|
||||
box lhs.apply_substitution(substitution),
|
||||
box rhs.apply_substitution(substitution),
|
||||
),
|
||||
BooleanExpression::Ge(ref lhs, ref rhs) => BooleanExpression::Ge(
|
||||
box lhs.apply_substitution(substitution),
|
||||
box rhs.apply_substitution(substitution),
|
||||
),
|
||||
BooleanExpression::Gt(ref lhs, ref rhs) => BooleanExpression::Gt(
|
||||
box lhs.apply_substitution(substitution),
|
||||
box rhs.apply_substitution(substitution),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> FieldElementExpression<T> {
|
||||
pub fn apply_substitution(&self, substitution: &Substitution) -> FieldElementExpression<T> {
|
||||
match *self {
|
||||
ref e @ FieldElementExpression::Number(_) => e.clone(),
|
||||
FieldElementExpression::Identifier(ref id) => {
|
||||
let mut new_name = id.clone();
|
||||
loop {
|
||||
match substitution.get(&new_name) {
|
||||
Some(x) => new_name = x.to_string(),
|
||||
None => return FieldElementExpression::Identifier(new_name),
|
||||
}
|
||||
}
|
||||
}
|
||||
FieldElementExpression::Add(ref e1, ref e2) => FieldElementExpression::Add(
|
||||
box e1.apply_substitution(substitution),
|
||||
box e2.apply_substitution(substitution),
|
||||
),
|
||||
FieldElementExpression::Sub(ref e1, ref e2) => FieldElementExpression::Sub(
|
||||
box e1.apply_substitution(substitution),
|
||||
box e2.apply_substitution(substitution),
|
||||
),
|
||||
FieldElementExpression::Mult(ref e1, ref e2) => FieldElementExpression::Mult(
|
||||
box e1.apply_substitution(substitution),
|
||||
box e2.apply_substitution(substitution),
|
||||
),
|
||||
FieldElementExpression::Div(ref e1, ref e2) => FieldElementExpression::Div(
|
||||
box e1.apply_substitution(substitution),
|
||||
box e2.apply_substitution(substitution),
|
||||
),
|
||||
FieldElementExpression::Pow(ref e1, ref e2) => FieldElementExpression::Pow(
|
||||
box e1.apply_substitution(substitution),
|
||||
box e2.apply_substitution(substitution),
|
||||
),
|
||||
FieldElementExpression::IfElse(ref c, ref e1, ref e2) => FieldElementExpression::IfElse(
|
||||
box c.apply_substitution(substitution),
|
||||
box e1.apply_substitution(substitution),
|
||||
box e2.apply_substitution(substitution),
|
||||
),
|
||||
FieldElementExpression::FunctionCall(ref i, ref p) => {
|
||||
for param in p {
|
||||
param.apply_substitution(substitution);
|
||||
}
|
||||
FieldElementExpression::FunctionCall(i.clone(), p.clone())
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_linear(&self) -> bool {
|
||||
match *self {
|
||||
FieldElementExpression::Number(_) | FieldElementExpression::Identifier(_) => true,
|
||||
FieldElementExpression::Add(ref x, ref y) | FieldElementExpression::Sub(ref x, ref y) => {
|
||||
x.is_linear() && y.is_linear()
|
||||
}
|
||||
FieldElementExpression::Mult(ref x, ref y) | FieldElementExpression::Div(ref x, ref y) => {
|
||||
match (x, y) {
|
||||
(box FieldElementExpression::Number(_), box FieldElementExpression::Number(_)) |
|
||||
(box FieldElementExpression::Number(_), box FieldElementExpression::Identifier(_)) |
|
||||
(box FieldElementExpression::Identifier(_), box FieldElementExpression::Number(_)) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Display for FieldElementExpression<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
FieldElementExpression::Number(ref i) => write!(f, "{}", i),
|
||||
FieldElementExpression::Identifier(ref var) => write!(f, "{}", var),
|
||||
FieldElementExpression::Add(ref lhs, ref rhs) => write!(f, "({} + {})", lhs, rhs),
|
||||
FieldElementExpression::Sub(ref lhs, ref rhs) => write!(f, "({} - {})", lhs, rhs),
|
||||
FieldElementExpression::Mult(ref lhs, ref rhs) => write!(f, "({} * {})", lhs, rhs),
|
||||
FieldElementExpression::Div(ref lhs, ref rhs) => write!(f, "({} / {})", lhs, rhs),
|
||||
FieldElementExpression::Pow(ref lhs, ref rhs) => write!(f, "{}**{}", lhs, rhs),
|
||||
FieldElementExpression::IfElse(ref condition, ref consequent, ref alternative) => write!(
|
||||
f,
|
||||
"if {} then {} else {} fi",
|
||||
condition,
|
||||
consequent,
|
||||
alternative
|
||||
),
|
||||
FieldElementExpression::FunctionCall(ref i, ref p) => {
|
||||
try!(write!(f, "{}(", i,));
|
||||
for (i, param) in p.iter().enumerate() {
|
||||
try!(write!(f, "{}", param));
|
||||
if i < p.len() - 1 {
|
||||
try!(write!(f, ", "));
|
||||
}
|
||||
}
|
||||
write!(f, ")")
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Display for BooleanExpression<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
BooleanExpression::Identifier(ref var) => write!(f, "{}", var),
|
||||
BooleanExpression::Lt(ref lhs, ref rhs) => write!(f, "{} < {}", lhs, rhs),
|
||||
BooleanExpression::Le(ref lhs, ref rhs) => write!(f, "{} <= {}", lhs, rhs),
|
||||
BooleanExpression::Eq(ref lhs, ref rhs) => write!(f, "{} == {}", lhs, rhs),
|
||||
BooleanExpression::Ge(ref lhs, ref rhs) => write!(f, "{} >= {}", lhs, rhs),
|
||||
BooleanExpression::Gt(ref lhs, ref rhs) => write!(f, "{} > {}", lhs, rhs),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Debug for BooleanExpression<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Debug for FieldElementExpression<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
FieldElementExpression::Number(ref i) => write!(f, "Num({})", i),
|
||||
FieldElementExpression::Identifier(ref var) => write!(f, "Ide({})", var),
|
||||
FieldElementExpression::Add(ref lhs, ref rhs) => write!(f, "Add({:?}, {:?})", lhs, rhs),
|
||||
FieldElementExpression::Sub(ref lhs, ref rhs) => write!(f, "Sub({:?}, {:?})", lhs, rhs),
|
||||
FieldElementExpression::Mult(ref lhs, ref rhs) => write!(f, "Mult({:?}, {:?})", lhs, rhs),
|
||||
FieldElementExpression::Div(ref lhs, ref rhs) => write!(f, "Div({:?}, {:?})", lhs, rhs),
|
||||
FieldElementExpression::Pow(ref lhs, ref rhs) => write!(f, "Pow({:?}, {:?})", lhs, rhs),
|
||||
FieldElementExpression::IfElse(ref condition, ref consequent, ref alternative) => write!(
|
||||
f,
|
||||
"IfElse({:?}, {:?}, {:?})",
|
||||
condition,
|
||||
consequent,
|
||||
alternative
|
||||
),
|
||||
FieldElementExpression::FunctionCall(ref i, ref p) => {
|
||||
try!(write!(f, "FunctionCall({:?}, (", i));
|
||||
try!(f.debug_list().entries(p.iter()).finish());
|
||||
write!(f, ")")
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<T: Field> TypedExpression<T> {
|
||||
pub fn apply_substitution(&self, substitution: &Substitution) -> TypedExpression<T> {
|
||||
match self {
|
||||
TypedExpression::Boolean(e) => e.apply_substitution(substitution).into(),
|
||||
TypedExpression::FieldElement(e) => e.apply_substitution(substitution).into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> TypedExpressionList<T> {
|
||||
pub fn apply_substitution(&self, substitution: &Substitution) -> TypedExpressionList<T> {
|
||||
match *self {
|
||||
TypedExpressionList::FunctionCall(ref id, ref inputs, ref types) => {
|
||||
TypedExpressionList::FunctionCall(id.clone(), inputs.iter().map(|i| i.apply_substitution(substitution)).collect(), types.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Display for TypedExpressionList<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
TypedExpressionList::FunctionCall(ref i, ref p, _) => {
|
||||
try!(write!(f, "{}(", i,));
|
||||
for (i, param) in p.iter().enumerate() {
|
||||
try!(write!(f, "{}", param));
|
||||
if i < p.len() - 1 {
|
||||
try!(write!(f, ", "));
|
||||
}
|
||||
}
|
||||
write!(f, ")")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Debug for TypedExpressionList<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
TypedExpressionList::FunctionCall(ref i, ref p, _) => {
|
||||
try!(write!(f, "FunctionCall({:?}, (", i));
|
||||
try!(f.debug_list().entries(p.iter()).finish());
|
||||
write!(f, ")")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
34
zokrates_core/src/types/constraints.rs
Normal file
34
zokrates_core/src/types/constraints.rs
Normal file
|
@ -0,0 +1,34 @@
|
|||
use field::Field;
|
||||
|
||||
#[derive(PartialEq, PartialOrd, Clone, Eq, Ord, Debug)]
|
||||
pub struct Constraints<T: Field> {
|
||||
pub constraints: Vec<Constraint<T>>
|
||||
}
|
||||
|
||||
impl<T: Field> Constraints<T> {
|
||||
pub fn none() -> Constraints<T> {
|
||||
Constraints {
|
||||
constraints: vec![]
|
||||
}
|
||||
}
|
||||
pub fn boolean() -> Constraints<T> {
|
||||
Constraints {
|
||||
constraints: vec![
|
||||
Constraint {
|
||||
a: box [T::from(1)],
|
||||
b: box [T::from(1)],
|
||||
c: box [T::from(1)],
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, PartialOrd, Clone, Eq, Ord, Debug)]
|
||||
pub struct Constraint<T: Field> {
|
||||
pub a: Box<[T]>,
|
||||
pub b: Box<[T]>,
|
||||
pub c: Box<[T]>,
|
||||
}
|
||||
|
||||
|
87
zokrates_core/src/types/conversions.rs
Normal file
87
zokrates_core/src/types/conversions.rs
Normal file
|
@ -0,0 +1,87 @@
|
|||
use flat_absy::*;
|
||||
use field::Field;
|
||||
use types::Type;
|
||||
use flat_absy::flat_parameter::FlatParameter;
|
||||
use helpers::{Helper, RustHelper, DirectiveStatement};
|
||||
use reduce::Reduce;
|
||||
use types::constraints::Constraint;
|
||||
|
||||
|
||||
pub fn cast<T: Field>(from: &Type, to: &Type) -> FlatFunction<T> {
|
||||
|
||||
let arguments = (0..from.get_primitive_count()).enumerate().map(|(index, _)| FlatParameter {
|
||||
id: format!("i{}", index),
|
||||
private: true
|
||||
}).collect();
|
||||
|
||||
let directive_inputs = (0..from.get_primitive_count()).enumerate().map(|(index, _)| format!("i{}", index)).collect();
|
||||
let directive_outputs: Vec<String> = (0..to.get_primitive_count()).enumerate().map(|(index, _)| format!("inter{}", index)).collect();
|
||||
|
||||
let conditions: Vec<FlatStatement<T>> = to.get_constraints().constraints.iter().map(|constraint: &Constraint<T>| {
|
||||
let rhs_a = match constraint.a.iter()
|
||||
.enumerate()
|
||||
.map(|(key, val)| FlatExpression::Mult(box FlatExpression::Number(val.clone()), box FlatExpression::Identifier(format!("inter{}",key.clone()))))
|
||||
.reduce(|acc, e| FlatExpression::Add(box acc, box e)) {
|
||||
Some(e @ FlatExpression::Mult(..)) => FlatExpression::Add(box FlatExpression::Number(T::zero()), box e), // the R1CS serializer only recognizes Add
|
||||
Some(e) => e,
|
||||
None => FlatExpression::Number(T::zero())
|
||||
};
|
||||
|
||||
let rhs_b = match constraint.b.iter()
|
||||
.enumerate()
|
||||
.map(|(key, val)| FlatExpression::Mult(box FlatExpression::Number(val.clone()), box FlatExpression::Identifier(format!("inter{}",key.clone()))))
|
||||
.reduce(|acc, e| FlatExpression::Add(box acc, box e)) {
|
||||
Some(e @ FlatExpression::Mult(..)) => FlatExpression::Add(box FlatExpression::Number(T::zero()), box e), // the R1CS serializer only recognizes Add
|
||||
Some(e) => e,
|
||||
None => FlatExpression::Number(T::zero())
|
||||
};
|
||||
|
||||
let lhs = match constraint.c.iter()
|
||||
.enumerate()
|
||||
.map(|(key, val)| FlatExpression::Mult(box FlatExpression::Number(val.clone()), box FlatExpression::Identifier(format!("inter{}",key.clone()))))
|
||||
.reduce(|acc, e| FlatExpression::Add(box acc, box e)) {
|
||||
Some(e @ FlatExpression::Mult(..)) => FlatExpression::Add(box FlatExpression::Number(T::zero()), box e), // the R1CS serializer only recognizes Add
|
||||
Some(e) => e,
|
||||
None => FlatExpression::Number(T::zero())
|
||||
};
|
||||
|
||||
FlatStatement::Condition(lhs, FlatExpression::Mult(box rhs_a, box rhs_b))
|
||||
}).collect();
|
||||
|
||||
let helper = match (from, to) {
|
||||
(Type::Boolean, Type::FieldElement) => {
|
||||
Helper::Rust(RustHelper::Identity)
|
||||
},
|
||||
(Type::FieldElement, Type::Boolean) => {
|
||||
Helper::Rust(RustHelper::Identity)
|
||||
}
|
||||
_ => panic!(format!("can't cast {} to {}", from, to))
|
||||
};
|
||||
|
||||
let return_count = to.get_primitive_count();
|
||||
|
||||
let outputs = directive_outputs.iter().map(|o| FlatExpression::Identifier(o.to_string())).collect();
|
||||
|
||||
let mut statements = conditions;
|
||||
|
||||
statements.insert(0, FlatStatement::Directive(
|
||||
DirectiveStatement {
|
||||
inputs: directive_inputs,
|
||||
outputs: directive_outputs,
|
||||
helper: helper
|
||||
}
|
||||
));
|
||||
|
||||
statements.push(FlatStatement::Return(
|
||||
FlatExpressionList {
|
||||
expressions: outputs
|
||||
}
|
||||
));
|
||||
|
||||
FlatFunction {
|
||||
id: format!("_{}_to_{}", from, to),
|
||||
arguments: arguments,
|
||||
statements: statements,
|
||||
return_count: return_count
|
||||
}
|
||||
}
|
48
zokrates_core/src/types/mod.rs
Normal file
48
zokrates_core/src/types/mod.rs
Normal file
|
@ -0,0 +1,48 @@
|
|||
use field::Field;
|
||||
use types::constraints::Constraints;
|
||||
use std::fmt;
|
||||
|
||||
pub mod signature;
|
||||
pub mod conversions;
|
||||
mod constraints;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum Type {
|
||||
FieldElement,
|
||||
Boolean
|
||||
}
|
||||
|
||||
impl fmt::Display for Type {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Type::FieldElement => write!(f, "field"),
|
||||
Type::Boolean => write!(f, "bool"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Type {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Type::FieldElement => write!(f, "field"),
|
||||
Type::Boolean => write!(f, "bool"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Type {
|
||||
fn get_constraints<T: Field>(&self) -> Constraints<T> {
|
||||
match self {
|
||||
Type::FieldElement => Constraints::none(),
|
||||
Type::Boolean => Constraints::boolean(),
|
||||
}
|
||||
}
|
||||
|
||||
// the number of field elements the type maps to
|
||||
pub fn get_primitive_count(&self) -> usize {
|
||||
match self {
|
||||
Type::FieldElement => 1,
|
||||
Type::Boolean => 1
|
||||
}
|
||||
}
|
||||
}
|
20
zokrates_core/src/types/signature.rs
Normal file
20
zokrates_core/src/types/signature.rs
Normal file
|
@ -0,0 +1,20 @@
|
|||
use types::Type;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub struct Signature {
|
||||
pub inputs: Vec<Type>,
|
||||
pub outputs: Vec<Type>
|
||||
}
|
||||
|
||||
impl fmt::Debug for Signature {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Signature(inputs: {:?}, outputs: {:?})", self.inputs, self.outputs)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Signature {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "({:?}) -> ({:?})", self.inputs, self.outputs)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue