diff --git a/zokrates_cli/src/ops/compile.rs b/zokrates_cli/src/ops/compile.rs index fcda43c9..a7f9e460 100644 --- a/zokrates_cli/src/ops/compile.rs +++ b/zokrates_cli/src/ops/compile.rs @@ -56,6 +56,10 @@ pub fn subcommand() -> App<'static, 'static> { .long("allow-unconstrained-variables") .help("Allow unconstrained variables by inserting dummy constraints") .required(false) + ).arg(Arg::with_name("isolate-branches") + .long("isolate-branches") + .help("Isolate the execution of branches: a panic in a branch only makes the program panic if this branch is being logically executed") + .required(false) ).arg(Arg::with_name("ztf") .long("ztf") .help("Write human readable output (ztf)") @@ -124,6 +128,7 @@ fn cli_compile(sub_matches: &ArgMatches) -> Result<(), String> { let config = CompileConfig { allow_unconstrained_variables: sub_matches.is_present("allow-unconstrained-variables"), + isolate_branches: sub_matches.is_present("isolate-branches"), }; let resolver = FileSystemResolver::with_stdlib_root(stdlib_path); diff --git a/zokrates_core/src/compile.rs b/zokrates_core/src/compile.rs index 87d27429..122be3c6 100644 --- a/zokrates_core/src/compile.rs +++ b/zokrates_core/src/compile.rs @@ -156,9 +156,10 @@ impl fmt::Display for CompileErrorInner { } } -#[derive(Debug, Default, Serialize, Deserialize)] +#[derive(Debug, Default, Serialize, Deserialize, Clone)] pub struct CompileConfig { pub allow_unconstrained_variables: bool, + pub isolate_branches: bool, } type FilePath = PathBuf; diff --git a/zokrates_core/src/flatten/mod.rs b/zokrates_core/src/flatten/mod.rs index d87c770e..8d2e821b 100644 --- a/zokrates_core/src/flatten/mod.rs +++ b/zokrates_core/src/flatten/mod.rs @@ -2177,25 +2177,34 @@ impl<'ast, T: Field> Flattener<'ast, T> { ZirStatement::IfElse(condition, consequence, alternative) => { let condition = self.flatten_boolean_expression(statements_flattened, condition); - let mut consequence_statements = vec![]; - let mut alternative_statements = vec![]; + if self.config.isolate_branches { + let mut consequence_statements = vec![]; + let mut alternative_statements = vec![]; - consequence - .into_iter() - .for_each(|s| self.flatten_statement(&mut consequence_statements, s)); - alternative - .into_iter() - .for_each(|s| self.flatten_statement(&mut alternative_statements, s)); + consequence + .into_iter() + .for_each(|s| self.flatten_statement(&mut consequence_statements, s)); + alternative + .into_iter() + .for_each(|s| self.flatten_statement(&mut alternative_statements, s)); - let consequence_statements = - self.make_conditional(consequence_statements, condition.clone()); - let alternative_statements = self.make_conditional( - alternative_statements, - FlatExpression::Sub(box FlatExpression::Number(T::one()), box condition), - ); + let consequence_statements = + self.make_conditional(consequence_statements, condition.clone()); + let alternative_statements = self.make_conditional( + alternative_statements, + FlatExpression::Sub(box FlatExpression::Number(T::one()), box condition), + ); - statements_flattened.extend(consequence_statements); - statements_flattened.extend(alternative_statements); + statements_flattened.extend(consequence_statements); + statements_flattened.extend(alternative_statements); + } else { + consequence + .into_iter() + .for_each(|s| self.flatten_statement(statements_flattened, s)); + alternative + .into_iter() + .for_each(|s| self.flatten_statement(statements_flattened, s)); + } } ZirStatement::Definition(assignee, expr) => { // define n variables with n the number of primitive types for v_type diff --git a/zokrates_core_test/tests/tests/panics/panic_isolation.json b/zokrates_core_test/tests/tests/panics/panic_isolation.json index 304266b6..401f2dde 100644 --- a/zokrates_core_test/tests/tests/panics/panic_isolation.json +++ b/zokrates_core_test/tests/tests/panics/panic_isolation.json @@ -1,5 +1,9 @@ { "entry_point": "./tests/tests/panics/panic_isolation.zok", + "config": { + "allow_unconstrained_variables": false, + "isolate_branches": true + }, "curves": ["Bn128"], "tests": [ { diff --git a/zokrates_core_test/tests/tests/panics/panic_no_isolation.json b/zokrates_core_test/tests/tests/panics/panic_no_isolation.json new file mode 100644 index 00000000..d815ea13 --- /dev/null +++ b/zokrates_core_test/tests/tests/panics/panic_no_isolation.json @@ -0,0 +1,28 @@ +{ + "entry_point": "./tests/tests/panics/panic_isolation.zok", + "config": { + "allow_unconstrained_variables": false, + "isolate_branches": false + }, + "curves": ["Bn128"], + "tests": [ + { + "input": { + "values": [ + "1", + "1", + "1", + "1" + ] + }, + "output": { + "Err": { + "UnsatisfiedConstraint": { + "left": "1", + "right": "0" + } + } + } + } + ] +} diff --git a/zokrates_test/src/lib.rs b/zokrates_test/src/lib.rs index 8730cb8b..a9e252a1 100644 --- a/zokrates_test/src/lib.rs +++ b/zokrates_test/src/lib.rs @@ -23,6 +23,7 @@ struct Tests { pub entry_point: Option, pub curves: Option>, pub max_constraint_count: Option, + pub config: Option, pub tests: Vec, } @@ -119,18 +120,14 @@ pub fn test_inner(test_path: &str) { fn compile_and_run(t: Tests) { let entry_point = t.entry_point.unwrap(); + let config = t.config.unwrap_or_default(); + let code = std::fs::read_to_string(&entry_point).unwrap(); let stdlib = std::fs::canonicalize("../zokrates_stdlib/stdlib").unwrap(); let resolver = FileSystemResolver::with_stdlib_root(stdlib.to_str().unwrap()); - let artifacts = compile::( - code, - entry_point.clone(), - Some(&resolver), - &CompileConfig::default(), - ) - .unwrap(); + let artifacts = compile::(code, entry_point.clone(), Some(&resolver), &config).unwrap(); let bin = artifacts.prog();