Merge branch 'master' of github.com:JacobEberhardt/ZoKrates into gm17
This commit is contained in:
commit
57fc5453dd
16 changed files with 486 additions and 222 deletions
|
@ -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
|
||||
|
|
10
Cargo.lock
generated
10
Cargo.lock
generated
|
@ -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"
|
||||
|
|
10
README.md
10
README.md
|
@ -1,25 +1,25 @@
|
|||
|
||||
<img src="http://www.redaktion.tu-berlin.de/fileadmin/fg308/icons/projekte/logos/ZoKrates_logo.svg" width="100%" height="180">
|
||||
|
||||
# Zokrates
|
||||
# ZoKrates
|
||||
|
||||
[](https://gitter.im/ZoKrates/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||

|
||||

|
||||
|
||||
|
||||
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.
|
||||
|
|
|
@ -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!
|
||||
>ZoKrates would welcome ideas to add support for such ceremonies!
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "zokrates_cli"
|
||||
version = "0.3.1"
|
||||
version = "0.3.2"
|
||||
authors = ["Jacob Eberhardt <jacob.eberhardt@tu-berlin.de>", "Dennis Kuhnert <mail@kyroy.com>", "Thibaut Schaeffer <thibaut@schaeff.fr>"]
|
||||
repository = "https://github.com/JacobEberhardt/ZoKrates.git"
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "zokrates_core"
|
||||
version = "0.3.1"
|
||||
version = "0.3.2"
|
||||
authors = ["Jacob Eberhardt <jacob.eberhardt@tu-berlin.de>", "Dennis Kuhnert <mail@kyroy.com>"]
|
||||
repository = "https://github.com/JacobEberhardt/ZoKrates"
|
||||
readme = "README.md"
|
||||
|
|
|
@ -272,7 +272,6 @@ pub enum FlatExpression<T: Field> {
|
|||
Identifier(FlatVariable),
|
||||
Add(Box<FlatExpression<T>>, Box<FlatExpression<T>>),
|
||||
Sub(Box<FlatExpression<T>>, Box<FlatExpression<T>>),
|
||||
Div(Box<FlatExpression<T>>, Box<FlatExpression<T>>),
|
||||
Mult(Box<FlatExpression<T>>, Box<FlatExpression<T>>),
|
||||
}
|
||||
|
||||
|
@ -313,10 +312,6 @@ impl<T: Field> FlatExpression<T> {
|
|||
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<T: Field> FlatExpression<T> {
|
|||
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<T: Field> FlatExpression<T> {
|
|||
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<T: Field> fmt::Display for FlatExpression<T> {
|
|||
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<T: Field> fmt::Debug for FlatExpression<T> {
|
|||
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<T: Field> From<FlatVariable> for FlatExpression<T> {
|
||||
fn from(v: FlatVariable) -> FlatExpression<T> {
|
||||
FlatExpression::Identifier(v)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct FlatExpressionList<T: Field> {
|
||||
pub expressions: Vec<FlatExpression<T>>,
|
||||
|
|
|
@ -692,17 +692,47 @@ impl Flattener {
|
|||
statements_flattened,
|
||||
right,
|
||||
);
|
||||
let new_left = {
|
||||
let new_left: FlatExpression<T> = {
|
||||
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<T> = {
|
||||
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 = [ , , ]
|
||||
|
|
|
@ -17,16 +17,17 @@ pub struct DirectiveStatement<T: Field> {
|
|||
}
|
||||
|
||||
impl<T: Field> DirectiveStatement<T> {
|
||||
pub fn new(outputs: Vec<FlatVariable>, helper: Helper, inputs: Vec<FlatVariable>) -> Self {
|
||||
pub fn new<E: Into<FlatExpression<T>>>(
|
||||
outputs: Vec<FlatVariable>,
|
||||
helper: Helper,
|
||||
inputs: Vec<E>,
|
||||
) -> 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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<T: Field> Executable<T> for RustHelper {
|
|||
assert_eq!(num, T::zero());
|
||||
Ok(res)
|
||||
}
|
||||
RustHelper::Div => Ok(vec![inputs[0].clone() / inputs[1].clone()]),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -240,6 +240,19 @@ fn parse_factor1<T: Field>(
|
|||
}
|
||||
}
|
||||
|
||||
// parse an identifier or select or function call
|
||||
fn parse_identified1<T: Field>(
|
||||
x: String,
|
||||
input: String,
|
||||
position: Position,
|
||||
) -> Result<(Expression<T>, String, Position), Error<T>> {
|
||||
match next_token::<T>(&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<T: Field>(
|
||||
input: &String,
|
||||
pos: &Position,
|
||||
|
@ -257,10 +270,9 @@ fn parse_factor<T: Field>(
|
|||
},
|
||||
Err(err) => Err(err),
|
||||
},
|
||||
(Token::Ide(x), s1, p1) => match next_token::<T>(&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<T: Field>(
|
|||
match next_token::<T>(&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<T: Field>(
|
|||
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<T: Field>(
|
|||
match next_token::<T>(&input, &pos) {
|
||||
(_, _, _) => match parse_expr(&input, &pos) {
|
||||
Ok((e1, s1, p1)) => match next_token::<T>(&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<T: Field>(
|
|||
},
|
||||
Err(err) => Err(err),
|
||||
},
|
||||
(Token::Ide(x), s1, p1) => match next_token::<T>(&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 };
|
||||
|
|
|
@ -389,73 +389,79 @@ fn parse_statement1<T: Field>(
|
|||
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)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -193,51 +193,6 @@ fn r1cs_expression<T: Field>(
|
|||
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<FlatVariable, usize> = 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,14 +49,6 @@ impl<T: Field> PropagateWithContext<T> for FlatExpression<T> {
|
|||
(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))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "zokrates_fs_resolver"
|
||||
version = "0.3.1"
|
||||
version = "0.3.2"
|
||||
authors = ["Thibaut Schaeffer <thibaut@schaeff.fr>"]
|
||||
repository = "https://github.com/JacobEberhardt/ZoKrates.git"
|
||||
|
||||
|
|
Loading…
Reference in a new issue