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

merge develop, resolve conflicts

This commit is contained in:
schaeff 2018-08-08 12:46:25 +02:00
commit 101bbb17f4
29 changed files with 1837 additions and 615 deletions

View file

@ -0,0 +1 @@
[0]

View file

@ -0,0 +1,2 @@
def main(a):
return if a == 1 then 1 else 0 fi

View file

@ -0,0 +1 @@
~out_0 0

View file

@ -0,0 +1 @@
[1]

View file

@ -0,0 +1,2 @@
def main(a):
return if a == 1 then 1 else 0 fi

View file

@ -0,0 +1 @@
~out_0 1

View file

@ -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();
}
}

View file

@ -0,0 +1,6 @@
def sub(a):
a = a + 3
return a
def main():
return sub(4)

View file

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

View 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)
}
}

View 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,
)
}
}

View file

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

View file

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

View file

@ -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() {

View file

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

View file

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

View file

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

View file

@ -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)),

View file

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

View file

@ -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()

View file

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

View file

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

View 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, ")")
}
}
}
}

View 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]>,
}

View 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
}
}

View 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
}
}
}

View 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)
}
}