diff --git a/.circleci/config.yml b/.circleci/config.yml index 78e4d63c..9d4ca794 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -26,7 +26,7 @@ jobs: command: WITH_LIBSNARK=1 LIBSNARK_SOURCE_PATH=$HOME/libsnark RUSTFLAGS="-D warnings" ./build.sh - run: name: Run tests - command: WITH_LIBSNARK=1 LIBSNARK_SOURCE_PATH=$HOME/libsnark RUSTFLAGS="-D warnings" cargo test --release + command: WITH_LIBSNARK=1 LIBSNARK_SOURCE_PATH=$HOME/libsnark RUSTFLAGS="-D warnings" cargo test --release -- --test-threads=1 - run: name: Run integration tests command: WITH_LIBSNARK=1 LIBSNARK_SOURCE_PATH=$HOME/libsnark RUSTFLAGS="-D warnings" cargo test --release -- --ignored diff --git a/Cargo.lock b/Cargo.lock index 93001cb3..8a6103c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -623,7 +623,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "zokrates_cli" -version = "0.3.1" +version = "0.3.2" dependencies = [ "assert_cli 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -631,13 +631,13 @@ dependencies = [ "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", - "zokrates_core 0.3.1", - "zokrates_fs_resolver 0.3.1", + "zokrates_core 0.3.2", + "zokrates_fs_resolver 0.3.2", ] [[package]] name = "zokrates_core" -version = "0.3.1" +version = "0.3.2" dependencies = [ "assert_cli 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "bimap 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -658,7 +658,7 @@ dependencies = [ [[package]] name = "zokrates_fs_resolver" -version = "0.3.1" +version = "0.3.2" [metadata] "checksum aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9a933f4e58658d7b12defcf96dc5c720f20832deebe3e0a19efd3b6aaeeb9e" diff --git a/README.md b/README.md index 7ec29708..25505365 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,25 @@ -# Zokrates +# ZoKrates [![Join the chat at https://gitter.im/ZoKrates/Lobby](https://badges.gitter.im/ZoKrates/Lobby.svg)](https://gitter.im/ZoKrates/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) ![Jenkins](https://img.shields.io/jenkins/s/https/jenkins.kyroy.com/job/ZoKrates/job/master.svg?label=master) ![Jenkins](https://img.shields.io/jenkins/s/https/jenkins.kyroy.com/job/ZoKrates/job/develop.svg?label=develop) -Zokrates is a toolbox for zkSNARKs on Ethereum. +ZoKrates is a toolbox for zkSNARKs on Ethereum. _This is a proof-of-concept implementation. It has not been tested for production._ ## Getting Started -Have a look at the documentation [zokrates.github.io](https://zokrates.github.io/) for more informations about using Zokrates. +Have a look at the [documentation](https://zokrates.github.io/) for more information about using ZoKrates. A getting started tutorial can be found [here](https://zokrates.github.io/sha256example.html). ## Getting Help -If you run into problems, Zokrates has a Gitter room. You can come ask for help at [gitter.im/ZoKrates/Lobby](https://gitter.im/ZoKrates/Lobby). +If you run into problems, ZoKrates has a Gitter room. You can come ask for help on [Gitter](https://gitter.im/ZoKrates/Lobby). ## License @@ -27,4 +27,6 @@ ZoKrates is released under the GNU Lesser General Public License v3. ## Contributing +We happily welcome contributions. You can either pick an existing issue, or reach out on [Gitter](https://gitter.im/ZoKrates/Lobby). + Unless you explicitly state otherwise, any contribution you intentionally submit for inclusion in the work shall be licensed as above, without any additional terms or conditions. diff --git a/zokrates_book/src/sha256example.md b/zokrates_book/src/sha256example.md index eec971b4..dbf6d368 100644 --- a/zokrates_book/src/sha256example.md +++ b/zokrates_book/src/sha256example.md @@ -76,7 +76,7 @@ First, Victor has to specify what hash he is interested in. Therefore, we have t ```zokrates import "LIBSNARK/sha256packed" -def main(field a, field b, field c, field d) -> (field): +def main(private field a, private field b, private field c, private field d) -> (field): h0, h1 = sha256packed(a, b, c, d) h0 == 263561599766550617289250058199814760685 h1 == 65303172752238645975888084098459749904 @@ -135,4 +135,4 @@ At this point, you’ve successfully ran you first zkSNARK on the Ethereum block > >In general, multiple parties may be interested in verifying the correctness of Alice's statement. For example, in the zero-knowledge based cryptocurrency Zcash, each node needs to be able to validate the correctness of transactions. In order to generalize the setup phase to these multi-party use-cases a tricky process, commonly referred to as “trusted setup” or "ceremony" needs to be conducted. > ->ZoKrates would welcome ideas to add support for such ceremonies! \ No newline at end of file +>ZoKrates would welcome ideas to add support for such ceremonies! diff --git a/zokrates_cli/Cargo.toml b/zokrates_cli/Cargo.toml index 8fc4e2ce..e996099e 100644 --- a/zokrates_cli/Cargo.toml +++ b/zokrates_cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zokrates_cli" -version = "0.3.1" +version = "0.3.2" authors = ["Jacob Eberhardt ", "Dennis Kuhnert ", "Thibaut Schaeffer "] repository = "https://github.com/JacobEberhardt/ZoKrates.git" diff --git a/zokrates_cli/src/bin.rs b/zokrates_cli/src/bin.rs index ea5fb1dc..a0f77c95 100644 --- a/zokrates_cli/src/bin.rs +++ b/zokrates_cli/src/bin.rs @@ -41,7 +41,7 @@ fn main() { // cli specification using clap library let matches = App::new("ZoKrates") .setting(AppSettings::SubcommandRequiredElseHelp) - .version("0.3.1") + .version("0.3.2") .author("Jacob Eberhardt, Thibaut Schaeffer, Dennis Kuhnert") .about("Supports generation of zkSNARKs from high level language code including Smart Contracts for proof verification on the Ethereum Blockchain.\n'I know that I show nothing!'") .subcommand(SubCommand::with_name("compile") diff --git a/zokrates_core/Cargo.toml b/zokrates_core/Cargo.toml index 6ba8d14d..5c8a9899 100644 --- a/zokrates_core/Cargo.toml +++ b/zokrates_core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zokrates_core" -version = "0.3.1" +version = "0.3.2" authors = ["Jacob Eberhardt ", "Dennis Kuhnert "] repository = "https://github.com/JacobEberhardt/ZoKrates" readme = "README.md" diff --git a/zokrates_core/src/flat_absy/mod.rs b/zokrates_core/src/flat_absy/mod.rs index 18373806..b163434d 100644 --- a/zokrates_core/src/flat_absy/mod.rs +++ b/zokrates_core/src/flat_absy/mod.rs @@ -272,7 +272,6 @@ pub enum FlatExpression { Identifier(FlatVariable), Add(Box>, Box>), Sub(Box>, Box>), - Div(Box>, Box>), Mult(Box>, Box>), } @@ -313,10 +312,6 @@ impl FlatExpression { box e1.apply_substitution(substitution, should_fallback), box e2.apply_substitution(substitution, should_fallback), ), - FlatExpression::Div(e1, e2) => FlatExpression::Div( - box e1.apply_substitution(substitution, should_fallback), - box e2.apply_substitution(substitution, should_fallback), - ), } } @@ -330,7 +325,6 @@ impl FlatExpression { FlatExpression::Add(ref x, ref y) => x.solve(inputs) + y.solve(inputs), FlatExpression::Sub(ref x, ref y) => x.solve(inputs) - y.solve(inputs), FlatExpression::Mult(ref x, ref y) => x.solve(inputs) * y.solve(inputs), - FlatExpression::Div(ref x, ref y) => x.solve(inputs) / y.solve(inputs), } } @@ -340,14 +334,12 @@ impl FlatExpression { FlatExpression::Add(ref x, ref y) | FlatExpression::Sub(ref x, ref y) => { x.is_linear() && y.is_linear() } - FlatExpression::Mult(ref x, ref y) | FlatExpression::Div(ref x, ref y) => { - match (x.clone(), y.clone()) { - (box FlatExpression::Number(_), box FlatExpression::Number(_)) - | (box FlatExpression::Number(_), box FlatExpression::Identifier(_)) - | (box FlatExpression::Identifier(_), box FlatExpression::Number(_)) => true, - _ => false, - } - } + FlatExpression::Mult(ref x, ref y) => match (x.clone(), y.clone()) { + (box FlatExpression::Number(_), box FlatExpression::Number(_)) + | (box FlatExpression::Number(_), box FlatExpression::Identifier(_)) + | (box FlatExpression::Identifier(_), box FlatExpression::Number(_)) => true, + _ => false, + }, } } } @@ -360,7 +352,6 @@ impl fmt::Display for FlatExpression { FlatExpression::Add(ref lhs, ref rhs) => write!(f, "({} + {})", lhs, rhs), FlatExpression::Sub(ref lhs, ref rhs) => write!(f, "({} - {})", lhs, rhs), FlatExpression::Mult(ref lhs, ref rhs) => write!(f, "({} * {})", lhs, rhs), - FlatExpression::Div(ref lhs, ref rhs) => write!(f, "({} / {})", lhs, rhs), } } } @@ -373,11 +364,16 @@ impl fmt::Debug for FlatExpression { FlatExpression::Add(ref lhs, ref rhs) => write!(f, "Add({:?}, {:?})", lhs, rhs), FlatExpression::Sub(ref lhs, ref rhs) => write!(f, "Sub({:?}, {:?})", lhs, rhs), FlatExpression::Mult(ref lhs, ref rhs) => write!(f, "Mult({:?}, {:?})", lhs, rhs), - FlatExpression::Div(ref lhs, ref rhs) => write!(f, "Div({:?}, {:?})", lhs, rhs), } } } +impl From for FlatExpression { + fn from(v: FlatVariable) -> FlatExpression { + FlatExpression::Identifier(v) + } +} + #[derive(Clone, PartialEq, Serialize, Deserialize)] pub struct FlatExpressionList { pub expressions: Vec>, diff --git a/zokrates_core/src/flatten/mod.rs b/zokrates_core/src/flatten/mod.rs index 9226390e..b542f516 100644 --- a/zokrates_core/src/flatten/mod.rs +++ b/zokrates_core/src/flatten/mod.rs @@ -692,17 +692,47 @@ impl Flattener { statements_flattened, right, ); - let new_left = { + let new_left: FlatExpression = { let id = self.use_sym(); statements_flattened.push(FlatStatement::Definition(id, left_flattened)); - FlatExpression::Identifier(id) + id.into() }; - let new_right = { + let new_right: FlatExpression = { let id = self.use_sym(); statements_flattened.push(FlatStatement::Definition(id, right_flattened)); - FlatExpression::Identifier(id) + id.into() }; - FlatExpression::Div(box new_left, box new_right) + + let invb = self.use_sym(); + let inverse = self.use_sym(); + + // # invb = 1/b + statements_flattened.push(FlatStatement::Directive(DirectiveStatement::new( + vec![invb], + Helper::Rust(RustHelper::Div), + vec![FlatExpression::Number(T::one()), new_right.clone()], + ))); + + // assert(invb * b == 1) + statements_flattened.push(FlatStatement::Condition( + FlatExpression::Number(T::one()), + FlatExpression::Mult(box invb.into(), box new_right.clone().into()), + )); + + // # c = a/b + statements_flattened.push(FlatStatement::Directive(DirectiveStatement::new( + vec![inverse], + Helper::Rust(RustHelper::Div), + vec![new_left.clone(), new_right.clone()], + ))); + + // assert(c * b == a) + statements_flattened.push(FlatStatement::Condition( + new_left.into(), + FlatExpression::Mult(box new_right, box inverse.into()), + )); + + inverse.into() } FieldElementExpression::Pow(box base, box exponent) => { match exponent { @@ -1935,6 +1965,121 @@ mod tests { flattener.flatten_field_expression(&functions_flattened, &vec![], &mut vec![], expression); } + #[test] + fn div() { + // a = 5 / b / b + let mut flattener = Flattener::new(FieldPrime::get_required_bits()); + let mut functions_flattened = vec![]; + let arguments_flattened = vec![]; + let mut statements_flattened = vec![]; + + let definition = TypedStatement::Definition( + TypedAssignee::Identifier(Variable::field_element("b")), + FieldElementExpression::Number(FieldPrime::from(42)).into(), + ); + + let statement = TypedStatement::Definition( + TypedAssignee::Identifier(Variable::field_element("a")), + FieldElementExpression::Div( + box FieldElementExpression::Div( + box FieldElementExpression::Number(FieldPrime::from(5)), + box FieldElementExpression::Identifier(String::from("b")), + ), + box FieldElementExpression::Identifier(String::from("b")), + ) + .into(), + ); + + flattener.flatten_statement( + &mut functions_flattened, + &arguments_flattened, + &mut statements_flattened, + definition, + ); + + flattener.flatten_statement( + &mut functions_flattened, + &arguments_flattened, + &mut statements_flattened, + statement, + ); + + // define b + let b = FlatVariable::new(0); + // define new wires for members of Div + let five = FlatVariable::new(1); + let b0 = FlatVariable::new(2); + // Define inverse of denominator to prevent div by 0 + let invb0 = FlatVariable::new(3); + // Define inverse + let sym_0 = FlatVariable::new(4); + // Define result, which is first member to next Div + let sym_1 = FlatVariable::new(5); + // Define second member + let b1 = FlatVariable::new(6); + // Define inverse of denominator to prevent div by 0 + let invb1 = FlatVariable::new(7); + // Define inverse + let sym_2 = FlatVariable::new(8); + // Define left hand side + let a = FlatVariable::new(9); + + assert_eq!( + statements_flattened, + vec![ + FlatStatement::Definition(b, FlatExpression::Number(FieldPrime::from(42))), + // inputs to first div (5/b) + FlatStatement::Definition(five, FlatExpression::Number(FieldPrime::from(5))), + FlatStatement::Definition(b0, b.into()), + // check div by 0 + FlatStatement::Directive(DirectiveStatement::new( + vec![invb0], + Helper::Rust(RustHelper::Div), + vec![FlatExpression::Number(FieldPrime::from(1)), b0.into()] + )), + FlatStatement::Condition( + FlatExpression::Number(FieldPrime::from(1)), + FlatExpression::Mult(box invb0.into(), box b0.into()), + ), + // execute div + FlatStatement::Directive(DirectiveStatement::new( + vec![sym_0], + Helper::Rust(RustHelper::Div), + vec![five, b0] + )), + FlatStatement::Condition( + five.into(), + FlatExpression::Mult(box b0.into(), box sym_0.into()), + ), + // inputs to second div (res/b) + FlatStatement::Definition(sym_1, sym_0.into()), + FlatStatement::Definition(b1, b.into()), + // check div by 0 + FlatStatement::Directive(DirectiveStatement::new( + vec![invb1], + Helper::Rust(RustHelper::Div), + vec![FlatExpression::Number(FieldPrime::from(1)), b1.into()] + )), + FlatStatement::Condition( + FlatExpression::Number(FieldPrime::from(1)), + FlatExpression::Mult(box invb1.into(), box b1.into()), + ), + // execute div + FlatStatement::Directive(DirectiveStatement::new( + vec![sym_2], + Helper::Rust(RustHelper::Div), + vec![sym_1, b1] + )), + FlatStatement::Condition( + sym_1.into(), + FlatExpression::Mult(box b1.into(), box sym_2.into()), + ), + // result + FlatStatement::Definition(a, sym_2.into()), + ] + ); + } + #[test] fn field_array() { // foo = [ , , ] diff --git a/zokrates_core/src/helpers/mod.rs b/zokrates_core/src/helpers/mod.rs index e7de0a23..a939174e 100644 --- a/zokrates_core/src/helpers/mod.rs +++ b/zokrates_core/src/helpers/mod.rs @@ -17,16 +17,17 @@ pub struct DirectiveStatement { } impl DirectiveStatement { - pub fn new(outputs: Vec, helper: Helper, inputs: Vec) -> Self { + pub fn new>>( + outputs: Vec, + helper: Helper, + inputs: Vec, + ) -> Self { let (in_len, out_len) = helper.get_signature(); assert_eq!(in_len, inputs.len()); assert_eq!(out_len, outputs.len()); DirectiveStatement { helper, - inputs: inputs - .into_iter() - .map(|i| FlatExpression::Identifier(i)) - .collect(), + inputs: inputs.into_iter().map(|i| i.into()).collect(), outputs, } } diff --git a/zokrates_core/src/helpers/rust.rs b/zokrates_core/src/helpers/rust.rs index 254e86b2..016e94b5 100644 --- a/zokrates_core/src/helpers/rust.rs +++ b/zokrates_core/src/helpers/rust.rs @@ -7,6 +7,7 @@ pub enum RustHelper { Identity, ConditionEq, Bits, + Div, } impl fmt::Display for RustHelper { @@ -15,6 +16,7 @@ impl fmt::Display for RustHelper { RustHelper::Identity => write!(f, "Identity"), RustHelper::ConditionEq => write!(f, "ConditionEq"), RustHelper::Bits => write!(f, "Bits"), + RustHelper::Div => write!(f, "Div"), } } } @@ -25,6 +27,7 @@ impl Signed for RustHelper { RustHelper::Identity => (1, 1), RustHelper::ConditionEq => (1, 2), RustHelper::Bits => (1, 254), + RustHelper::Div => (2, 1), } } } @@ -52,6 +55,7 @@ impl Executable for RustHelper { assert_eq!(num, T::zero()); Ok(res) } + RustHelper::Div => Ok(vec![inputs[0].clone() / inputs[1].clone()]), } } } diff --git a/zokrates_core/src/parser/parse/expression.rs b/zokrates_core/src/parser/parse/expression.rs index 9247def9..2df658c3 100644 --- a/zokrates_core/src/parser/parse/expression.rs +++ b/zokrates_core/src/parser/parse/expression.rs @@ -240,6 +240,19 @@ fn parse_factor1( } } +// parse an identifier or select or function call +fn parse_identified1( + x: String, + input: String, + position: Position, +) -> Result<(Expression, String, Position), Error> { + match next_token::(&input, &position) { + (Token::Open, s1, p1) => parse_function_call(x, s1, p1), + (Token::LeftBracket, s1, p1) => parse_array_select(x, s1, p1), + _ => Ok((Expression::Identifier(x), input, position)), + } +} + fn parse_factor( input: &String, pos: &Position, @@ -257,10 +270,9 @@ fn parse_factor( }, Err(err) => Err(err), }, - (Token::Ide(x), s1, p1) => match next_token::(&s1, &p1) { - (Token::Open, s2, p2) => parse_function_call(x, s2, p2), - (Token::LeftBracket, s2, p2) => parse_array_select(x, s2, p2), - _ => parse_factor1(Expression::Identifier(x), s1, p1), + (Token::Ide(x), s1, p1) => match parse_identified1(x, s1, p1) { + Ok((e2, s2, p2)) => parse_factor1(e2, s2, p2), + e => e, }, (Token::Num(x), s1, p1) => parse_factor1(Expression::Number(x), s1, p1), (t1, _, p1) => Err(Error { @@ -338,10 +350,7 @@ pub fn parse_function_call( match next_token::(&s, &p) { // no arguments (Token::Close, s1, p1) => { - match parse_term1(Expression::FunctionCall(ide, args), s1, p1) { - Ok((e2, s2, p2)) => return parse_expr1(e2, s2, p2), - Err(err) => return Err(err), - } + return parse_term1(Expression::FunctionCall(ide, args), s1, p1); } // at least one argument (_, _, _) => match parse_expr(&s, &p) { @@ -353,10 +362,7 @@ pub fn parse_function_call( p = p2; } (Token::Close, s2, p2) => { - match parse_term1(Expression::FunctionCall(ide, args), s2, p2) { - Ok((e3, s3, p3)) => return parse_expr1(e3, s3, p3), - Err(err) => return Err(err), - } + return parse_term1(Expression::FunctionCall(ide, args), s2, p2) } (t2, _, p2) => { return Err(Error { @@ -430,14 +436,11 @@ pub fn parse_array_select( match next_token::(&input, &pos) { (_, _, _) => match parse_expr(&input, &pos) { Ok((e1, s1, p1)) => match next_token::(&s1, &p1) { - (Token::RightBracket, s2, p2) => match parse_term1( + (Token::RightBracket, s2, p2) => parse_term1( Expression::Select(box Expression::Identifier(ide), box e1), s2, p2, - ) { - Ok((e3, s3, p3)) => parse_expr1(e3, s3, p3), - Err(err) => Err(err), - }, + ), (t2, _, p2) => Err(Error { expected: vec![Token::RightBracket], got: t2, @@ -469,13 +472,12 @@ pub fn parse_expr( }, Err(err) => Err(err), }, - (Token::Ide(x), s1, p1) => match next_token::(&s1, &p1) { - (Token::Open, s2, p2) => parse_function_call(x, s2, p2), - (Token::LeftBracket, s2, p2) => parse_array_select(x, s2, p2), - _ => match parse_term1(Expression::Identifier(x), s1, p1) { - Ok((e2, s2, p2)) => parse_expr1(e2, s2, p2), - Err(err) => Err(err), + (Token::Ide(x), s1, p1) => match parse_identified1(x, s1, p1) { + Ok((e2, s2, p2)) => match parse_term1(e2, s2, p2) { + Ok((e3, s3, p3)) => parse_expr1(e3, s3, p3), + e => e, }, + e => e, }, (Token::Num(x), s1, p1) => match parse_term1(Expression::Number(x), s1, p1) { Ok((e2, s2, p2)) => parse_expr1(e2, s2, p2), @@ -495,6 +497,169 @@ mod tests { use super::*; use field::FieldPrime; + mod terms { + use super::*; + + #[test] + fn parse_number_sum() { + let pos = Position { line: 45, col: 121 }; + let string = String::from("1 + 2 + 3"); + let expr = Expression::Add( + box Expression::Add( + box Expression::Number(FieldPrime::from(1)), + box Expression::Number(FieldPrime::from(2)), + ), + box Expression::Number(FieldPrime::from(3)), + ); + assert_eq!( + Ok((expr, String::from(""), pos.col(string.len() as isize))), + parse_expr(&string, &pos) + ); + } + + #[test] + fn parse_number_sub() { + let pos = Position { line: 45, col: 121 }; + let string = String::from("1 - 2 - 3"); + let expr = Expression::Sub( + box Expression::Sub( + box Expression::Number(FieldPrime::from(1)), + box Expression::Number(FieldPrime::from(2)), + ), + box Expression::Number(FieldPrime::from(3)), + ); + assert_eq!( + Ok((expr, String::from(""), pos.col(string.len() as isize))), + parse_expr(&string, &pos) + ); + } + + #[test] + fn parse_function_call_single_sub() { + let pos = Position { line: 45, col: 121 }; + let string = String::from("1 - f(a)"); + let expr = Expression::Sub( + box Expression::Number(FieldPrime::from(1)), + box Expression::FunctionCall( + String::from("f"), + vec![Expression::Identifier(String::from("a"))], + ), + ); + assert_eq!( + Ok((expr, String::from(""), pos.col(string.len() as isize))), + parse_expr(&string, &pos) + ); + } + + #[test] + fn parse_function_call_sub() { + let pos = Position { line: 45, col: 121 }; + let string = String::from("1 - f() - 3"); + let expr = Expression::Sub( + box Expression::Sub( + box Expression::Number(FieldPrime::from(1)), + box Expression::FunctionCall(String::from("f"), vec![]), + ), + box Expression::Number(FieldPrime::from(3)), + ); + assert_eq!( + Ok((expr, String::from(""), pos.col(string.len() as isize))), + parse_expr(&string, &pos) + ); + } + + #[test] + fn parse_function_call_add() { + let pos = Position { line: 45, col: 121 }; + let string = String::from("1 + f() + 3"); + let expr = Expression::Add( + box Expression::Add( + box Expression::Number(FieldPrime::from(1)), + box Expression::FunctionCall(String::from("f"), vec![]), + ), + box Expression::Number(FieldPrime::from(3)), + ); + assert_eq!( + Ok((expr, String::from(""), pos.col(string.len() as isize))), + parse_expr(&string, &pos) + ); + } + + #[test] + fn parse_select_sub() { + let pos = Position { line: 45, col: 121 }; + let string = String::from("1 - f[2] - 3"); + let expr = Expression::Sub( + box Expression::Sub( + box Expression::Number(FieldPrime::from(1)), + box Expression::Select( + box Expression::Identifier(String::from("f")), + box Expression::Number(FieldPrime::from(2)), + ), + ), + box Expression::Number(FieldPrime::from(3)), + ); + assert_eq!( + Ok((expr, String::from(""), pos.col(string.len() as isize))), + parse_expr(&string, &pos) + ); + } + + #[test] + fn parse_select_add() { + let pos = Position { line: 45, col: 121 }; + let string = String::from("1 + f[2] + 3"); + let expr = Expression::Add( + box Expression::Add( + box Expression::Number(FieldPrime::from(1)), + box Expression::Select( + box Expression::Identifier(String::from("f")), + box Expression::Number(FieldPrime::from(2)), + ), + ), + box Expression::Number(FieldPrime::from(3)), + ); + assert_eq!( + Ok((expr, String::from(""), pos.col(string.len() as isize))), + parse_expr(&string, &pos) + ); + } + + #[test] + fn parse_identifier_sub() { + let pos = Position { line: 45, col: 121 }; + let string = String::from("1 - f - 3"); + let expr = Expression::Sub( + box Expression::Sub( + box Expression::Number(FieldPrime::from(1)), + box Expression::Identifier(String::from("f")), + ), + box Expression::Number(FieldPrime::from(3)), + ); + assert_eq!( + Ok((expr, String::from(""), pos.col(string.len() as isize))), + parse_expr(&string, &pos) + ); + } + + #[test] + fn parse_identifier_add() { + let pos = Position { line: 45, col: 121 }; + let string = String::from("1 + f + 3"); + let expr = Expression::Add( + box Expression::Add( + box Expression::Number(FieldPrime::from(1)), + box Expression::Identifier(String::from("f")), + ), + box Expression::Number(FieldPrime::from(3)), + ); + assert_eq!( + Ok((expr, String::from(""), pos.col(string.len() as isize))), + parse_expr(&string, &pos) + ); + } + } + #[test] fn parse_if_then_else_ok() { let pos = Position { line: 45, col: 121 }; diff --git a/zokrates_core/src/parser/parse/statement.rs b/zokrates_core/src/parser/parse/statement.rs index 51d8e991..b5612b72 100644 --- a/zokrates_core/src/parser/parse/statement.rs +++ b/zokrates_core/src/parser/parse/statement.rs @@ -389,73 +389,79 @@ fn parse_statement1( Err(err) => Err(err), }, (Token::Open, s1, p1) => match parse_function_call(ide, s1, p1) { - Ok((e3, s3, p3)) => match next_token(&s3, &p3) { - (Token::Eqeq, s4, p4) => match parse_expr(&s4, &p4) { - Ok((e5, s5, p5)) => match next_token(&s5, &p5) { - (Token::InlineComment(_), ref s6, _) => { - assert_eq!(s6, ""); - Ok((vec![Statement::Condition(e3, e5)], s5, p5)) - } - (Token::Unknown(ref t6), ref s6, _) if t6 == "" => { - assert_eq!(s6, ""); - Ok((vec![Statement::Condition(e3, e5)], s5, p5)) - } - (t6, _, p6) => Err(Error { - expected: vec![ - Token::Add, - Token::Sub, - Token::Pow, - Token::Mult, - Token::Div, - Token::Unknown("".to_string()), - ], - got: t6, - pos: p6, - }), + Ok((e3, s3, p3)) => match parse_expr1(e3, s3, p3) { + Ok((e4, s4, p4)) => match next_token(&s4, &p4) { + (Token::Eqeq, s5, p5) => match parse_expr(&s5, &p5) { + Ok((e6, s6, p6)) => match next_token(&s6, &p6) { + (Token::InlineComment(_), ref s7, _) => { + assert_eq!(s7, ""); + Ok((vec![Statement::Condition(e4, e6)], s6, p6)) + } + (Token::Unknown(ref t7), ref s7, _) if t7 == "" => { + assert_eq!(s7, ""); + Ok((vec![Statement::Condition(e4, e6)], s6, p6)) + } + (t7, _, p7) => Err(Error { + expected: vec![ + Token::Add, + Token::Sub, + Token::Pow, + Token::Mult, + Token::Div, + Token::Unknown("".to_string()), + ], + got: t7, + pos: p7, + }), + }, + Err(err) => Err(err), }, - Err(err) => Err(err), + (t4, _, p4) => Err(Error { + expected: vec![Token::Eqeq], + got: t4, + pos: p4, + }), }, - (t4, _, p4) => Err(Error { - expected: vec![Token::Eqeq], - got: t4, - pos: p4, - }), + Err(err) => Err(err), }, Err(err) => Err(err), }, (Token::LeftBracket, s1, p1) => match parse_array_select(ide, s1, p1) { - Ok((e3, s3, p3)) => match next_token(&s3, &p3) { - (Token::Eqeq, s4, p4) => match parse_expr(&s4, &p4) { - Ok((e5, s5, p5)) => match next_token(&s5, &p5) { - (Token::InlineComment(_), ref s6, _) => { - assert_eq!(s6, ""); - Ok((vec![Statement::Condition(e3, e5)], s5, p5)) - } - (Token::Unknown(ref t6), ref s6, _) if t6 == "" => { - assert_eq!(s6, ""); - Ok((vec![Statement::Condition(e3, e5)], s5, p5)) - } - (t6, _, p6) => Err(Error { - expected: vec![ - Token::Add, - Token::Sub, - Token::Pow, - Token::Mult, - Token::Div, - Token::Unknown("".to_string()), - ], - got: t6, - pos: p6, - }), + Ok((e3, s3, p3)) => match parse_expr1(e3, s3, p3) { + Ok((e4, s4, p4)) => match next_token(&s4, &p4) { + (Token::Eqeq, s5, p5) => match parse_expr(&s5, &p5) { + Ok((e6, s6, p6)) => match next_token(&s6, &p6) { + (Token::InlineComment(_), ref s7, _) => { + assert_eq!(s7, ""); + Ok((vec![Statement::Condition(e4, e6)], s6, p6)) + } + (Token::Unknown(ref t7), ref s7, _) if t7 == "" => { + assert_eq!(s7, ""); + Ok((vec![Statement::Condition(e4, e6)], s6, p6)) + } + (t7, _, p7) => Err(Error { + expected: vec![ + Token::Add, + Token::Sub, + Token::Pow, + Token::Mult, + Token::Div, + Token::Unknown("".to_string()), + ], + got: t7, + pos: p7, + }), + }, + Err(err) => Err(err), }, - Err(err) => Err(err), + (Token::Eq, s5, p5) => parse_definition1(Assignee::from(e4), s5, p5), + (t4, _, p4) => Err(Error { + expected: vec![Token::Eqeq], + got: t4, + pos: p4, + }), }, - (Token::Eq, s4, p4) => parse_definition1(Assignee::from(e3), s4, p4), - (t4, _, p4) => Err(Error { - expected: vec![Token::Eqeq], - got: t4, - pos: p4, - }), + Err(err) => Err(err), }, Err(err) => Err(err), }, @@ -580,5 +586,48 @@ mod tests { parse_statement1(String::from("foo"), string, pos) ); } + + #[test] + fn left_call_in_assertion2() { + let pos = Position { line: 45, col: 121 }; + let string = String::from("() - g() - 1 == 1"); + let cond = Statement::Condition( + Expression::Sub( + box Expression::Sub( + box Expression::FunctionCall(String::from("foo"), vec![]), + box Expression::FunctionCall(String::from("g"), vec![]), + ), + box Expression::Number(FieldPrime::from(1)), + ), + Expression::Number(FieldPrime::from(1)), + ); + assert_eq!( + Ok((vec![cond], String::from(""), pos.col(string.len() as isize))), + parse_statement1(String::from("foo"), string, pos) + ); + } + + #[test] + fn left_select_in_assertion2() { + let pos = Position { line: 45, col: 121 }; + let string = String::from("[3] - g() - 1 == 1"); + let cond = Statement::Condition( + Expression::Sub( + box Expression::Sub( + box Expression::Select( + box Expression::Identifier(String::from("foo")), + box Expression::Number(FieldPrime::from(3)), + ), + box Expression::FunctionCall(String::from("g"), vec![]), + ), + box Expression::Number(FieldPrime::from(1)), + ), + Expression::Number(FieldPrime::from(1)), + ); + assert_eq!( + Ok((vec![cond], String::from(""), pos.col(string.len() as isize))), + parse_statement1(String::from("foo"), string, pos) + ); + } } } diff --git a/zokrates_core/src/r1cs.rs b/zokrates_core/src/r1cs.rs index 5aef0582..c4bcc298 100644 --- a/zokrates_core/src/r1cs.rs +++ b/zokrates_core/src/r1cs.rs @@ -193,51 +193,6 @@ fn r1cs_expression( c_row.push((provide_variable_idx(variables, &key), value)); } } - Div(lhs, rhs) => { - // a / b = c --> c * b = a - match lhs { - box Number(x) => c_row.push((0, x)), - box Identifier(x) => c_row.push((provide_variable_idx(variables, &x), T::one())), - box e @ Add(..) => { - for (key, value) in count_variables_add(&e) { - c_row.push((provide_variable_idx(variables, &key), value)); - } - } - box e @ Sub(..) => { - return r1cs_expression( - Mult(box linear_expr, rhs), - e, - variables, - a_row, - b_row, - c_row, - ) - } - box Mult(box Number(ref x1), box Number(ref x2)) => { - c_row.push((0, x1.clone() * x2)) - } - box Mult(box Number(ref x), box Identifier(ref v)) - | box Mult(box Identifier(ref v), box Number(ref x)) => { - c_row.push((provide_variable_idx(variables, v), x.clone())) - } - e @ _ => panic!("(lhs) not supported: {:?}", e), - }; - match rhs { - box Number(x) => b_row.push((0, x)), - box Identifier(x) => b_row.push((provide_variable_idx(variables, &x), T::one())), - box Mult(box Number(ref x1), box Number(ref x2)) => { - b_row.push((0, x1.clone() * x2)) - } - box Mult(box Number(ref x), box Identifier(ref v)) - | box Mult(box Identifier(ref v), box Number(ref x)) => { - b_row.push((provide_variable_idx(variables, v), x.clone())) - } - e @ _ => panic!("(rhs) not supported: {:?}", e), - }; - for (key, value) in count_variables_add(&linear_expr) { - a_row.push((provide_variable_idx(variables, &key), value)); - } - } Identifier(var) => { a_row.push((provide_variable_idx(variables, &var), T::one())); b_row.push((0, T::one())); @@ -659,37 +614,5 @@ mod tests { c_row ); } - - #[test] - fn div() { - // x = (3 * x) / (y * 6) --> x * (y * 6) = 3 * x - - let one = FlatVariable::one(); - let x = FlatVariable::new(0); - let y = FlatVariable::new(1); - - let lhs = Identifier(x); - let rhs = Div( - box Mult(box Number(FieldPrime::from(3)), box Identifier(x)), - box Mult(box Identifier(y), box Number(FieldPrime::from(6))), - ); - - let mut a_row = Vec::new(); - let mut b_row = Vec::new(); - let mut c_row = Vec::new(); - - let mut variables: HashMap = HashMap::new(); - variables.insert(one, 0); - variables.insert(x, 1); - variables.insert(y, 2); - - r1cs_expression(lhs, rhs, &mut variables, &mut a_row, &mut b_row, &mut c_row); - a_row.sort_by(sort_tup); - b_row.sort_by(sort_tup); - c_row.sort_by(sort_tup); - assert_eq!(vec![(1, FieldPrime::from(1))], a_row); // x - assert_eq!(vec![(2, FieldPrime::from(6))], b_row); // y * 6 - assert_eq!(vec![(1, FieldPrime::from(3))], c_row); // 3 * x - } } } diff --git a/zokrates_core/src/static_analysis/flat_propagation.rs b/zokrates_core/src/static_analysis/flat_propagation.rs index a57c9aee..f936fbfc 100644 --- a/zokrates_core/src/static_analysis/flat_propagation.rs +++ b/zokrates_core/src/static_analysis/flat_propagation.rs @@ -49,14 +49,6 @@ impl PropagateWithContext for FlatExpression { (e1, e2) => FlatExpression::Mult(box e1, box e2), } } - FlatExpression::Div(box e1, box e2) => { - match (e1.propagate(constants), e2.propagate(constants)) { - (FlatExpression::Number(n1), FlatExpression::Number(n2)) => { - FlatExpression::Number(n1 / n2) - } - (e1, e2) => FlatExpression::Div(box e1, box e2), - } - } } } } @@ -173,19 +165,6 @@ mod tests { FlatExpression::Number(FieldPrime::from(6)) ); } - - #[test] - fn div() { - let e = FlatExpression::Div( - box FlatExpression::Number(FieldPrime::from(6)), - box FlatExpression::Number(FieldPrime::from(2)), - ); - - assert_eq!( - e.propagate(&mut HashMap::new()), - FlatExpression::Number(FieldPrime::from(3)) - ); - } } } } diff --git a/zokrates_fs_resolver/Cargo.toml b/zokrates_fs_resolver/Cargo.toml index 51179550..1a654ebe 100644 --- a/zokrates_fs_resolver/Cargo.toml +++ b/zokrates_fs_resolver/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zokrates_fs_resolver" -version = "0.3.1" +version = "0.3.2" authors = ["Thibaut Schaeffer "] repository = "https://github.com/JacobEberhardt/ZoKrates.git"