diff --git a/zokrates_cli/src/bin.rs b/zokrates_cli/src/bin.rs index 0976d890..60572d6e 100644 --- a/zokrates_cli/src/bin.rs +++ b/zokrates_cli/src/bin.rs @@ -16,7 +16,7 @@ use std::io::{stdin, BufReader, BufWriter, Read, Write}; use std::path::{Path, PathBuf}; use std::string::String; use zokrates_abi::Encode; -use zokrates_core::compile::{check, compile, CompilationArtifacts, CompileError}; +use zokrates_core::compile::{check, compile, CompilationArtifacts, CompileConfig, CompileError}; use zokrates_core::ir::{self, ProgEnum}; use zokrates_core::proof_system::*; use zokrates_core::typed_absy::abi::Abi; @@ -261,6 +261,8 @@ fn cli_compile(sub_matches: &ArgMatches) -> Result<(), String> { let hr_output_path = bin_output_path.to_path_buf().with_extension("ztf"); + let is_release = sub_matches.occurrences_of("release") > 0; + let file = File::open(path.clone()) .map_err(|why| format!("Couldn't open input file {}: {}", path.display(), why))?; @@ -281,9 +283,11 @@ fn cli_compile(sub_matches: &ArgMatches) -> Result<(), String> { ) }; + let compilation_config = CompileConfig::default().with_is_release(is_release); + let resolver = FileSystemResolver::new(); let artifacts: CompilationArtifacts = - compile(source, path, Some(&resolver)).map_err(|e| { + compile(source, path, Some(&resolver), &compilation_config).map_err(|e| { format!( "Compilation failed:\n\n{}", e.0.iter() @@ -460,6 +464,10 @@ fn cli() -> Result<(), String> { .long("light") .help("Skip logs and human readable output") .required(false) + ).arg(Arg::with_name("release") + .long("release") + .help("Apply release optimisations to minimise constraint count. This increases compilation time.") + .required(false) ) ) .subcommand(SubCommand::with_name("check") @@ -934,7 +942,7 @@ mod tests { let resolver = FileSystemResolver::new(); let _: CompilationArtifacts = - compile(source, path, Some(&resolver)).unwrap(); + compile(source, path, Some(&resolver), &CompileConfig::default()).unwrap(); } } @@ -956,7 +964,7 @@ mod tests { let resolver = FileSystemResolver::new(); let artifacts: CompilationArtifacts = - compile(source, path, Some(&resolver)).unwrap(); + compile(source, path, Some(&resolver), &CompileConfig::default()).unwrap(); let interpreter = ir::Interpreter::default(); @@ -985,7 +993,7 @@ mod tests { let resolver = FileSystemResolver::new(); let artifacts: CompilationArtifacts = - compile(source, path, Some(&resolver)).unwrap(); + compile(source, path, Some(&resolver), &CompileConfig::default()).unwrap(); let interpreter = ir::Interpreter::default(); diff --git a/zokrates_core/src/compile.rs b/zokrates_core/src/compile.rs index c54c9719..d31865aa 100644 --- a/zokrates_core/src/compile.rs +++ b/zokrates_core/src/compile.rs @@ -9,7 +9,6 @@ use imports::{self, Importer}; use ir; use macros; use macros::process_macros; -use optimizer::Optimize; use semantics::{self, Checker}; use static_analysis::Analyse; use std::collections::HashMap; @@ -141,12 +140,29 @@ impl fmt::Display for CompileErrorInner { } } +#[derive(Debug, Default)] +pub struct CompileConfig { + is_release: bool, +} + +impl CompileConfig { + pub fn with_is_release(mut self, is_release: bool) -> Self { + self.is_release = is_release; + self + } + + pub fn is_release(&self) -> bool { + self.is_release + } +} + type FilePath = PathBuf; pub fn compile>( source: String, location: FilePath, resolver: Option<&dyn Resolver>, + config: &CompileConfig, ) -> Result, CompileErrors> { let arena = Arena::new(); @@ -164,7 +180,7 @@ pub fn compile>( let ir_prog = ir::Prog::from(program_flattened); // optimize - let optimized_ir_prog = ir_prog.optimize(); + let optimized_ir_prog = ir_prog.optimize(config); // analyse (check for unused constraints) let optimized_ir_prog = optimized_ir_prog.analyse(); @@ -264,6 +280,7 @@ mod test { source, "./path/to/file".into(), None::<&dyn Resolver>, + &CompileConfig::default(), ); assert!(res.unwrap_err().0[0] .value() @@ -282,6 +299,7 @@ mod test { source, "./path/to/file".into(), None::<&dyn Resolver>, + &CompileConfig::default(), ); assert!(res.is_ok()); } @@ -362,6 +380,7 @@ struct Bar { field a } main.to_string(), "main".into(), Some(&CustomResolver), + &CompileConfig::default(), ) .unwrap(); diff --git a/zokrates_core/src/optimizer/mod.rs b/zokrates_core/src/optimizer/mod.rs index 9cca70f3..687e107d 100644 --- a/zokrates_core/src/optimizer/mod.rs +++ b/zokrates_core/src/optimizer/mod.rs @@ -11,18 +11,19 @@ mod tautology; use self::duplicate::DuplicateOptimizer; use self::redefinition::RedefinitionOptimizer; use self::tautology::TautologyOptimizer; +use compile::CompileConfig; use crate::ir::Prog; use zokrates_field::Field; -pub trait Optimize { - fn optimize(self) -> Self; -} - -impl Optimize for Prog { - fn optimize(self) -> Self { - // remove redefinitions - let r = RedefinitionOptimizer::optimize(self); +impl Prog { + pub fn optimize(self, config: &CompileConfig) -> Self { + let r = if config.is_release() { + // remove redefinitions + RedefinitionOptimizer::optimize(self) + } else { + self + }; // remove constraints that are always satisfied let r = TautologyOptimizer::optimize(r); // remove duplicate constraints diff --git a/zokrates_core/tests/out_of_range.rs b/zokrates_core/tests/out_of_range.rs index ce9a5b3a..571eb571 100644 --- a/zokrates_core/tests/out_of_range.rs +++ b/zokrates_core/tests/out_of_range.rs @@ -5,7 +5,7 @@ extern crate zokrates_field; use std::io; use zokrates_common::Resolver; use zokrates_core::{ - compile::{compile, CompilationArtifacts}, + compile::{compile, CompilationArtifacts, CompileConfig}, ir::Interpreter, }; use zokrates_field::Bn128Field; @@ -28,6 +28,7 @@ fn out_of_range() { source, "./path/to/file".into(), None::<&dyn Resolver>, + &CompileConfig::default(), ) .unwrap(); diff --git a/zokrates_js/src/lib.rs b/zokrates_js/src/lib.rs index e2faca23..98374d89 100644 --- a/zokrates_js/src/lib.rs +++ b/zokrates_js/src/lib.rs @@ -5,7 +5,9 @@ use std::path::PathBuf; use wasm_bindgen::prelude::*; use zokrates_abi::{parse_strict, Decode, Encode, Inputs}; use zokrates_common::Resolver; -use zokrates_core::compile::{compile as core_compile, CompilationArtifacts, CompileError}; +use zokrates_core::compile::{ + compile as core_compile, CompilationArtifacts, CompileConfig, CompileError, +}; use zokrates_core::imports::Error; use zokrates_core::ir; use zokrates_core::proof_system::{self, ProofSystem, SolidityAbi}; @@ -104,6 +106,7 @@ pub fn compile( source.as_string().unwrap(), PathBuf::from(location.as_string().unwrap()), Some(&resolver), + &CompileConfig::default().with_is_release(true), ) .map_err(|ce| { JsValue::from_str(&format!( diff --git a/zokrates_test/src/lib.rs b/zokrates_test/src/lib.rs index be048631..2618349f 100644 --- a/zokrates_test/src/lib.rs +++ b/zokrates_test/src/lib.rs @@ -75,7 +75,7 @@ fn compare(result: ir::ExecutionResult, expected: TestResult) -> Re } use std::io::{BufReader, Read}; -use zokrates_core::compile::compile; +use zokrates_core::compile::{compile, CompileConfig}; use zokrates_fs_resolver::FileSystemResolver; pub fn test_inner(test_path: &str) { @@ -96,7 +96,13 @@ fn compile_and_run(t: Tests) { let code = std::fs::read_to_string(&t.entry_point).unwrap(); let resolver = FileSystemResolver::new(); - let artifacts = compile::(code, t.entry_point.clone(), Some(&resolver)).unwrap(); + let artifacts = compile::( + code, + t.entry_point.clone(), + Some(&resolver), + &CompileConfig::default().with_is_release(true), + ) + .unwrap(); let bin = artifacts.prog();