Merge pull request #1041 from Zokrates/transient-ir
Iterator based compilation
This commit is contained in:
commit
192cfd1321
58 changed files with 1172 additions and 1238 deletions
23
Cargo.lock
generated
23
Cargo.lock
generated
|
@ -1074,6 +1074,12 @@ version = "0.3.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||
|
||||
[[package]]
|
||||
name = "half"
|
||||
version = "1.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.11.2"
|
||||
|
@ -1845,6 +1851,16 @@ dependencies = [
|
|||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_cbor"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5"
|
||||
dependencies = [
|
||||
"half",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.130"
|
||||
|
@ -2383,7 +2399,6 @@ name = "zokrates_cli"
|
|||
version = "0.7.8"
|
||||
dependencies = [
|
||||
"assert_cli",
|
||||
"bincode",
|
||||
"cfg-if 0.1.10",
|
||||
"clap",
|
||||
"dirs",
|
||||
|
@ -2393,8 +2408,11 @@ dependencies = [
|
|||
"lazy_static",
|
||||
"log",
|
||||
"regex 0.2.11",
|
||||
"serde",
|
||||
"serde_cbor",
|
||||
"serde_json",
|
||||
"tempdir",
|
||||
"typed-arena",
|
||||
"zokrates_abi",
|
||||
"zokrates_core",
|
||||
"zokrates_field",
|
||||
|
@ -2421,7 +2439,6 @@ dependencies = [
|
|||
"ark-relations",
|
||||
"ark-serialize",
|
||||
"bellman_ce",
|
||||
"bincode",
|
||||
"cc",
|
||||
"cfg-if 0.1.10",
|
||||
"cmake",
|
||||
|
@ -2441,6 +2458,7 @@ dependencies = [
|
|||
"reduce",
|
||||
"regex 0.2.11",
|
||||
"serde",
|
||||
"serde_cbor",
|
||||
"serde_json",
|
||||
"sha2 0.9.8",
|
||||
"typed-arena",
|
||||
|
@ -2545,6 +2563,7 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"typed-arena",
|
||||
"zokrates_abi",
|
||||
"zokrates_core",
|
||||
"zokrates_field",
|
||||
|
|
1
changelogs/unreleased/1041-schaeff
Normal file
1
changelogs/unreleased/1041-schaeff
Normal file
|
@ -0,0 +1 @@
|
|||
Reduce compiler memory usage using iterators, change the serialization format to CBOR
|
|
@ -31,7 +31,7 @@ Create this file under the name `get_hash.zok`:
|
|||
|
||||
Compile the program to a form that is usable for zero knowledge proofs. This command writes
|
||||
the binary to `get_hash`. You can see a textual representation, somewhat analogous to assembler
|
||||
coming from a compiler, at `get_hash.ztf` enabled by the `--ztf` command line option.
|
||||
coming from a compiler, at `get_hash.ztf` created by the `inspect` command.
|
||||
```
|
||||
{{#include ../../../zokrates_cli/examples/book/rng_tutorial/test.sh:10}}
|
||||
```
|
||||
|
|
|
@ -16,13 +16,15 @@ log = "0.4"
|
|||
env_logger = "0.9.0"
|
||||
cfg-if = "0.1"
|
||||
clap = "2.26.2"
|
||||
bincode = "0.8.0"
|
||||
serde_cbor = "0.11.2"
|
||||
regex = "0.2"
|
||||
zokrates_field = { version = "0.4", path = "../zokrates_field", default-features = false }
|
||||
zokrates_abi = { version = "0.1", path = "../zokrates_abi" }
|
||||
zokrates_core = { version = "0.6", path = "../zokrates_core", default-features = false }
|
||||
typed-arena = "1.4.1"
|
||||
zokrates_fs_resolver = { version = "0.5", path = "../zokrates_fs_resolver"}
|
||||
serde_json = "1.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
dirs = "3.0.1"
|
||||
lazy_static = "1.4.0"
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ function zokrates() {
|
|||
ZOKRATES_STDLIB=$stdlib $bin $*
|
||||
}
|
||||
|
||||
zokrates compile -i get_hash.zok -o get_hash --ztf
|
||||
zokrates compile -i get_hash.zok -o get_hash && zokrates inspect -i get_hash
|
||||
zokrates compute-witness --verbose -i get_hash -a 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||
|
||||
mkdir alice bob
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
def main(private field a) -> field:
|
||||
return 1
|
|
@ -43,6 +43,7 @@ fn cli() -> Result<(), String> {
|
|||
)
|
||||
.subcommands(vec![
|
||||
compile::subcommand(),
|
||||
inspect::subcommand(),
|
||||
check::subcommand(),
|
||||
compute_witness::subcommand(),
|
||||
#[cfg(feature = "ark")]
|
||||
|
@ -60,6 +61,7 @@ fn cli() -> Result<(), String> {
|
|||
|
||||
match matches.subcommand() {
|
||||
("compile", Some(sub_matches)) => compile::exec(sub_matches),
|
||||
("inspect", Some(sub_matches)) => inspect::exec(sub_matches),
|
||||
("check", Some(sub_matches)) => check::exec(sub_matches),
|
||||
("compute-witness", Some(sub_matches)) => compute_witness::exec(sub_matches),
|
||||
#[cfg(feature = "ark")]
|
||||
|
@ -115,6 +117,7 @@ mod tests {
|
|||
use std::fs::File;
|
||||
use std::io::{BufReader, Read};
|
||||
use std::string::String;
|
||||
use typed_arena::Arena;
|
||||
use zokrates_core::compile::{compile, CompilationArtifacts, CompileConfig};
|
||||
use zokrates_core::ir;
|
||||
use zokrates_field::Bn128Field;
|
||||
|
@ -154,11 +157,15 @@ mod tests {
|
|||
|
||||
let stdlib = std::fs::canonicalize("../zokrates_stdlib/stdlib").unwrap();
|
||||
let resolver = FileSystemResolver::with_stdlib_root(stdlib.to_str().unwrap());
|
||||
|
||||
let arena = Arena::new();
|
||||
|
||||
let res = compile::<Bn128Field, _>(
|
||||
source,
|
||||
path,
|
||||
Some(&resolver),
|
||||
&CompileConfig::default(),
|
||||
CompileConfig::default(),
|
||||
&arena,
|
||||
);
|
||||
assert_eq!(res.is_err(), should_error);
|
||||
}
|
||||
|
@ -189,8 +196,16 @@ mod tests {
|
|||
let stdlib = std::fs::canonicalize("../zokrates_stdlib/stdlib").unwrap();
|
||||
let resolver = FileSystemResolver::with_stdlib_root(stdlib.to_str().unwrap());
|
||||
|
||||
let artifacts: CompilationArtifacts<Bn128Field> =
|
||||
compile(source, path, Some(&resolver), &CompileConfig::default()).unwrap();
|
||||
let arena = Arena::new();
|
||||
|
||||
let artifacts: CompilationArtifacts<Bn128Field, _> = compile(
|
||||
source,
|
||||
path,
|
||||
Some(&resolver),
|
||||
CompileConfig::default(),
|
||||
&arena,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let interpreter = ir::Interpreter::default();
|
||||
|
||||
|
@ -221,8 +236,16 @@ mod tests {
|
|||
let stdlib = std::fs::canonicalize("../zokrates_stdlib/stdlib").unwrap();
|
||||
let resolver = FileSystemResolver::with_stdlib_root(stdlib.to_str().unwrap());
|
||||
|
||||
let artifacts: CompilationArtifacts<Bn128Field> =
|
||||
compile(source, path, Some(&resolver), &CompileConfig::default()).unwrap();
|
||||
let arena = Arena::new();
|
||||
|
||||
let artifacts: CompilationArtifacts<Bn128Field, _> = compile(
|
||||
source,
|
||||
path,
|
||||
Some(&resolver),
|
||||
CompileConfig::default(),
|
||||
&arena,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let interpreter = ir::Interpreter::default();
|
||||
|
||||
|
|
|
@ -4,15 +4,16 @@ use clap::{App, Arg, ArgMatches, SubCommand};
|
|||
use serde_json::to_writer_pretty;
|
||||
use std::convert::TryFrom;
|
||||
use std::fs::File;
|
||||
use std::io::{BufReader, BufWriter, Read, Write};
|
||||
use std::io::{BufReader, BufWriter, Read};
|
||||
use std::path::{Path, PathBuf};
|
||||
use zokrates_core::compile::{compile, CompilationArtifacts, CompileConfig, CompileError};
|
||||
use typed_arena::Arena;
|
||||
use zokrates_core::compile::{compile, CompileConfig, CompileError};
|
||||
use zokrates_field::{Bls12_377Field, Bls12_381Field, Bn128Field, Bw6_761Field, Field};
|
||||
use zokrates_fs_resolver::FileSystemResolver;
|
||||
|
||||
pub fn subcommand() -> App<'static, 'static> {
|
||||
SubCommand::with_name("compile")
|
||||
.about("Compiles into flattened conditions. Produces two files: human-readable '.ztf' file for debugging and binary file")
|
||||
.about("Compiles into a runnable constraint system")
|
||||
.arg(Arg::with_name("input")
|
||||
.short("i")
|
||||
.long("input")
|
||||
|
@ -52,24 +53,10 @@ pub fn subcommand() -> App<'static, 'static> {
|
|||
.required(false)
|
||||
.possible_values(constants::CURVES)
|
||||
.default_value(constants::BN128)
|
||||
).arg(Arg::with_name("allow-unconstrained-variables")
|
||||
.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)")
|
||||
.required(false)
|
||||
)
|
||||
.arg(Arg::with_name("light") // TODO: deprecated, should be removed
|
||||
.long("light")
|
||||
.required(false)
|
||||
.overrides_with_all(&["ztf", "verbose"])
|
||||
.hidden(true)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -84,20 +71,10 @@ pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> {
|
|||
}
|
||||
|
||||
fn cli_compile<T: Field>(sub_matches: &ArgMatches) -> Result<(), String> {
|
||||
// TODO: remove the warning once light flag is removed entirely
|
||||
if sub_matches.is_present("light") {
|
||||
println!(
|
||||
"Warning: the --light flag is deprecated and will be removed in a coming release.\n\
|
||||
Terminal output is now off by default and can be activated with the --verbose flag.\n\
|
||||
Human-readable output file (ztf) is now off by default and can be activated with the --ztf flag.\n"
|
||||
)
|
||||
}
|
||||
|
||||
println!("Compiling {}\n", sub_matches.value_of("input").unwrap());
|
||||
let path = PathBuf::from(sub_matches.value_of("input").unwrap());
|
||||
let bin_output_path = Path::new(sub_matches.value_of("output").unwrap());
|
||||
let abi_spec_path = Path::new(sub_matches.value_of("abi-spec").unwrap());
|
||||
let hr_output_path = bin_output_path.to_path_buf().with_extension("ztf");
|
||||
|
||||
log::debug!("Load entry point file {}", path.display());
|
||||
|
||||
|
@ -128,16 +105,17 @@ fn cli_compile<T: Field>(sub_matches: &ArgMatches) -> Result<(), String> {
|
|||
)),
|
||||
}?;
|
||||
|
||||
let config = CompileConfig::default()
|
||||
.allow_unconstrained_variables(sub_matches.is_present("allow-unconstrained-variables"))
|
||||
.isolate_branches(sub_matches.is_present("isolate-branches"));
|
||||
let config =
|
||||
CompileConfig::default().isolate_branches(sub_matches.is_present("isolate-branches"));
|
||||
|
||||
let resolver = FileSystemResolver::with_stdlib_root(stdlib_path);
|
||||
|
||||
log::debug!("Compile");
|
||||
|
||||
let artifacts: CompilationArtifacts<T> = compile(source, path, Some(&resolver), &config)
|
||||
.map_err(|e| {
|
||||
let arena = Arena::new();
|
||||
|
||||
let artifacts =
|
||||
compile::<T, _>(source, path, Some(&resolver), config, &arena).map_err(|e| {
|
||||
format!(
|
||||
"Compilation failed:\n\n{}",
|
||||
e.0.iter()
|
||||
|
@ -147,10 +125,7 @@ fn cli_compile<T: Field>(sub_matches: &ArgMatches) -> Result<(), String> {
|
|||
)
|
||||
})?;
|
||||
|
||||
let program_flattened = artifacts.prog();
|
||||
|
||||
// number of constraints the flattened program will translate to.
|
||||
let num_constraints = program_flattened.constraint_count();
|
||||
let (program_flattened, abi) = artifacts.into_inner();
|
||||
|
||||
// serialize flattened program and write to binary file
|
||||
log::debug!("Serialize program");
|
||||
|
@ -166,34 +141,9 @@ fn cli_compile<T: Field>(sub_matches: &ArgMatches) -> Result<(), String> {
|
|||
let abi_spec_file = File::create(&abi_spec_path)
|
||||
.map_err(|why| format!("Could not create {}: {}", abi_spec_path.display(), why))?;
|
||||
|
||||
let abi = artifacts.abi();
|
||||
|
||||
let mut writer = BufWriter::new(abi_spec_file);
|
||||
to_writer_pretty(&mut writer, &abi).map_err(|_| "Unable to write data to file.".to_string())?;
|
||||
|
||||
if sub_matches.is_present("verbose") {
|
||||
// debugging output
|
||||
println!("Compiled program:\n{}", program_flattened);
|
||||
}
|
||||
|
||||
println!("Compiled code written to '{}'", bin_output_path.display());
|
||||
|
||||
if sub_matches.is_present("ztf") {
|
||||
// write human-readable output file
|
||||
log::debug!("Serialize human readable program");
|
||||
let hr_output_file = File::create(&hr_output_path)
|
||||
.map_err(|why| format!("Could not create {}: {}", hr_output_path.display(), why))?;
|
||||
|
||||
let mut hrofb = BufWriter::new(hr_output_file);
|
||||
writeln!(&mut hrofb, "{}", program_flattened)
|
||||
.map_err(|_| "Unable to write data to file".to_string())?;
|
||||
hrofb
|
||||
.flush()
|
||||
.map_err(|_| "Unable to flush buffer".to_string())?;
|
||||
|
||||
println!("Human readable code to '{}'", hr_output_path.display());
|
||||
}
|
||||
|
||||
println!("Number of constraints: {}", num_constraints);
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -76,16 +76,13 @@ pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> {
|
|||
}
|
||||
}
|
||||
|
||||
fn cli_compute<T: Field>(ir_prog: ir::Prog<T>, sub_matches: &ArgMatches) -> Result<(), String> {
|
||||
fn cli_compute<T: Field, I: Iterator<Item = ir::Statement<T>>>(
|
||||
ir_prog: ir::ProgIterator<T, I>,
|
||||
sub_matches: &ArgMatches,
|
||||
) -> Result<(), String> {
|
||||
println!("Computing witness...");
|
||||
|
||||
let verbose = sub_matches.is_present("verbose");
|
||||
|
||||
// print deserialized flattened program if in verbose mode
|
||||
if verbose {
|
||||
println!("{}", ir_prog);
|
||||
}
|
||||
|
||||
let is_stdin = sub_matches.is_present("stdin");
|
||||
let is_abi = sub_matches.is_present("abi");
|
||||
|
||||
|
@ -106,7 +103,7 @@ fn cli_compute<T: Field>(ir_prog: ir::Prog<T>, sub_matches: &ArgMatches) -> Resu
|
|||
}
|
||||
false => ConcreteSignature::new()
|
||||
.inputs(vec![ConcreteType::FieldElement; ir_prog.arguments.len()])
|
||||
.outputs(vec![ConcreteType::FieldElement; ir_prog.returns.len()]),
|
||||
.outputs(vec![ConcreteType::FieldElement; ir_prog.return_count]),
|
||||
};
|
||||
|
||||
use zokrates_abi::Inputs;
|
||||
|
@ -140,7 +137,7 @@ fn cli_compute<T: Field>(ir_prog: ir::Prog<T>, sub_matches: &ArgMatches) -> Resu
|
|||
}
|
||||
Err(_) => Err(String::from("???")),
|
||||
},
|
||||
false => match ir_prog.arguments_count() {
|
||||
false => match ir_prog.arguments.len() {
|
||||
0 => Ok(Inputs::Raw(vec![])),
|
||||
_ => match stdin.read_to_string(&mut input) {
|
||||
Ok(_) => {
|
||||
|
@ -162,7 +159,7 @@ fn cli_compute<T: Field>(ir_prog: ir::Prog<T>, sub_matches: &ArgMatches) -> Resu
|
|||
let interpreter = ir::Interpreter::default();
|
||||
|
||||
let witness = interpreter
|
||||
.execute(&ir_prog, &arguments.encode())
|
||||
.execute(ir_prog, &arguments.encode())
|
||||
.map_err(|e| format!("Execution failed: {}", e))?;
|
||||
|
||||
use zokrates_abi::Decode;
|
||||
|
|
|
@ -105,29 +105,33 @@ pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> {
|
|||
match parameters {
|
||||
#[cfg(feature = "bellman")]
|
||||
Parameters(BackendParameter::Bellman, _, SchemeParameter::G16) => match prog {
|
||||
ProgEnum::Bn128Program(p) => cli_generate_proof::<_, G16, Bellman>(p, sub_matches),
|
||||
ProgEnum::Bls12_381Program(p) => cli_generate_proof::<_, G16, Bellman>(p, sub_matches),
|
||||
ProgEnum::Bn128Program(p) => cli_generate_proof::<_, _, G16, Bellman>(p, sub_matches),
|
||||
ProgEnum::Bls12_381Program(p) => {
|
||||
cli_generate_proof::<_, _, G16, Bellman>(p, sub_matches)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
#[cfg(feature = "ark")]
|
||||
Parameters(BackendParameter::Ark, _, SchemeParameter::GM17) => match prog {
|
||||
ProgEnum::Bls12_377Program(p) => cli_generate_proof::<_, GM17, Ark>(p, sub_matches),
|
||||
ProgEnum::Bw6_761Program(p) => cli_generate_proof::<_, GM17, Ark>(p, sub_matches),
|
||||
ProgEnum::Bn128Program(p) => cli_generate_proof::<_, GM17, Ark>(p, sub_matches),
|
||||
ProgEnum::Bls12_377Program(p) => cli_generate_proof::<_, _, GM17, Ark>(p, sub_matches),
|
||||
ProgEnum::Bw6_761Program(p) => cli_generate_proof::<_, _, GM17, Ark>(p, sub_matches),
|
||||
ProgEnum::Bn128Program(p) => cli_generate_proof::<_, _, GM17, Ark>(p, sub_matches),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
#[cfg(feature = "ark")]
|
||||
Parameters(BackendParameter::Ark, _, SchemeParameter::MARLIN) => match prog {
|
||||
ProgEnum::Bls12_377Program(p) => cli_generate_proof::<_, Marlin, Ark>(p, sub_matches),
|
||||
ProgEnum::Bw6_761Program(p) => cli_generate_proof::<_, Marlin, Ark>(p, sub_matches),
|
||||
ProgEnum::Bn128Program(p) => cli_generate_proof::<_, Marlin, Ark>(p, sub_matches),
|
||||
ProgEnum::Bls12_377Program(p) => {
|
||||
cli_generate_proof::<_, _, Marlin, Ark>(p, sub_matches)
|
||||
}
|
||||
ProgEnum::Bw6_761Program(p) => cli_generate_proof::<_, _, Marlin, Ark>(p, sub_matches),
|
||||
ProgEnum::Bn128Program(p) => cli_generate_proof::<_, _, Marlin, Ark>(p, sub_matches),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
#[cfg(feature = "libsnark")]
|
||||
Parameters(BackendParameter::Libsnark, CurveParameter::Bn128, SchemeParameter::GM17) => {
|
||||
match prog {
|
||||
ProgEnum::Bn128Program(p) => {
|
||||
cli_generate_proof::<_, GM17, Libsnark>(p, sub_matches)
|
||||
cli_generate_proof::<_, _, GM17, Libsnark>(p, sub_matches)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
@ -136,7 +140,7 @@ pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> {
|
|||
Parameters(BackendParameter::Libsnark, CurveParameter::Bn128, SchemeParameter::PGHR13) => {
|
||||
match prog {
|
||||
ProgEnum::Bn128Program(p) => {
|
||||
cli_generate_proof::<_, PGHR13, Libsnark>(p, sub_matches)
|
||||
cli_generate_proof::<_, _, PGHR13, Libsnark>(p, sub_matches)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
@ -145,8 +149,13 @@ pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> {
|
|||
}
|
||||
}
|
||||
|
||||
fn cli_generate_proof<T: Field, S: Scheme<T>, B: Backend<T, S>>(
|
||||
program: ir::Prog<T>,
|
||||
fn cli_generate_proof<
|
||||
T: Field,
|
||||
I: Iterator<Item = ir::Statement<T>>,
|
||||
S: Scheme<T>,
|
||||
B: Backend<T, S>,
|
||||
>(
|
||||
program: ir::ProgIterator<T, I>,
|
||||
sub_matches: &ArgMatches,
|
||||
) -> Result<(), String> {
|
||||
println!("Generating proof...");
|
||||
|
|
|
@ -49,12 +49,17 @@ pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> {
|
|||
}
|
||||
}
|
||||
|
||||
fn cli_smtlib2<T: Field>(ir_prog: ir::Prog<T>, sub_matches: &ArgMatches) -> Result<(), String> {
|
||||
fn cli_smtlib2<T: Field, I: Iterator<Item = ir::Statement<T>>>(
|
||||
ir_prog: ir::ProgIterator<T, I>,
|
||||
sub_matches: &ArgMatches,
|
||||
) -> Result<(), String> {
|
||||
println!("Generating SMTLib2...");
|
||||
|
||||
let output_path = Path::new(sub_matches.value_of("output").unwrap());
|
||||
let mut output_file = File::create(output_path).unwrap();
|
||||
|
||||
let ir_prog = ir_prog.collect();
|
||||
|
||||
output_file
|
||||
.write(format!("{}", SMTLib2Display(&ir_prog)).as_bytes())
|
||||
.map_err(|why| format!("Could not save smtlib2: {:?}", why))?;
|
||||
|
|
56
zokrates_cli/src/ops/inspect.rs
Normal file
56
zokrates_cli/src/ops/inspect.rs
Normal file
|
@ -0,0 +1,56 @@
|
|||
use crate::constants::FLATTENED_CODE_DEFAULT_PATH;
|
||||
use clap::{App, Arg, ArgMatches, SubCommand};
|
||||
use std::fs::File;
|
||||
use std::io::{BufReader, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
use zokrates_core::ir;
|
||||
use zokrates_core::ir::ProgEnum;
|
||||
use zokrates_field::Field;
|
||||
|
||||
pub fn subcommand() -> App<'static, 'static> {
|
||||
SubCommand::with_name("inspect")
|
||||
.about("Outputs a compiled program to a file in a human readable format")
|
||||
.arg(
|
||||
Arg::with_name("input")
|
||||
.short("i")
|
||||
.long("input")
|
||||
.help("Path of the binary")
|
||||
.value_name("FILE")
|
||||
.takes_value(true)
|
||||
.required(false)
|
||||
.default_value(FLATTENED_CODE_DEFAULT_PATH),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> {
|
||||
// read compiled program
|
||||
let path = Path::new(sub_matches.value_of("input").unwrap());
|
||||
let file =
|
||||
File::open(&path).map_err(|why| format!("Could not open {}: {}", path.display(), why))?;
|
||||
|
||||
let mut reader = BufReader::new(file);
|
||||
|
||||
match ProgEnum::deserialize(&mut reader)? {
|
||||
ProgEnum::Bn128Program(p) => cli_inspect(p, sub_matches),
|
||||
ProgEnum::Bls12_377Program(p) => cli_inspect(p, sub_matches),
|
||||
ProgEnum::Bls12_381Program(p) => cli_inspect(p, sub_matches),
|
||||
ProgEnum::Bw6_761Program(p) => cli_inspect(p, sub_matches),
|
||||
}
|
||||
}
|
||||
|
||||
fn cli_inspect<T: Field, I: Iterator<Item = ir::Statement<T>>>(
|
||||
ir_prog: ir::ProgIterator<T, I>,
|
||||
sub_matches: &ArgMatches,
|
||||
) -> Result<(), String> {
|
||||
let output_path = PathBuf::from(sub_matches.value_of("input").unwrap()).with_extension("ztf");
|
||||
let mut output_file = File::create(&output_path).unwrap();
|
||||
|
||||
let ir_prog: ir::Prog<T> = ir_prog.collect();
|
||||
|
||||
output_file
|
||||
.write(format!("{}", ir_prog).as_bytes())
|
||||
.map_err(|why| format!("Could not save ztf: {:?}", why))?;
|
||||
|
||||
println!("ztf file written to '{}'", output_path.display());
|
||||
Ok(())
|
||||
}
|
|
@ -5,6 +5,7 @@ pub mod export_verifier;
|
|||
#[cfg(any(feature = "bellman", feature = "ark", feature = "libsnark"))]
|
||||
pub mod generate_proof;
|
||||
pub mod generate_smtlib2;
|
||||
pub mod inspect;
|
||||
pub mod print_proof;
|
||||
#[cfg(any(feature = "bellman", feature = "ark", feature = "libsnark"))]
|
||||
pub mod setup;
|
||||
|
|
|
@ -105,19 +105,23 @@ pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> {
|
|||
match parameters {
|
||||
#[cfg(feature = "bellman")]
|
||||
Parameters(BackendParameter::Bellman, _, SchemeParameter::G16) => match prog {
|
||||
ProgEnum::Bn128Program(p) => cli_setup_non_universal::<_, G16, Bellman>(p, sub_matches),
|
||||
ProgEnum::Bn128Program(p) => {
|
||||
cli_setup_non_universal::<_, _, G16, Bellman>(p, sub_matches)
|
||||
}
|
||||
ProgEnum::Bls12_381Program(p) => {
|
||||
cli_setup_non_universal::<_, G16, Bellman>(p, sub_matches)
|
||||
cli_setup_non_universal::<_, _, G16, Bellman>(p, sub_matches)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
#[cfg(feature = "ark")]
|
||||
Parameters(BackendParameter::Ark, _, SchemeParameter::GM17) => match prog {
|
||||
ProgEnum::Bls12_377Program(p) => {
|
||||
cli_setup_non_universal::<_, GM17, Ark>(p, sub_matches)
|
||||
cli_setup_non_universal::<_, _, GM17, Ark>(p, sub_matches)
|
||||
}
|
||||
ProgEnum::Bw6_761Program(p) => cli_setup_non_universal::<_, GM17, Ark>(p, sub_matches),
|
||||
ProgEnum::Bn128Program(p) => cli_setup_non_universal::<_, GM17, Ark>(p, sub_matches),
|
||||
ProgEnum::Bw6_761Program(p) => {
|
||||
cli_setup_non_universal::<_, _, GM17, Ark>(p, sub_matches)
|
||||
}
|
||||
ProgEnum::Bn128Program(p) => cli_setup_non_universal::<_, _, GM17, Ark>(p, sub_matches),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
#[cfg(feature = "ark")]
|
||||
|
@ -137,13 +141,13 @@ pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> {
|
|||
|
||||
match prog {
|
||||
ProgEnum::Bls12_377Program(p) => {
|
||||
cli_setup_universal::<_, Marlin, Ark>(p, setup, sub_matches)
|
||||
cli_setup_universal::<_, _, Marlin, Ark>(p, setup, sub_matches)
|
||||
}
|
||||
ProgEnum::Bn128Program(p) => {
|
||||
cli_setup_universal::<_, Marlin, Ark>(p, setup, sub_matches)
|
||||
cli_setup_universal::<_, _, Marlin, Ark>(p, setup, sub_matches)
|
||||
}
|
||||
ProgEnum::Bw6_761Program(p) => {
|
||||
cli_setup_universal::<_, Marlin, Ark>(p, setup, sub_matches)
|
||||
cli_setup_universal::<_, _, Marlin, Ark>(p, setup, sub_matches)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
@ -152,7 +156,7 @@ pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> {
|
|||
Parameters(BackendParameter::Libsnark, CurveParameter::Bn128, SchemeParameter::GM17) => {
|
||||
match prog {
|
||||
ProgEnum::Bn128Program(p) => {
|
||||
cli_setup_non_universal::<_, GM17, Libsnark>(p, sub_matches)
|
||||
cli_setup_non_universal::<_, _, GM17, Libsnark>(p, sub_matches)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
@ -161,7 +165,7 @@ pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> {
|
|||
Parameters(BackendParameter::Libsnark, CurveParameter::Bn128, SchemeParameter::PGHR13) => {
|
||||
match prog {
|
||||
ProgEnum::Bn128Program(p) => {
|
||||
cli_setup_non_universal::<_, PGHR13, Libsnark>(p, sub_matches)
|
||||
cli_setup_non_universal::<_, _, PGHR13, Libsnark>(p, sub_matches)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
@ -170,17 +174,17 @@ pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> {
|
|||
}
|
||||
}
|
||||
|
||||
fn cli_setup_non_universal<T: Field, S: NonUniversalScheme<T>, B: NonUniversalBackend<T, S>>(
|
||||
program: ir::Prog<T>,
|
||||
fn cli_setup_non_universal<
|
||||
T: Field,
|
||||
I: Iterator<Item = ir::Statement<T>>,
|
||||
S: NonUniversalScheme<T>,
|
||||
B: NonUniversalBackend<T, S>,
|
||||
>(
|
||||
program: ir::ProgIterator<T, I>,
|
||||
sub_matches: &ArgMatches,
|
||||
) -> Result<(), String> {
|
||||
println!("Performing setup...");
|
||||
|
||||
// print deserialized flattened program if in verbose mode
|
||||
if sub_matches.is_present("verbose") {
|
||||
println!("{}", program);
|
||||
}
|
||||
|
||||
// get paths for proving and verification keys
|
||||
let pk_path = Path::new(sub_matches.value_of("proving-key-path").unwrap());
|
||||
let vk_path = Path::new(sub_matches.value_of("verification-key-path").unwrap());
|
||||
|
@ -214,18 +218,18 @@ fn cli_setup_non_universal<T: Field, S: NonUniversalScheme<T>, B: NonUniversalBa
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn cli_setup_universal<T: Field, S: UniversalScheme<T>, B: UniversalBackend<T, S>>(
|
||||
program: ir::Prog<T>,
|
||||
fn cli_setup_universal<
|
||||
T: Field,
|
||||
I: Iterator<Item = ir::Statement<T>>,
|
||||
S: UniversalScheme<T>,
|
||||
B: UniversalBackend<T, S>,
|
||||
>(
|
||||
program: ir::ProgIterator<T, I>,
|
||||
srs: Vec<u8>,
|
||||
sub_matches: &ArgMatches,
|
||||
) -> Result<(), String> {
|
||||
println!("Performing setup...");
|
||||
|
||||
// print deserialized flattened program if in verbose mode
|
||||
if sub_matches.is_present("verbose") {
|
||||
println!("{}", program);
|
||||
}
|
||||
|
||||
// get paths for proving and verification keys
|
||||
let pk_path = Path::new(sub_matches.value_of("proving-key-path").unwrap());
|
||||
let vk_path = Path::new(sub_matches.value_of("verification-key-path").unwrap());
|
||||
|
|
|
@ -26,7 +26,7 @@ reduce = "0.1.1"
|
|||
# serialization and deserialization
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
bincode = "0.8.0"
|
||||
serde_cbor = "0.11.2"
|
||||
hex = "0.4.2"
|
||||
regex = "0.2"
|
||||
zokrates_field = { version = "0.4.0", path = "../zokrates_field", default-features = false }
|
||||
|
|
|
@ -4,13 +4,12 @@
|
|||
//! @author Thibaut Schaeffer <thibaut@schaeff.fr>
|
||||
//! @date 2018
|
||||
use crate::absy::{Module, OwnedModuleId, Program};
|
||||
use crate::flatten::Flattener;
|
||||
use crate::flatten::FlattenerIterator;
|
||||
use crate::imports::{self, Importer};
|
||||
use crate::ir;
|
||||
use crate::macros;
|
||||
use crate::semantics::{self, Checker};
|
||||
use crate::static_analysis;
|
||||
use crate::static_analysis::Analyse;
|
||||
use crate::typed_absy::abi::Abi;
|
||||
use crate::zir::ZirProgram;
|
||||
use macros::process_macros;
|
||||
|
@ -25,19 +24,30 @@ use zokrates_field::Field;
|
|||
use zokrates_pest_ast as pest;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CompilationArtifacts<T: Field> {
|
||||
prog: ir::Prog<T>,
|
||||
pub struct CompilationArtifacts<T, I: IntoIterator<Item = ir::Statement<T>>> {
|
||||
prog: ir::ProgIterator<T, I>,
|
||||
abi: Abi,
|
||||
}
|
||||
|
||||
impl<T: Field> CompilationArtifacts<T> {
|
||||
pub fn prog(&self) -> &ir::Prog<T> {
|
||||
&self.prog
|
||||
impl<T, I: IntoIterator<Item = ir::Statement<T>>> CompilationArtifacts<T, I> {
|
||||
pub fn prog(self) -> ir::ProgIterator<T, I> {
|
||||
self.prog
|
||||
}
|
||||
|
||||
pub fn abi(&self) -> &Abi {
|
||||
&self.abi
|
||||
}
|
||||
|
||||
pub fn into_inner(self) -> (ir::ProgIterator<T, I>, Abi) {
|
||||
(self.prog, self.abi)
|
||||
}
|
||||
|
||||
pub fn collect(self) -> CompilationArtifacts<T, Vec<ir::Statement<T>>> {
|
||||
CompilationArtifacts {
|
||||
prog: self.prog.collect(),
|
||||
abi: self.abi,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -162,19 +172,13 @@ impl fmt::Display for CompileErrorInner {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone, Copy)]
|
||||
pub struct CompileConfig {
|
||||
#[serde(default)]
|
||||
pub allow_unconstrained_variables: bool,
|
||||
#[serde(default)]
|
||||
pub isolate_branches: bool,
|
||||
}
|
||||
|
||||
impl CompileConfig {
|
||||
pub fn allow_unconstrained_variables(mut self, flag: bool) -> Self {
|
||||
self.allow_unconstrained_variables = flag;
|
||||
self
|
||||
}
|
||||
pub fn isolate_branches(mut self, flag: bool) -> Self {
|
||||
self.isolate_branches = flag;
|
||||
self
|
||||
|
@ -183,41 +187,29 @@ impl CompileConfig {
|
|||
|
||||
type FilePath = PathBuf;
|
||||
|
||||
pub fn compile<T: Field, E: Into<imports::Error>>(
|
||||
pub fn compile<'ast, T: Field, E: Into<imports::Error>>(
|
||||
source: String,
|
||||
location: FilePath,
|
||||
resolver: Option<&dyn Resolver<E>>,
|
||||
config: &CompileConfig,
|
||||
) -> Result<CompilationArtifacts<T>, CompileErrors> {
|
||||
let arena = Arena::new();
|
||||
|
||||
let (typed_ast, abi) = check_with_arena(source, location.clone(), resolver, config, &arena)?;
|
||||
config: CompileConfig,
|
||||
arena: &'ast Arena<String>,
|
||||
) -> Result<CompilationArtifacts<T, impl IntoIterator<Item = ir::Statement<T>> + 'ast>, CompileErrors>
|
||||
{
|
||||
let (typed_ast, abi): (crate::zir::ZirProgram<'_, T>, _) =
|
||||
check_with_arena(source, location, resolver, &config, arena)?;
|
||||
|
||||
// flatten input program
|
||||
log::debug!("Flatten");
|
||||
let program_flattened = Flattener::flatten(typed_ast, config);
|
||||
log::trace!("\n{}", program_flattened);
|
||||
|
||||
// constant propagation after call resolution
|
||||
log::debug!("Propagate flat program");
|
||||
let program_flattened = program_flattened.propagate();
|
||||
log::trace!("\n{}", program_flattened);
|
||||
let program_flattened = FlattenerIterator::from_function_and_config(typed_ast.main, config);
|
||||
|
||||
// convert to ir
|
||||
log::debug!("Convert to IR");
|
||||
let ir_prog = ir::Prog::from(program_flattened);
|
||||
log::trace!("\n{}", ir_prog);
|
||||
let ir_prog = ir::from_flat::from_flat(program_flattened);
|
||||
|
||||
// optimize
|
||||
log::debug!("Optimise IR");
|
||||
let optimized_ir_prog = ir_prog.optimize();
|
||||
|
||||
// analyse ir (check constraints)
|
||||
log::debug!("Analyse IR");
|
||||
let optimized_ir_prog = optimized_ir_prog
|
||||
.analyse()
|
||||
.map_err(|e| CompileErrorInner::from(e).in_file(location.as_path()))?;
|
||||
|
||||
Ok(CompilationArtifacts {
|
||||
prog: optimized_ir_prog,
|
||||
abi,
|
||||
|
@ -329,13 +321,18 @@ mod test {
|
|||
return foo()
|
||||
"#
|
||||
.to_string();
|
||||
let res: Result<CompilationArtifacts<Bn128Field>, CompileErrors> = compile(
|
||||
let arena = Arena::new();
|
||||
let res: Result<CompilationArtifacts<Bn128Field, _>, CompileErrors> = compile(
|
||||
source,
|
||||
"./path/to/file".into(),
|
||||
None::<&dyn Resolver<io::Error>>,
|
||||
&CompileConfig::default(),
|
||||
);
|
||||
assert!(res.unwrap_err().0[0]
|
||||
CompileConfig::default(),
|
||||
&arena,
|
||||
)
|
||||
.map(|res| res.collect());
|
||||
|
||||
let e = res.unwrap_err();
|
||||
assert!(e.0[0]
|
||||
.value()
|
||||
.to_string()
|
||||
.contains(&"Cannot resolve import without a resolver"));
|
||||
|
@ -348,11 +345,15 @@ mod test {
|
|||
return 1
|
||||
"#
|
||||
.to_string();
|
||||
let res: Result<CompilationArtifacts<Bn128Field>, CompileErrors> = compile(
|
||||
|
||||
let arena = Arena::new();
|
||||
|
||||
let res: Result<CompilationArtifacts<Bn128Field, _>, CompileErrors> = compile(
|
||||
source,
|
||||
"./path/to/file".into(),
|
||||
None::<&dyn Resolver<io::Error>>,
|
||||
&CompileConfig::default(),
|
||||
CompileConfig::default(),
|
||||
&arena,
|
||||
);
|
||||
assert!(res.is_ok());
|
||||
}
|
||||
|
@ -429,11 +430,14 @@ struct Bar { field a }
|
|||
}
|
||||
}
|
||||
|
||||
let arena = Arena::new();
|
||||
|
||||
let artifacts = compile::<Bn128Field, io::Error>(
|
||||
main.to_string(),
|
||||
"main".into(),
|
||||
Some(&CustomResolver),
|
||||
&CompileConfig::default(),
|
||||
CompileConfig::default(),
|
||||
&arena,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::absy::{
|
|||
ConstantGenericNode, Expression,
|
||||
};
|
||||
use crate::flat_absy::{
|
||||
FlatDirective, FlatExpression, FlatExpressionList, FlatFunction, FlatParameter, FlatStatement,
|
||||
FlatDirective, FlatExpression, FlatFunctionIterator, FlatParameter, FlatStatement,
|
||||
FlatVariable, RuntimeError,
|
||||
};
|
||||
use crate::solvers::Solver;
|
||||
|
@ -312,18 +312,6 @@ impl FlatEmbed {
|
|||
FlatEmbed::SnarkVerifyBls12377 => "_SNARK_VERIFY_BLS12_377",
|
||||
}
|
||||
}
|
||||
|
||||
/// Actually get the `FlatFunction` that this `FlatEmbed` represents
|
||||
pub fn synthetize<T: Field>(&self, generics: &[u32]) -> FlatFunction<T> {
|
||||
match self {
|
||||
FlatEmbed::Unpack => unpack_to_bitwidth(generics[0] as usize),
|
||||
#[cfg(feature = "bellman")]
|
||||
FlatEmbed::Sha256Round => sha256_round(),
|
||||
#[cfg(feature = "ark")]
|
||||
FlatEmbed::SnarkVerifyBls12377 => snark_verify_bls12_377(generics[0] as usize),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// util to convert a vector of `(variable_id, coefficient)` to a flat_expression
|
||||
|
@ -357,13 +345,17 @@ fn flat_expression_from_vec<T: Field>(v: &[(usize, T)]) -> FlatExpression<T> {
|
|||
/// - constraint system variables
|
||||
/// - arguments
|
||||
#[cfg(feature = "bellman")]
|
||||
pub fn sha256_round<T: Field>() -> FlatFunction<T> {
|
||||
pub fn sha256_round<T: Field>(
|
||||
) -> FlatFunctionIterator<T, impl IntoIterator<Item = FlatStatement<T>>> {
|
||||
use zokrates_field::Bn128Field;
|
||||
assert_eq!(T::id(), Bn128Field::id());
|
||||
|
||||
// Define iterators for all indices at hand
|
||||
let (r1cs, input_indices, current_hash_indices, output_indices) =
|
||||
generate_sha256_round_constraints::<Bn256>();
|
||||
|
||||
// The output count
|
||||
let return_count = output_indices.len();
|
||||
// indices of the input
|
||||
let input_indices = input_indices.into_iter();
|
||||
// indices of the current hash
|
||||
|
@ -375,18 +367,21 @@ pub fn sha256_round<T: Field>() -> FlatFunction<T> {
|
|||
let cs_indices = 0..variable_count;
|
||||
// indices of the arguments to the function
|
||||
// apply an offset of `variable_count` to get the indice of our dummy `input` argument
|
||||
let input_argument_indices = input_indices
|
||||
let input_argument_indices: Vec<_> = input_indices
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|i| i + variable_count);
|
||||
.map(|i| i + variable_count)
|
||||
.collect();
|
||||
// apply an offset of `variable_count` to get the indice of our dummy `current_hash` argument
|
||||
let current_hash_argument_indices = current_hash_indices
|
||||
let current_hash_argument_indices: Vec<_> = current_hash_indices
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|i| i + variable_count);
|
||||
.map(|i| i + variable_count)
|
||||
.collect();
|
||||
// define parameters to the function based on the variables
|
||||
let arguments = input_argument_indices
|
||||
.clone()
|
||||
.into_iter()
|
||||
.chain(current_hash_argument_indices.clone())
|
||||
.map(|i| FlatParameter {
|
||||
id: FlatVariable::new(i),
|
||||
|
@ -401,7 +396,7 @@ pub fn sha256_round<T: Field>() -> FlatFunction<T> {
|
|||
);
|
||||
let input_binding_statements =
|
||||
// bind input and current_hash to inputs
|
||||
input_indices.chain(current_hash_indices).zip(input_argument_indices.clone().chain(current_hash_argument_indices.clone())).map(|(cs_index, argument_index)| {
|
||||
input_indices.chain(current_hash_indices).zip(input_argument_indices.clone().into_iter().chain(current_hash_argument_indices.clone())).map(|(cs_index, argument_index)| {
|
||||
FlatStatement::Condition(
|
||||
FlatVariable::new(cs_index).into(),
|
||||
FlatVariable::new(argument_index).into(),
|
||||
|
@ -423,36 +418,39 @@ pub fn sha256_round<T: Field>() -> FlatFunction<T> {
|
|||
});
|
||||
|
||||
// define which subset of the witness is returned
|
||||
let outputs: Vec<FlatExpression<T>> = output_indices
|
||||
.map(|o| FlatExpression::Identifier(FlatVariable::new(o)))
|
||||
.collect();
|
||||
let outputs = output_indices.map(|o| FlatExpression::Identifier(FlatVariable::new(o)));
|
||||
// insert a directive to set the witness based on the bellman gadget and inputs
|
||||
let directive_statement = FlatStatement::Directive(FlatDirective {
|
||||
outputs: cs_indices.map(FlatVariable::new).collect(),
|
||||
inputs: input_argument_indices
|
||||
.into_iter()
|
||||
.chain(current_hash_argument_indices)
|
||||
.map(|i| FlatVariable::new(i).into())
|
||||
.collect(),
|
||||
solver: Solver::Sha256Round,
|
||||
});
|
||||
// insert a statement to return the subset of the witness
|
||||
let return_statement = FlatStatement::Return(FlatExpressionList {
|
||||
expressions: outputs,
|
||||
});
|
||||
let return_statements = outputs
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(index, e)| FlatStatement::Definition(FlatVariable::public(index), e));
|
||||
let statements = std::iter::once(directive_statement)
|
||||
.chain(std::iter::once(one_binding_statement))
|
||||
.chain(input_binding_statements)
|
||||
.chain(constraint_statements)
|
||||
.chain(std::iter::once(return_statement))
|
||||
.collect();
|
||||
FlatFunction {
|
||||
.chain(return_statements);
|
||||
|
||||
FlatFunctionIterator {
|
||||
arguments,
|
||||
statements,
|
||||
return_count,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ark")]
|
||||
pub fn snark_verify_bls12_377<T: Field>(n: usize) -> FlatFunction<T> {
|
||||
pub fn snark_verify_bls12_377<T: Field>(
|
||||
n: usize,
|
||||
) -> FlatFunctionIterator<T, impl IntoIterator<Item = FlatStatement<T>>> {
|
||||
use zokrates_field::Bw6_761Field;
|
||||
assert_eq!(T::id(), Bw6_761Field::id());
|
||||
|
||||
|
@ -528,9 +526,10 @@ pub fn snark_verify_bls12_377<T: Field>(n: usize) -> FlatFunction<T> {
|
|||
})
|
||||
.collect();
|
||||
|
||||
let return_statement = FlatStatement::Return(FlatExpressionList {
|
||||
expressions: vec![FlatExpression::Identifier(FlatVariable::new(out_index))],
|
||||
});
|
||||
let return_statement = FlatStatement::Definition(
|
||||
FlatVariable::public(0),
|
||||
FlatExpression::Identifier(FlatVariable::new(out_index)),
|
||||
);
|
||||
|
||||
// insert a directive to set the witness
|
||||
let directive_statement = FlatStatement::Directive(FlatDirective {
|
||||
|
@ -543,16 +542,16 @@ pub fn snark_verify_bls12_377<T: Field>(n: usize) -> FlatFunction<T> {
|
|||
solver: Solver::SnarkVerifyBls12377(n),
|
||||
});
|
||||
|
||||
let statements: Vec<_> = std::iter::once(directive_statement)
|
||||
let statements = std::iter::once(directive_statement)
|
||||
.chain(std::iter::once(one_binding_statement))
|
||||
.chain(input_binding_statements)
|
||||
.chain(constraint_statements)
|
||||
.chain(std::iter::once(return_statement))
|
||||
.collect();
|
||||
.chain(std::iter::once(return_statement));
|
||||
|
||||
FlatFunction {
|
||||
FlatFunctionIterator {
|
||||
arguments,
|
||||
statements,
|
||||
return_count: 1,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -575,7 +574,9 @@ fn use_variable(
|
|||
/// # Remarks
|
||||
/// * the return value of the `FlatFunction` is not deterministic if `bit_width >= T::get_required_bits()`
|
||||
/// as some elements can have multiple representations: For example, `unpack(0)` is `[0, ..., 0]` but also `unpack(p)`
|
||||
pub fn unpack_to_bitwidth<T: Field>(bit_width: usize) -> FlatFunction<T> {
|
||||
pub fn unpack_to_bitwidth<T: Field>(
|
||||
bit_width: usize,
|
||||
) -> FlatFunctionIterator<T, impl IntoIterator<Item = FlatStatement<T>>> {
|
||||
let mut counter = 0;
|
||||
|
||||
let mut layout = HashMap::new();
|
||||
|
@ -599,11 +600,12 @@ pub fn unpack_to_bitwidth<T: Field>(bit_width: usize) -> FlatFunction<T> {
|
|||
|
||||
let solver = Solver::bits(bit_width);
|
||||
|
||||
let outputs = directive_outputs
|
||||
#[allow(clippy::needless_collect)]
|
||||
let outputs: Vec<_> = directive_outputs
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(_, o)| FlatExpression::Identifier(*o))
|
||||
.collect::<Vec<_>>();
|
||||
.collect();
|
||||
|
||||
// o253, o252, ... o{253 - (bit_width - 1)} are bits
|
||||
let mut statements: Vec<FlatStatement<T>> = (0..bit_width)
|
||||
|
@ -648,13 +650,17 @@ pub fn unpack_to_bitwidth<T: Field>(bit_width: usize) -> FlatFunction<T> {
|
|||
}),
|
||||
);
|
||||
|
||||
statements.push(FlatStatement::Return(FlatExpressionList {
|
||||
expressions: outputs,
|
||||
}));
|
||||
statements.extend(
|
||||
outputs
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(index, e)| FlatStatement::Definition(FlatVariable::public(index), e)),
|
||||
);
|
||||
|
||||
FlatFunction {
|
||||
FlatFunctionIterator {
|
||||
arguments,
|
||||
statements,
|
||||
statements: statements.into_iter(),
|
||||
return_count: bit_width,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -669,17 +675,13 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn split254() {
|
||||
let unpack: FlatFunction<Bn128Field> =
|
||||
unpack_to_bitwidth(Bn128Field::get_required_bits());
|
||||
let unpack =
|
||||
unpack_to_bitwidth::<Bn128Field>(Bn128Field::get_required_bits()).collect();
|
||||
|
||||
assert_eq!(
|
||||
unpack.arguments,
|
||||
vec![FlatParameter::private(FlatVariable::new(0))]
|
||||
);
|
||||
assert_eq!(
|
||||
unpack.statements.len(),
|
||||
Bn128Field::get_required_bits() + 1 + 1 + 1
|
||||
); // 128 bit checks, 1 directive, 1 sum check, 1 return
|
||||
assert_eq!(
|
||||
unpack.statements[0],
|
||||
FlatStatement::Directive(FlatDirective::new(
|
||||
|
@ -691,13 +693,9 @@ mod tests {
|
|||
))
|
||||
);
|
||||
assert_eq!(
|
||||
*unpack.statements.last().unwrap(),
|
||||
FlatStatement::Return(FlatExpressionList {
|
||||
expressions: (0..Bn128Field::get_required_bits())
|
||||
.map(|i| FlatExpression::Identifier(FlatVariable::new(i + 1)))
|
||||
.collect()
|
||||
})
|
||||
);
|
||||
unpack.statements.len(),
|
||||
Bn128Field::get_required_bits() + 1 + 1 + Bn128Field::get_required_bits()
|
||||
) // 254 bit checks, 1 directive, 1 sum check, 254 returns
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -711,24 +709,13 @@ mod tests {
|
|||
fn generate_sha256_constraints() {
|
||||
let compiled = sha256_round::<Bn128Field>();
|
||||
|
||||
let compiled = compiled.collect();
|
||||
|
||||
// function should have 768 inputs
|
||||
assert_eq!(compiled.arguments.len(), 768);
|
||||
|
||||
// function should return 256 values
|
||||
assert_eq!(
|
||||
compiled
|
||||
.statements
|
||||
.iter()
|
||||
.filter_map(|s| match s {
|
||||
FlatStatement::Return(v) => Some(v),
|
||||
_ => None,
|
||||
})
|
||||
.next()
|
||||
.unwrap()
|
||||
.expressions
|
||||
.len(),
|
||||
256,
|
||||
);
|
||||
assert_eq!(compiled.return_count, 256,);
|
||||
|
||||
// directive should take 768 inputs and return n_var outputs
|
||||
let directive = compiled
|
||||
|
@ -768,18 +755,16 @@ mod tests {
|
|||
)
|
||||
);
|
||||
|
||||
let flat_prog = crate::flat_absy::FlatProg { main: compiled };
|
||||
|
||||
let prog = crate::ir::Prog::from(flat_prog);
|
||||
|
||||
let input: Vec<_> = (0..512)
|
||||
.map(|_| 0)
|
||||
.chain((0..256).map(|_| 1))
|
||||
.map(Bn128Field::from)
|
||||
.collect();
|
||||
|
||||
let ir = crate::ir::from_flat::from_flat(compiled);
|
||||
|
||||
let interpreter = Interpreter::default();
|
||||
interpreter.execute(&prog, &input).unwrap();
|
||||
interpreter.execute(ir, &input).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,42 +98,43 @@ impl fmt::Display for RuntimeError {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct FlatProg<T: Field> {
|
||||
/// FlatFunctions of the program
|
||||
pub main: FlatFunction<T>,
|
||||
}
|
||||
pub type FlatProg<T> = FlatFunction<T>;
|
||||
|
||||
impl<T: Field> fmt::Display for FlatProg<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.main)
|
||||
}
|
||||
}
|
||||
pub type FlatFunction<T> = FlatFunctionIterator<T, Vec<FlatStatement<T>>>;
|
||||
|
||||
impl<T: Field> fmt::Debug for FlatProg<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "flat_program(main: {}\t)", self.main)
|
||||
}
|
||||
}
|
||||
pub type FlatProgIterator<T, I> = FlatFunctionIterator<T, I>;
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct FlatFunction<T: Field> {
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub struct FlatFunctionIterator<T, I: IntoIterator<Item = FlatStatement<T>>> {
|
||||
/// Arguments of the function
|
||||
pub arguments: Vec<FlatParameter>,
|
||||
/// Vector of statements that are executed when running the function
|
||||
pub statements: Vec<FlatStatement<T>>,
|
||||
pub statements: I,
|
||||
/// Number of outputs
|
||||
pub return_count: usize,
|
||||
}
|
||||
|
||||
impl<T, I: IntoIterator<Item = FlatStatement<T>>> FlatFunctionIterator<T, I> {
|
||||
pub fn collect(self) -> FlatFunction<T> {
|
||||
FlatFunction {
|
||||
statements: self.statements.into_iter().collect(),
|
||||
arguments: self.arguments,
|
||||
return_count: self.return_count,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Display for FlatFunction<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"def main({}):\n{}",
|
||||
"def main({}) -> {}:\n{}",
|
||||
self.arguments
|
||||
.iter()
|
||||
.map(|x| format!("{}", x))
|
||||
.collect::<Vec<_>>()
|
||||
.join(","),
|
||||
self.return_count,
|
||||
self.statements
|
||||
.iter()
|
||||
.map(|x| format!("\t{}", x))
|
||||
|
@ -143,21 +144,6 @@ impl<T: Field> fmt::Display for FlatFunction<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Debug for FlatFunction<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"FlatFunction(arguments: {:?}):\n{}",
|
||||
self.arguments,
|
||||
self.statements
|
||||
.iter()
|
||||
.map(|x| format!("\t{:?}", x))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n"),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculates a flattened function based on a R1CS (A, B, C) and returns that flattened function:
|
||||
/// * The Rank 1 Constraint System (R1CS) is defined as:
|
||||
/// * `<A,x>*<B,x> = <C,x>` for a witness `x`
|
||||
|
@ -168,9 +154,8 @@ impl<T: Field> fmt::Debug for FlatFunction<T> {
|
|||
///
|
||||
/// * r1cs - R1CS in standard JSON data format
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum FlatStatement<T: Field> {
|
||||
Return(FlatExpressionList<T>),
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub enum FlatStatement<T> {
|
||||
Condition(FlatExpression<T>, FlatExpression<T>, RuntimeError),
|
||||
Definition(FlatVariable, FlatExpression<T>),
|
||||
Directive(FlatDirective<T>),
|
||||
|
@ -180,7 +165,6 @@ impl<T: Field> fmt::Display for FlatStatement<T> {
|
|||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
FlatStatement::Definition(ref lhs, ref rhs) => write!(f, "{} = {}", lhs, rhs),
|
||||
FlatStatement::Return(ref expr) => write!(f, "return {}", expr),
|
||||
FlatStatement::Condition(ref lhs, ref rhs, ref message) => {
|
||||
write!(f, "{} == {} // {}", lhs, rhs, message)
|
||||
}
|
||||
|
@ -189,19 +173,6 @@ impl<T: Field> fmt::Display for FlatStatement<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Debug for FlatStatement<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
FlatStatement::Definition(ref lhs, ref rhs) => write!(f, "{} = {}", lhs, rhs),
|
||||
FlatStatement::Return(ref expr) => write!(f, "FlatReturn({:?})", expr),
|
||||
FlatStatement::Condition(ref lhs, ref rhs, ref error) => {
|
||||
write!(f, "FlatCondition({:?}, {:?}, {:?})", lhs, rhs, error)
|
||||
}
|
||||
FlatStatement::Directive(ref d) => write!(f, "{:?}", d),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> FlatStatement<T> {
|
||||
pub fn apply_substitution(
|
||||
self,
|
||||
|
@ -212,7 +183,6 @@ impl<T: Field> FlatStatement<T> {
|
|||
*id.apply_substitution(substitution),
|
||||
x.apply_substitution(substitution),
|
||||
),
|
||||
FlatStatement::Return(x) => FlatStatement::Return(x.apply_substitution(substitution)),
|
||||
FlatStatement::Condition(x, y, message) => FlatStatement::Condition(
|
||||
x.apply_substitution(substitution),
|
||||
y.apply_substitution(substitution),
|
||||
|
@ -241,13 +211,13 @@ impl<T: Field> FlatStatement<T> {
|
|||
}
|
||||
|
||||
#[derive(Clone, Hash, Debug, PartialEq, Eq)]
|
||||
pub struct FlatDirective<T: Field> {
|
||||
pub struct FlatDirective<T> {
|
||||
pub inputs: Vec<FlatExpression<T>>,
|
||||
pub outputs: Vec<FlatVariable>,
|
||||
pub solver: Solver,
|
||||
}
|
||||
|
||||
impl<T: Field> FlatDirective<T> {
|
||||
impl<T> FlatDirective<T> {
|
||||
pub fn new<E: Into<FlatExpression<T>>>(
|
||||
outputs: Vec<FlatVariable>,
|
||||
solver: Solver,
|
||||
|
@ -284,7 +254,7 @@ impl<T: Field> fmt::Display for FlatDirective<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub enum FlatExpression<T> {
|
||||
Number(T),
|
||||
Identifier(FlatVariable),
|
||||
|
@ -358,62 +328,12 @@ impl<T: Field> fmt::Display for FlatExpression<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: fmt::Debug> fmt::Debug for FlatExpression<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
FlatExpression::Number(ref i) => write!(f, "Num({:?})", i),
|
||||
FlatExpression::Identifier(ref var) => write!(f, "Ide({})", var),
|
||||
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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> From<FlatVariable> for FlatExpression<T> {
|
||||
fn from(v: FlatVariable) -> FlatExpression<T> {
|
||||
FlatExpression::Identifier(v)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct FlatExpressionList<T> {
|
||||
pub expressions: Vec<FlatExpression<T>>,
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Display for FlatExpressionList<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
for (i, param) in self.expressions.iter().enumerate() {
|
||||
write!(f, "{}", param)?;
|
||||
if i < self.expressions.len() - 1 {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
}
|
||||
write!(f, "")
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> FlatExpressionList<T> {
|
||||
pub fn apply_substitution(
|
||||
self,
|
||||
substitution: &HashMap<FlatVariable, FlatVariable>,
|
||||
) -> FlatExpressionList<T> {
|
||||
FlatExpressionList {
|
||||
expressions: self
|
||||
.expressions
|
||||
.into_iter()
|
||||
.map(|e| e.apply_substitution(substitution))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Debug for FlatExpressionList<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "ExpressionList({:?})", self.expressions)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub struct Error {
|
||||
message: String,
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -5,8 +5,8 @@ use crate::ir::*;
|
|||
use zokrates_field::Field;
|
||||
|
||||
pub trait Folder<T: Field>: Sized {
|
||||
fn fold_module(&mut self, p: Prog<T>) -> Prog<T> {
|
||||
fold_module(self, p)
|
||||
fn fold_program(&mut self, p: Prog<T>) -> Prog<T> {
|
||||
fold_program(self, p)
|
||||
}
|
||||
|
||||
fn fold_argument(&mut self, p: FlatParameter) -> FlatParameter {
|
||||
|
@ -34,7 +34,7 @@ pub trait Folder<T: Field>: Sized {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn fold_module<T: Field, F: Folder<T>>(f: &mut F, p: Prog<T>) -> Prog<T> {
|
||||
pub fn fold_program<T: Field, F: Folder<T>>(f: &mut F, p: Prog<T>) -> Prog<T> {
|
||||
Prog {
|
||||
arguments: p
|
||||
.arguments
|
||||
|
@ -46,7 +46,7 @@ pub fn fold_module<T: Field, F: Folder<T>>(f: &mut F, p: Prog<T>) -> Prog<T> {
|
|||
.into_iter()
|
||||
.flat_map(|s| f.fold_statement(s))
|
||||
.collect(),
|
||||
returns: p.returns.into_iter().map(|v| f.fold_variable(v)).collect(),
|
||||
return_count: p.return_count,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use crate::flat_absy::{FlatDirective, FlatExpression, FlatProg, FlatStatement, FlatVariable};
|
||||
use crate::ir::{Directive, LinComb, Prog, QuadComb, Statement};
|
||||
use crate::flat_absy::{
|
||||
FlatDirective, FlatExpression, FlatProgIterator, FlatStatement, FlatVariable,
|
||||
};
|
||||
use crate::ir::{Directive, LinComb, ProgIterator, QuadComb, Statement};
|
||||
use zokrates_field::Field;
|
||||
|
||||
impl<T: Field> QuadComb<T> {
|
||||
|
@ -17,49 +19,13 @@ impl<T: Field> QuadComb<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Field> From<FlatProg<T>> for Prog<T> {
|
||||
fn from(flat_prog: FlatProg<T>) -> Prog<T> {
|
||||
// get the main function
|
||||
let main = flat_prog.main;
|
||||
|
||||
let return_expressions: Vec<FlatExpression<T>> = main
|
||||
.statements
|
||||
.iter()
|
||||
.filter_map(|s| match s {
|
||||
FlatStatement::Return(el) => Some(el.expressions.clone()),
|
||||
_ => None,
|
||||
})
|
||||
.next()
|
||||
.unwrap();
|
||||
|
||||
Prog {
|
||||
arguments: main.arguments,
|
||||
returns: return_expressions
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, _)| FlatVariable::public(index))
|
||||
.collect(),
|
||||
statements: main
|
||||
.statements
|
||||
.into_iter()
|
||||
.filter_map(|s| match s {
|
||||
FlatStatement::Return(..) => None,
|
||||
s => Some(s.into()),
|
||||
})
|
||||
.chain(
|
||||
return_expressions
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(index, expression)| {
|
||||
Statement::Constraint(
|
||||
QuadComb::from_flat_expression(expression),
|
||||
FlatVariable::public(index).into(),
|
||||
None,
|
||||
)
|
||||
}),
|
||||
)
|
||||
.collect(),
|
||||
}
|
||||
pub fn from_flat<T: Field, I: IntoIterator<Item = FlatStatement<T>>>(
|
||||
flat_prog_iterator: FlatProgIterator<T, I>,
|
||||
) -> ProgIterator<T, impl IntoIterator<Item = Statement<T>>> {
|
||||
ProgIterator {
|
||||
statements: flat_prog_iterator.statements.into_iter().map(Into::into),
|
||||
arguments: flat_prog_iterator.arguments,
|
||||
return_count: flat_prog_iterator.return_count,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,6 +45,10 @@ impl<T: Field> From<FlatExpression<T>> for LinComb<T> {
|
|||
box FlatExpression::Identifier(v1),
|
||||
box FlatExpression::Number(n1),
|
||||
) => LinComb::summand(n1, v1),
|
||||
FlatExpression::Mult(
|
||||
box FlatExpression::Number(n1),
|
||||
box FlatExpression::Number(n2),
|
||||
) => LinComb::summand(n1 * n2, FlatVariable::one()),
|
||||
e => unreachable!("{}", e),
|
||||
}
|
||||
}
|
||||
|
@ -104,7 +74,6 @@ impl<T: Field> From<FlatStatement<T>> for Statement<T> {
|
|||
e => Statement::Constraint(LinComb::from(e).into(), var.into(), None),
|
||||
},
|
||||
FlatStatement::Directive(ds) => Statement::Directive(ds.into()),
|
||||
_ => panic!("return should be handled at the function level"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::flat_absy::flat_variable::FlatVariable;
|
||||
use crate::flat_absy::RuntimeError;
|
||||
use crate::ir::{LinComb, Prog, QuadComb, Statement, Witness};
|
||||
use crate::ir::{LinComb, ProgIterator, QuadComb, Statement, Witness};
|
||||
use crate::solvers::Solver;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::BTreeMap;
|
||||
|
@ -9,8 +9,6 @@ use zokrates_field::Field;
|
|||
|
||||
pub type ExecutionResult<T> = Result<Witness<T>, Error>;
|
||||
|
||||
impl<T: Field> Prog<T> {}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Interpreter {
|
||||
/// Whether we should try to give out-of-range bit decompositions when the input is not a single summand.
|
||||
|
@ -27,8 +25,12 @@ impl Interpreter {
|
|||
}
|
||||
|
||||
impl Interpreter {
|
||||
pub fn execute<T: Field>(&self, program: &Prog<T>, inputs: &[T]) -> ExecutionResult<T> {
|
||||
self.check_inputs(program, inputs)?;
|
||||
pub fn execute<T: Field, I: IntoIterator<Item = Statement<T>>>(
|
||||
&self,
|
||||
program: ProgIterator<T, I>,
|
||||
inputs: &[T],
|
||||
) -> ExecutionResult<T> {
|
||||
self.check_inputs(&program, inputs)?;
|
||||
let mut witness = BTreeMap::new();
|
||||
witness.insert(FlatVariable::one(), T::one());
|
||||
|
||||
|
@ -36,7 +38,7 @@ impl Interpreter {
|
|||
witness.insert(arg.id, value.clone());
|
||||
}
|
||||
|
||||
for statement in program.statements.iter() {
|
||||
for statement in program.statements.into_iter() {
|
||||
match statement {
|
||||
Statement::Constraint(quad, lin, error) => match lin.is_assignee(&witness) {
|
||||
true => {
|
||||
|
@ -47,9 +49,7 @@ impl Interpreter {
|
|||
let lhs_value = quad.evaluate(&witness).unwrap();
|
||||
let rhs_value = lin.evaluate(&witness).unwrap();
|
||||
if lhs_value != rhs_value {
|
||||
return Err(Error::UnsatisfiedConstraint {
|
||||
error: error.to_owned(),
|
||||
});
|
||||
return Err(Error::UnsatisfiedConstraint { error });
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -108,7 +108,11 @@ impl Interpreter {
|
|||
.collect()
|
||||
}
|
||||
|
||||
fn check_inputs<T: Field, U>(&self, program: &Prog<T>, inputs: &[U]) -> Result<(), Error> {
|
||||
fn check_inputs<T: Field, I: IntoIterator<Item = Statement<T>>, U>(
|
||||
&self,
|
||||
program: &ProgIterator<T, I>,
|
||||
inputs: &[U],
|
||||
) -> Result<(), Error> {
|
||||
if program.arguments.len() == inputs.len() {
|
||||
Ok(())
|
||||
} else {
|
||||
|
|
|
@ -8,7 +8,7 @@ use zokrates_field::Field;
|
|||
|
||||
mod expression;
|
||||
pub mod folder;
|
||||
mod from_flat;
|
||||
pub mod from_flat;
|
||||
mod interpreter;
|
||||
mod serialize;
|
||||
pub mod smtlib2;
|
||||
|
@ -74,25 +74,30 @@ impl<T: Field> fmt::Display for Statement<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Hash, PartialEq, Eq, Default)]
|
||||
pub struct Prog<T> {
|
||||
pub statements: Vec<Statement<T>>,
|
||||
pub type Prog<T> = ProgIterator<T, Vec<Statement<T>>>;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
|
||||
pub struct ProgIterator<T, I: IntoIterator<Item = Statement<T>>> {
|
||||
pub arguments: Vec<FlatParameter>,
|
||||
pub returns: Vec<FlatVariable>,
|
||||
pub return_count: usize,
|
||||
pub statements: I,
|
||||
}
|
||||
|
||||
impl<T: Field> Prog<T> {
|
||||
pub fn constraint_count(&self) -> usize {
|
||||
self.statements
|
||||
.iter()
|
||||
.filter(|s| matches!(s, Statement::Constraint(..)))
|
||||
.count()
|
||||
impl<T, I: IntoIterator<Item = Statement<T>>> ProgIterator<T, I> {
|
||||
pub fn collect(self) -> ProgIterator<T, Vec<Statement<T>>> {
|
||||
ProgIterator {
|
||||
statements: self.statements.into_iter().collect::<Vec<_>>(),
|
||||
arguments: self.arguments,
|
||||
return_count: self.return_count,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn arguments_count(&self) -> usize {
|
||||
self.arguments.len()
|
||||
pub fn returns(&self) -> Vec<FlatVariable> {
|
||||
(0..self.return_count).map(FlatVariable::public).collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field, I: IntoIterator<Item = Statement<T>>> ProgIterator<T, I> {
|
||||
pub fn public_inputs(&self, witness: &Witness<T>) -> Vec<T> {
|
||||
self.arguments
|
||||
.iter()
|
||||
|
@ -103,24 +108,43 @@ impl<T: Field> Prog<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> Prog<T> {
|
||||
pub fn constraint_count(&self) -> usize {
|
||||
self.statements
|
||||
.iter()
|
||||
.filter(|s| matches!(s, Statement::Constraint(..)))
|
||||
.count()
|
||||
}
|
||||
|
||||
pub fn into_prog_iter(self) -> ProgIterator<T, impl IntoIterator<Item = Statement<T>>> {
|
||||
ProgIterator {
|
||||
statements: self.statements.into_iter(),
|
||||
arguments: self.arguments,
|
||||
return_count: self.return_count,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Display for Prog<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
writeln!(
|
||||
f,
|
||||
"def main({}) -> ({}):\n{}\n\treturn {}",
|
||||
"def main({}) -> ({}):",
|
||||
self.arguments
|
||||
.iter()
|
||||
.map(|v| format!("{}", v))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", "),
|
||||
self.returns.len(),
|
||||
self.statements
|
||||
.iter()
|
||||
.map(|s| format!("\t{}", s))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n"),
|
||||
self.returns
|
||||
.iter()
|
||||
self.return_count,
|
||||
)?;
|
||||
for s in &self.statements {
|
||||
writeln!(f, "\t{}", s)?;
|
||||
}
|
||||
writeln!(
|
||||
f,
|
||||
"\treturn {}",
|
||||
(0..self.return_count)
|
||||
.map(FlatVariable::public)
|
||||
.map(|e| format!("{}", e))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::ir::Prog;
|
||||
use bincode::{deserialize_from, serialize_into, Infinite};
|
||||
use crate::ir::{Prog, ProgIterator, Statement};
|
||||
use serde_cbor;
|
||||
use std::io::{Read, Write};
|
||||
use zokrates_field::*;
|
||||
|
||||
|
@ -7,24 +7,115 @@ const ZOKRATES_MAGIC: &[u8; 4] = &[0x5a, 0x4f, 0x4b, 0];
|
|||
const ZOKRATES_VERSION_1: &[u8; 4] = &[0, 0, 0, 1];
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub enum ProgEnum {
|
||||
Bls12_381Program(Prog<Bls12_381Field>),
|
||||
Bn128Program(Prog<Bn128Field>),
|
||||
Bls12_377Program(Prog<Bls12_377Field>),
|
||||
Bw6_761Program(Prog<Bw6_761Field>),
|
||||
pub enum ProgEnum<
|
||||
Bls12_381I: IntoIterator<Item = Statement<Bls12_381Field>>,
|
||||
Bn128I: IntoIterator<Item = Statement<Bn128Field>>,
|
||||
Bls12_377I: IntoIterator<Item = Statement<Bls12_377Field>>,
|
||||
Bw6_761I: IntoIterator<Item = Statement<Bw6_761Field>>,
|
||||
> {
|
||||
Bls12_381Program(ProgIterator<Bls12_381Field, Bls12_381I>),
|
||||
Bn128Program(ProgIterator<Bn128Field, Bn128I>),
|
||||
Bls12_377Program(ProgIterator<Bls12_377Field, Bls12_377I>),
|
||||
Bw6_761Program(ProgIterator<Bw6_761Field, Bw6_761I>),
|
||||
}
|
||||
|
||||
impl<T: Field> Prog<T> {
|
||||
pub fn serialize<W: Write>(&self, mut w: W) {
|
||||
type MemoryProgEnum = ProgEnum<
|
||||
Vec<Statement<Bls12_381Field>>,
|
||||
Vec<Statement<Bn128Field>>,
|
||||
Vec<Statement<Bls12_377Field>>,
|
||||
Vec<Statement<Bw6_761Field>>,
|
||||
>;
|
||||
|
||||
use serde::{Serialize, Serializer};
|
||||
use std::cell::Cell;
|
||||
|
||||
impl<
|
||||
Bls12_381I: IntoIterator<Item = Statement<Bls12_381Field>>,
|
||||
Bn128I: IntoIterator<Item = Statement<Bn128Field>>,
|
||||
Bls12_377I: IntoIterator<Item = Statement<Bls12_377Field>>,
|
||||
Bw6_761I: IntoIterator<Item = Statement<Bw6_761Field>>,
|
||||
> ProgEnum<Bls12_381I, Bn128I, Bls12_377I, Bw6_761I>
|
||||
{
|
||||
pub fn collect(self) -> MemoryProgEnum {
|
||||
match self {
|
||||
ProgEnum::Bls12_381Program(p) => ProgEnum::Bls12_381Program(p.collect()),
|
||||
ProgEnum::Bn128Program(p) => ProgEnum::Bn128Program(p.collect()),
|
||||
ProgEnum::Bls12_377Program(p) => ProgEnum::Bls12_377Program(p.collect()),
|
||||
ProgEnum::Bw6_761Program(p) => ProgEnum::Bw6_761Program(p.collect()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_as_cbor<T: Serialize + std::fmt::Debug, I, W>(
|
||||
out: &mut W,
|
||||
prog_iterator: ProgIterator<T, I>,
|
||||
) -> serde_cbor::Result<()>
|
||||
where
|
||||
I: IntoIterator<Item = Statement<T>>,
|
||||
W: Write,
|
||||
{
|
||||
struct Wrapper<U>(Cell<Option<U>>);
|
||||
|
||||
struct SerializableProgIterator<T: Serialize, I: IntoIterator<Item = Statement<T>>> {
|
||||
arguments: Vec<crate::flat_absy::FlatParameter>,
|
||||
return_count: usize,
|
||||
statements: Wrapper<I>,
|
||||
}
|
||||
|
||||
impl<T, I> Serialize for SerializableProgIterator<T, I>
|
||||
where
|
||||
T: Serialize + std::fmt::Debug,
|
||||
I: IntoIterator<Item = Statement<T>>,
|
||||
{
|
||||
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
|
||||
use serde::ser::SerializeStruct;
|
||||
|
||||
let mut spi = s.serialize_struct("SerializableProgIterator", 3)?;
|
||||
spi.serialize_field("arguments", &self.arguments)?;
|
||||
spi.serialize_field("return_count", &self.return_count)?;
|
||||
spi.serialize_field("statements", &self.statements)?;
|
||||
spi.end()
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, P> Serialize for Wrapper<I>
|
||||
where
|
||||
I: IntoIterator<Item = P>,
|
||||
P: Serialize + std::fmt::Debug,
|
||||
{
|
||||
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
|
||||
s.collect_seq(self.0.take().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
serde_cbor::to_writer(
|
||||
out,
|
||||
&SerializableProgIterator {
|
||||
arguments: prog_iterator.arguments,
|
||||
return_count: prog_iterator.return_count,
|
||||
statements: Wrapper(Cell::new(Some(prog_iterator.statements))),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
impl<T: Field, I: IntoIterator<Item = Statement<T>>> ProgIterator<T, I> {
|
||||
pub fn serialize<W: Write>(self, mut w: W) {
|
||||
w.write_all(ZOKRATES_MAGIC).unwrap();
|
||||
w.write_all(ZOKRATES_VERSION_1).unwrap();
|
||||
w.write_all(&T::id()).unwrap();
|
||||
|
||||
serialize_into(&mut w, self, Infinite).unwrap();
|
||||
write_as_cbor(&mut w, self).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
impl ProgEnum {
|
||||
impl
|
||||
ProgEnum<
|
||||
std::vec::IntoIter<Statement<Bls12_381Field>>,
|
||||
std::vec::IntoIter<Statement<Bn128Field>>,
|
||||
std::vec::IntoIter<Statement<Bls12_377Field>>,
|
||||
std::vec::IntoIter<Statement<Bw6_761Field>>,
|
||||
>
|
||||
{
|
||||
pub fn deserialize<R: Read>(mut r: R) -> Result<Self, String> {
|
||||
// Check the magic number, `ZOK`
|
||||
let mut magic = [0; 4];
|
||||
|
@ -44,18 +135,42 @@ impl ProgEnum {
|
|||
.map_err(|_| String::from("Cannot read curve identifier"))?;
|
||||
|
||||
match curve {
|
||||
m if m == Bls12_381Field::id() => Ok(ProgEnum::Bls12_381Program(
|
||||
deserialize_from(&mut r, Infinite).unwrap(),
|
||||
)),
|
||||
m if m == Bn128Field::id() => Ok(ProgEnum::Bn128Program(
|
||||
deserialize_from(&mut r, Infinite).unwrap(),
|
||||
)),
|
||||
m if m == Bls12_377Field::id() => Ok(ProgEnum::Bls12_377Program(
|
||||
deserialize_from(&mut r, Infinite).unwrap(),
|
||||
)),
|
||||
m if m == Bw6_761Field::id() => Ok(ProgEnum::Bw6_761Program(
|
||||
deserialize_from(&mut r, Infinite).unwrap(),
|
||||
)),
|
||||
m if m == Bls12_381Field::id() => {
|
||||
let p: Prog<Bls12_381Field> = serde_cbor::from_reader(r).unwrap();
|
||||
|
||||
Ok(ProgEnum::Bls12_381Program(ProgIterator {
|
||||
statements: p.statements.into_iter(),
|
||||
arguments: p.arguments,
|
||||
return_count: p.return_count,
|
||||
}))
|
||||
}
|
||||
m if m == Bn128Field::id() => {
|
||||
let p: Prog<Bn128Field> = serde_cbor::from_reader(r).unwrap();
|
||||
|
||||
Ok(ProgEnum::Bn128Program(ProgIterator {
|
||||
statements: p.statements.into_iter(),
|
||||
arguments: p.arguments,
|
||||
return_count: p.return_count,
|
||||
}))
|
||||
}
|
||||
m if m == Bls12_377Field::id() => {
|
||||
let p: Prog<Bls12_377Field> = serde_cbor::from_reader(r).unwrap();
|
||||
|
||||
Ok(ProgEnum::Bls12_377Program(ProgIterator {
|
||||
statements: p.statements.into_iter(),
|
||||
arguments: p.arguments,
|
||||
return_count: p.return_count,
|
||||
}))
|
||||
}
|
||||
m if m == Bw6_761Field::id() => {
|
||||
let p: Prog<Bw6_761Field> = serde_cbor::from_reader(r).unwrap();
|
||||
|
||||
Ok(ProgEnum::Bw6_761Program(ProgIterator {
|
||||
statements: p.statements.into_iter(),
|
||||
arguments: p.arguments,
|
||||
return_count: p.return_count,
|
||||
}))
|
||||
}
|
||||
_ => Err(String::from("Unknown curve identifier")),
|
||||
}
|
||||
} else {
|
||||
|
@ -79,7 +194,7 @@ mod tests {
|
|||
let p: ir::Prog<Bn128Field> = ir::Prog::default();
|
||||
|
||||
let mut buffer = Cursor::new(vec![]);
|
||||
p.serialize(&mut buffer);
|
||||
p.clone().serialize(&mut buffer);
|
||||
|
||||
// rewind back to the beginning of the file
|
||||
buffer.seek(SeekFrom::Start(0)).unwrap();
|
||||
|
@ -87,12 +202,12 @@ mod tests {
|
|||
// deserialize
|
||||
let deserialized_p = ProgEnum::deserialize(buffer).unwrap();
|
||||
|
||||
assert_eq!(ProgEnum::Bn128Program(p), deserialized_p);
|
||||
assert_eq!(ProgEnum::Bn128Program(p), deserialized_p.collect());
|
||||
|
||||
let p: ir::Prog<Bls12_381Field> = ir::Prog::default();
|
||||
|
||||
let mut buffer = Cursor::new(vec![]);
|
||||
p.serialize(&mut buffer);
|
||||
p.clone().serialize(&mut buffer);
|
||||
|
||||
// rewind back to the beginning of the file
|
||||
buffer.seek(SeekFrom::Start(0)).unwrap();
|
||||
|
@ -100,6 +215,6 @@ mod tests {
|
|||
// deserialize
|
||||
let deserialized_p = ProgEnum::deserialize(buffer).unwrap();
|
||||
|
||||
assert_eq!(ProgEnum::Bls12_381Program(p), deserialized_p);
|
||||
assert_eq!(ProgEnum::Bls12_381Program(p), deserialized_p.collect());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,9 +49,6 @@ pub fn visit_module<T: Field, F: Visitor<T>>(f: &mut F, p: &Prog<T>) {
|
|||
for expr in p.statements.iter() {
|
||||
f.visit_statement(expr);
|
||||
}
|
||||
for expr in p.returns.iter() {
|
||||
f.visit_variable(expr);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_statement<T: Field, F: Visitor<T>>(f: &mut F, s: &Statement<T>) {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::ir::{folder::Folder, LinComb};
|
||||
use zokrates_field::Field;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Canonicalizer;
|
||||
|
||||
impl<T: Field> Folder<T> for Canonicalizer {
|
||||
|
|
|
@ -12,49 +12,18 @@
|
|||
use crate::flat_absy::flat_variable::FlatVariable;
|
||||
use crate::ir::folder::*;
|
||||
use crate::ir::*;
|
||||
use crate::optimizer::canonicalizer::Canonicalizer;
|
||||
use crate::solvers::Solver;
|
||||
use std::collections::hash_map::{Entry, HashMap};
|
||||
use zokrates_field::Field;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DirectiveOptimizer<T: Field> {
|
||||
#[derive(Debug, Default)]
|
||||
pub struct DirectiveOptimizer<T> {
|
||||
calls: HashMap<(Solver, Vec<QuadComb<T>>), Vec<FlatVariable>>,
|
||||
/// Map of renamings for reassigned variables while processing the program.
|
||||
substitution: HashMap<FlatVariable, FlatVariable>,
|
||||
}
|
||||
|
||||
impl<T: Field> DirectiveOptimizer<T> {
|
||||
fn new() -> DirectiveOptimizer<T> {
|
||||
DirectiveOptimizer {
|
||||
calls: HashMap::new(),
|
||||
substitution: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn optimize(p: Prog<T>) -> Prog<T> {
|
||||
DirectiveOptimizer::new().fold_module(p)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> Folder<T> for DirectiveOptimizer<T> {
|
||||
fn fold_module(&mut self, p: Prog<T>) -> Prog<T> {
|
||||
// in order to correctly identify duplicates, we need to first canonicalize the statements
|
||||
|
||||
let mut canonicalizer = Canonicalizer;
|
||||
|
||||
let p = Prog {
|
||||
statements: p
|
||||
.statements
|
||||
.into_iter()
|
||||
.flat_map(|s| canonicalizer.fold_statement(s))
|
||||
.collect(),
|
||||
..p
|
||||
};
|
||||
|
||||
fold_module(self, p)
|
||||
}
|
||||
|
||||
fn fold_variable(&mut self, v: FlatVariable) -> FlatVariable {
|
||||
*self.substitution.get(&v).unwrap_or(&v)
|
||||
}
|
||||
|
|
|
@ -16,25 +16,13 @@ fn hash<T: Field>(s: &Statement<T>) -> Hash {
|
|||
hasher.finish()
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct DuplicateOptimizer {
|
||||
seen: HashSet<Hash>,
|
||||
}
|
||||
|
||||
impl DuplicateOptimizer {
|
||||
fn new() -> Self {
|
||||
DuplicateOptimizer {
|
||||
seen: HashSet::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn optimize<T: Field>(p: Prog<T>) -> Prog<T> {
|
||||
Self::new().fold_module(p)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> Folder<T> for DuplicateOptimizer {
|
||||
fn fold_module(&mut self, p: Prog<T>) -> Prog<T> {
|
||||
fn fold_program(&mut self, p: Prog<T>) -> Prog<T> {
|
||||
// in order to correctly identify duplicates, we need to first canonicalize the statements
|
||||
let mut canonicalizer = Canonicalizer;
|
||||
|
||||
|
@ -47,7 +35,7 @@ impl<T: Field> Folder<T> for DuplicateOptimizer {
|
|||
..p
|
||||
};
|
||||
|
||||
fold_module(self, p)
|
||||
fold_program(self, p)
|
||||
}
|
||||
|
||||
fn fold_statement(&mut self, s: Statement<T>) -> Vec<Statement<T>> {
|
||||
|
@ -87,13 +75,16 @@ mod tests {
|
|||
LinComb::zero(),
|
||||
),
|
||||
],
|
||||
returns: vec![],
|
||||
return_count: 0,
|
||||
arguments: vec![],
|
||||
};
|
||||
|
||||
let expected = p.clone();
|
||||
|
||||
assert_eq!(DuplicateOptimizer::optimize(p), expected);
|
||||
assert_eq!(
|
||||
DuplicateOptimizer::default().fold_program(p).collect(),
|
||||
expected
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -120,7 +111,7 @@ mod tests {
|
|||
constraint.clone(),
|
||||
constraint.clone(),
|
||||
],
|
||||
returns: vec![],
|
||||
return_count: 0,
|
||||
arguments: vec![],
|
||||
};
|
||||
|
||||
|
@ -135,10 +126,13 @@ mod tests {
|
|||
LinComb::zero(),
|
||||
),
|
||||
],
|
||||
returns: vec![],
|
||||
return_count: 0,
|
||||
arguments: vec![],
|
||||
};
|
||||
|
||||
assert_eq!(DuplicateOptimizer::optimize(p), expected);
|
||||
assert_eq!(
|
||||
DuplicateOptimizer::default().fold_program(p).collect(),
|
||||
expected
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,41 +10,56 @@ mod duplicate;
|
|||
mod redefinition;
|
||||
mod tautology;
|
||||
|
||||
use self::canonicalizer::Canonicalizer;
|
||||
use self::directive::DirectiveOptimizer;
|
||||
use self::duplicate::DuplicateOptimizer;
|
||||
use self::redefinition::RedefinitionOptimizer;
|
||||
use self::tautology::TautologyOptimizer;
|
||||
|
||||
use crate::ir::Prog;
|
||||
use crate::ir::{ProgIterator, Statement};
|
||||
use zokrates_field::Field;
|
||||
|
||||
impl<T: Field> Prog<T> {
|
||||
pub fn optimize(self) -> Self {
|
||||
impl<T: Field, I: IntoIterator<Item = Statement<T>>> ProgIterator<T, I> {
|
||||
pub fn optimize(self) -> ProgIterator<T, impl IntoIterator<Item = Statement<T>>> {
|
||||
// remove redefinitions
|
||||
log::debug!("Constraints: {}", self.constraint_count());
|
||||
log::debug!("Optimizer: Remove redefinitions");
|
||||
let r = RedefinitionOptimizer::optimize(self);
|
||||
log::trace!("\n{}\n", r);
|
||||
log::debug!(
|
||||
"Optimizer: Remove redefinitions and tautologies and directives and duplicates"
|
||||
);
|
||||
|
||||
// remove constraints that are always satisfied
|
||||
log::debug!("Constraints: {}", r.constraint_count());
|
||||
log::debug!("Optimizer: Remove tautologies");
|
||||
let r = TautologyOptimizer::optimize(r);
|
||||
log::trace!("\n{}\n", r);
|
||||
// define all optimizer steps
|
||||
let mut redefinition_optimizer = RedefinitionOptimizer::init(&self);
|
||||
let mut tautologies_optimizer = TautologyOptimizer::default();
|
||||
let mut directive_optimizer = DirectiveOptimizer::default();
|
||||
let mut canonicalizer = Canonicalizer::default();
|
||||
let mut duplicate_optimizer = DuplicateOptimizer::default();
|
||||
|
||||
// deduplicate directives which take the same input
|
||||
log::debug!("Constraints: {}", r.constraint_count());
|
||||
log::debug!("Optimizer: Remove duplicate directive");
|
||||
let r = DirectiveOptimizer::optimize(r);
|
||||
log::trace!("\n{}\n", r);
|
||||
use crate::ir::folder::Folder;
|
||||
|
||||
// remove duplicate constraints
|
||||
log::debug!("Constraints: {}", r.constraint_count());
|
||||
log::debug!("Optimizer: Remove duplicate constraints");
|
||||
let r = DuplicateOptimizer::optimize(r);
|
||||
log::trace!("\n{}\n", r);
|
||||
let r = ProgIterator {
|
||||
arguments: self
|
||||
.arguments
|
||||
.into_iter()
|
||||
.map(|a| redefinition_optimizer.fold_argument(a))
|
||||
.map(|a| {
|
||||
<TautologyOptimizer as Folder<T>>::fold_argument(&mut tautologies_optimizer, a)
|
||||
})
|
||||
.map(|a| directive_optimizer.fold_argument(a))
|
||||
.map(|a| {
|
||||
<DuplicateOptimizer as Folder<T>>::fold_argument(&mut duplicate_optimizer, a)
|
||||
})
|
||||
.collect(),
|
||||
statements: self
|
||||
.statements
|
||||
.into_iter()
|
||||
.flat_map(move |s| redefinition_optimizer.fold_statement(s))
|
||||
.flat_map(move |s| tautologies_optimizer.fold_statement(s))
|
||||
.flat_map(move |s| canonicalizer.fold_statement(s))
|
||||
.flat_map(move |s| directive_optimizer.fold_statement(s))
|
||||
.flat_map(move |s| duplicate_optimizer.fold_statement(s)),
|
||||
return_count: self.return_count,
|
||||
};
|
||||
|
||||
log::debug!("Constraints: {}", r.constraint_count());
|
||||
log::debug!("Done");
|
||||
r
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,51 +37,35 @@
|
|||
// - otherwise return `c_0`
|
||||
|
||||
use crate::flat_absy::flat_variable::FlatVariable;
|
||||
use crate::flat_absy::FlatParameter;
|
||||
use crate::ir::folder::{fold_module, Folder};
|
||||
use crate::ir::folder::Folder;
|
||||
use crate::ir::LinComb;
|
||||
use crate::ir::*;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use zokrates_field::Field;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RedefinitionOptimizer<T: Field> {
|
||||
pub struct RedefinitionOptimizer<T> {
|
||||
/// Map of renamings for reassigned variables while processing the program.
|
||||
substitution: HashMap<FlatVariable, CanonicalLinComb<T>>,
|
||||
/// Set of variables that should not be substituted
|
||||
ignore: HashSet<FlatVariable>,
|
||||
pub ignore: HashSet<FlatVariable>,
|
||||
}
|
||||
|
||||
impl<T: Field> RedefinitionOptimizer<T> {
|
||||
fn new() -> Self {
|
||||
impl<T> RedefinitionOptimizer<T> {
|
||||
pub fn init<I: IntoIterator<Item = Statement<T>>>(p: &ProgIterator<T, I>) -> Self {
|
||||
RedefinitionOptimizer {
|
||||
substitution: HashMap::new(),
|
||||
ignore: HashSet::new(),
|
||||
ignore: vec![FlatVariable::one()]
|
||||
.into_iter()
|
||||
.chain(p.arguments.iter().map(|p| p.id))
|
||||
.chain(p.returns())
|
||||
.into_iter()
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn optimize(p: Prog<T>) -> Prog<T> {
|
||||
RedefinitionOptimizer::new().fold_module(p)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> Folder<T> for RedefinitionOptimizer<T> {
|
||||
fn fold_module(&mut self, p: Prog<T>) -> Prog<T> {
|
||||
// to prevent the optimiser from replacing outputs, add them to the ignored set
|
||||
self.ignore.extend(p.returns.iter().cloned());
|
||||
|
||||
// to prevent the optimiser from replacing ~one, add it to the ignored set
|
||||
self.ignore.insert(FlatVariable::one());
|
||||
|
||||
fold_module(self, p)
|
||||
}
|
||||
|
||||
fn fold_argument(&mut self, a: FlatParameter) -> FlatParameter {
|
||||
// to prevent the optimiser from replacing user input, add it to the ignored set
|
||||
self.ignore.insert(a.id);
|
||||
a
|
||||
}
|
||||
|
||||
fn fold_statement(&mut self, s: Statement<T>) -> Vec<Statement<T>> {
|
||||
match s {
|
||||
Statement::Constraint(quad, lin, message) => {
|
||||
|
@ -225,29 +209,31 @@ mod tests {
|
|||
|
||||
let x = FlatParameter::public(FlatVariable::new(0));
|
||||
let y = FlatVariable::new(1);
|
||||
let z = FlatVariable::new(2);
|
||||
let out = FlatVariable::public(0);
|
||||
|
||||
let p: Prog<Bn128Field> = Prog {
|
||||
arguments: vec![x],
|
||||
statements: vec![Statement::definition(y, x.id), Statement::definition(z, y)],
|
||||
returns: vec![z],
|
||||
statements: vec![
|
||||
Statement::definition(y, x.id),
|
||||
Statement::definition(out, y),
|
||||
],
|
||||
return_count: 1,
|
||||
};
|
||||
|
||||
let optimized: Prog<Bn128Field> = Prog {
|
||||
arguments: vec![x],
|
||||
statements: vec![Statement::definition(z, x.id)],
|
||||
returns: vec![z],
|
||||
statements: vec![Statement::definition(out, x.id)],
|
||||
return_count: 1,
|
||||
};
|
||||
|
||||
let mut optimizer = RedefinitionOptimizer::new();
|
||||
assert_eq!(optimizer.fold_module(p), optimized);
|
||||
let mut optimizer = RedefinitionOptimizer::init(&p);
|
||||
assert_eq!(optimizer.fold_program(p), optimized);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keep_one() {
|
||||
// def main(x):
|
||||
// one = x
|
||||
// return one
|
||||
|
||||
let one = FlatVariable::one();
|
||||
let x = FlatParameter::public(FlatVariable::new(0));
|
||||
|
@ -255,13 +241,13 @@ mod tests {
|
|||
let p: Prog<Bn128Field> = Prog {
|
||||
arguments: vec![x],
|
||||
statements: vec![Statement::definition(one, x.id)],
|
||||
returns: vec![x.id],
|
||||
return_count: 1,
|
||||
};
|
||||
|
||||
let optimized = p.clone();
|
||||
|
||||
let mut optimizer = RedefinitionOptimizer::new();
|
||||
assert_eq!(optimizer.fold_module(p), optimized);
|
||||
let mut optimizer = RedefinitionOptimizer::init(&p);
|
||||
assert_eq!(optimizer.fold_program(p), optimized);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -270,7 +256,7 @@ mod tests {
|
|||
// y = x
|
||||
// z = y
|
||||
// z == y
|
||||
// return z
|
||||
// ~out_0 = z
|
||||
|
||||
// ->
|
||||
|
||||
|
@ -281,6 +267,7 @@ mod tests {
|
|||
let x = FlatParameter::public(FlatVariable::new(0));
|
||||
let y = FlatVariable::new(1);
|
||||
let z = FlatVariable::new(2);
|
||||
let out = FlatVariable::public(0);
|
||||
|
||||
let p: Prog<Bn128Field> = Prog {
|
||||
arguments: vec![x],
|
||||
|
@ -288,21 +275,22 @@ mod tests {
|
|||
Statement::definition(y, x.id),
|
||||
Statement::definition(z, y),
|
||||
Statement::constraint(z, y),
|
||||
Statement::definition(out, z),
|
||||
],
|
||||
returns: vec![z],
|
||||
return_count: 1,
|
||||
};
|
||||
|
||||
let optimized: Prog<Bn128Field> = Prog {
|
||||
arguments: vec![x],
|
||||
statements: vec![
|
||||
Statement::definition(z, x.id),
|
||||
Statement::constraint(z, x.id),
|
||||
Statement::constraint(x.id, x.id),
|
||||
Statement::definition(out, x.id),
|
||||
],
|
||||
returns: vec![z],
|
||||
return_count: 1,
|
||||
};
|
||||
|
||||
let mut optimizer = RedefinitionOptimizer::new();
|
||||
assert_eq!(optimizer.fold_module(p), optimized);
|
||||
let mut optimizer = RedefinitionOptimizer::init(&p);
|
||||
assert_eq!(optimizer.fold_program(p), optimized);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -312,7 +300,8 @@ mod tests {
|
|||
// t = 1
|
||||
// z = y
|
||||
// w = t
|
||||
// return z, w
|
||||
// ~out_0 = z
|
||||
// ~out_1 = w
|
||||
|
||||
// ->
|
||||
|
||||
|
@ -324,6 +313,8 @@ mod tests {
|
|||
let z = FlatVariable::new(2);
|
||||
let t = FlatVariable::new(3);
|
||||
let w = FlatVariable::new(4);
|
||||
let out_1 = FlatVariable::public(0);
|
||||
let out_0 = FlatVariable::public(1);
|
||||
|
||||
let p: Prog<Bn128Field> = Prog {
|
||||
arguments: vec![x],
|
||||
|
@ -332,22 +323,24 @@ mod tests {
|
|||
Statement::definition(t, Bn128Field::from(1)),
|
||||
Statement::definition(z, y),
|
||||
Statement::definition(w, t),
|
||||
Statement::definition(out_0, z),
|
||||
Statement::definition(out_1, w),
|
||||
],
|
||||
returns: vec![z, w],
|
||||
return_count: 2,
|
||||
};
|
||||
|
||||
let optimized: Prog<Bn128Field> = Prog {
|
||||
arguments: vec![x],
|
||||
statements: vec![
|
||||
Statement::definition(z, x.id),
|
||||
Statement::definition(w, Bn128Field::from(1)),
|
||||
Statement::definition(out_0, x.id),
|
||||
Statement::definition(out_1, Bn128Field::from(1)),
|
||||
],
|
||||
returns: vec![z, w],
|
||||
return_count: 2,
|
||||
};
|
||||
|
||||
let mut optimizer = RedefinitionOptimizer::new();
|
||||
let mut optimizer = RedefinitionOptimizer::init(&p);
|
||||
|
||||
assert_eq!(optimizer.fold_module(p), optimized);
|
||||
assert_eq!(optimizer.fold_program(p), optimized);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -357,21 +350,20 @@ mod tests {
|
|||
// b = a + x + y
|
||||
// c = b + x + y
|
||||
// 2*c == 6*x + 6*y
|
||||
// r = a + b + c
|
||||
// return r
|
||||
// ~out_0 = a + b + c
|
||||
|
||||
// ->
|
||||
|
||||
// def main(x, y) -> (1):
|
||||
// 1*x + 1*y + 2*x + 2*y + 3*x + 3*y == 6*x + 6*y // will be eliminated as a tautology
|
||||
// return 6*x + 6*y
|
||||
// ~out_0 = 6*x + 6*y
|
||||
|
||||
let x = FlatParameter::public(FlatVariable::new(0));
|
||||
let y = FlatParameter::public(FlatVariable::new(1));
|
||||
let a = FlatVariable::new(2);
|
||||
let b = FlatVariable::new(3);
|
||||
let c = FlatVariable::new(4);
|
||||
let r = FlatVariable::new(5);
|
||||
let r = FlatVariable::public(0);
|
||||
|
||||
let p: Prog<Bn128Field> = Prog {
|
||||
arguments: vec![x, y],
|
||||
|
@ -391,7 +383,7 @@ mod tests {
|
|||
),
|
||||
Statement::definition(r, LinComb::from(a) + LinComb::from(b) + LinComb::from(c)),
|
||||
],
|
||||
returns: vec![r],
|
||||
return_count: 1,
|
||||
};
|
||||
|
||||
let expected: Prog<Bn128Field> = Prog {
|
||||
|
@ -411,12 +403,12 @@ mod tests {
|
|||
+ LinComb::summand(3, y.id),
|
||||
),
|
||||
],
|
||||
returns: vec![r],
|
||||
return_count: 1,
|
||||
};
|
||||
|
||||
let mut optimizer = RedefinitionOptimizer::new();
|
||||
let mut optimizer = RedefinitionOptimizer::init(&p);
|
||||
|
||||
let optimized = optimizer.fold_module(p);
|
||||
let optimized = optimizer.fold_program(p);
|
||||
|
||||
assert_eq!(optimized, expected);
|
||||
}
|
||||
|
@ -448,13 +440,13 @@ mod tests {
|
|||
),
|
||||
Statement::definition(z, LinComb::from(x.id)),
|
||||
],
|
||||
returns: vec![],
|
||||
return_count: 0,
|
||||
};
|
||||
|
||||
let optimized = p.clone();
|
||||
|
||||
let mut optimizer = RedefinitionOptimizer::new();
|
||||
assert_eq!(optimizer.fold_module(p), optimized);
|
||||
let mut optimizer = RedefinitionOptimizer::init(&p);
|
||||
assert_eq!(optimizer.fold_program(p), optimized);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -476,12 +468,12 @@ mod tests {
|
|||
Statement::constraint(x.id, Bn128Field::from(1)),
|
||||
Statement::constraint(x.id, Bn128Field::from(2)),
|
||||
],
|
||||
returns: vec![x.id],
|
||||
return_count: 1,
|
||||
};
|
||||
|
||||
let optimized = p.clone();
|
||||
|
||||
let mut optimizer = RedefinitionOptimizer::new();
|
||||
assert_eq!(optimizer.fold_module(p), optimized);
|
||||
let mut optimizer = RedefinitionOptimizer::init(&p);
|
||||
assert_eq!(optimizer.fold_program(p), optimized);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,17 +10,8 @@ use crate::ir::folder::Folder;
|
|||
use crate::ir::*;
|
||||
use zokrates_field::Field;
|
||||
|
||||
pub struct TautologyOptimizer {}
|
||||
|
||||
impl TautologyOptimizer {
|
||||
fn new() -> TautologyOptimizer {
|
||||
TautologyOptimizer {}
|
||||
}
|
||||
|
||||
pub fn optimize<T: Field>(p: Prog<T>) -> Prog<T> {
|
||||
TautologyOptimizer::new().fold_module(p)
|
||||
}
|
||||
}
|
||||
#[derive(Default)]
|
||||
pub struct TautologyOptimizer;
|
||||
|
||||
impl<T: Field> Folder<T> for TautologyOptimizer {
|
||||
fn fold_statement(&mut self, s: Statement<T>) -> Vec<Statement<T>> {
|
||||
|
|
|
@ -6,7 +6,7 @@ use ark_gm17::{
|
|||
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
|
||||
use zokrates_field::{ArkFieldExtensions, Bw6_761Field, Field};
|
||||
|
||||
use crate::ir::{Prog, Witness};
|
||||
use crate::ir::{ProgIterator, Statement, Witness};
|
||||
use crate::proof_system::ark::Ark;
|
||||
use crate::proof_system::ark::Computation;
|
||||
use crate::proof_system::ark::{parse_fr, parse_g1, parse_g2, parse_g2_fq};
|
||||
|
@ -15,7 +15,9 @@ use crate::proof_system::Scheme;
|
|||
use crate::proof_system::{Backend, NonUniversalBackend, Proof, SetupKeypair};
|
||||
|
||||
impl<T: Field + ArkFieldExtensions + NotBw6_761Field> NonUniversalBackend<T, GM17> for Ark {
|
||||
fn setup(program: Prog<T>) -> SetupKeypair<<GM17 as Scheme<T>>::VerificationKey> {
|
||||
fn setup<I: IntoIterator<Item = Statement<T>>>(
|
||||
program: ProgIterator<T, I>,
|
||||
) -> SetupKeypair<<GM17 as Scheme<T>>::VerificationKey> {
|
||||
let parameters = Computation::without_witness(program).setup();
|
||||
|
||||
let mut pk: Vec<u8> = Vec::new();
|
||||
|
@ -40,23 +42,12 @@ impl<T: Field + ArkFieldExtensions + NotBw6_761Field> NonUniversalBackend<T, GM1
|
|||
}
|
||||
|
||||
impl<T: Field + ArkFieldExtensions + NotBw6_761Field> Backend<T, GM17> for Ark {
|
||||
fn generate_proof(
|
||||
program: Prog<T>,
|
||||
fn generate_proof<I: IntoIterator<Item = Statement<T>>>(
|
||||
program: ProgIterator<T, I>,
|
||||
witness: Witness<T>,
|
||||
proving_key: Vec<u8>,
|
||||
) -> Proof<<GM17 as Scheme<T>>::ProofPoints> {
|
||||
let computation = Computation::with_witness(program, witness);
|
||||
let params = ProvingKey::<<T as ArkFieldExtensions>::ArkEngine>::deserialize_uncompressed(
|
||||
&mut proving_key.as_slice(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let proof = computation.clone().prove(¶ms);
|
||||
let proof_points = ProofPoints {
|
||||
a: parse_g1::<T>(&proof.a),
|
||||
b: parse_g2::<T>(&proof.b),
|
||||
c: parse_g1::<T>(&proof.c),
|
||||
};
|
||||
|
||||
let inputs = computation
|
||||
.public_inputs_values()
|
||||
|
@ -64,6 +55,18 @@ impl<T: Field + ArkFieldExtensions + NotBw6_761Field> Backend<T, GM17> for Ark {
|
|||
.map(parse_fr::<T>)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let params = ProvingKey::<<T as ArkFieldExtensions>::ArkEngine>::deserialize_uncompressed(
|
||||
&mut proving_key.as_slice(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let proof = computation.prove(¶ms);
|
||||
let proof_points = ProofPoints {
|
||||
a: parse_g1::<T>(&proof.a),
|
||||
b: parse_g2::<T>(&proof.b),
|
||||
c: parse_g1::<T>(&proof.c),
|
||||
};
|
||||
|
||||
Proof::new(proof_points, inputs)
|
||||
}
|
||||
|
||||
|
@ -108,8 +111,8 @@ impl<T: Field + ArkFieldExtensions + NotBw6_761Field> Backend<T, GM17> for Ark {
|
|||
}
|
||||
|
||||
impl NonUniversalBackend<Bw6_761Field, GM17> for Ark {
|
||||
fn setup(
|
||||
program: Prog<Bw6_761Field>,
|
||||
fn setup<I: IntoIterator<Item = Statement<Bw6_761Field>>>(
|
||||
program: ProgIterator<Bw6_761Field, I>,
|
||||
) -> SetupKeypair<<GM17 as Scheme<Bw6_761Field>>::VerificationKey> {
|
||||
let parameters = Computation::without_witness(program).setup();
|
||||
|
||||
|
@ -135,24 +138,12 @@ impl NonUniversalBackend<Bw6_761Field, GM17> for Ark {
|
|||
}
|
||||
|
||||
impl Backend<Bw6_761Field, GM17> for Ark {
|
||||
fn generate_proof(
|
||||
program: Prog<Bw6_761Field>,
|
||||
fn generate_proof<I: IntoIterator<Item = Statement<Bw6_761Field>>>(
|
||||
program: ProgIterator<Bw6_761Field, I>,
|
||||
witness: Witness<Bw6_761Field>,
|
||||
proving_key: Vec<u8>,
|
||||
) -> Proof<<GM17 as Scheme<Bw6_761Field>>::ProofPoints> {
|
||||
let computation = Computation::with_witness(program, witness);
|
||||
let params =
|
||||
ProvingKey::<<Bw6_761Field as ArkFieldExtensions>::ArkEngine>::deserialize_uncompressed(
|
||||
&mut proving_key.as_slice(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let proof = computation.clone().prove(¶ms);
|
||||
let proof_points = ProofPoints {
|
||||
a: parse_g1::<Bw6_761Field>(&proof.a),
|
||||
b: parse_g2_fq::<Bw6_761Field>(&proof.b),
|
||||
c: parse_g1::<Bw6_761Field>(&proof.c),
|
||||
};
|
||||
|
||||
let inputs = computation
|
||||
.public_inputs_values()
|
||||
|
@ -160,6 +151,19 @@ impl Backend<Bw6_761Field, GM17> for Ark {
|
|||
.map(parse_fr::<Bw6_761Field>)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let params =
|
||||
ProvingKey::<<Bw6_761Field as ArkFieldExtensions>::ArkEngine>::deserialize_uncompressed(
|
||||
&mut proving_key.as_slice(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let proof = computation.prove(¶ms);
|
||||
let proof_points = ProofPoints {
|
||||
a: parse_g1::<Bw6_761Field>(&proof.a),
|
||||
b: parse_g2_fq::<Bw6_761Field>(&proof.b),
|
||||
c: parse_g1::<Bw6_761Field>(&proof.c),
|
||||
};
|
||||
|
||||
Proof::new(proof_points, inputs)
|
||||
}
|
||||
|
||||
|
@ -260,7 +264,7 @@ mod tests {
|
|||
fn verify_bls12_377_field() {
|
||||
let program: Prog<Bls12_377Field> = Prog {
|
||||
arguments: vec![FlatParameter::public(FlatVariable::new(0))],
|
||||
returns: vec![FlatVariable::public(0)],
|
||||
return_count: 1,
|
||||
statements: vec![Statement::constraint(
|
||||
FlatVariable::new(0),
|
||||
FlatVariable::public(0),
|
||||
|
@ -271,11 +275,14 @@ mod tests {
|
|||
let interpreter = Interpreter::default();
|
||||
|
||||
let witness = interpreter
|
||||
.execute(&program, &[Bls12_377Field::from(42)])
|
||||
.execute(program.clone(), &[Bls12_377Field::from(42)])
|
||||
.unwrap();
|
||||
|
||||
let proof =
|
||||
<Ark as Backend<Bls12_377Field, GM17>>::generate_proof(program, witness, keypair.pk);
|
||||
let proof = <Ark as Backend<Bls12_377Field, GM17>>::generate_proof(
|
||||
program.into(),
|
||||
witness,
|
||||
keypair.pk,
|
||||
);
|
||||
let ans = <Ark as Backend<Bls12_377Field, GM17>>::verify(keypair.vk, proof);
|
||||
|
||||
assert!(ans);
|
||||
|
@ -285,7 +292,7 @@ mod tests {
|
|||
fn verify_bw6_761_field() {
|
||||
let program: Prog<Bw6_761Field> = Prog {
|
||||
arguments: vec![FlatParameter::public(FlatVariable::new(0))],
|
||||
returns: vec![FlatVariable::public(0)],
|
||||
return_count: 1,
|
||||
statements: vec![Statement::constraint(
|
||||
FlatVariable::new(0),
|
||||
FlatVariable::public(0),
|
||||
|
@ -296,7 +303,7 @@ mod tests {
|
|||
let interpreter = Interpreter::default();
|
||||
|
||||
let witness = interpreter
|
||||
.execute(&program, &[Bw6_761Field::from(42)])
|
||||
.execute(program.clone(), &[Bw6_761Field::from(42)])
|
||||
.unwrap();
|
||||
|
||||
let proof =
|
||||
|
|
|
@ -10,7 +10,7 @@ use sha2::Sha256;
|
|||
|
||||
use zokrates_field::{ArkFieldExtensions, Field};
|
||||
|
||||
use crate::ir::{Prog, Witness};
|
||||
use crate::ir::{ProgIterator, Statement, Witness};
|
||||
use crate::proof_system::ark::parse_fr;
|
||||
use crate::proof_system::ark::Ark;
|
||||
use crate::proof_system::ark::Computation;
|
||||
|
@ -45,10 +45,12 @@ impl<T: Field + ArkFieldExtensions> UniversalBackend<T, marlin::Marlin> for Ark
|
|||
res
|
||||
}
|
||||
|
||||
fn setup(
|
||||
universal_srs: Vec<u8>,
|
||||
program: Prog<T>,
|
||||
fn setup<I: IntoIterator<Item = Statement<T>>>(
|
||||
srs: Vec<u8>,
|
||||
program: ProgIterator<T, I>,
|
||||
) -> Result<SetupKeypair<<marlin::Marlin as Scheme<T>>::VerificationKey>, String> {
|
||||
let program = program.collect();
|
||||
|
||||
if program.constraint_count() < MINIMUM_CONSTRAINT_COUNT {
|
||||
return Err(format!("Programs must have a least {} constraints. This program is too small to generate a setup with Marlin, see [this issue](https://github.com/arkworks-rs/marlin/issues/79)", MINIMUM_CONSTRAINT_COUNT));
|
||||
}
|
||||
|
@ -61,7 +63,7 @@ impl<T: Field + ArkFieldExtensions> UniversalBackend<T, marlin::Marlin> for Ark
|
|||
T::ArkEngine,
|
||||
DensePolynomial<<<T as ArkFieldExtensions>::ArkEngine as PairingEngine>::Fr>,
|
||||
>,
|
||||
>::deserialize(&mut universal_srs.as_slice())
|
||||
>::deserialize(&mut srs.as_slice())
|
||||
.unwrap();
|
||||
|
||||
let (pk, vk) = ArkMarlin::<
|
||||
|
@ -91,8 +93,8 @@ impl<T: Field + ArkFieldExtensions> UniversalBackend<T, marlin::Marlin> for Ark
|
|||
}
|
||||
|
||||
impl<T: Field + ArkFieldExtensions> Backend<T, marlin::Marlin> for Ark {
|
||||
fn generate_proof(
|
||||
program: Prog<T>,
|
||||
fn generate_proof<I: IntoIterator<Item = Statement<T>>>(
|
||||
program: ProgIterator<T, I>,
|
||||
witness: Witness<T>,
|
||||
proving_key: Vec<u8>,
|
||||
) -> Proof<<marlin::Marlin as Scheme<T>>::ProofPoints> {
|
||||
|
@ -199,7 +201,7 @@ mod tests {
|
|||
fn verify_bls12_377_field() {
|
||||
let program: Prog<Bls12_377Field> = Prog {
|
||||
arguments: vec![FlatParameter::private(FlatVariable::new(0))],
|
||||
returns: vec![FlatVariable::public(0)],
|
||||
return_count: 1,
|
||||
statements: vec![
|
||||
Statement::constraint(
|
||||
QuadComb::from_linear_combinations(
|
||||
|
@ -214,15 +216,19 @@ mod tests {
|
|||
|
||||
let srs = <Ark as UniversalBackend<Bls12_377Field, Marlin>>::universal_setup(5);
|
||||
let keypair =
|
||||
<Ark as UniversalBackend<Bls12_377Field, Marlin>>::setup(srs, program.clone()).unwrap();
|
||||
<Ark as UniversalBackend<Bls12_377Field, Marlin>>::setup(srs, program.clone().into())
|
||||
.unwrap();
|
||||
let interpreter = Interpreter::default();
|
||||
|
||||
let witness = interpreter
|
||||
.execute(&program, &[Bls12_377Field::from(42)])
|
||||
.execute(program.clone(), &[Bls12_377Field::from(42)])
|
||||
.unwrap();
|
||||
|
||||
let proof =
|
||||
<Ark as Backend<Bls12_377Field, Marlin>>::generate_proof(program, witness, keypair.pk);
|
||||
let proof = <Ark as Backend<Bls12_377Field, Marlin>>::generate_proof(
|
||||
program.clone(),
|
||||
witness,
|
||||
keypair.pk,
|
||||
);
|
||||
let ans = <Ark as Backend<Bls12_377Field, Marlin>>::verify(keypair.vk, proof);
|
||||
|
||||
assert!(ans);
|
||||
|
@ -232,7 +238,7 @@ mod tests {
|
|||
fn verify_bw6_761_field() {
|
||||
let program: Prog<Bw6_761Field> = Prog {
|
||||
arguments: vec![FlatParameter::private(FlatVariable::new(0))],
|
||||
returns: vec![FlatVariable::public(0)],
|
||||
return_count: 1,
|
||||
statements: vec![
|
||||
Statement::constraint(
|
||||
QuadComb::from_linear_combinations(
|
||||
|
@ -251,7 +257,7 @@ mod tests {
|
|||
let interpreter = Interpreter::default();
|
||||
|
||||
let witness = interpreter
|
||||
.execute(&program, &[Bw6_761Field::from(42)])
|
||||
.execute(program.clone(), &[Bw6_761Field::from(42)])
|
||||
.unwrap();
|
||||
|
||||
let proof =
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
pub mod gm17;
|
||||
pub mod marlin;
|
||||
|
||||
use crate::ir::{CanonicalLinComb, Prog, Statement, Witness};
|
||||
use crate::ir::{CanonicalLinComb, ProgIterator, Statement, Witness};
|
||||
use ark_gm17::Proof;
|
||||
use ark_gm17::{
|
||||
create_random_proof, generate_random_parameters, prepare_verifying_key, verify_proof,
|
||||
|
@ -24,20 +24,20 @@ use rand_0_7::SeedableRng;
|
|||
pub struct Ark;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Computation<T> {
|
||||
program: Prog<T>,
|
||||
pub struct Computation<T, I: IntoIterator<Item = Statement<T>>> {
|
||||
program: ProgIterator<T, I>,
|
||||
witness: Option<Witness<T>>,
|
||||
}
|
||||
|
||||
impl<T: Field> Computation<T> {
|
||||
pub fn with_witness(program: Prog<T>, witness: Witness<T>) -> Self {
|
||||
impl<T, I: IntoIterator<Item = Statement<T>>> Computation<T, I> {
|
||||
pub fn with_witness(program: ProgIterator<T, I>, witness: Witness<T>) -> Self {
|
||||
Computation {
|
||||
program,
|
||||
witness: Some(witness),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn without_witness(program: Prog<T>) -> Self {
|
||||
pub fn without_witness(program: ProgIterator<T, I>) -> Self {
|
||||
Computation {
|
||||
program,
|
||||
witness: None,
|
||||
|
@ -79,7 +79,7 @@ fn ark_combination<T: Field + ArkFieldExtensions>(
|
|||
.fold(LinearCombination::zero(), |acc, e| acc + e)
|
||||
}
|
||||
|
||||
impl<T: Field + ArkFieldExtensions> Prog<T> {
|
||||
impl<T: Field + ArkFieldExtensions, I: IntoIterator<Item = Statement<T>>> ProgIterator<T, I> {
|
||||
pub fn generate_constraints(
|
||||
self,
|
||||
cs: ConstraintSystemRef<<<T as ArkFieldExtensions>::ArkEngine as PairingEngine>::Fr>,
|
||||
|
@ -148,17 +148,16 @@ impl<T: Field + ArkFieldExtensions> Prog<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Field + ArkFieldExtensions> Computation<T> {
|
||||
impl<T: Field + ArkFieldExtensions, I: IntoIterator<Item = Statement<T>>> Computation<T, I> {
|
||||
pub fn prove(self, params: &ProvingKey<T::ArkEngine>) -> Proof<T::ArkEngine> {
|
||||
let rng = &mut rand_0_7::rngs::StdRng::from_entropy();
|
||||
|
||||
let proof = create_random_proof(self.clone(), params, rng).unwrap();
|
||||
let public_inputs = self.public_inputs_values();
|
||||
|
||||
let proof = create_random_proof(self, params, rng).unwrap();
|
||||
|
||||
let pvk = prepare_verifying_key(¶ms.vk);
|
||||
|
||||
// extract public inputs
|
||||
let public_inputs = self.public_inputs_values();
|
||||
|
||||
assert!(verify_proof(&pvk, &proof, &public_inputs).unwrap());
|
||||
|
||||
proof
|
||||
|
@ -180,9 +179,9 @@ impl<T: Field + ArkFieldExtensions> Computation<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Field + ArkFieldExtensions>
|
||||
impl<T: Field + ArkFieldExtensions, I: IntoIterator<Item = Statement<T>>>
|
||||
ConstraintSynthesizer<<<T as ArkFieldExtensions>::ArkEngine as PairingEngine>::Fr>
|
||||
for Computation<T>
|
||||
for Computation<T, I>
|
||||
{
|
||||
fn generate_constraints(
|
||||
self,
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::proof_system::{Backend, NonUniversalBackend, Proof, SetupKeypair};
|
|||
use zokrates_field::BellmanFieldExtensions;
|
||||
use zokrates_field::Field;
|
||||
|
||||
use crate::ir::{Prog, Witness};
|
||||
use crate::ir::{ProgIterator, Statement, Witness};
|
||||
use crate::proof_system::bellman::Bellman;
|
||||
use crate::proof_system::bellman::Computation;
|
||||
use crate::proof_system::bellman::{parse_g1, parse_g2};
|
||||
|
@ -18,8 +18,8 @@ use crate::proof_system::Scheme;
|
|||
const G16_WARNING: &str = "WARNING: You are using the G16 scheme which is subject to malleability. See zokrates.github.io/toolbox/proving_schemes.html#g16-malleability for implications.";
|
||||
|
||||
impl<T: Field + BellmanFieldExtensions> Backend<T, G16> for Bellman {
|
||||
fn generate_proof(
|
||||
program: Prog<T>,
|
||||
fn generate_proof<I: IntoIterator<Item = Statement<T>>>(
|
||||
program: ProgIterator<T, I>,
|
||||
witness: Witness<T>,
|
||||
proving_key: Vec<u8>,
|
||||
) -> Proof<<G16 as Scheme<T>>::ProofPoints> {
|
||||
|
@ -28,19 +28,19 @@ impl<T: Field + BellmanFieldExtensions> Backend<T, G16> for Bellman {
|
|||
let computation = Computation::with_witness(program, witness);
|
||||
let params = Parameters::read(proving_key.as_slice(), true).unwrap();
|
||||
|
||||
let proof = computation.clone().prove(¶ms);
|
||||
let proof_points = ProofPoints {
|
||||
a: parse_g1::<T>(&proof.a),
|
||||
b: parse_g2::<T>(&proof.b),
|
||||
c: parse_g1::<T>(&proof.c),
|
||||
};
|
||||
|
||||
let public_inputs: Vec<String> = computation
|
||||
.public_inputs_values()
|
||||
.iter()
|
||||
.map(|e| format!("0x{}", to_hex(e)))
|
||||
.collect();
|
||||
|
||||
let proof = computation.prove(¶ms);
|
||||
let proof_points = ProofPoints {
|
||||
a: parse_g1::<T>(&proof.a),
|
||||
b: parse_g2::<T>(&proof.b),
|
||||
c: parse_g1::<T>(&proof.c),
|
||||
};
|
||||
|
||||
Proof::new(proof_points, public_inputs)
|
||||
}
|
||||
|
||||
|
@ -84,7 +84,9 @@ impl<T: Field + BellmanFieldExtensions> Backend<T, G16> for Bellman {
|
|||
}
|
||||
|
||||
impl<T: Field + BellmanFieldExtensions> NonUniversalBackend<T, G16> for Bellman {
|
||||
fn setup(program: Prog<T>) -> SetupKeypair<<G16 as Scheme<T>>::VerificationKey> {
|
||||
fn setup<I: IntoIterator<Item = Statement<T>>>(
|
||||
program: ProgIterator<T, I>,
|
||||
) -> SetupKeypair<<G16 as Scheme<T>>::VerificationKey> {
|
||||
println!("{}", G16_WARNING);
|
||||
|
||||
let parameters = Computation::without_witness(program).setup();
|
||||
|
@ -143,22 +145,26 @@ mod tests {
|
|||
fn verify() {
|
||||
let program: Prog<Bn128Field> = Prog {
|
||||
arguments: vec![FlatParameter::public(FlatVariable::new(0))],
|
||||
returns: vec![FlatVariable::public(0)],
|
||||
return_count: 1,
|
||||
statements: vec![Statement::constraint(
|
||||
FlatVariable::new(0),
|
||||
FlatVariable::public(0),
|
||||
)],
|
||||
};
|
||||
|
||||
let keypair = <Bellman as NonUniversalBackend<Bn128Field, G16>>::setup(program.clone());
|
||||
let keypair =
|
||||
<Bellman as NonUniversalBackend<Bn128Field, G16>>::setup(program.clone().into());
|
||||
let interpreter = Interpreter::default();
|
||||
|
||||
let witness = interpreter
|
||||
.execute(&program, &[Bn128Field::from(42)])
|
||||
.execute(program.clone().into(), &[Bn128Field::from(42)])
|
||||
.unwrap();
|
||||
|
||||
let proof =
|
||||
<Bellman as Backend<Bn128Field, G16>>::generate_proof(program, witness, keypair.pk);
|
||||
let proof = <Bellman as Backend<Bn128Field, G16>>::generate_proof(
|
||||
program.into(),
|
||||
witness,
|
||||
keypair.pk,
|
||||
);
|
||||
let ans = <Bellman as Backend<Bn128Field, G16>>::verify(keypair.vk, proof);
|
||||
|
||||
assert!(ans);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
pub mod groth16;
|
||||
|
||||
use crate::ir::{CanonicalLinComb, Prog, Statement, Witness};
|
||||
use crate::ir::{CanonicalLinComb, ProgIterator, Statement, Witness};
|
||||
use bellman::groth16::Proof;
|
||||
use bellman::groth16::{
|
||||
create_random_proof, generate_random_parameters, prepare_verifying_key, verify_proof,
|
||||
|
@ -20,20 +20,20 @@ pub use self::parse::*;
|
|||
pub struct Bellman;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Computation<T> {
|
||||
program: Prog<T>,
|
||||
pub struct Computation<T, I: IntoIterator<Item = Statement<T>>> {
|
||||
program: ProgIterator<T, I>,
|
||||
witness: Option<Witness<T>>,
|
||||
}
|
||||
|
||||
impl<T: Field> Computation<T> {
|
||||
pub fn with_witness(program: Prog<T>, witness: Witness<T>) -> Self {
|
||||
impl<T: Field, I: IntoIterator<Item = Statement<T>>> Computation<T, I> {
|
||||
pub fn with_witness(program: ProgIterator<T, I>, witness: Witness<T>) -> Self {
|
||||
Computation {
|
||||
program,
|
||||
witness: Some(witness),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn without_witness(program: Prog<T>) -> Self {
|
||||
pub fn without_witness(program: ProgIterator<T, I>) -> Self {
|
||||
Computation {
|
||||
program,
|
||||
witness: None,
|
||||
|
@ -81,7 +81,7 @@ fn bellman_combination<T: BellmanFieldExtensions, CS: ConstraintSystem<T::Bellma
|
|||
.fold(LinearCombination::zero(), |acc, e| acc + e)
|
||||
}
|
||||
|
||||
impl<T: BellmanFieldExtensions + Field> Prog<T> {
|
||||
impl<T: BellmanFieldExtensions + Field, I: IntoIterator<Item = Statement<T>>> ProgIterator<T, I> {
|
||||
pub fn synthesize<CS: ConstraintSystem<T::BellmanEngine>>(
|
||||
self,
|
||||
cs: &mut CS,
|
||||
|
@ -145,7 +145,7 @@ impl<T: BellmanFieldExtensions + Field> Prog<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: BellmanFieldExtensions + Field> Computation<T> {
|
||||
impl<T: BellmanFieldExtensions + Field, I: IntoIterator<Item = Statement<T>>> Computation<T, I> {
|
||||
fn get_random_seed(&self) -> Result<[u32; 8], getrandom::Error> {
|
||||
let mut seed = [0u8; 32];
|
||||
getrandom::getrandom(&mut seed)?;
|
||||
|
@ -163,13 +163,13 @@ impl<T: BellmanFieldExtensions + Field> Computation<T> {
|
|||
let seed = self.get_random_seed().unwrap();
|
||||
let rng = &mut ChaChaRng::from_seed(seed.as_ref());
|
||||
|
||||
let proof = create_random_proof(self.clone(), params, rng).unwrap();
|
||||
|
||||
let pvk = prepare_verifying_key(¶ms.vk);
|
||||
|
||||
// extract public inputs
|
||||
let public_inputs = self.public_inputs_values();
|
||||
|
||||
let proof = create_random_proof(self, params, rng).unwrap();
|
||||
|
||||
let pvk = prepare_verifying_key(¶ms.vk);
|
||||
|
||||
assert!(verify_proof(&pvk, &proof, &public_inputs).unwrap());
|
||||
|
||||
proof
|
||||
|
@ -192,7 +192,9 @@ impl<T: BellmanFieldExtensions + Field> Computation<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: BellmanFieldExtensions + Field> Circuit<T::BellmanEngine> for Computation<T> {
|
||||
impl<T: BellmanFieldExtensions + Field, I: IntoIterator<Item = Statement<T>>>
|
||||
Circuit<T::BellmanEngine> for Computation<T, I>
|
||||
{
|
||||
fn synthesize<CS: ConstraintSystem<T::BellmanEngine>>(
|
||||
self,
|
||||
cs: &mut CS,
|
||||
|
@ -251,6 +253,7 @@ mod tests {
|
|||
mod prove {
|
||||
use super::*;
|
||||
use crate::flat_absy::FlatParameter;
|
||||
use crate::ir::Prog;
|
||||
|
||||
#[test]
|
||||
fn empty() {
|
||||
|
@ -258,7 +261,7 @@ mod tests {
|
|||
|
||||
let interpreter = Interpreter::default();
|
||||
|
||||
let witness = interpreter.execute(&program, &[]).unwrap();
|
||||
let witness = interpreter.execute(program.clone(), &[]).unwrap();
|
||||
let computation = Computation::with_witness(program, witness);
|
||||
|
||||
let params = computation.clone().setup();
|
||||
|
@ -269,7 +272,7 @@ mod tests {
|
|||
fn identity() {
|
||||
let program: Prog<Bn128Field> = Prog {
|
||||
arguments: vec![FlatParameter::private(FlatVariable::new(0))],
|
||||
returns: vec![FlatVariable::public(0)],
|
||||
return_count: 1,
|
||||
statements: vec![Statement::constraint(
|
||||
FlatVariable::new(0),
|
||||
FlatVariable::public(0),
|
||||
|
@ -279,7 +282,7 @@ mod tests {
|
|||
let interpreter = Interpreter::default();
|
||||
|
||||
let witness = interpreter
|
||||
.execute(&program, &[Bn128Field::from(0)])
|
||||
.execute(program.clone(), &[Bn128Field::from(0)])
|
||||
.unwrap();
|
||||
|
||||
let computation = Computation::with_witness(program, witness);
|
||||
|
@ -292,7 +295,7 @@ mod tests {
|
|||
fn public_identity() {
|
||||
let program: Prog<Bn128Field> = Prog {
|
||||
arguments: vec![FlatParameter::public(FlatVariable::new(0))],
|
||||
returns: vec![FlatVariable::public(0)],
|
||||
return_count: 1,
|
||||
statements: vec![Statement::constraint(
|
||||
FlatVariable::new(0),
|
||||
FlatVariable::public(0),
|
||||
|
@ -302,7 +305,7 @@ mod tests {
|
|||
let interpreter = Interpreter::default();
|
||||
|
||||
let witness = interpreter
|
||||
.execute(&program, &[Bn128Field::from(0)])
|
||||
.execute(program.clone(), &[Bn128Field::from(0)])
|
||||
.unwrap();
|
||||
|
||||
let computation = Computation::with_witness(program, witness);
|
||||
|
@ -315,7 +318,7 @@ mod tests {
|
|||
fn no_arguments() {
|
||||
let program: Prog<Bn128Field> = Prog {
|
||||
arguments: vec![],
|
||||
returns: vec![FlatVariable::public(0)],
|
||||
return_count: 1,
|
||||
statements: vec![Statement::constraint(
|
||||
FlatVariable::one(),
|
||||
FlatVariable::public(0),
|
||||
|
@ -324,7 +327,7 @@ mod tests {
|
|||
|
||||
let interpreter = Interpreter::default();
|
||||
|
||||
let witness = interpreter.execute(&program, &[]).unwrap();
|
||||
let witness = interpreter.execute(program.clone(), &[]).unwrap();
|
||||
let computation = Computation::with_witness(program, witness);
|
||||
|
||||
let params = computation.clone().setup();
|
||||
|
@ -340,7 +343,7 @@ mod tests {
|
|||
FlatParameter::private(FlatVariable::new(42)),
|
||||
FlatParameter::public(FlatVariable::new(51)),
|
||||
],
|
||||
returns: vec![FlatVariable::public(0), FlatVariable::public(1)],
|
||||
return_count: 2,
|
||||
statements: vec![
|
||||
Statement::constraint(
|
||||
LinComb::from(FlatVariable::new(42)) + LinComb::from(FlatVariable::new(51)),
|
||||
|
@ -356,7 +359,7 @@ mod tests {
|
|||
let interpreter = Interpreter::default();
|
||||
|
||||
let witness = interpreter
|
||||
.execute(&program, &[Bn128Field::from(3), Bn128Field::from(4)])
|
||||
.execute(program.clone(), &[Bn128Field::from(3), Bn128Field::from(4)])
|
||||
.unwrap();
|
||||
let computation = Computation::with_witness(program, witness);
|
||||
|
||||
|
@ -368,7 +371,7 @@ mod tests {
|
|||
fn one() {
|
||||
let program: Prog<Bn128Field> = Prog {
|
||||
arguments: vec![FlatParameter::public(FlatVariable::new(42))],
|
||||
returns: vec![FlatVariable::public(0)],
|
||||
return_count: 1,
|
||||
statements: vec![Statement::constraint(
|
||||
LinComb::from(FlatVariable::new(42)) + LinComb::one(),
|
||||
FlatVariable::public(0),
|
||||
|
@ -378,7 +381,7 @@ mod tests {
|
|||
let interpreter = Interpreter::default();
|
||||
|
||||
let witness = interpreter
|
||||
.execute(&program, &[Bn128Field::from(3)])
|
||||
.execute(program.clone(), &[Bn128Field::from(3)])
|
||||
.unwrap();
|
||||
|
||||
let computation = Computation::with_witness(program, witness);
|
||||
|
@ -394,7 +397,7 @@ mod tests {
|
|||
FlatParameter::private(FlatVariable::new(42)),
|
||||
FlatParameter::public(FlatVariable::new(51)),
|
||||
],
|
||||
returns: vec![FlatVariable::public(0)],
|
||||
return_count: 1,
|
||||
statements: vec![Statement::constraint(
|
||||
LinComb::from(FlatVariable::new(42)) + LinComb::from(FlatVariable::new(51)),
|
||||
FlatVariable::public(0),
|
||||
|
@ -404,7 +407,7 @@ mod tests {
|
|||
let interpreter = Interpreter::default();
|
||||
|
||||
let witness = interpreter
|
||||
.execute(&program, &[Bn128Field::from(3), Bn128Field::from(4)])
|
||||
.execute(program.clone(), &[Bn128Field::from(3), Bn128Field::from(4)])
|
||||
.unwrap();
|
||||
let computation = Computation::with_witness(program, witness);
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::ir::{Prog, Witness};
|
||||
use crate::ir::{ProgIterator, Statement, Witness};
|
||||
use crate::proof_system::gm17::{ProofPoints, VerificationKey, GM17};
|
||||
use crate::proof_system::libsnark::ffi::{c_free, Buffer, ProofResult, SetupResult};
|
||||
use crate::proof_system::libsnark::{
|
||||
|
@ -39,11 +39,13 @@ extern "C" {
|
|||
}
|
||||
|
||||
impl Backend<Bn128Field, GM17> for Libsnark {
|
||||
fn generate_proof(
|
||||
program: Prog<Bn128Field>,
|
||||
fn generate_proof<I: IntoIterator<Item = Statement<Bn128Field>>>(
|
||||
program: ProgIterator<Bn128Field, I>,
|
||||
witness: Witness<Bn128Field>,
|
||||
proving_key: Vec<u8>,
|
||||
) -> Proof<<GM17 as Scheme<Bn128Field>>::ProofPoints> {
|
||||
let program = program.collect();
|
||||
|
||||
let (public_inputs_arr, public_inputs_length, private_inputs_arr, private_inputs_length) =
|
||||
prepare_generate_proof(program.clone(), witness.clone());
|
||||
|
||||
|
@ -130,9 +132,11 @@ impl Backend<Bn128Field, GM17> for Libsnark {
|
|||
}
|
||||
|
||||
impl NonUniversalBackend<Bn128Field, GM17> for Libsnark {
|
||||
fn setup(
|
||||
program: Prog<Bn128Field>,
|
||||
fn setup<I: IntoIterator<Item = Statement<Bn128Field>>>(
|
||||
program: ProgIterator<Bn128Field, I>,
|
||||
) -> SetupKeypair<<GM17 as Scheme<Bn128Field>>::VerificationKey> {
|
||||
let program = program.collect();
|
||||
|
||||
let (a_arr, b_arr, c_arr, a_vec, b_vec, c_vec, num_constraints, num_variables, num_inputs) =
|
||||
prepare_setup(program);
|
||||
|
||||
|
@ -200,7 +204,7 @@ mod tests {
|
|||
fn verify() {
|
||||
let program: Prog<Bn128Field> = Prog {
|
||||
arguments: vec![FlatParameter::private(FlatVariable::new(0))],
|
||||
returns: vec![FlatVariable::public(0)],
|
||||
return_count: 1,
|
||||
statements: vec![Statement::constraint(
|
||||
FlatVariable::new(0),
|
||||
FlatVariable::public(0),
|
||||
|
@ -211,7 +215,7 @@ mod tests {
|
|||
let interpreter = Interpreter::default();
|
||||
|
||||
let witness = interpreter
|
||||
.execute(&program, &vec![Bn128Field::from(42)])
|
||||
.execute(program.clone(), &vec![Bn128Field::from(42)])
|
||||
.unwrap();
|
||||
|
||||
let proof =
|
||||
|
|
|
@ -230,7 +230,7 @@ pub fn r1cs_program<T: Field>(
|
|||
|
||||
// ~out are added after main's arguments, since we want variables (columns)
|
||||
// in the r1cs to be aligned like "public inputs | private inputs"
|
||||
let main_return_count = prog.returns.len();
|
||||
let main_return_count = prog.returns().len();
|
||||
|
||||
for i in 0..main_return_count {
|
||||
provide_variable_idx(&mut variables, &FlatVariable::public(i));
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::proof_system::libsnark::{
|
|||
};
|
||||
use crate::proof_system::{Backend, G1Affine, G2Affine, NonUniversalBackend, Proof, SetupKeypair};
|
||||
|
||||
use crate::ir::{Prog, Witness};
|
||||
use crate::ir::{ProgIterator, Statement, Witness};
|
||||
use crate::proof_system::libsnark::serialization::{read_g1, read_g2, write_g1, write_g2};
|
||||
use crate::proof_system::pghr13::{ProofPoints, VerificationKey, PGHR13};
|
||||
use crate::proof_system::Scheme;
|
||||
|
@ -42,11 +42,13 @@ extern "C" {
|
|||
}
|
||||
|
||||
impl Backend<Bn128Field, PGHR13> for Libsnark {
|
||||
fn generate_proof(
|
||||
program: Prog<Bn128Field>,
|
||||
fn generate_proof<I: IntoIterator<Item = Statement<Bn128Field>>>(
|
||||
program: ProgIterator<Bn128Field, I>,
|
||||
witness: Witness<Bn128Field>,
|
||||
proving_key: Vec<u8>,
|
||||
) -> Proof<<PGHR13 as Scheme<Bn128Field>>::ProofPoints> {
|
||||
let program = program.collect();
|
||||
|
||||
let (public_inputs_arr, public_inputs_length, private_inputs_arr, private_inputs_length) =
|
||||
prepare_generate_proof(program.clone(), witness.clone());
|
||||
|
||||
|
@ -156,9 +158,11 @@ impl Backend<Bn128Field, PGHR13> for Libsnark {
|
|||
}
|
||||
|
||||
impl NonUniversalBackend<Bn128Field, PGHR13> for Libsnark {
|
||||
fn setup(
|
||||
program: Prog<Bn128Field>,
|
||||
fn setup<I: IntoIterator<Item = Statement<Bn128Field>>>(
|
||||
program: ProgIterator<Bn128Field, I>,
|
||||
) -> SetupKeypair<<PGHR13 as Scheme<Bn128Field>>::VerificationKey> {
|
||||
let program = program.collect();
|
||||
|
||||
let (a_arr, b_arr, c_arr, a_vec, b_vec, c_vec, num_constraints, num_variables, num_inputs) =
|
||||
prepare_setup(program);
|
||||
|
||||
|
@ -230,7 +234,7 @@ mod tests {
|
|||
fn verify() {
|
||||
let program: Prog<Bn128Field> = Prog {
|
||||
arguments: vec![FlatParameter::private(FlatVariable::new(0))],
|
||||
returns: vec![FlatVariable::public(0)],
|
||||
return_count: 1,
|
||||
statements: vec![Statement::constraint(
|
||||
FlatVariable::new(0),
|
||||
FlatVariable::public(0),
|
||||
|
@ -241,7 +245,7 @@ mod tests {
|
|||
let interpreter = Interpreter::default();
|
||||
|
||||
let witness = interpreter
|
||||
.execute(&program, &vec![Bn128Field::from(42)])
|
||||
.execute(program.clone(), &vec![Bn128Field::from(42)])
|
||||
.unwrap();
|
||||
|
||||
let proof =
|
||||
|
|
|
@ -80,8 +80,8 @@ impl ToString for G2Affine {
|
|||
}
|
||||
|
||||
pub trait Backend<T: Field, S: Scheme<T>> {
|
||||
fn generate_proof(
|
||||
program: ir::Prog<T>,
|
||||
fn generate_proof<I: IntoIterator<Item = ir::Statement<T>>>(
|
||||
program: ir::ProgIterator<T, I>,
|
||||
witness: ir::Witness<T>,
|
||||
proving_key: Vec<u8>,
|
||||
) -> Proof<S::ProofPoints>;
|
||||
|
@ -89,14 +89,16 @@ pub trait Backend<T: Field, S: Scheme<T>> {
|
|||
fn verify(vk: S::VerificationKey, proof: Proof<S::ProofPoints>) -> bool;
|
||||
}
|
||||
pub trait NonUniversalBackend<T: Field, S: NonUniversalScheme<T>>: Backend<T, S> {
|
||||
fn setup(program: ir::Prog<T>) -> SetupKeypair<S::VerificationKey>;
|
||||
fn setup<I: IntoIterator<Item = ir::Statement<T>>>(
|
||||
program: ir::ProgIterator<T, I>,
|
||||
) -> SetupKeypair<S::VerificationKey>;
|
||||
}
|
||||
|
||||
pub trait UniversalBackend<T: Field, S: UniversalScheme<T>>: Backend<T, S> {
|
||||
fn universal_setup(size: u32) -> Vec<u8>;
|
||||
|
||||
fn setup(
|
||||
fn setup<I: IntoIterator<Item = ir::Statement<T>>>(
|
||||
srs: Vec<u8>,
|
||||
program: ir::Prog<T>,
|
||||
program: ir::ProgIterator<T, I>,
|
||||
) -> Result<SetupKeypair<S::VerificationKey>, String>;
|
||||
}
|
||||
|
|
|
@ -811,6 +811,7 @@ impl<'ast, T: Field> Checker<'ast, T> {
|
|||
.get(&import.module_id)
|
||||
.unwrap()
|
||||
.functions_iter()
|
||||
.into_iter()
|
||||
.filter(|d| d.key.id == import.symbol_id)
|
||||
.map(|d| DeclarationFunctionKey {
|
||||
module: import.module_id.to_path_buf(),
|
||||
|
@ -1050,6 +1051,7 @@ impl<'ast, T: Field> Checker<'ast, T> {
|
|||
fn check_single_main(module: &TypedModule<T>) -> Result<(), ErrorInner> {
|
||||
match module
|
||||
.functions_iter()
|
||||
.into_iter()
|
||||
.filter(|d| d.key.id == "main")
|
||||
.count()
|
||||
{
|
||||
|
|
|
@ -55,13 +55,6 @@ impl<T: Field> PropagateWithContext<T> for FlatExpression<T> {
|
|||
impl<T: Field> FlatStatement<T> {
|
||||
fn propagate(self, constants: &mut HashMap<FlatVariable, T>) -> Option<FlatStatement<T>> {
|
||||
match self {
|
||||
FlatStatement::Return(list) => Some(FlatStatement::Return(FlatExpressionList {
|
||||
expressions: list
|
||||
.expressions
|
||||
.into_iter()
|
||||
.map(|e| e.propagate(constants))
|
||||
.collect(),
|
||||
})),
|
||||
FlatStatement::Definition(var, expr) => match expr.propagate(constants) {
|
||||
FlatExpression::Number(n) => {
|
||||
constants.insert(var, n);
|
||||
|
@ -101,14 +94,6 @@ impl<T: Field> Propagate<T> for FlatFunction<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Field> FlatProg<T> {
|
||||
pub fn propagate(self) -> FlatProg<T> {
|
||||
let main = self.main.propagate();
|
||||
|
||||
FlatProg { main }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
|
@ -14,7 +14,6 @@ mod propagation;
|
|||
mod reducer;
|
||||
mod struct_concretizer;
|
||||
mod uint_optimizer;
|
||||
mod unconstrained_vars;
|
||||
mod variable_write_remover;
|
||||
mod zir_propagation;
|
||||
|
||||
|
@ -26,10 +25,8 @@ use self::propagation::Propagator;
|
|||
use self::reducer::reduce_program;
|
||||
use self::struct_concretizer::StructConcretizer;
|
||||
use self::uint_optimizer::UintOptimizer;
|
||||
use self::unconstrained_vars::UnconstrainedVariableDetector;
|
||||
use self::variable_write_remover::VariableWriteRemover;
|
||||
use crate::compile::CompileConfig;
|
||||
use crate::ir::Prog;
|
||||
use crate::static_analysis::constant_resolver::ConstantResolver;
|
||||
use crate::static_analysis::zir_propagation::ZirPropagator;
|
||||
use crate::typed_absy::{abi::Abi, TypedProgram};
|
||||
|
@ -37,20 +34,12 @@ use crate::zir::ZirProgram;
|
|||
use std::fmt;
|
||||
use zokrates_field::Field;
|
||||
|
||||
pub trait Analyse {
|
||||
type Error;
|
||||
|
||||
fn analyse(self) -> Result<Self, Self::Error>
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
Reducer(self::reducer::Error),
|
||||
Propagation(self::propagation::Error),
|
||||
ZirPropagation(self::zir_propagation::Error),
|
||||
NonConstantArgument(self::constant_argument_checker::Error),
|
||||
UnconstrainedVariable(self::unconstrained_vars::Error),
|
||||
OutOfBounds(self::out_of_bounds::Error),
|
||||
}
|
||||
|
||||
|
@ -84,12 +73,6 @@ impl From<constant_argument_checker::Error> for Error {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<unconstrained_vars::Error> for Error {
|
||||
fn from(e: unconstrained_vars::Error) -> Self {
|
||||
Error::UnconstrainedVariable(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
|
@ -97,7 +80,6 @@ impl fmt::Display for Error {
|
|||
Error::Propagation(e) => write!(f, "{}", e),
|
||||
Error::ZirPropagation(e) => write!(f, "{}", e),
|
||||
Error::NonConstantArgument(e) => write!(f, "{}", e),
|
||||
Error::UnconstrainedVariable(e) => write!(f, "{}", e),
|
||||
Error::OutOfBounds(e) => write!(f, "{}", e),
|
||||
}
|
||||
}
|
||||
|
@ -176,13 +158,3 @@ impl<'ast, T: Field> TypedProgram<'ast, T> {
|
|||
Ok((zir, abi))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> Analyse for Prog<T> {
|
||||
type Error = Error;
|
||||
|
||||
fn analyse(self) -> Result<Self, Self::Error> {
|
||||
log::debug!("Static analyser: Detect unconstrained zir");
|
||||
UnconstrainedVariableDetector::detect(&self).map_err(Error::from)?;
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,164 +0,0 @@
|
|||
use crate::flat_absy::{FlatParameter, FlatVariable};
|
||||
use crate::ir::visitor::Visitor;
|
||||
use crate::ir::Directive;
|
||||
use crate::ir::Prog;
|
||||
use std::collections::HashSet;
|
||||
use std::fmt;
|
||||
use zokrates_field::Field;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct UnconstrainedVariableDetector {
|
||||
pub(self) variables: HashSet<FlatVariable>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct Error(usize);
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"Found unconstrained variables during IR analysis (found {} occurrence{}). If this is intentional, use the `--allow-unconstrained-variables` flag.",
|
||||
self.0,
|
||||
if self.0 == 1 { "" } else { "s" }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl UnconstrainedVariableDetector {
|
||||
pub fn detect<T: Field>(p: &Prog<T>) -> Result<(), Error> {
|
||||
let mut instance = Self::default();
|
||||
instance.visit_module(p);
|
||||
|
||||
if instance.variables.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error(instance.variables.len()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> Visitor<T> for UnconstrainedVariableDetector {
|
||||
fn visit_argument(&mut self, p: &FlatParameter) {
|
||||
if p.private {
|
||||
self.variables.insert(p.id);
|
||||
}
|
||||
}
|
||||
fn visit_variable(&mut self, v: &FlatVariable) {
|
||||
self.variables.remove(v);
|
||||
}
|
||||
fn visit_directive(&mut self, d: &Directive<T>) {
|
||||
self.variables.extend(d.outputs.iter());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::flat_absy::FlatVariable;
|
||||
use crate::ir::{LinComb, Prog, QuadComb, Statement};
|
||||
use crate::solvers::Solver;
|
||||
use zokrates_field::Bn128Field;
|
||||
|
||||
#[test]
|
||||
fn unconstrained_private_input() {
|
||||
// def main(_0) -> (1):
|
||||
// (1 * ~one) * (42 * ~one) == 1 * ~out_0
|
||||
// return ~out_0
|
||||
|
||||
let _0 = FlatParameter::private(FlatVariable::new(0)); // unused private parameter
|
||||
|
||||
let one = FlatVariable::one();
|
||||
let out_0 = FlatVariable::public(0);
|
||||
|
||||
let p: Prog<Bn128Field> = Prog {
|
||||
arguments: vec![_0],
|
||||
statements: vec![Statement::constraint(
|
||||
QuadComb::from_linear_combinations(
|
||||
LinComb::summand(1, one),
|
||||
LinComb::summand(42, one),
|
||||
),
|
||||
LinComb::summand(1, out_0),
|
||||
)],
|
||||
returns: vec![out_0],
|
||||
};
|
||||
|
||||
let result = UnconstrainedVariableDetector::detect(&p);
|
||||
assert_eq!(
|
||||
result.expect_err("expected an error").to_string(),
|
||||
"Found unconstrained variables during IR analysis (found 1 occurrence). If this is intentional, use the `--allow-unconstrained-variables` flag."
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn constrained_private_input() {
|
||||
// def main(_0) -> (1):
|
||||
// (1 * ~one) * (1 * _0) == 1 * ~out_0
|
||||
// return ~out_0
|
||||
|
||||
let _0 = FlatParameter::private(FlatVariable::new(0));
|
||||
let out_0 = FlatVariable::public(0);
|
||||
|
||||
let p: Prog<Bn128Field> = Prog {
|
||||
arguments: vec![_0],
|
||||
statements: vec![Statement::definition(out_0, LinComb::from(_0.id))],
|
||||
returns: vec![out_0],
|
||||
};
|
||||
|
||||
let result = UnconstrainedVariableDetector::detect(&p);
|
||||
assert_eq!(result, Ok(()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn constrained_directive() {
|
||||
// def main(_0) -> (1):
|
||||
// # _1, _2 = ConditionEq((-42) * ~one + 1 * _0)
|
||||
// ((-42) * ~one + 1 * _0) * (1 * _2) == 1 * _1
|
||||
// (1 * ~one + (-1) * _1) * ((-42) * ~one + 1 * _0) == 0
|
||||
// (1 * ~one) * (1 * ~one + (-1) * _1) == 1 * ~out_0
|
||||
// return ~out_0
|
||||
|
||||
let v_0 = FlatParameter::private(FlatVariable::new(0));
|
||||
let v_1 = FlatVariable::new(1);
|
||||
let v_2 = FlatVariable::new(2);
|
||||
|
||||
let out_0 = FlatVariable::public(0);
|
||||
let one = FlatVariable::one();
|
||||
|
||||
let p: Prog<Bn128Field> = Prog {
|
||||
arguments: vec![v_0],
|
||||
statements: vec![
|
||||
Statement::Directive(Directive {
|
||||
inputs: vec![(LinComb::summand(-42, one) + LinComb::summand(1, v_0.id)).into()],
|
||||
outputs: vec![v_1, v_2],
|
||||
solver: Solver::ConditionEq,
|
||||
}),
|
||||
Statement::constraint(
|
||||
QuadComb::from_linear_combinations(
|
||||
LinComb::summand(-42, one) + LinComb::summand(1, v_0.id),
|
||||
LinComb::summand(1, v_2),
|
||||
),
|
||||
LinComb::summand(1, v_1),
|
||||
),
|
||||
Statement::constraint(
|
||||
QuadComb::from_linear_combinations(
|
||||
LinComb::summand(1, one) + LinComb::summand(-1, v_1),
|
||||
LinComb::summand(-42, one) + LinComb::summand(1, v_0.id),
|
||||
),
|
||||
LinComb::zero(),
|
||||
),
|
||||
Statement::constraint(
|
||||
QuadComb::from_linear_combinations(
|
||||
LinComb::summand(1, one),
|
||||
LinComb::summand(1, one) + LinComb::summand(-1, v_1),
|
||||
),
|
||||
LinComb::summand(1, out_0),
|
||||
),
|
||||
],
|
||||
returns: vec![out_0],
|
||||
};
|
||||
|
||||
let result = UnconstrainedVariableDetector::detect(&p);
|
||||
assert_eq!(result, Ok(()));
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@ extern crate zokrates_core;
|
|||
extern crate zokrates_field;
|
||||
|
||||
use std::io;
|
||||
use typed_arena::Arena;
|
||||
use zokrates_common::Resolver;
|
||||
use zokrates_core::compile::CompileConfig;
|
||||
use zokrates_core::{
|
||||
|
@ -26,11 +27,14 @@ fn lt_field() {
|
|||
// the fact that `2*10000 - 2*5555` has two distinct bit decompositions
|
||||
// we chose the one which is out of range, ie the sum check features an overflow
|
||||
|
||||
let res: CompilationArtifacts<Bn128Field> = compile(
|
||||
let arena = Arena::new();
|
||||
|
||||
let res: CompilationArtifacts<Bn128Field, _> = compile(
|
||||
source,
|
||||
"./path/to/file".into(),
|
||||
None::<&dyn Resolver<io::Error>>,
|
||||
&CompileConfig::default(),
|
||||
CompileConfig::default(),
|
||||
&arena,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
@ -58,11 +62,14 @@ fn lt_uint() {
|
|||
// the fact that `2*10000 - 2*5555` has two distinct bit decompositions
|
||||
// we chose the one which is out of range, ie the sum check features an overflow
|
||||
|
||||
let res: CompilationArtifacts<Bn128Field> = compile(
|
||||
let arena = Arena::new();
|
||||
|
||||
let res: CompilationArtifacts<Bn128Field, _> = compile(
|
||||
source,
|
||||
"./path/to/file".into(),
|
||||
None::<&dyn Resolver<io::Error>>,
|
||||
&CompileConfig::default(),
|
||||
CompileConfig::default(),
|
||||
&arena,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
@ -99,13 +106,16 @@ fn unpack256() {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
let res: CompilationArtifacts<Bn128Field> = compile(
|
||||
let arena = Arena::new();
|
||||
|
||||
let res: CompilationArtifacts<Bn128Field, _> = compile(
|
||||
source,
|
||||
"./path/to/file".into(),
|
||||
Some(&FileSystemResolver::with_stdlib_root(
|
||||
stdlib_path.to_str().unwrap(),
|
||||
)),
|
||||
&CompileConfig::default(),
|
||||
CompileConfig::default(),
|
||||
&arena,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
@ -139,13 +149,16 @@ fn unpack256_unchecked() {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
let res: CompilationArtifacts<Bn128Field> = compile(
|
||||
let arena = Arena::new();
|
||||
|
||||
let res: CompilationArtifacts<Bn128Field, _> = compile(
|
||||
source,
|
||||
"./path/to/file".into(),
|
||||
Some(&FileSystemResolver::with_stdlib_root(
|
||||
stdlib_path.to_str().unwrap(),
|
||||
)),
|
||||
&CompileConfig::default(),
|
||||
CompileConfig::default(),
|
||||
&arena,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ use zokrates_core::proof_system::groth16::G16;
|
|||
fn generate_proof() {
|
||||
let program: Prog<Bn128Field> = Prog {
|
||||
arguments: vec![FlatParameter::public(FlatVariable::new(0))],
|
||||
returns: vec![FlatVariable::new(0)],
|
||||
return_count: 1,
|
||||
statements: vec![Statement::constraint(
|
||||
FlatVariable::new(0),
|
||||
FlatVariable::new(0),
|
||||
|
@ -25,7 +25,7 @@ fn generate_proof() {
|
|||
|
||||
let interpreter = Interpreter::default();
|
||||
let witness = interpreter
|
||||
.execute(&program, &[Bn128Field::from(42)])
|
||||
.execute(program.clone(), &[Bn128Field::from(42)])
|
||||
.unwrap();
|
||||
|
||||
let keypair = <Bellman as NonUniversalBackend<Bn128Field, G16>>::setup(program.clone());
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
"entry_point": "./tests/tests/panics/deep_branch.zok",
|
||||
"curves": ["Bn128"],
|
||||
"config": {
|
||||
"allow_unconstrained_variables": false,
|
||||
"isolate_branches": true
|
||||
},
|
||||
"tests": [
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
"entry_point": "./tests/tests/panics/internal_panic.zok",
|
||||
"curves": ["Bn128"],
|
||||
"config": {
|
||||
"allow_unconstrained_variables": false,
|
||||
"isolate_branches": true
|
||||
},
|
||||
"tests": [
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
{
|
||||
"entry_point": "./tests/tests/panics/panic_isolation.zok",
|
||||
"config": {
|
||||
"allow_unconstrained_variables": false,
|
||||
"isolate_branches": true
|
||||
},
|
||||
"curves": ["Bn128"],
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
{
|
||||
"entry_point": "./tests/tests/panics/panic_isolation.zok",
|
||||
"config": {
|
||||
"allow_unconstrained_variables": false,
|
||||
"isolate_branches": false
|
||||
},
|
||||
"curves": ["Bn128"],
|
||||
|
|
|
@ -54,7 +54,10 @@ impl fmt::Debug for FieldParseError {
|
|||
}
|
||||
|
||||
pub trait Field:
|
||||
From<i32>
|
||||
'static
|
||||
+ Sync
|
||||
+ Send
|
||||
+ From<i32>
|
||||
+ From<u8>
|
||||
+ From<u32>
|
||||
+ From<usize>
|
||||
|
|
19
zokrates_js/Cargo.lock
generated
19
zokrates_js/Cargo.lock
generated
|
@ -701,6 +701,12 @@ version = "0.25.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7"
|
||||
|
||||
[[package]]
|
||||
name = "half"
|
||||
version = "1.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.11.2"
|
||||
|
@ -1215,6 +1221,16 @@ dependencies = [
|
|||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_cbor"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5"
|
||||
dependencies = [
|
||||
"half",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.130"
|
||||
|
@ -1558,7 +1574,6 @@ name = "zokrates_core"
|
|||
version = "0.6.7"
|
||||
dependencies = [
|
||||
"bellman_ce",
|
||||
"bincode",
|
||||
"cfg-if 0.1.10",
|
||||
"csv",
|
||||
"ff_ce 0.9.0",
|
||||
|
@ -1574,6 +1589,7 @@ dependencies = [
|
|||
"reduce",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_cbor",
|
||||
"serde_json",
|
||||
"typed-arena",
|
||||
"zokrates_common",
|
||||
|
@ -1624,6 +1640,7 @@ dependencies = [
|
|||
"js-sys",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"typed-arena",
|
||||
"wasm-bindgen",
|
||||
"zokrates_abi",
|
||||
"zokrates_common",
|
||||
|
|
|
@ -12,6 +12,7 @@ js-sys = "0.3.33"
|
|||
serde = { version = "^1.0.59", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
wasm-bindgen = { version = "0.2.46", features = ["serde-serialize"] }
|
||||
typed-arena = "1.4.1"
|
||||
zokrates_core = { path = "../zokrates_core", features = ["wasm", "bellman"], default-features = false }
|
||||
zokrates_common = { path = "../zokrates_common" }
|
||||
zokrates_field = { path = "../zokrates_field", default-features = false, features = ["bellman"] }
|
||||
|
|
1
zokrates_js/index.d.ts
vendored
1
zokrates_js/index.d.ts
vendored
|
@ -10,7 +10,6 @@ declare module 'zokrates-js' {
|
|||
export type ResolveCallback = (location: string, path: string) => ResolverResult;
|
||||
|
||||
export interface CompileConfig {
|
||||
allow_unconstrained_variables?: boolean,
|
||||
isolate_branches?: boolean
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ use serde::{Deserialize, Serialize};
|
|||
use serde_json::to_string_pretty;
|
||||
use std::io::Cursor;
|
||||
use std::path::PathBuf;
|
||||
use typed_arena::Arena;
|
||||
use wasm_bindgen::prelude::*;
|
||||
use zokrates_abi::{parse_strict, Decode, Encode, Inputs};
|
||||
use zokrates_common::Resolver;
|
||||
|
@ -41,13 +42,15 @@ pub struct ComputationResult {
|
|||
fn deserialize_program(value: &[u8]) -> Result<ir::Prog<Bn128Field>, JsValue> {
|
||||
let prog = ir::ProgEnum::deserialize(value).map_err(|err| JsValue::from_str(&err))?;
|
||||
match prog {
|
||||
ir::ProgEnum::Bn128Program(p) => Ok(p),
|
||||
ir::ProgEnum::Bn128Program(p) => Ok(p.collect()),
|
||||
_ => Err(JsValue::from_str("Unsupported binary")),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_program(program: &ir::Prog<Bn128Field>) -> Vec<u8> {
|
||||
fn serialize_program<I: IntoIterator<Item = ir::Statement<Bn128Field>>>(
|
||||
program: ir::ProgIterator<Bn128Field, I>,
|
||||
) -> Vec<u8> {
|
||||
let mut buffer = Cursor::new(vec![]);
|
||||
program.serialize(&mut buffer);
|
||||
buffer.into_inner()
|
||||
|
@ -106,11 +109,15 @@ pub fn compile(
|
|||
let config: CompileConfig = config.into_serde().unwrap_or_default();
|
||||
|
||||
let fmt_error = |e: &CompileError| format!("{}:{}", e.file().display(), e.value());
|
||||
let artifacts: CompilationArtifacts<Bn128Field> = core_compile(
|
||||
|
||||
let arena = Arena::new();
|
||||
|
||||
let artifacts: CompilationArtifacts<Bn128Field, _> = core_compile(
|
||||
source.as_string().unwrap(),
|
||||
PathBuf::from(location.as_string().unwrap()),
|
||||
Some(&resolver),
|
||||
&config,
|
||||
config,
|
||||
&arena,
|
||||
)
|
||||
.map_err(|ce| {
|
||||
JsValue::from_str(
|
||||
|
@ -123,8 +130,8 @@ pub fn compile(
|
|||
})?;
|
||||
|
||||
let result = CompilationResult {
|
||||
program: serialize_program(artifacts.prog()),
|
||||
abi: to_string_pretty(artifacts.abi()).unwrap(),
|
||||
program: serialize_program(artifacts.prog()),
|
||||
};
|
||||
|
||||
Ok(JsValue::from_serde(&result).unwrap())
|
||||
|
@ -146,7 +153,7 @@ pub fn compute_witness(program: &[u8], abi: JsValue, args: JsValue) -> Result<Js
|
|||
let interpreter = ir::Interpreter::default();
|
||||
|
||||
let witness = interpreter
|
||||
.execute(&program_flattened, &inputs.encode())
|
||||
.execute(program_flattened, &inputs.encode())
|
||||
.map_err(|err| JsValue::from_str(&format!("Execution failed: {}", err)))?;
|
||||
|
||||
let return_values: serde_json::Value =
|
||||
|
|
|
@ -1318,7 +1318,7 @@ mod tests {
|
|||
span: Span::new(source, 76, 77).unwrap()
|
||||
}
|
||||
))),
|
||||
Span::new(&source, 59, 80).unwrap()
|
||||
Span::new(source, 59, 80).unwrap()
|
||||
)],
|
||||
span: Span::new(source, 52, 80).unwrap(),
|
||||
})],
|
||||
|
|
|
@ -12,5 +12,6 @@ zokrates_abi = { version = "0.1", path = "../zokrates_abi" }
|
|||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
serde_json = "1.0"
|
||||
typed-arena = "1.4.1"
|
||||
|
||||
[lib]
|
||||
|
|
|
@ -149,10 +149,14 @@ fn compile_and_run<T: Field>(t: Tests) {
|
|||
let stdlib = std::fs::canonicalize("../zokrates_stdlib/stdlib").unwrap();
|
||||
let resolver = FileSystemResolver::with_stdlib_root(stdlib.to_str().unwrap());
|
||||
|
||||
let artifacts = compile::<T, _>(code, entry_point.clone(), Some(&resolver), &config).unwrap();
|
||||
let arena = typed_arena::Arena::new();
|
||||
|
||||
let bin = artifacts.prog();
|
||||
let abi = artifacts.abi();
|
||||
let artifacts =
|
||||
compile::<T, _>(code, entry_point.clone(), Some(&resolver), config, &arena).unwrap();
|
||||
|
||||
let (bin, abi) = artifacts.into_inner();
|
||||
// here we do want the program in memory because we want to run many tests on it
|
||||
let bin = bin.collect();
|
||||
|
||||
if let Some(target_count) = t.max_constraint_count {
|
||||
let count = bin.constraint_count();
|
||||
|
@ -184,7 +188,7 @@ fn compile_and_run<T: Field>(t: Tests) {
|
|||
.unwrap()
|
||||
};
|
||||
|
||||
let output = interpreter.execute(bin, &input);
|
||||
let output = interpreter.execute(bin.clone(), &input);
|
||||
|
||||
if let Err(e) = compare(output, test.output) {
|
||||
let mut code = File::open(&entry_point).unwrap();
|
||||
|
|
Loading…
Reference in a new issue