1
0
Fork 0
mirror of synced 2025-09-24 04:40:05 +00:00

Merge branch 'develop' of github.com:Zokrates/ZoKrates into u8-playground

This commit is contained in:
schaeff 2020-07-03 18:26:00 +02:00
commit 959e7e5991
31 changed files with 1116 additions and 960 deletions

View file

@ -3,6 +3,6 @@
dir=$1
for file in $dir/*.cpp $dir/*.hpp; do
for file in $dir/*.cpp $dir/*.hpp $dir/*.tcc; do
clang-format -i -style=WebKit -verbose $file
done

View file

@ -5,19 +5,27 @@
// @date 2017
mod constants;
mod helpers;
use constants::*;
use helpers::*;
use clap::{App, AppSettings, Arg, ArgMatches, SubCommand};
use serde_json::{from_reader, to_writer_pretty, Value};
use std::convert::TryFrom;
use std::env;
use std::fs::File;
use std::io::{stdin, BufReader, BufWriter, Read, Write};
use std::path::{Path, PathBuf};
use std::string::String;
use zokrates_abi::Encode;
use zokrates_core::compile::{check, compile, CompilationArtifacts, CompileError};
use zokrates_core::compile::{check, compile, CompilationArtifacts, CompileConfig, CompileError};
use zokrates_core::ir::{self, ProgEnum};
use zokrates_core::proof_system::bellman::groth16::G16;
#[cfg(feature = "libsnark")]
use zokrates_core::proof_system::libsnark::gm17::GM17;
#[cfg(feature = "libsnark")]
use zokrates_core::proof_system::libsnark::pghr13::PGHR13;
use zokrates_core::proof_system::*;
use zokrates_core::typed_absy::abi::Abi;
use zokrates_core::typed_absy::{types::Signature, Type};
@ -62,12 +70,13 @@ fn cli_generate_proof<T: Field, P: ProofSystem<T>>(
let proof = P::generate_proof(program, witness, pk);
let mut proof_file = File::create(proof_path).unwrap();
proof_file
.write(proof.as_ref())
.map_err(|why| format!("Couldn't write to {}: {}", proof_path.display(), why))?;
let proof = serde_json::to_string_pretty(&proof).unwrap();
println!("Proof:\n{}", format!("{}", proof));
proof_file
.write(proof.as_bytes())
.map_err(|why| format!("Couldn't write to {}: {}", proof_path.display(), why))?;
Ok(())
}
@ -80,14 +89,13 @@ fn cli_export_verifier<T: Field, P: ProofSystem<T>>(
let input_path = Path::new(sub_matches.value_of("input").unwrap());
let input_file = File::open(&input_path)
.map_err(|why| format!("Couldn't open {}: {}", input_path.display(), why))?;
let mut reader = BufReader::new(input_file);
let reader = BufReader::new(input_file);
let mut vk = String::new();
reader
.read_to_string(&mut vk)
.map_err(|why| format!("Couldn't read {}: {}", input_path.display(), why))?;
let vk = serde_json::from_reader(reader)
.map_err(|why| format!("Couldn't deserialize verifying key: {}", why))?;
let abi = SolidityAbi::from(sub_matches.value_of("solidity-abi").unwrap())?;
let verifier = P::export_solidity_verifier(vk, abi);
//write output file
@ -100,6 +108,7 @@ fn cli_export_verifier<T: Field, P: ProofSystem<T>>(
writer
.write_all(&verifier.as_bytes())
.map_err(|_| "Failed writing output to file.".to_string())?;
println!("Finished exporting verifier.");
Ok(())
}
@ -126,7 +135,11 @@ fn cli_setup<T: Field, P: ProofSystem<T>>(
let mut vk_file = File::create(vk_path)
.map_err(|why| format!("couldn't create {}: {}", vk_path.display(), why))?;
vk_file
.write(keypair.vk.as_ref())
.write(
serde_json::to_string_pretty(&keypair.vk)
.unwrap()
.as_bytes(),
)
.map_err(|why| format!("couldn't write to {}: {}", vk_path.display(), why))?;
// write proving key
@ -261,6 +274,8 @@ fn cli_compile<T: Field>(sub_matches: &ArgMatches) -> Result<(), String> {
let hr_output_path = bin_output_path.to_path_buf().with_extension("ztf");
let is_release = sub_matches.occurrences_of("release") > 0;
let file = File::open(path.clone())
.map_err(|why| format!("Couldn't open input file {}: {}", path.display(), why))?;
@ -269,21 +284,21 @@ fn cli_compile<T: Field>(sub_matches: &ArgMatches) -> Result<(), String> {
reader.read_to_string(&mut source).unwrap();
let fmt_error = |e: &CompileError| {
let file = e.file().canonicalize().unwrap();
format!(
"{}:{}",
e.file()
.canonicalize()
.unwrap()
.strip_prefix(std::env::current_dir().unwrap())
.unwrap()
file.strip_prefix(std::env::current_dir().unwrap())
.unwrap_or(file.as_path())
.display(),
e.value()
)
};
let compilation_config = CompileConfig::default().with_is_release(is_release);
let resolver = FileSystemResolver::new();
let artifacts: CompilationArtifacts<T> =
compile(source, path, Some(&resolver)).map_err(|e| {
compile(source, path, Some(&resolver), &compilation_config).map_err(|e| {
format!(
"Compilation failed:\n\n{}",
e.0.iter()
@ -356,13 +371,11 @@ fn cli_check<T: Field>(sub_matches: &ArgMatches) -> Result<(), String> {
reader.read_to_string(&mut source).unwrap();
let fmt_error = |e: &CompileError| {
let file = e.file().canonicalize().unwrap();
format!(
"{}:{}",
e.file()
.canonicalize()
.unwrap()
.strip_prefix(std::env::current_dir().unwrap())
.unwrap()
file.strip_prefix(std::env::current_dir().unwrap())
.unwrap_or(file.as_path())
.display(),
e.value()
)
@ -386,12 +399,20 @@ fn cli_check<T: Field>(sub_matches: &ArgMatches) -> Result<(), String> {
fn cli_verify<T: Field, P: ProofSystem<T>>(sub_matches: &ArgMatches) -> Result<(), String> {
let vk_path = Path::new(sub_matches.value_of("verification-key-path").unwrap());
let vk = std::fs::read_to_string(vk_path)
.map_err(|why| format!("Couldn't read {}: {}", vk_path.display(), why))?;
let vk_file = File::open(&vk_path)
.map_err(|why| format!("Couldn't open {}: {}", vk_path.display(), why))?;
let vk_reader = BufReader::new(vk_file);
let vk = serde_json::from_reader(vk_reader)
.map_err(|why| format!("Couldn't deserialize verification key: {}", why))?;
let proof_path = Path::new(sub_matches.value_of("proof-path").unwrap());
let proof = std::fs::read_to_string(proof_path)
.map_err(|why| format!("Couldn't read {}: {}", proof_path.display(), why))?;
let proof_file = File::open(&proof_path)
.map_err(|why| format!("Couldn't open {}: {}", proof_path.display(), why))?;
let proof_reader = BufReader::new(proof_file);
let proof = serde_json::from_reader(proof_reader)
.map_err(|why| format!("Couldn't deserialize proof: {}", why))?;
println!("Performing verification...");
println!(
@ -414,6 +435,7 @@ fn cli() -> Result<(), String> {
const WITNESS_DEFAULT_PATH: &str = "witness";
const JSON_PROOF_PATH: &str = "proof.json";
let default_curve = env::var("ZOKRATES_CURVE").unwrap_or(constants::BN128.into());
let default_backend = env::var("ZOKRATES_BACKEND").unwrap_or(constants::BELLMAN.into());
let default_scheme = env::var("ZOKRATES_PROVING_SCHEME").unwrap_or(constants::G16.into());
let default_solidity_abi = "v1";
@ -460,6 +482,10 @@ fn cli() -> Result<(), String> {
.long("light")
.help("Skip logs and human readable output")
.required(false)
).arg(Arg::with_name("release")
.long("release")
.help("Apply release optimisations to minimise constraint count. This increases compilation time.")
.required(false)
)
)
.subcommand(SubCommand::with_name("check")
@ -507,11 +533,18 @@ fn cli() -> Result<(), String> {
.takes_value(true)
.required(false)
.default_value(VERIFICATION_KEY_DEFAULT_PATH)
).arg(Arg::with_name("backend")
.short("b")
.long("backend")
.help("Backend to use")
.takes_value(true)
.required(false)
.possible_values(BACKENDS)
.default_value(&default_backend)
).arg(Arg::with_name("proving-scheme")
.short("s")
.long("proving-scheme")
.help("Proving scheme to use in the setup")
.value_name("FILE")
.takes_value(true)
.required(false)
.possible_values(SCHEMES)
@ -548,6 +581,14 @@ fn cli() -> Result<(), String> {
.required(false)
.possible_values(CURVES)
.default_value(&default_curve)
).arg(Arg::with_name("backend")
.short("b")
.long("backend")
.help("Backend to use")
.takes_value(true)
.required(false)
.possible_values(BACKENDS)
.default_value(&default_backend)
).arg(Arg::with_name("proving-scheme")
.short("s")
.long("proving-scheme")
@ -649,6 +690,14 @@ fn cli() -> Result<(), String> {
.takes_value(true)
.required(false)
.default_value(FLATTENED_CODE_DEFAULT_PATH)
).arg(Arg::with_name("backend")
.short("b")
.long("backend")
.help("Backend to use")
.takes_value(true)
.required(false)
.possible_values(BACKENDS)
.default_value(&default_backend)
).arg(Arg::with_name("proving-scheme")
.short("s")
.long("proving-scheme")
@ -698,6 +747,14 @@ fn cli() -> Result<(), String> {
.takes_value(true)
.required(false)
.default_value(VERIFICATION_KEY_DEFAULT_PATH)
).arg(Arg::with_name("backend")
.short("b")
.long("backend")
.help("Backend to use")
.takes_value(true)
.required(false)
.possible_values(BACKENDS)
.default_value(&default_backend)
).arg(Arg::with_name("proving-scheme")
.short("s")
.long("proving-scheme")
@ -720,12 +777,10 @@ fn cli() -> Result<(), String> {
match matches.subcommand() {
("compile", Some(sub_matches)) => {
let curve = sub_matches.value_of("curve").unwrap();
let curve = Curve::try_from(sub_matches.value_of("curve").unwrap())?;
match curve {
constants::BN128 => cli_compile::<Bn128Field>(sub_matches)?,
constants::BLS12_381 => cli_compile::<Bls12Field>(sub_matches)?,
_ => unreachable!(),
Curve::Bn128 => cli_compile::<Bn128Field>(sub_matches)?,
Curve::Bls12 => cli_compile::<Bls12Field>(sub_matches)?,
}
}
("check", Some(sub_matches)) => {
@ -738,8 +793,6 @@ fn cli() -> Result<(), String> {
}
}
("compute-witness", Some(sub_matches)) => {
println!("Computing witness...");
// read compiled program
let path = Path::new(sub_matches.value_of("input").unwrap());
let file = File::open(&path)
@ -753,90 +806,106 @@ fn cli() -> Result<(), String> {
}
}
("setup", Some(sub_matches)) => {
let proof_system = sub_matches.value_of("proving-scheme").unwrap();
// read compiled program
let path = Path::new(sub_matches.value_of("input").unwrap());
let file = File::open(&path)
.map_err(|why| format!("Couldn't open {}: {}", path.display(), why))?;
let mut reader = BufReader::new(file);
let prog = ProgEnum::deserialize(&mut reader)?;
match proof_system {
constants::G16 => match prog {
ProgEnum::Bn128Program(p) => cli_setup::<_, G16>(p, sub_matches)?,
ProgEnum::Bls12Program(p) => cli_setup::<_, G16>(p, sub_matches)?,
let dimensions = Dimensions::try_from((
sub_matches.value_of("backend").unwrap(),
match prog {
ProgEnum::Bn128Program(_) => constants::BN128,
ProgEnum::Bls12Program(_) => constants::BLS12_381,
},
sub_matches.value_of("proving-scheme").unwrap(),
))?;
match dimensions {
Dimensions(Backend::Bellman, _, ProvingScheme::G16) => match prog {
ProgEnum::Bn128Program(p) => cli_setup::<_, G16>(p, sub_matches),
ProgEnum::Bls12Program(p) => cli_setup::<_, G16>(p, sub_matches),
},
#[cfg(feature = "libsnark")]
constants::PGHR13 => match prog {
ProgEnum::Bn128Program(p) => cli_setup::<_, PGHR13>(p, sub_matches)?,
_ => unimplemented!(),
Dimensions(Backend::Libsnark, Curve::Bn128, ProvingScheme::GM17) => match prog {
ProgEnum::Bn128Program(p) => cli_setup::<_, GM17>(p, sub_matches),
_ => unreachable!(),
},
#[cfg(feature = "libsnark")]
constants::GM17 => match prog {
ProgEnum::Bn128Program(p) => cli_setup::<_, GM17>(p, sub_matches)?,
_ => unimplemented!(),
Dimensions(Backend::Libsnark, Curve::Bn128, ProvingScheme::PGHR13) => match prog {
ProgEnum::Bn128Program(p) => cli_setup::<_, PGHR13>(p, sub_matches),
_ => unreachable!(),
},
#[cfg(feature = "libsnark")]
_ => unreachable!(),
}
}?
}
("export-verifier", Some(sub_matches)) => {
let curve = sub_matches.value_of("curve").unwrap();
let proof_system = sub_matches.value_of("proving-scheme").unwrap();
let dimensions = Dimensions::try_from((
sub_matches.value_of("backend").unwrap(),
sub_matches.value_of("curve").unwrap(),
sub_matches.value_of("proving-scheme").unwrap(),
))?;
match proof_system {
constants::G16 => match curve {
constants::BN128 => cli_export_verifier::<Bn128Field, G16>(sub_matches)?,
constants::BLS12_381 => cli_export_verifier::<Bls12Field, G16>(sub_matches)?,
_ => unimplemented!(),
},
match dimensions {
Dimensions(Backend::Bellman, Curve::Bn128, ProvingScheme::G16) => {
cli_export_verifier::<Bn128Field, G16>(sub_matches)
}
Dimensions(Backend::Bellman, Curve::Bls12, ProvingScheme::G16) => {
cli_export_verifier::<Bls12Field, G16>(sub_matches)
}
#[cfg(feature = "libsnark")]
constants::PGHR13 => match curve {
constants::BN128 => cli_export_verifier::<Bn128Field, PGHR13>(sub_matches)?,
_ => unimplemented!(),
},
Dimensions(Backend::Libsnark, Curve::Bn128, ProvingScheme::GM17) => {
cli_export_verifier::<Bn128Field, GM17>(sub_matches)
}
#[cfg(feature = "libsnark")]
Dimensions(Backend::Libsnark, Curve::Bn128, ProvingScheme::PGHR13) => {
cli_export_verifier::<Bn128Field, PGHR13>(sub_matches)
}
#[cfg(feature = "libsnark")]
constants::GM17 => match curve {
constants::BN128 => cli_export_verifier::<Bn128Field, GM17>(sub_matches)?,
_ => unimplemented!(),
},
_ => unreachable!(),
}
}?
}
("generate-proof", Some(sub_matches)) => {
let proof_system = sub_matches.value_of("proving-scheme").unwrap();
let program_path = Path::new(sub_matches.value_of("input").unwrap());
let program_file = File::open(&program_path)
.map_err(|why| format!("Couldn't open {}: {}", program_path.display(), why))?;
let mut reader = BufReader::new(program_file);
let prog = ProgEnum::deserialize(&mut reader)?;
match proof_system {
constants::G16 => match prog {
ProgEnum::Bn128Program(p) => cli_generate_proof::<_, G16>(p, sub_matches)?,
ProgEnum::Bls12Program(p) => cli_generate_proof::<_, G16>(p, sub_matches)?,
let dimensions = Dimensions::try_from((
sub_matches.value_of("backend").unwrap(),
match prog {
ProgEnum::Bn128Program(_) => constants::BN128,
ProgEnum::Bls12Program(_) => constants::BLS12_381,
},
sub_matches.value_of("proving-scheme").unwrap(),
))?;
match dimensions {
Dimensions(Backend::Bellman, _, ProvingScheme::G16) => match prog {
ProgEnum::Bn128Program(p) => cli_generate_proof::<_, G16>(p, sub_matches),
ProgEnum::Bls12Program(p) => cli_generate_proof::<_, G16>(p, sub_matches),
},
#[cfg(feature = "libsnark")]
constants::PGHR13 => match prog {
ProgEnum::Bn128Program(p) => cli_generate_proof::<_, PGHR13>(p, sub_matches)?,
_ => unimplemented!(),
Dimensions(Backend::Libsnark, Curve::Bn128, ProvingScheme::GM17) => match prog {
ProgEnum::Bn128Program(p) => cli_generate_proof::<_, GM17>(p, sub_matches),
_ => unreachable!(),
},
#[cfg(feature = "libsnark")]
constants::GM17 => match prog {
ProgEnum::Bn128Program(p) => cli_generate_proof::<_, GM17>(p, sub_matches)?,
_ => unimplemented!(),
Dimensions(Backend::Libsnark, Curve::Bn128, ProvingScheme::PGHR13) => match prog {
ProgEnum::Bn128Program(p) => cli_generate_proof::<_, PGHR13>(p, sub_matches),
_ => unreachable!(),
},
#[cfg(feature = "libsnark")]
_ => unreachable!(),
}
}?
}
("print-proof", Some(sub_matches)) => {
let format = sub_matches.value_of("format").unwrap();
let path = Path::new(sub_matches.value_of("proof-path").unwrap());
let file = File::open(&path)
@ -872,27 +941,30 @@ fn cli() -> Result<(), String> {
}
}
("verify", Some(sub_matches)) => {
let curve = sub_matches.value_of("curve").unwrap();
let proof_system = sub_matches.value_of("proving-scheme").unwrap();
let dimensions = Dimensions::try_from((
sub_matches.value_of("backend").unwrap(),
sub_matches.value_of("curve").unwrap(),
sub_matches.value_of("proving-scheme").unwrap(),
))?;
match proof_system {
constants::G16 => match curve {
constants::BN128 => cli_verify::<Bn128Field, G16>(sub_matches)?,
constants::BLS12_381 => cli_verify::<Bls12Field, G16>(sub_matches)?,
_ => unimplemented!(),
},
match dimensions {
Dimensions(Backend::Bellman, Curve::Bn128, ProvingScheme::G16) => {
cli_verify::<Bn128Field, G16>(sub_matches)
}
Dimensions(Backend::Bellman, Curve::Bls12, ProvingScheme::G16) => {
cli_verify::<Bls12Field, G16>(sub_matches)
}
#[cfg(feature = "libsnark")]
constants::PGHR13 => match curve {
constants::BN128 => cli_verify::<Bn128Field, PGHR13>(sub_matches)?,
_ => unimplemented!(),
},
Dimensions(Backend::Libsnark, Curve::Bn128, ProvingScheme::GM17) => {
cli_verify::<Bn128Field, GM17>(sub_matches)
}
#[cfg(feature = "libsnark")]
Dimensions(Backend::Libsnark, Curve::Bn128, ProvingScheme::PGHR13) => {
cli_verify::<Bn128Field, PGHR13>(sub_matches)
}
#[cfg(feature = "libsnark")]
constants::GM17 => match curve {
constants::BN128 => cli_verify::<Bn128Field, GM17>(sub_matches)?,
_ => unimplemented!(),
},
_ => unreachable!(),
}
}?
}
_ => unreachable!(),
}
@ -934,7 +1006,7 @@ mod tests {
let resolver = FileSystemResolver::new();
let _: CompilationArtifacts<Bn128Field> =
compile(source, path, Some(&resolver)).unwrap();
compile(source, path, Some(&resolver), &CompileConfig::default()).unwrap();
}
}
@ -956,7 +1028,7 @@ mod tests {
let resolver = FileSystemResolver::new();
let artifacts: CompilationArtifacts<Bn128Field> =
compile(source, path, Some(&resolver)).unwrap();
compile(source, path, Some(&resolver), &CompileConfig::default()).unwrap();
let interpreter = ir::Interpreter::default();
@ -985,7 +1057,7 @@ mod tests {
let resolver = FileSystemResolver::new();
let artifacts: CompilationArtifacts<Bn128Field> =
compile(source, path, Some(&resolver)).unwrap();
compile(source, path, Some(&resolver), &CompileConfig::default()).unwrap();
let interpreter = ir::Interpreter::default();

View file

@ -1,3 +1,11 @@
pub const BELLMAN: &str = "bellman";
#[cfg(feature = "libsnark")]
pub const LIBSNARK: &str = "libsnark";
#[cfg(feature = "libsnark")]
pub const BACKENDS: &[&str] = &[BELLMAN, LIBSNARK];
#[cfg(not(feature = "libsnark"))]
pub const BACKENDS: &[&str] = &[BELLMAN];
pub const BN128: &str = "bn128";
pub const BLS12_381: &str = "bls12_381";
pub const CURVES: &[&str] = &[BN128, BLS12_381];

View file

@ -0,0 +1,96 @@
use core::convert::TryFrom;
use crate::constants::*;
pub enum Curve {
Bn128,
Bls12,
}
pub enum Backend {
Bellman,
#[cfg(feature = "libsnark")]
Libsnark,
}
pub enum ProvingScheme {
G16,
#[cfg(feature = "libsnark")]
GM17,
#[cfg(feature = "libsnark")]
PGHR13,
}
impl TryFrom<&str> for Curve {
type Error = String;
fn try_from(s: &str) -> Result<Self, Self::Error> {
match s {
BN128 => Ok(Curve::Bn128),
BLS12_381 => Ok(Curve::Bls12),
_ => Err(format!("Unknown curve {}", s)),
}
}
}
impl TryFrom<&str> for Backend {
type Error = String;
fn try_from(s: &str) -> Result<Self, Self::Error> {
match s {
BELLMAN => Ok(Backend::Bellman),
#[cfg(feature = "libsnark")]
LIBSNARK => Ok(Backend::Libsnark),
_ => Err(format!("Unknown backend {}", s)),
}
}
}
impl TryFrom<&str> for ProvingScheme {
type Error = String;
fn try_from(s: &str) -> Result<Self, Self::Error> {
match s {
G16 => Ok(ProvingScheme::G16),
#[cfg(feature = "libsnark")]
GM17 => Ok(ProvingScheme::GM17),
#[cfg(feature = "libsnark")]
PGHR13 => Ok(ProvingScheme::PGHR13),
_ => Err(format!("Unknown proving scheme {}", s)),
}
}
}
pub struct Dimensions(pub Backend, pub Curve, pub ProvingScheme);
impl TryFrom<(&str, &str, &str)> for Dimensions {
type Error = String;
fn try_from(s: (&str, &str, &str)) -> Result<Dimensions, Self::Error> {
let backend = Backend::try_from(s.0)?;
let curve = Curve::try_from(s.1)?;
let proving_scheme = ProvingScheme::try_from(s.2)?;
match (&backend, &curve, &proving_scheme) {
(Backend::Bellman, Curve::Bn128, ProvingScheme::G16) => {
Ok(Dimensions(backend, curve, proving_scheme))
}
(Backend::Bellman, Curve::Bls12, ProvingScheme::G16) => {
Ok(Dimensions(backend, curve, proving_scheme))
}
#[cfg(feature = "libsnark")]
(Backend::Libsnark, Curve::Bn128, ProvingScheme::GM17) => {
Ok(Dimensions(backend, curve, proving_scheme))
}
#[cfg(feature = "libsnark")]
(Backend::Libsnark, Curve::Bn128, ProvingScheme::PGHR13) => {
Ok(Dimensions(backend, curve, proving_scheme))
}
#[cfg(feature = "libsnark")]
_ => Err(format!(
"Unsupported combination of dimensions (backend: {}, curve: {}, proving scheme: {})",
s.0, s.1, s.2
)),
}
}
}

View file

@ -14,6 +14,17 @@ mod integration {
use zokrates_abi::{parse_strict, Encode};
use zokrates_core::typed_absy::abi::Abi;
macro_rules! map(
{
$($key:expr => $value:expr),+ } => {
{
let mut m = ::std::collections::HashMap::new();
$(m.insert($key, $value);)+
m
}
};
);
#[test]
#[ignore]
fn test_compile_and_witness_dir() {
@ -194,72 +205,84 @@ mod integration {
}
#[cfg(feature = "libsnark")]
let schemes = ["pghr13", "gm17", "g16"];
let backends = map! {
"bellman" => ["g16"],
"libsnark" => ["gm17", "pghr13"]
};
#[cfg(not(feature = "libsnark"))]
let schemes = ["g16"];
let backends = map! {"bellman" => ["g16"]};
for scheme in &schemes {
// SETUP
assert_cli::Assert::command(&[
"../target/release/zokrates",
"setup",
"-i",
flattened_path.to_str().unwrap(),
"-p",
proving_key_path.to_str().unwrap(),
"-v",
verification_key_path.to_str().unwrap(),
"--proving-scheme",
scheme,
])
.succeeds()
.unwrap();
for (backend, schemes) in backends {
for scheme in &schemes {
// SETUP
assert_cli::Assert::command(&[
"../target/release/zokrates",
"setup",
"-i",
flattened_path.to_str().unwrap(),
"-p",
proving_key_path.to_str().unwrap(),
"-v",
verification_key_path.to_str().unwrap(),
"--backend",
backend,
"--proving-scheme",
scheme,
])
.succeeds()
.unwrap();
// EXPORT-VERIFIER
assert_cli::Assert::command(&[
"../target/release/zokrates",
"export-verifier",
"-i",
verification_key_path.to_str().unwrap(),
"-o",
verification_contract_path.to_str().unwrap(),
"--proving-scheme",
scheme,
])
.succeeds()
.unwrap();
// EXPORT-VERIFIER
assert_cli::Assert::command(&[
"../target/release/zokrates",
"export-verifier",
"-i",
verification_key_path.to_str().unwrap(),
"-o",
verification_contract_path.to_str().unwrap(),
"--backend",
backend,
"--proving-scheme",
scheme,
])
.succeeds()
.unwrap();
// GENERATE-PROOF
assert_cli::Assert::command(&[
"../target/release/zokrates",
"generate-proof",
"-i",
flattened_path.to_str().unwrap(),
"-w",
witness_path.to_str().unwrap(),
"-p",
proving_key_path.to_str().unwrap(),
"--proving-scheme",
scheme,
"-j",
proof_path.to_str().unwrap(),
])
.succeeds()
.unwrap();
// GENERATE-PROOF
assert_cli::Assert::command(&[
"../target/release/zokrates",
"generate-proof",
"-i",
flattened_path.to_str().unwrap(),
"-w",
witness_path.to_str().unwrap(),
"-p",
proving_key_path.to_str().unwrap(),
"--backend",
backend,
"--proving-scheme",
scheme,
"-j",
proof_path.to_str().unwrap(),
])
.succeeds()
.unwrap();
// TEST VERIFIER
// TEST VERIFIER
assert_cli::Assert::command(&[
"node",
"test.js",
verification_contract_path.to_str().unwrap(),
proof_path.to_str().unwrap(),
scheme,
"v1",
])
.current_dir(concat!(env!("OUT_DIR"), "/contract"))
.succeeds()
.unwrap();
assert_cli::Assert::command(&[
"node",
"test.js",
verification_contract_path.to_str().unwrap(),
proof_path.to_str().unwrap(),
scheme,
"v1",
])
.current_dir(concat!(env!("OUT_DIR"), "/contract"))
.succeeds()
.unwrap();
}
}
}
}

View file

@ -56,7 +56,6 @@ fn main() {
.include(libsnark_source_path.join("depends/libfqfft"))
.define("CURVE_ALT_BN128", None)
.file("lib/ffi.cpp")
.file("lib/util.cpp")
.file("lib/gm17.cpp")
.file("lib/pghr13.cpp")
.compile("libsnark_wrapper.a");

View file

@ -6,7 +6,7 @@
*/
#include "gm17.hpp"
#include "util.hpp"
#include <cassert>
#include <sstream>
#include <string>
@ -17,203 +17,173 @@
// contains required interfaces and types (keypair, proof, generator, prover, verifier)
#include <libsnark/zk_proof_systems/ppzksnark/r1cs_se_ppzksnark/r1cs_se_ppzksnark.hpp>
typedef long integer_coeff_t;
using namespace libsnark;
using std::cout;
using std::endl;
#include "util.tcc"
namespace gm17 {
r1cs_se_ppzksnark_constraint_system<libff::alt_bn128_pp> createConstraintSystem(const uint8_t* a, const uint8_t* b, const uint8_t* c, int32_t a_len, int32_t b_len, int32_t c_len, int32_t constraints, int32_t variables, int32_t inputs)
{
r1cs_se_ppzksnark_constraint_system<libff::alt_bn128_pp> cs;
cs.primary_input_size = inputs;
cs.auxiliary_input_size = variables - inputs - 1; // ~one not included
cout << "num variables: " << variables << endl;
cout << "num constraints: " << constraints << endl;
cout << "num inputs: " << inputs << endl;
struct VariableValueMapping {
int constraint_id;
int variable_id;
uint8_t variable_value[32];
};
const VariableValueMapping* a_vvmap = (VariableValueMapping*)a;
const VariableValueMapping* b_vvmap = (VariableValueMapping*)b;
const VariableValueMapping* c_vvmap = (VariableValueMapping*)c;
int a_id = 0;
int b_id = 0;
int c_id = 0;
// initialize curve parameters
libff::alt_bn128_pp::init_public_params();
for (int row = 0; row < constraints; row++) {
linear_combination<libff::Fr<libff::alt_bn128_pp>> lin_comb_a, lin_comb_b, lin_comb_c;
while (a_id < a_len && a_vvmap[a_id].constraint_id == row) {
libff::bigint<libff::alt_bn128_r_limbs> value = libsnarkBigintFromBytes(a_vvmap[a_id].variable_value);
if (!value.is_zero()) {
lin_comb_a.add_term(a_vvmap[a_id].variable_id, value);
}
a_id++;
}
while (b_id < b_len && b_vvmap[b_id].constraint_id == row) {
libff::bigint<libff::alt_bn128_r_limbs> value = libsnarkBigintFromBytes(b_vvmap[b_id].variable_value);
if (!value.is_zero()) {
lin_comb_b.add_term(b_vvmap[b_id].variable_id, value);
}
b_id++;
}
while (c_id < c_len && c_vvmap[c_id].constraint_id == row) {
libff::bigint<libff::alt_bn128_r_limbs> value = libsnarkBigintFromBytes(c_vvmap[c_id].variable_value);
if (!value.is_zero()) {
lin_comb_c.add_term(c_vvmap[c_id].variable_id, value);
}
c_id++;
}
cs.add_constraint(r1cs_constraint<libff::Fr<libff::alt_bn128_pp>>(lin_comb_a, lin_comb_b, lin_comb_c));
}
return cs;
}
r1cs_se_ppzksnark_keypair<libff::alt_bn128_pp> generateKeypair(const r1cs_se_ppzksnark_constraint_system<libff::alt_bn128_pp>& cs)
{
return r1cs_se_ppzksnark_generator<libff::alt_bn128_pp>(cs); //from r1cs_se_ppzksnark.hpp
}
std::string serializeVerificationKey(r1cs_se_ppzksnark_verification_key<libff::alt_bn128_pp>* vk)
template <mp_size_t Q, typename ppT, typename G1, typename G2>
std::string serializeVerificationKey(r1cs_se_ppzksnark_verification_key<ppT>* vk)
{
std::stringstream ss;
unsigned queryLength = vk->query.size();
ss << "vk.h=" << outputPointG2AffineAsHex(vk->H) << endl;
ss << "vk.g_alpha=" << outputPointG1AffineAsHex(vk->G_alpha) << endl;
ss << "vk.h_beta=" << outputPointG2AffineAsHex(vk->H_beta) << endl;
ss << "vk.g_gamma=" << outputPointG1AffineAsHex(vk->G_gamma) << endl;
ss << "vk.h_gamma=" << outputPointG2AffineAsHex(vk->H_gamma) << endl;
ss << "vk.query.len()=" << queryLength << endl;
ss << "{";
ss << "\"h\":" << outputPointG2AffineAsHexJson<Q, G2>(vk->H) << ",";
ss << "\"g_alpha\":" << outputPointG1AffineAsHexJson<Q, G1>(vk->G_alpha) << ",";
ss << "\"h_beta\":" << outputPointG2AffineAsHexJson<Q, G2>(vk->H_beta) << ",";
ss << "\"g_gamma\":" << outputPointG1AffineAsHexJson<Q, G1>(vk->G_gamma) << ",";
ss << "\"h_gamma\":" << outputPointG2AffineAsHexJson<Q, G2>(vk->H_gamma) << ",";
ss << "\"query\":[";
for (size_t i = 0; i < queryLength; ++i) {
auto vk_query_i = outputPointG1AffineAsHex(vk->query[i]);
ss << "vk.query[" << i << "]=" << vk_query_i << endl;
if (i != 0)
ss << ",";
ss << outputPointG1AffineAsHexJson<Q, G1>(vk->query[i]);
}
ss << "vk.raw=" << toHexString(serialize(*vk)) << endl;
ss << "],";
ss << "\"raw\":\"" << encodeToHexString<2>(serialize(*vk)) << "\"";
ss << "}";
std::string str = ss.str();
return str;
}
std::string serializeProof(r1cs_se_ppzksnark_proof<libff::alt_bn128_pp>* proof, const uint8_t* public_inputs, int32_t public_inputs_length)
template <mp_size_t Q, mp_size_t R, typename ppT, typename G1, typename G2>
std::string serializeProof(r1cs_se_ppzksnark_proof<ppT>* proof, const uint8_t* public_inputs, int32_t public_inputs_length)
{
std::stringstream ss;
ss << "{"
<< "\n";
ss << "\t\"proof\": {"
<< "\n";
ss << "\t\t\"a\": " << outputPointG1AffineAsHexJson(proof->A) << ",\n";
ss << "\t\t\"b\": " << outputPointG2AffineAsHexJson(proof->B) << ",\n";
ss << "\t\t\"c\": " << outputPointG1AffineAsHexJson(proof->C) << "\n";
ss << "\t},"
<< "\n";
ss << "\t\"inputs\": "
<< "[";
ss << "{";
ss << "\"proof\":{";
ss << "\"a\":" << outputPointG1AffineAsHexJson<Q, G1>(proof->A) << ",";
ss << "\"b\":" << outputPointG2AffineAsHexJson<Q, G2>(proof->B) << ",";
ss << "\"c\":" << outputPointG1AffineAsHexJson<Q, G1>(proof->C);
ss << "},";
ss << "\"inputs\":[";
for (int i = 1; i < public_inputs_length; i++) {
if (i != 1) {
ss << ",";
}
ss << outputInputAsHex(libsnarkBigintFromBytes(public_inputs + i * 32));
ss << outputInputAsHex<R>(libsnarkBigintFromBytes<R>(public_inputs + (i * R * sizeof(mp_limb_t))));
}
ss << "],\n";
ss << "\t\"raw\": \"" << toHexString(serialize(*proof)) << "\"\n";
ss << "}"
<< "\n";
ss << "],";
ss << "\"raw\":\"" << encodeToHexString<2>(serialize(*proof)) << "\"";
ss << "}";
std::string str = ss.str();
return str;
}
}
setup_result_t gm17_setup(const uint8_t* A, const uint8_t* B, const uint8_t* C, int32_t a_len, int32_t b_len, int32_t c_len, int32_t constraints, int32_t variables, int32_t inputs)
template <mp_size_t Q, mp_size_t R, typename ppT, typename G1, typename G2>
setup_result_t setup(const uint8_t* a, const uint8_t* b, const uint8_t* c, int32_t a_len, int32_t b_len, int32_t c_len, int32_t constraints, int32_t variables, int32_t inputs)
{
libff::inhibit_profiling_info = true;
libff::inhibit_profiling_counters = true;
// initialize curve parameters
libff::alt_bn128_pp::init_public_params();
ppT::init_public_params();
auto cs = gm17::createConstraintSystem(A, B, C, a_len, b_len, c_len, constraints, variables, inputs);
auto cs = createConstraintSystem<r1cs_se_ppzksnark_constraint_system, R, ppT>(a, b, c, a_len, b_len, c_len, constraints, variables, inputs);
assert(cs.num_variables() >= (unsigned)inputs);
assert(cs.num_inputs() == (unsigned)inputs);
assert(cs.num_constraints() == (unsigned)constraints);
// create keypair
auto keypair = r1cs_se_ppzksnark_generator<libff::alt_bn128_pp>(cs);
auto vk = gm17::serializeVerificationKey(&keypair.vk);
r1cs_se_ppzksnark_keypair<ppT> keypair = r1cs_se_ppzksnark_generator<ppT>(cs);
auto vk = serializeVerificationKey<Q, ppT, G1, G2>(&keypair.vk);
buffer_t vk_buf = create_buffer(vk);
buffer_t pk_buf = create_buffer(keypair.pk);
buffer_t vk_buf = createBuffer(vk);
buffer_t pk_buf = createBuffer(keypair.pk);
setup_result_t result(vk_buf, pk_buf);
return result;
}
proof_result_t gm17_generate_proof(buffer_t* pk_buf, const uint8_t* public_inputs, int32_t public_inputs_length, const uint8_t* private_inputs, int32_t private_inputs_length)
{
libff::inhibit_profiling_info = true;
libff::inhibit_profiling_counters = true;
//initialize curve parameters
libff::alt_bn128_pp::init_public_params();
r1cs_se_ppzksnark_proving_key<libff::alt_bn128_pp> proving_key;
from_buffer<r1cs_se_ppzksnark_proving_key<libff::alt_bn128_pp>>(pk_buf, proving_key);
// assign variables based on witness values, excludes ~one
r1cs_variable_assignment<libff::Fr<libff::alt_bn128_pp>> full_variable_assignment;
for (int i = 1; i < public_inputs_length; i++) {
full_variable_assignment.push_back(libff::Fr<libff::alt_bn128_pp>(libsnarkBigintFromBytes(public_inputs + i * 32)));
}
for (int i = 0; i < private_inputs_length; i++) {
full_variable_assignment.push_back(libff::Fr<libff::alt_bn128_pp>(libsnarkBigintFromBytes(private_inputs + i * 32)));
}
// split up variables into primary and auxiliary inputs. Does *NOT* include the constant 1
// Public variables belong to primary input, private variables are auxiliary input.
r1cs_primary_input<libff::Fr<libff::alt_bn128_pp>> primary_input(full_variable_assignment.begin(), full_variable_assignment.begin() + public_inputs_length - 1);
r1cs_primary_input<libff::Fr<libff::alt_bn128_pp>> auxiliary_input(full_variable_assignment.begin() + public_inputs_length - 1, full_variable_assignment.end());
// for debugging
// cout << "full variable assignment:" << endl << full_variable_assignment;
// cout << "primary input:" << endl << primary_input;
// cout << "auxiliary input:" << endl << auxiliary_input;
// Proof Generation
auto proof = r1cs_se_ppzksnark_prover<libff::alt_bn128_pp>(proving_key, primary_input, auxiliary_input);
auto proof_json = gm17::serializeProof(&proof, public_inputs, public_inputs_length);
buffer_t proof_buf = create_buffer(proof_json);
proof_result_t result(proof_buf);
return result;
}
bool gm17_verify(buffer_t* vk_buf, buffer_t* proof_buf, const uint8_t* public_inputs, int32_t public_inputs_length)
template <mp_size_t Q, mp_size_t R, typename ppT, typename G1, typename G2>
proof_result_t generateProof(buffer_t* pk_buf, const uint8_t* public_inputs, int32_t public_inputs_length, const uint8_t* private_inputs, int32_t private_inputs_length)
{
libff::inhibit_profiling_info = true;
libff::inhibit_profiling_counters = true;
// initialize curve parameters
libff::alt_bn128_pp::init_public_params();
ppT::init_public_params();
r1cs_se_ppzksnark_verification_key<libff::alt_bn128_pp> vk;
r1cs_se_ppzksnark_proof<libff::alt_bn128_pp> proof;
r1cs_se_ppzksnark_proving_key<ppT> proving_key;
fromBuffer<r1cs_se_ppzksnark_proving_key<ppT>>(pk_buf, proving_key);
from_buffer<r1cs_se_ppzksnark_verification_key<libff::alt_bn128_pp>>(vk_buf, vk);
from_buffer<r1cs_se_ppzksnark_proof<libff::alt_bn128_pp>>(proof_buf, proof);
r1cs_primary_input<libff::Fr<libff::alt_bn128_pp>> primary_input;
for (int i = 0; i < public_inputs_length; i++) {
primary_input.push_back(libff::Fr<libff::alt_bn128_pp>(libsnarkBigintFromBytes(public_inputs + i * 32)));
r1cs_variable_assignment<libff::Fr<ppT>> full_variable_assignment;
for (int i = 1; i < public_inputs_length; i++) {
full_variable_assignment.push_back(libff::Fr<ppT>(libsnarkBigintFromBytes<R>(public_inputs + (i * R * sizeof(mp_limb_t)))));
}
for (int i = 0; i < private_inputs_length; i++) {
full_variable_assignment.push_back(libff::Fr<ppT>(libsnarkBigintFromBytes<R>(private_inputs + (i * R * sizeof(mp_limb_t)))));
}
return r1cs_se_ppzksnark_verifier_strong_IC<libff::alt_bn128_pp>(vk, primary_input, proof);
r1cs_primary_input<libff::Fr<ppT>> primary_input(
full_variable_assignment.begin(),
full_variable_assignment.begin() + public_inputs_length - 1);
r1cs_primary_input<libff::Fr<ppT>> auxiliary_input(
full_variable_assignment.begin() + public_inputs_length - 1,
full_variable_assignment.end());
r1cs_se_ppzksnark_proof<ppT> proof = r1cs_se_ppzksnark_prover<ppT>(proving_key, primary_input, auxiliary_input);
std::string json = serializeProof<Q, R, ppT, G1, G2>(&proof, public_inputs, public_inputs_length);
buffer_t proof_buf = createBuffer(json);
proof_result_t result(proof_buf);
return result;
}
template <mp_size_t R, typename ppT>
bool verify(buffer_t* vk_buf, buffer_t* proof_buf, const uint8_t* public_inputs, int32_t public_inputs_length)
{
libff::inhibit_profiling_info = true;
libff::inhibit_profiling_counters = true;
// initialize curve parameters
ppT::init_public_params();
r1cs_se_ppzksnark_verification_key<ppT> vk;
r1cs_se_ppzksnark_proof<ppT> proof;
fromBuffer<r1cs_se_ppzksnark_verification_key<ppT>>(vk_buf, vk);
fromBuffer<r1cs_se_ppzksnark_proof<ppT>>(proof_buf, proof);
r1cs_primary_input<libff::Fr<ppT>> primary_input;
for (int i = 0; i < public_inputs_length; i++) {
primary_input.push_back(libff::Fr<ppT>(libsnarkBigintFromBytes<R>(public_inputs + (i * R * sizeof(mp_limb_t)))));
}
return r1cs_se_ppzksnark_verifier_strong_IC<ppT>(vk, primary_input, proof);
}
}
setup_result_t gm17_bn128_setup(const uint8_t* a, const uint8_t* b, const uint8_t* c, int32_t a_len, int32_t b_len, int32_t c_len, int32_t constraints, int32_t variables, int32_t inputs)
{
return gm17::setup<libff::alt_bn128_q_limbs,
libff::alt_bn128_r_limbs,
libff::alt_bn128_pp,
libff::alt_bn128_G1,
libff::alt_bn128_G2>(a, b, c, a_len, b_len, c_len, constraints, variables, inputs);
}
proof_result_t gm17_bn128_generate_proof(buffer_t* pk_buf,
const uint8_t* public_inputs,
int32_t public_inputs_length,
const uint8_t* private_inputs,
int32_t private_inputs_length)
{
return gm17::generateProof<libff::alt_bn128_q_limbs,
libff::alt_bn128_r_limbs,
libff::alt_bn128_pp,
libff::alt_bn128_G1,
libff::alt_bn128_G2>(pk_buf,
public_inputs,
public_inputs_length,
private_inputs,
private_inputs_length);
}
bool gm17_bn128_verify(buffer_t* vk_buf, buffer_t* proof_buf, const uint8_t* public_inputs, int32_t public_inputs_length)
{
return gm17::verify<libff::alt_bn128_r_limbs,
libff::alt_bn128_pp>(vk_buf, proof_buf, public_inputs, public_inputs_length);
}

View file

@ -13,7 +13,7 @@ extern "C" {
#include "ffi.hpp"
setup_result_t gm17_setup(
setup_result_t gm17_bn128_setup(
const uint8_t* a,
const uint8_t* b,
const uint8_t* c,
@ -24,14 +24,14 @@ setup_result_t gm17_setup(
int32_t variables,
int32_t inputs);
proof_result_t gm17_generate_proof(
proof_result_t gm17_bn128_generate_proof(
buffer_t* pk_buf,
const uint8_t* public_inputs,
int32_t public_inputs_length,
const uint8_t* private_inputs,
int32_t private_inputs_length);
bool gm17_verify(
bool gm17_bn128_verify(
buffer_t* vk_buf,
buffer_t* proof_buf,
const uint8_t* public_inputs,

View file

@ -6,223 +6,190 @@
*/
#include "pghr13.hpp"
#include "util.hpp"
#include <cassert>
#include <sstream>
#include <string>
// contains definitions of alt_bn128 ec public parameters
// contains definition of alt_bn128 ec public parameters
#include "libff/algebra/curves/alt_bn128/alt_bn128_pp.hpp"
// contains required interfaces and types (keypair, proof, generator, prover, verifier)
#include <libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp>
typedef long integer_coeff_t;
using namespace libsnark;
using std::cout;
using std::endl;
#include "util.tcc"
namespace pghr13 {
r1cs_ppzksnark_constraint_system<libff::alt_bn128_pp> createConstraintSystem(const uint8_t* a, const uint8_t* b, const uint8_t* c, int a_len, int b_len, int c_len, int constraints, int variables, int inputs)
{
r1cs_ppzksnark_constraint_system<libff::alt_bn128_pp> cs;
cs.primary_input_size = inputs;
cs.auxiliary_input_size = variables - inputs - 1; // ~one not included
cout << "num variables: " << variables << endl;
cout << "num constraints: " << constraints << endl;
cout << "num inputs: " << inputs << endl;
struct VariableValueMapping {
int constraint_id;
int variable_id;
uint8_t variable_value[32];
};
const VariableValueMapping* a_vvmap = (VariableValueMapping*)a;
const VariableValueMapping* b_vvmap = (VariableValueMapping*)b;
const VariableValueMapping* c_vvmap = (VariableValueMapping*)c;
int a_id = 0;
int b_id = 0;
int c_id = 0;
// initialize curve parameters
libff::alt_bn128_pp::init_public_params();
for (int row = 0; row < constraints; row++) {
linear_combination<libff::Fr<libff::alt_bn128_pp>> lin_comb_a, lin_comb_b, lin_comb_c;
while (a_id < a_len && a_vvmap[a_id].constraint_id == row) {
libff::bigint<libff::alt_bn128_r_limbs> value = libsnarkBigintFromBytes(a_vvmap[a_id].variable_value);
if (!value.is_zero()) {
lin_comb_a.add_term(a_vvmap[a_id].variable_id, value);
}
a_id++;
}
while (b_id < b_len && b_vvmap[b_id].constraint_id == row) {
libff::bigint<libff::alt_bn128_r_limbs> value = libsnarkBigintFromBytes(b_vvmap[b_id].variable_value);
if (!value.is_zero()) {
lin_comb_b.add_term(b_vvmap[b_id].variable_id, value);
}
b_id++;
}
while (c_id < c_len && c_vvmap[c_id].constraint_id == row) {
libff::bigint<libff::alt_bn128_r_limbs> value = libsnarkBigintFromBytes(c_vvmap[c_id].variable_value);
if (!value.is_zero()) {
lin_comb_c.add_term(c_vvmap[c_id].variable_id, value);
}
c_id++;
}
cs.add_constraint(r1cs_constraint<libff::Fr<libff::alt_bn128_pp>>(lin_comb_a, lin_comb_b, lin_comb_c));
}
return cs;
}
r1cs_ppzksnark_keypair<libff::alt_bn128_pp> generateKeypair(const r1cs_ppzksnark_constraint_system<libff::alt_bn128_pp>& cs)
{
return r1cs_ppzksnark_generator<libff::alt_bn128_pp>(cs); // from r1cs_ppzksnark.hpp
}
std::string serializeVerificationKey(r1cs_ppzksnark_verification_key<libff::alt_bn128_pp>* vk)
template <mp_size_t Q, typename ppT, typename G1, typename G2>
std::string serializeVerificationKey(r1cs_ppzksnark_verification_key<ppT>* vk)
{
std::stringstream ss;
unsigned icLength = vk->encoded_IC_query.rest.indices.size() + 1;
unsigned icLength = vk->encoded_IC_query.rest.indices.size();
ss << "vk.a=" << outputPointG2AffineAsHex(vk->alphaA_g2) << endl;
ss << "vk.b=" << outputPointG1AffineAsHex(vk->alphaB_g1) << endl;
ss << "vk.c=" << outputPointG2AffineAsHex(vk->alphaC_g2) << endl;
ss << "vk.gamma=" << outputPointG2AffineAsHex(vk->gamma_g2) << endl;
ss << "vk.gamma_beta_1=" << outputPointG1AffineAsHex(vk->gamma_beta_g1) << endl;
ss << "vk.gamma_beta_2=" << outputPointG2AffineAsHex(vk->gamma_beta_g2) << endl;
ss << "vk.z=" << outputPointG2AffineAsHex(vk->rC_Z_g2) << endl;
ss << "vk.ic.len()=" << icLength << endl;
ss << "vk.ic[0]=" << outputPointG1AffineAsHex(vk->encoded_IC_query.first) << endl;
for (size_t i = 1; i < icLength; ++i) {
auto vk_ic_i = outputPointG1AffineAsHex(vk->encoded_IC_query.rest.values[i - 1]);
ss << "vk.ic[" << i << "]=" << vk_ic_i << endl;
ss << "{";
ss << "\"a\":" << outputPointG2AffineAsHexJson<Q, G2>(vk->alphaA_g2) << ",";
ss << "\"b\":" << outputPointG1AffineAsHexJson<Q, G1>(vk->alphaB_g1) << ",";
ss << "\"c\":" << outputPointG2AffineAsHexJson<Q, G2>(vk->alphaC_g2) << ",";
ss << "\"gamma\":" << outputPointG2AffineAsHexJson<Q, G2>(vk->gamma_g2) << ",";
ss << "\"gamma_beta_1\":" << outputPointG1AffineAsHexJson<Q, G1>(vk->gamma_beta_g1) << ",";
ss << "\"gamma_beta_2\":" << outputPointG2AffineAsHexJson<Q, G2>(vk->gamma_beta_g2) << ",";
ss << "\"z\":" << outputPointG2AffineAsHexJson<Q, G2>(vk->rC_Z_g2) << ",";
ss << "\"ic\":[";
ss << outputPointG1AffineAsHexJson<Q, G1>(vk->encoded_IC_query.first);
for (size_t i = 0; i < icLength; ++i) {
ss << ",";
ss << outputPointG1AffineAsHexJson<Q, G1>(vk->encoded_IC_query.rest.values[i]);
}
ss << "vk.raw=" << toHexString(serialize(*vk)) << endl;
ss << "],";
ss << "\"raw\":\"" << encodeToHexString<2>(serialize(*vk)) << "\"";
ss << "}";
std::string str = ss.str();
return str;
}
std::string serializeProof(r1cs_ppzksnark_proof<libff::alt_bn128_pp>* proof, const uint8_t* public_inputs, int public_inputs_length)
template <mp_size_t Q, mp_size_t R, typename ppT, typename G1, typename G2>
std::string serializeProof(r1cs_ppzksnark_proof<ppT>* proof, const uint8_t* public_inputs, int public_inputs_length)
{
std::stringstream ss;
ss << "{"
<< "\n";
ss << "\t\"proof\": {"
<< "\n";
ss << "\t\t\"a\": " << outputPointG1AffineAsHexJson(proof->g_A.g) << ",\n";
ss << "\t\t\"a_p\": " << outputPointG1AffineAsHexJson(proof->g_A.h) << ",\n";
ss << "\t\t\"b\": " << outputPointG2AffineAsHexJson(proof->g_B.g) << ",\n";
ss << "\t\t\"b_p\": " << outputPointG1AffineAsHexJson(proof->g_B.h) << ",\n";
ss << "\t\t\"c\": " << outputPointG1AffineAsHexJson(proof->g_C.g) << ",\n";
ss << "\t\t\"c_p\": " << outputPointG1AffineAsHexJson(proof->g_C.h) << ",\n";
ss << "\t\t\"h\": " << outputPointG1AffineAsHexJson(proof->g_H) << ",\n";
ss << "\t\t\"k\": " << outputPointG1AffineAsHexJson(proof->g_K) << "\n";
ss << "\t},"
<< "\n";
ss << "\t\"inputs\": "
<< "[";
ss << "{";
ss << "\"proof\":{";
ss << "\"a\":" << outputPointG1AffineAsHexJson<Q, G1>(proof->g_A.g) << ",";
ss << "\"a_p\":" << outputPointG1AffineAsHexJson<Q, G1>(proof->g_A.h) << ",";
ss << "\"b\":" << outputPointG2AffineAsHexJson<Q, G2>(proof->g_B.g) << ",";
ss << "\"b_p\":" << outputPointG1AffineAsHexJson<Q, G1>(proof->g_B.h) << ",";
ss << "\"c\":" << outputPointG1AffineAsHexJson<Q, G1>(proof->g_C.g) << ",";
ss << "\"c_p\":" << outputPointG1AffineAsHexJson<Q, G1>(proof->g_C.h) << ",";
ss << "\"h\":" << outputPointG1AffineAsHexJson<Q, G1>(proof->g_H) << ",";
ss << "\"k\":" << outputPointG1AffineAsHexJson<Q, G1>(proof->g_K);
ss << "},";
ss << "\"inputs\":[";
for (int i = 1; i < public_inputs_length; i++) {
if (i != 1) {
ss << ",";
}
ss << outputInputAsHex(libsnarkBigintFromBytes(public_inputs + i * 32));
ss << outputInputAsHex<R>(libsnarkBigintFromBytes<R>(public_inputs + (i * R * sizeof(mp_limb_t))));
}
ss << "],\n";
ss << "\t\"raw\": \"" << toHexString(serialize(*proof)) << "\"\n";
ss << "}"
<< "\n";
ss << "],";
ss << "\"raw\":\"" << encodeToHexString<2>(serialize(*proof)) << "\"";
ss << "}";
std::string str = ss.str();
return str;
}
}
setup_result_t pghr13_setup(const uint8_t* A, const uint8_t* B, const uint8_t* C, int32_t a_len, int32_t b_len, int32_t c_len, int32_t constraints, int32_t variables, int32_t inputs)
template <mp_size_t Q, mp_size_t R, typename ppT, typename G1, typename G2>
setup_result_t setup(const uint8_t* a, const uint8_t* b, const uint8_t* c, int32_t a_len, int32_t b_len, int32_t c_len, int32_t constraints, int32_t variables, int32_t inputs)
{
libff::inhibit_profiling_info = true;
libff::inhibit_profiling_counters = true;
// initialize curve parameters
libff::alt_bn128_pp::init_public_params();
auto cs = pghr13::createConstraintSystem(A, B, C, a_len, b_len, c_len, constraints, variables, inputs);
ppT::init_public_params();
auto cs = createConstraintSystem<r1cs_ppzksnark_constraint_system, R, ppT>(a, b, c, a_len, b_len, c_len, constraints, variables, inputs);
assert(cs.num_variables() >= (unsigned)inputs);
assert(cs.num_inputs() == (unsigned)inputs);
assert(cs.num_constraints() == (unsigned)constraints);
// create keypair
auto keypair = r1cs_ppzksnark_generator<libff::alt_bn128_pp>(cs);
auto vk = pghr13::serializeVerificationKey(&keypair.vk);
r1cs_ppzksnark_keypair<ppT> keypair = r1cs_ppzksnark_generator<ppT>(cs);
auto vk = serializeVerificationKey<Q, ppT, G1, G2>(&keypair.vk);
buffer_t vk_buf = create_buffer(vk);
buffer_t pk_buf = create_buffer(keypair.pk);
buffer_t vk_buf = createBuffer(vk);
buffer_t pk_buf = createBuffer(keypair.pk);
setup_result_t result(vk_buf, pk_buf);
return result;
}
proof_result_t pghr13_generate_proof(buffer_t* pk_buf, const uint8_t* public_inputs, int32_t public_inputs_length, const uint8_t* private_inputs, int32_t private_inputs_length)
template <mp_size_t Q, mp_size_t R, typename ppT, typename G1, typename G2>
proof_result_t generateProof(buffer_t* pk_buf, const uint8_t* public_inputs, int32_t public_inputs_length, const uint8_t* private_inputs, int32_t private_inputs_length)
{
libff::inhibit_profiling_info = true;
libff::inhibit_profiling_counters = true;
// initialize curve parameters
libff::alt_bn128_pp::init_public_params();
ppT::init_public_params();
r1cs_ppzksnark_proving_key<libff::alt_bn128_pp> proving_key;
from_buffer<r1cs_ppzksnark_proving_key<libff::alt_bn128_pp>>(pk_buf, proving_key);
r1cs_ppzksnark_proving_key<ppT> proving_key;
fromBuffer<r1cs_ppzksnark_proving_key<ppT>>(pk_buf, proving_key);
// assign variables based on witness values, excludes ~one
r1cs_variable_assignment<libff::Fr<libff::alt_bn128_pp>> full_variable_assignment;
r1cs_variable_assignment<libff::Fr<ppT>> full_variable_assignment;
for (int i = 1; i < public_inputs_length; i++) {
full_variable_assignment.push_back(libff::Fr<libff::alt_bn128_pp>(libsnarkBigintFromBytes(public_inputs + i * 32)));
full_variable_assignment.push_back(libff::Fr<ppT>(libsnarkBigintFromBytes<R>(public_inputs + (i * R * sizeof(mp_limb_t)))));
}
for (int i = 0; i < private_inputs_length; i++) {
full_variable_assignment.push_back(libff::Fr<libff::alt_bn128_pp>(libsnarkBigintFromBytes(private_inputs + i * 32)));
full_variable_assignment.push_back(libff::Fr<ppT>(libsnarkBigintFromBytes<R>(private_inputs + (i * R * sizeof(mp_limb_t)))));
}
// split up variables into primary and auxiliary inputs. Does *NOT* include the constant 1
// Public variables belong to primary input, private variables are auxiliary input.
r1cs_primary_input<libff::Fr<libff::alt_bn128_pp>> primary_input(full_variable_assignment.begin(), full_variable_assignment.begin() + public_inputs_length - 1);
r1cs_primary_input<libff::Fr<libff::alt_bn128_pp>> auxiliary_input(full_variable_assignment.begin() + public_inputs_length - 1, full_variable_assignment.end());
r1cs_primary_input<libff::Fr<ppT>> primary_input(
full_variable_assignment.begin(),
full_variable_assignment.begin() + public_inputs_length - 1);
// for debugging
// cout << "full variable assignment:" << endl << full_variable_assignment;
// cout << "primary input:" << endl << primary_input;
// cout << "auxiliary input:" << endl << auxiliary_input;
r1cs_primary_input<libff::Fr<ppT>> auxiliary_input(
full_variable_assignment.begin() + public_inputs_length - 1,
full_variable_assignment.end());
// Proof Generation
auto proof = r1cs_ppzksnark_prover<libff::alt_bn128_pp>(proving_key, primary_input, auxiliary_input);
auto proof_json = pghr13::serializeProof(&proof, public_inputs, public_inputs_length);
r1cs_ppzksnark_proof<ppT> proof = r1cs_ppzksnark_prover<ppT>(proving_key, primary_input, auxiliary_input);
std::string json = serializeProof<Q, R, ppT, G1, G2>(&proof, public_inputs, public_inputs_length);
buffer_t proof_buf = create_buffer(proof_json);
buffer_t proof_buf = createBuffer(json);
proof_result_t result(proof_buf);
return result;
}
bool pghr13_verify(buffer_t* vk_buf, buffer_t* proof_buf, const uint8_t* public_inputs, int32_t public_inputs_length)
template <mp_size_t R, typename ppT>
bool verify(buffer_t* vk_buf, buffer_t* proof_buf, const uint8_t* public_inputs, int32_t public_inputs_length)
{
libff::inhibit_profiling_info = true;
libff::inhibit_profiling_counters = true;
// initialize curve parameters
libff::alt_bn128_pp::init_public_params();
ppT::init_public_params();
r1cs_ppzksnark_verification_key<libff::alt_bn128_pp> vk;
r1cs_ppzksnark_proof<libff::alt_bn128_pp> proof;
r1cs_ppzksnark_verification_key<ppT> vk;
r1cs_ppzksnark_proof<ppT> proof;
from_buffer<r1cs_ppzksnark_verification_key<libff::alt_bn128_pp>>(vk_buf, vk);
from_buffer<r1cs_ppzksnark_proof<libff::alt_bn128_pp>>(proof_buf, proof);
fromBuffer<r1cs_ppzksnark_verification_key<ppT>>(vk_buf, vk);
fromBuffer<r1cs_ppzksnark_proof<ppT>>(proof_buf, proof);
r1cs_primary_input<libff::Fr<libff::alt_bn128_pp>> primary_input;
r1cs_primary_input<libff::Fr<ppT>> primary_input;
for (int i = 0; i < public_inputs_length; i++) {
primary_input.push_back(libff::Fr<libff::alt_bn128_pp>(libsnarkBigintFromBytes(public_inputs + i * 32)));
primary_input.push_back(libff::Fr<ppT>(libsnarkBigintFromBytes<R>(public_inputs + (i * R * sizeof(mp_limb_t)))));
}
return r1cs_ppzksnark_verifier_strong_IC<libff::alt_bn128_pp>(vk, primary_input, proof);
return r1cs_ppzksnark_verifier_strong_IC<ppT>(vk, primary_input, proof);
}
}
setup_result_t pghr13_bn128_setup(const uint8_t* a, const uint8_t* b, const uint8_t* c, int32_t a_len, int32_t b_len, int32_t c_len, int32_t constraints, int32_t variables, int32_t inputs)
{
return pghr13::setup<libff::alt_bn128_q_limbs,
libff::alt_bn128_r_limbs,
libff::alt_bn128_pp,
libff::alt_bn128_G1,
libff::alt_bn128_G2>(a, b, c, a_len, b_len, c_len, constraints, variables, inputs);
}
proof_result_t pghr13_bn128_generate_proof(buffer_t* pk_buf,
const uint8_t* public_inputs,
int32_t public_inputs_length,
const uint8_t* private_inputs,
int32_t private_inputs_length)
{
return pghr13::generateProof<libff::alt_bn128_q_limbs,
libff::alt_bn128_r_limbs,
libff::alt_bn128_pp,
libff::alt_bn128_G1,
libff::alt_bn128_G2>(pk_buf,
public_inputs,
public_inputs_length,
private_inputs,
private_inputs_length);
}
bool pghr13_bn128_verify(buffer_t* vk_buf, buffer_t* proof_buf, const uint8_t* public_inputs, int32_t public_inputs_length)
{
return pghr13::verify<libff::alt_bn128_r_limbs,
libff::alt_bn128_pp>(vk_buf, proof_buf, public_inputs, public_inputs_length);
}

View file

@ -13,7 +13,7 @@ extern "C" {
#include "ffi.hpp"
setup_result_t pghr13_setup(
setup_result_t pghr13_bn128_setup(
const uint8_t* a,
const uint8_t* b,
const uint8_t* c,
@ -24,14 +24,14 @@ setup_result_t pghr13_setup(
int32_t variables,
int32_t inputs);
proof_result_t pghr13_generate_proof(
proof_result_t pghr13_bn128_generate_proof(
buffer_t* pk_buf,
const uint8_t* public_inputs,
int32_t public_inputs_length,
const uint8_t* private_inputs,
int32_t private_inputs_length);
bool pghr13_verify(
bool pghr13_bn128_verify(
buffer_t* vk_buf,
buffer_t* proof_buf,
const uint8_t* public_inputs,

View file

@ -1,75 +0,0 @@
/**
* @file util.cpp
* @author Jacob Eberhardt <jacob.eberhardt@tu-berlin.de
* @author Dennis Kuhnert <dennis.kuhnert@campus.tu-berlin.de>
* @date 2017
*/
#include "util.hpp"
// conversion byte[32] <-> libsnark bigint.
libff::bigint<libff::alt_bn128_r_limbs> libsnarkBigintFromBytes(const uint8_t* _x)
{
libff::bigint<libff::alt_bn128_r_limbs> x;
for (unsigned i = 0; i < 4; i++) {
for (unsigned j = 0; j < 8; j++) {
x.data[3 - i] |= uint64_t(_x[i * 8 + j]) << (8 * (7 - j));
}
}
return x;
}
std::string toHexString(const std::string& in)
{
std::ostringstream out;
out << std::setfill('0');
for (unsigned char const& c : in) {
out << std::hex << std::setw(2) << static_cast<unsigned int>(c);
}
return out.str();
}
std::string HexStringFromLibsnarkBigint(libff::bigint<libff::alt_bn128_r_limbs> _x)
{
uint8_t x[32];
for (unsigned i = 0; i < 4; i++) {
for (unsigned j = 0; j < 8; j++) {
x[i * 8 + j] = uint8_t(uint64_t(_x.data[3 - i]) >> (8 * (7 - j)));
}
}
std::string tmp((char*)x, 32);
return toHexString(tmp);
}
std::string outputInputAsHex(libff::bigint<libff::alt_bn128_r_limbs> _x)
{
return "\"0x" + HexStringFromLibsnarkBigint(_x) + "\"";
}
std::string outputPointG1AffineAsHex(libff::alt_bn128_G1 _p)
{
libff::alt_bn128_G1 aff = _p;
aff.to_affine_coordinates();
return "0x" + HexStringFromLibsnarkBigint(aff.X.as_bigint()) + ", 0x" + HexStringFromLibsnarkBigint(aff.Y.as_bigint());
}
std::string outputPointG1AffineAsHexJson(libff::alt_bn128_G1 _p)
{
libff::alt_bn128_G1 aff = _p;
aff.to_affine_coordinates();
return "[\"0x" + HexStringFromLibsnarkBigint(aff.X.as_bigint()) + "\", \"0x" + HexStringFromLibsnarkBigint(aff.Y.as_bigint()) + "\"]";
}
std::string outputPointG2AffineAsHex(libff::alt_bn128_G2 _p)
{
libff::alt_bn128_G2 aff = _p;
aff.to_affine_coordinates();
return "[0x" + HexStringFromLibsnarkBigint(aff.X.c1.as_bigint()) + ", 0x" + HexStringFromLibsnarkBigint(aff.X.c0.as_bigint()) + "], [0x" + HexStringFromLibsnarkBigint(aff.Y.c1.as_bigint()) + ", 0x" + HexStringFromLibsnarkBigint(aff.Y.c0.as_bigint()) + "]";
}
std::string outputPointG2AffineAsHexJson(libff::alt_bn128_G2 _p)
{
libff::alt_bn128_G2 aff = _p;
aff.to_affine_coordinates();
return "[[\"0x" + HexStringFromLibsnarkBigint(aff.X.c1.as_bigint()) + "\", \"0x" + HexStringFromLibsnarkBigint(aff.X.c0.as_bigint()) + "\"], [\"0x" + HexStringFromLibsnarkBigint(aff.Y.c1.as_bigint()) + "\", \"0x" + HexStringFromLibsnarkBigint(aff.Y.c0.as_bigint()) + "\"]]";
}

View file

@ -1,50 +0,0 @@
#pragma once
// contains definitions of alt_bn128 ec public parameters
#include "ffi.hpp"
#include "libff/algebra/curves/alt_bn128/alt_bn128_pp.hpp"
#include <cassert>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
libff::bigint<libff::alt_bn128_r_limbs> libsnarkBigintFromBytes(const uint8_t* _x);
std::string toHexString(const std::string& s);
std::string HexStringFromLibsnarkBigint(libff::bigint<libff::alt_bn128_r_limbs> _x);
std::string outputInputAsHex(libff::bigint<libff::alt_bn128_r_limbs> _x);
std::string outputPointG1AffineAsHex(libff::alt_bn128_G1 _p);
std::string outputPointG1AffineAsHexJson(libff::alt_bn128_G1 _p);
std::string outputPointG2AffineAsHex(libff::alt_bn128_G2 _p);
std::string outputPointG2AffineAsHexJson(libff::alt_bn128_G2 _p);
template <typename T>
inline void from_buffer(buffer_t* buffer, T& t)
{
std::string tmp((char*)buffer->data, buffer->length);
std::stringstream ss(tmp);
ss >> t;
}
template <typename T>
inline std::string serialize(const T& t)
{
std::stringstream ss;
ss << t;
return ss.str();
}
template <typename T>
inline buffer_t create_buffer(T& t)
{
std::string tmp = serialize(t);
size_t length = tmp.length();
buffer_t buffer;
buffer.data = (uint8_t*)malloc(length);
buffer.length = length;
tmp.copy(reinterpret_cast<char*>(buffer.data), buffer.length);
return buffer;
}

159
zokrates_core/lib/util.tcc Normal file
View file

@ -0,0 +1,159 @@
#pragma once
#include "ffi.hpp"
#include <cassert>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
template <int W>
std::string encodeToHexString(const std::string& in)
{
std::ostringstream out;
out << std::setfill('0');
for (unsigned char const& c : in) {
out << std::hex << std::setw(W) << static_cast<unsigned int>(c);
}
return out.str();
}
// conversion byte[N] <-> libsnark bigint.
template <mp_size_t N>
libff::bigint<N> libsnarkBigintFromBytes(const uint8_t* _x)
{
libff::bigint<N> x;
for (unsigned i = 0; i < N; i++) {
for (unsigned j = 0; j < 8; j++) {
x.data[N - 1 - i] |= uint64_t(_x[i * 8 + j]) << (8 * (7 - j));
}
}
return x;
}
template <mp_size_t N>
std::string hexStringFromLibsnarkBigint(libff::bigint<N> _x)
{
uint8_t x[N * sizeof(mp_limb_t)];
for (unsigned i = 0; i < N; i++) {
for (unsigned j = 0; j < 8; j++) {
x[i * 8 + j] = uint8_t(uint64_t(_x.data[N - 1 - i]) >> (8 * (7 - j)));
}
}
std::string tmp((char*)x, N * sizeof(mp_limb_t));
return encodeToHexString<2>(tmp);
}
template <mp_size_t Q>
std::string outputInputAsHex(libff::bigint<Q> _x)
{
return "\"0x" + hexStringFromLibsnarkBigint<Q>(_x) + "\"";
}
template <mp_size_t Q, typename G1>
std::string outputPointG1AffineAsHexJson(G1 _p)
{
G1 aff = _p;
aff.to_affine_coordinates();
return "[\"0x" + hexStringFromLibsnarkBigint<Q>(aff.X.as_bigint()) + "\",\"0x" + hexStringFromLibsnarkBigint<Q>(aff.Y.as_bigint()) + "\"]";
}
template <mp_size_t Q, typename G2>
std::string outputPointG2AffineAsHexJson(G2 _p)
{
G2 aff = _p;
aff.to_affine_coordinates();
return "[[\"0x" + hexStringFromLibsnarkBigint<Q>(aff.X.c1.as_bigint()) + "\",\"0x" + hexStringFromLibsnarkBigint<Q>(aff.X.c0.as_bigint()) + "\"], [\"0x" + hexStringFromLibsnarkBigint<Q>(aff.Y.c1.as_bigint()) + "\", \"0x" + hexStringFromLibsnarkBigint<Q>(aff.Y.c0.as_bigint()) + "\"]]";
}
template <template <typename ppT> class ConstraintSystem, mp_size_t R, typename ppT>
ConstraintSystem<ppT> createConstraintSystem(const uint8_t* a,
const uint8_t* b,
const uint8_t* c,
int32_t a_len,
int32_t b_len,
int32_t c_len,
int32_t constraints,
int32_t variables,
int32_t inputs)
{
ConstraintSystem<ppT> cs;
cs.primary_input_size = inputs;
cs.auxiliary_input_size = variables - inputs - 1; // ~one not included
std::cout << "num variables: " << variables << std::endl;
std::cout << "num constraints: " << constraints << std::endl;
std::cout << "num inputs: " << inputs << std::endl;
struct VariableValueMapping {
int constraint_id;
int variable_id;
uint8_t variable_value[R * sizeof(mp_limb_t)];
};
const VariableValueMapping* a_vvmap = (VariableValueMapping*)a;
const VariableValueMapping* b_vvmap = (VariableValueMapping*)b;
const VariableValueMapping* c_vvmap = (VariableValueMapping*)c;
int a_id = 0;
int b_id = 0;
int c_id = 0;
for (int row = 0; row < constraints; row++) {
linear_combination<libff::Fr<ppT>> lin_comb_a, lin_comb_b, lin_comb_c;
while (a_id < a_len && a_vvmap[a_id].constraint_id == row) {
libff::bigint<R> value = libsnarkBigintFromBytes<R>(a_vvmap[a_id].variable_value);
if (!value.is_zero()) {
lin_comb_a.add_term(a_vvmap[a_id].variable_id, value);
}
a_id++;
}
while (b_id < b_len && b_vvmap[b_id].constraint_id == row) {
libff::bigint<R> value = libsnarkBigintFromBytes<R>(b_vvmap[b_id].variable_value);
if (!value.is_zero()) {
lin_comb_b.add_term(b_vvmap[b_id].variable_id, value);
}
b_id++;
}
while (c_id < c_len && c_vvmap[c_id].constraint_id == row) {
libff::bigint<R> value = libsnarkBigintFromBytes<R>(c_vvmap[c_id].variable_value);
if (!value.is_zero()) {
lin_comb_c.add_term(c_vvmap[c_id].variable_id, value);
}
c_id++;
}
cs.add_constraint(r1cs_constraint<libff::Fr<ppT>>(lin_comb_a, lin_comb_b, lin_comb_c));
}
return cs;
}
template <typename T>
inline void fromBuffer(buffer_t* buffer, T& t)
{
std::string tmp((char*)buffer->data, buffer->length);
std::stringstream ss(tmp);
ss >> t;
}
template <typename T>
inline std::string serialize(const T& t)
{
std::stringstream ss;
ss << t;
return ss.str();
}
template <typename T>
inline buffer_t createBuffer(T& t)
{
std::string tmp = serialize(t);
size_t length = tmp.length();
buffer_t buffer;
buffer.data = (uint8_t*)malloc(length);
buffer.length = length;
tmp.copy(reinterpret_cast<char*>(buffer.data), buffer.length);
return buffer;
}

View file

@ -9,7 +9,6 @@ use imports::{self, Importer};
use ir;
use macros;
use macros::process_macros;
use optimizer::Optimize;
use semantics::{self, Checker};
use static_analysis::Analyse;
use std::collections::HashMap;
@ -141,12 +140,29 @@ impl fmt::Display for CompileErrorInner {
}
}
#[derive(Debug, Default)]
pub struct CompileConfig {
is_release: bool,
}
impl CompileConfig {
pub fn with_is_release(mut self, is_release: bool) -> Self {
self.is_release = is_release;
self
}
pub fn is_release(&self) -> bool {
self.is_release
}
}
type FilePath = PathBuf;
pub fn compile<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();
@ -162,7 +178,7 @@ pub fn compile<T: Field, E: Into<imports::Error>>(
let ir_prog = ir::Prog::from(program_flattened);
// optimize
let optimized_ir_prog = ir_prog.optimize();
let optimized_ir_prog = ir_prog.optimize(config);
// analyse (check for unused constraints)
let optimized_ir_prog = optimized_ir_prog.analyse();
@ -264,6 +280,7 @@ mod test {
source,
"./path/to/file".into(),
None::<&dyn Resolver<io::Error>>,
&CompileConfig::default(),
);
assert!(res.unwrap_err().0[0]
.value()
@ -282,6 +299,7 @@ mod test {
source,
"./path/to/file".into(),
None::<&dyn Resolver<io::Error>>,
&CompileConfig::default(),
);
assert!(res.is_ok());
}
@ -362,6 +380,7 @@ struct Bar { field a }
main.to_string(),
"main".into(),
Some(&CustomResolver),
&CompileConfig::default(),
)
.unwrap();

View file

@ -13,18 +13,19 @@ use self::directive::DirectiveOptimizer;
use self::duplicate::DuplicateOptimizer;
use self::redefinition::RedefinitionOptimizer;
use self::tautology::TautologyOptimizer;
use compile::CompileConfig;
use crate::ir::Prog;
use zokrates_field::Field;
pub trait Optimize {
fn optimize(self) -> Self;
}
impl<T: Field> Optimize for Prog<T> {
fn optimize(self) -> Self {
// remove redefinitions
let r = RedefinitionOptimizer::optimize(self);
impl<T: Field> Prog<T> {
pub fn optimize(self, config: &CompileConfig) -> Self {
let r = if config.is_release() {
// remove redefinitions
RedefinitionOptimizer::optimize(self)
} else {
self
};
// remove constraints that are always satisfied
let r = TautologyOptimizer::optimize(r);
// // deduplicate directives which take the same input

View file

@ -7,55 +7,73 @@ use regex::Regex;
use zokrates_field::Field;
use crate::ir;
use crate::proof_system::bn128::utils::bellman::Computation;
use crate::proof_system::bn128::utils::bellman::{
parse_fr, parse_g1, parse_g1_hex, parse_g2, parse_g2_hex,
};
use crate::proof_system::bn128::utils::parser::parse_vk;
use crate::proof_system::bn128::utils::solidity::{
use crate::proof_system::bellman::Computation;
use crate::proof_system::bellman::{parse_fr, parse_g1, parse_g2};
use crate::proof_system::solidity::{
SOLIDITY_G2_ADDITION_LIB, SOLIDITY_PAIRING_LIB, SOLIDITY_PAIRING_LIB_V2,
};
use crate::proof_system::{ProofSystem, SetupKeypair};
use proof_system::bn128::{G1PairingPoint, G2PairingPoint, Proof};
use proof_system::SolidityAbi;
use proof_system::{G1Affine, G2Affine, Proof, ProofSystem, SetupKeypair, SolidityAbi};
const G16_WARNING: &str = "WARNING: You are using the G16 scheme which is subject to malleability. See zokrates.github.io/reference/proving_schemes.html#g16-malleability for implications.";
pub struct G16 {}
#[derive(Serialize, Deserialize)]
struct G16ProofPoints {
a: G1PairingPoint,
b: G2PairingPoint,
c: G1PairingPoint,
pub struct ProofPoints {
a: G1Affine,
b: G2Affine,
c: G1Affine,
}
impl G16ProofPoints {
fn new(a: G1PairingPoint, b: G2PairingPoint, c: G1PairingPoint) -> Self {
G16ProofPoints { a, b, c }
}
#[derive(Serialize, Deserialize)]
pub struct VerificationKey {
alpha: G1Affine,
beta: G2Affine,
gamma: G2Affine,
delta: G2Affine,
gamma_abc: Vec<G1Affine>,
raw: String,
}
impl<T: Field> ProofSystem<T> for G16 {
fn setup(program: ir::Prog<T>) -> SetupKeypair {
type VerificationKey = VerificationKey;
type ProofPoints = ProofPoints;
fn setup(program: ir::Prog<T>) -> SetupKeypair<VerificationKey> {
#[cfg(not(target_arch = "wasm32"))]
std::env::set_var("BELLMAN_VERBOSE", "0");
println!("{}", G16_WARNING);
let parameters = Computation::without_witness(program).setup();
let vk = serialize_vk::<T>(&parameters.vk);
let mut pk: Vec<u8> = Vec::new();
parameters.write(&mut pk).unwrap();
let mut vk_raw: Vec<u8> = Vec::new();
SetupKeypair::from(vk, pk)
parameters.write(&mut pk).unwrap();
parameters.vk.write(&mut vk_raw).unwrap();
let vk = VerificationKey {
alpha: parse_g1::<T>(&parameters.vk.alpha_g1),
beta: parse_g2::<T>(&parameters.vk.beta_g2),
gamma: parse_g2::<T>(&parameters.vk.gamma_g2),
delta: parse_g2::<T>(&parameters.vk.delta_g2),
gamma_abc: parameters
.vk
.ic
.iter()
.map(|g1| parse_g1::<T>(g1))
.collect(),
raw: hex::encode(vk_raw),
};
SetupKeypair::new(vk, pk)
}
fn generate_proof(
program: ir::Prog<T>,
witness: ir::Witness<T>,
proving_key: Vec<u8>,
) -> String {
) -> Proof<ProofPoints> {
#[cfg(not(target_arch = "wasm32"))]
std::env::set_var("BELLMAN_VERBOSE", "0");
@ -65,11 +83,12 @@ impl<T: Field> ProofSystem<T> for G16 {
let params = Parameters::read(proving_key.as_slice(), true).unwrap();
let proof = computation.clone().prove(&params);
let proof_points = G16ProofPoints::new(
parse_g1::<T>(&proof.a),
parse_g2::<T>(&proof.b),
parse_g1::<T>(&proof.c),
);
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()
@ -80,11 +99,10 @@ impl<T: Field> ProofSystem<T> for G16 {
let mut raw: Vec<u8> = Vec::new();
proof.write(&mut raw).unwrap();
Proof::<G16ProofPoints>::new(proof_points, inputs, hex::encode(&raw)).to_json_pretty()
Proof::<ProofPoints>::new(proof_points, inputs, hex::encode(&raw))
}
fn export_solidity_verifier(vk: String, abi: SolidityAbi) -> String {
let vk_map = parse_vk(vk).unwrap();
fn export_solidity_verifier(vk: VerificationKey, abi: SolidityAbi) -> String {
let (mut template_text, solidity_pairing_lib) = match abi {
SolidityAbi::V1 => (
String::from(CONTRACT_TEMPLATE),
@ -101,14 +119,23 @@ impl<T: Field> ProofSystem<T> for G16 {
let vk_gamma_abc_repeat_regex = Regex::new(r#"(<%vk_gamma_abc_pts%>)"#).unwrap();
let vk_input_len_regex = Regex::new(r#"(<%vk_input_length%>)"#).unwrap();
let keys = vec!["vk.alpha", "vk.beta", "vk.gamma", "vk.delta"];
for key in keys.iter() {
template_text = vk_regex
.replace(template_text.as_str(), vk_map.get(*key).unwrap().as_str())
.into_owned();
}
template_text = vk_regex
.replace(template_text.as_str(), vk.alpha.to_string().as_str())
.into_owned();
let gamma_abc_count: usize = vk_map.get("vk.gamma_abc.len()").unwrap().parse().unwrap();
template_text = vk_regex
.replace(template_text.as_str(), vk.beta.to_string().as_str())
.into_owned();
template_text = vk_regex
.replace(template_text.as_str(), vk.gamma.to_string().as_str())
.into_owned();
template_text = vk_regex
.replace(template_text.as_str(), vk.delta.to_string().as_str())
.into_owned();
let gamma_abc_count: usize = vk.gamma_abc.len();
template_text = vk_gamma_abc_len_regex
.replace(
template_text.as_str(),
@ -124,19 +151,16 @@ impl<T: Field> ProofSystem<T> for G16 {
.into_owned();
let mut gamma_abc_repeat_text = String::new();
for x in 0..gamma_abc_count {
for (i, g1) in vk.gamma_abc.iter().enumerate() {
gamma_abc_repeat_text.push_str(
format!(
"vk.gamma_abc[{}] = Pairing.G1Point({});",
x,
vk_map
.get(format!("vk.gamma_abc[{}]", x).as_str())
.unwrap()
.as_str()
i,
g1.to_string().as_str()
)
.as_str(),
);
if x < gamma_abc_count - 1 {
if i < gamma_abc_count - 1 {
gamma_abc_repeat_text.push_str("\n ");
}
}
@ -154,20 +178,18 @@ impl<T: Field> ProofSystem<T> for G16 {
)
}
fn verify(vk: String, proof: String) -> bool {
let map = parse_vk(vk).unwrap();
let vk_raw = hex::decode(map.get("vk.raw").unwrap()).unwrap();
fn verify(vk: VerificationKey, proof: Proof<ProofPoints>) -> bool {
let vk_raw = hex::decode(vk.raw.clone()).unwrap();
let proof_raw = hex::decode(proof.raw.clone()).unwrap();
let vk: VerifyingKey<T::BellmanEngine> = VerifyingKey::read(vk_raw.as_slice()).unwrap();
let pvk: PreparedVerifyingKey<T::BellmanEngine> = prepare_verifying_key(&vk);
let g16_proof = Proof::<G16ProofPoints>::from_str(proof.as_str());
let bellman_proof: BellmanProof<T::BellmanEngine> =
BellmanProof::read(proof_raw.as_slice()).unwrap();
let raw_proof = hex::decode(g16_proof.raw).unwrap();
let proof: BellmanProof<T::BellmanEngine> =
BellmanProof::read(raw_proof.as_slice()).unwrap();
let public_inputs: Vec<_> = g16_proof
let public_inputs: Vec<_> = proof
.inputs
.iter()
.map(|s| {
@ -177,51 +199,10 @@ impl<T: Field> ProofSystem<T> for G16 {
})
.collect::<Vec<_>>();
verify_proof(&pvk, &proof, &public_inputs).unwrap()
verify_proof(&pvk, &bellman_proof, &public_inputs).unwrap()
}
}
fn serialize_vk<T: Field>(vk: &VerifyingKey<T::BellmanEngine>) -> String {
let mut writer = csv::WriterBuilder::new()
.delimiter(b'=')
.from_writer(vec![]);
writer
.write_record(&["vk.alpha", parse_g1_hex::<T>(&vk.alpha_g1).as_str()])
.unwrap();
writer
.write_record(&["vk.beta", parse_g2_hex::<T>(&vk.beta_g2).as_str()])
.unwrap();
writer
.write_record(&["vk.gamma", parse_g2_hex::<T>(&vk.gamma_g2).as_str()])
.unwrap();
writer
.write_record(&["vk.delta", parse_g2_hex::<T>(&vk.delta_g2).as_str()])
.unwrap();
writer
.write_record(&["vk.gamma_abc.len()", vk.ic.len().to_string().as_str()])
.unwrap();
let mut e = vk.ic.iter().enumerate();
while let Some((i, x)) = e.next() {
writer
.write_record(&[
format!("vk.gamma_abc[{}]", i).as_str(),
parse_g1_hex::<T>(x).as_str(),
])
.unwrap()
}
let mut raw: Vec<u8> = Vec::new();
vk.write(&mut raw).unwrap();
writer
.write_record(&["vk.raw", hex::encode(&raw).as_str()])
.unwrap();
String::from_utf8(writer.into_inner().unwrap()).unwrap()
}
const CONTRACT_TEMPLATE_V2: &str = r#"
contract Verifier {
using Pairing for *;

View file

@ -1,3 +1,5 @@
pub mod groth16;
extern crate rand;
use crate::ir::{CanonicalLinComb, Prog, Statement, Witness};
@ -209,6 +211,7 @@ mod parse {
use lazy_static::lazy_static;
use super::*;
use proof_system::{G1Affine, G2Affine};
use regex::Regex;
lazy_static! {
@ -227,10 +230,10 @@ mod parse {
pub fn parse_g1<T: Field>(
e: &<T::BellmanEngine as bellman::pairing::Engine>::G1Affine,
) -> (String, String) {
) -> G1Affine {
let raw_e = e.to_string();
let captures = G1_REGEX.captures(&raw_e).unwrap();
(
G1Affine(
captures.name(&"x").unwrap().as_str().to_string(),
captures.name(&"y").unwrap().as_str().to_string(),
)
@ -238,15 +241,15 @@ mod parse {
pub fn parse_g2<T: Field>(
e: &<T::BellmanEngine as bellman::pairing::Engine>::G2Affine,
) -> ((String, String), (String, String)) {
) -> G2Affine {
let raw_e = e.to_string();
let captures = G2_REGEX.captures(&raw_e).unwrap();
(
(
G2Affine(
G1Affine(
captures.name(&"x1").unwrap().as_str().to_string(),
captures.name(&"x0").unwrap().as_str().to_string(),
),
(
G1Affine(
captures.name(&"y1").unwrap().as_str().to_string(),
captures.name(&"y0").unwrap().as_str().to_string(),
),
@ -258,26 +261,6 @@ mod parse {
let captures = FR_REGEX.captures(&raw_e).unwrap();
captures.name(&"x").unwrap().as_str().to_string()
}
pub fn parse_g1_hex<T: Field>(
e: &<T::BellmanEngine as bellman::pairing::Engine>::G1Affine,
) -> String {
let parsed = parse_g1::<T>(e);
format!("{}, {}", parsed.0, parsed.1)
}
pub fn parse_g2_hex<T: Field>(
e: &<T::BellmanEngine as bellman::pairing::Engine>::G2Affine,
) -> String {
let parsed = parse_g2::<T>(e);
format!(
"[{}, {}], [{}, {}]",
(parsed.0).0,
(parsed.0).1,
(parsed.1).0,
(parsed.1).1
)
}
}
#[cfg(test)]

View file

@ -1,36 +0,0 @@
mod g16;
#[cfg(feature = "libsnark")]
mod gm17;
#[cfg(feature = "libsnark")]
mod pghr13;
mod utils;
pub use self::g16::G16;
#[cfg(feature = "libsnark")]
pub use self::gm17::GM17;
#[cfg(feature = "libsnark")]
pub use self::pghr13::PGHR13;
use serde::{Deserialize, Serialize};
type G1PairingPoint = (String, String);
type G2PairingPoint = (G1PairingPoint, G1PairingPoint);
#[derive(Serialize, Deserialize)]
struct Proof<T> {
proof: T,
inputs: Vec<String>,
raw: String,
}
impl<'a, T: Serialize + Deserialize<'a>> Proof<T> {
fn new(proof: T, inputs: Vec<String>, raw: String) -> Self {
Proof { proof, inputs, raw }
}
fn from_str(proof: &'a str) -> Proof<T> {
serde_json::from_str(proof).expect("Invalid proof json format")
}
fn to_json_pretty(&self) -> String {
serde_json::to_string_pretty(self).unwrap()
}
}

View file

@ -1,7 +0,0 @@
pub mod bellman;
#[cfg(feature = "libsnark")]
pub mod ffi;
#[cfg(feature = "libsnark")]
pub mod libsnark;
pub mod parser;
pub mod solidity;

View file

@ -1,60 +0,0 @@
use std::collections::HashMap;
pub fn parse_vk(vk: String) -> Result<HashMap<String, String>, csv::Error> {
let mut reader = csv::ReaderBuilder::new()
.delimiter(b'=')
.has_headers(false)
.trim(csv::Trim::All)
.flexible(false)
.from_reader(vk.trim().as_bytes());
let mut map = HashMap::new();
let mut iterator = reader.deserialize::<(String, String)>();
while let Some(r) = iterator.next() {
let r = r?;
map.insert(r.0, r.1);
}
Ok(map)
}
#[cfg(test)]
mod tests {
use proof_system::bn128::utils::parser::parse_vk;
#[test]
fn parse_valid_input() {
let example: String = r#"
a = 1
b = 2
"#
.to_string();
let map = parse_vk(example).unwrap();
assert_eq!("1", map.get("a").unwrap());
assert_eq!("2", map.get("b").unwrap());
}
#[test]
#[should_panic]
fn panic_on_invalid_delimiter() {
parse_vk("a , 1".to_string()).unwrap();
}
#[test]
#[should_panic]
fn panic_on_unequal_lengths() {
let example: String = r#"
a = 1
b = 2 = 3
"#
.to_string();
parse_vk(example).unwrap();
}
#[test]
fn parse_empty() {
let map = parse_vk(String::new()).unwrap();
assert!(map.is_empty());
}
}

View file

@ -1,14 +1,10 @@
use ir;
use proof_system::bn128::utils::ffi::{Buffer, ProofResult, SetupResult};
use proof_system::bn128::utils::libsnark::{
prepare_generate_proof, prepare_public_inputs, prepare_setup,
};
use proof_system::bn128::utils::parser::parse_vk;
use proof_system::bn128::utils::solidity::{
use proof_system::libsnark::ffi::{Buffer, ProofResult, SetupResult};
use proof_system::libsnark::{prepare_generate_proof, prepare_public_inputs, prepare_setup};
use proof_system::solidity::{
SOLIDITY_G2_ADDITION_LIB, SOLIDITY_PAIRING_LIB, SOLIDITY_PAIRING_LIB_V2,
};
use proof_system::bn128::{G1PairingPoint, G2PairingPoint, Proof};
use proof_system::{ProofSystem, SetupKeypair, SolidityAbi};
use proof_system::{G1Affine, G2Affine, Proof, ProofSystem, SetupKeypair, SolidityAbi};
use regex::Regex;
use zokrates_field::Bn128Field;
@ -17,14 +13,25 @@ use zokrates_field::Field;
pub struct GM17 {}
#[derive(Serialize, Deserialize)]
struct GM17ProofPoints {
a: G1PairingPoint,
b: G2PairingPoint,
c: G1PairingPoint,
pub struct VerificationKey {
h: G2Affine,
g_alpha: G1Affine,
h_beta: G2Affine,
g_gamma: G1Affine,
h_gamma: G2Affine,
query: Vec<G1Affine>,
raw: String,
}
#[derive(Serialize, Deserialize)]
pub struct ProofPoints {
a: G1Affine,
b: G2Affine,
c: G1Affine,
}
extern "C" {
fn gm17_setup(
fn gm17_bn128_setup(
a: *const u8,
b: *const u8,
c: *const u8,
@ -36,7 +43,7 @@ extern "C" {
inputs: i32,
) -> SetupResult;
fn gm17_generate_proof(
fn gm17_bn128_generate_proof(
pk_buf: *mut Buffer,
public_query_inputs: *const u8,
public_query_inputs_length: i32,
@ -44,7 +51,7 @@ extern "C" {
private_inputs_length: i32,
) -> ProofResult;
fn gm17_verify(
fn gm17_bn128_verify(
vk_buf: *mut Buffer,
proof_buf: *mut Buffer,
public_inputs: *const u8,
@ -53,12 +60,15 @@ extern "C" {
}
impl ProofSystem<Bn128Field> for GM17 {
fn setup(program: ir::Prog<Bn128Field>) -> SetupKeypair {
type VerificationKey = VerificationKey;
type ProofPoints = ProofPoints;
fn setup(program: ir::Prog<Bn128Field>) -> SetupKeypair<VerificationKey> {
let (a_arr, b_arr, c_arr, a_vec, b_vec, c_vec, num_constraints, num_variables, num_inputs) =
prepare_setup(program);
let keypair = unsafe {
let result: SetupResult = gm17_setup(
let result: SetupResult = gm17_bn128_setup(
a_arr.as_ptr(),
b_arr.as_ptr(),
c_arr.as_ptr(),
@ -83,21 +93,22 @@ impl ProofSystem<Bn128Field> for GM17 {
(vk, pk)
};
SetupKeypair::from(String::from_utf8(keypair.0).unwrap(), keypair.1)
let vk = serde_json::from_str(String::from_utf8(keypair.0).unwrap().as_str()).unwrap();
SetupKeypair::new(vk, keypair.1)
}
fn generate_proof(
program: ir::Prog<Bn128Field>,
witness: ir::Witness<Bn128Field>,
proving_key: Vec<u8>,
) -> String {
) -> Proof<ProofPoints> {
let (public_inputs_arr, public_inputs_length, private_inputs_arr, private_inputs_length) =
prepare_generate_proof(program, witness);
let mut pk_buffer = Buffer::from_vec(&proving_key);
let proof = unsafe {
let result = gm17_generate_proof(
let result = gm17_bn128_generate_proof(
&mut pk_buffer as *mut _,
public_inputs_arr[0].as_ptr(),
public_inputs_length as i32,
@ -118,11 +129,10 @@ impl ProofSystem<Bn128Field> for GM17 {
proof
};
String::from_utf8(proof).unwrap()
serde_json::from_str(String::from_utf8(proof).unwrap().as_str()).unwrap()
}
fn export_solidity_verifier(vk: String, abi: SolidityAbi) -> String {
let vk_map = parse_vk(vk).unwrap();
fn export_solidity_verifier(vk: VerificationKey, abi: SolidityAbi) -> String {
let (mut template_text, solidity_pairing_lib) = match abi {
SolidityAbi::V1 => (
String::from(CONTRACT_TEMPLATE),
@ -140,21 +150,27 @@ impl ProofSystem<Bn128Field> for GM17 {
let vk_query_repeat_regex = Regex::new(r#"(<%vk_query_pts%>)"#).unwrap();
let vk_input_len_regex = Regex::new(r#"(<%vk_input_length%>)"#).unwrap();
let keys = vec![
"vk.h",
"vk.g_alpha",
"vk.h_beta",
"vk.g_gamma",
"vk.h_gamma",
];
template_text = vk_regex
.replace(template_text.as_str(), vk.h.to_string().as_str())
.into_owned();
for key in keys.iter() {
template_text = vk_regex
.replace(template_text.as_str(), vk_map.get(*key).unwrap().as_str())
.into_owned();
}
template_text = vk_regex
.replace(template_text.as_str(), vk.g_alpha.to_string().as_str())
.into_owned();
let query_count: usize = vk_map.get("vk.query.len()").unwrap().parse().unwrap();
template_text = vk_regex
.replace(template_text.as_str(), vk.h_beta.to_string().as_str())
.into_owned();
template_text = vk_regex
.replace(template_text.as_str(), vk.g_gamma.to_string().as_str())
.into_owned();
template_text = vk_regex
.replace(template_text.as_str(), vk.h_gamma.to_string().as_str())
.into_owned();
let query_count: usize = vk.query.len();
template_text = vk_query_len_regex
.replace(template_text.as_str(), format!("{}", query_count).as_str())
.into_owned();
@ -167,19 +183,16 @@ impl ProofSystem<Bn128Field> for GM17 {
.into_owned();
let mut query_repeat_text = String::new();
for x in 0..query_count {
for (i, g1) in vk.query.iter().enumerate() {
query_repeat_text.push_str(
format!(
"vk.query[{}] = Pairing.G1Point({});",
x,
vk_map
.get(format!("vk.query[{}]", x).as_str())
.unwrap()
.as_str()
i,
g1.to_string().as_str()
)
.as_str(),
);
if x < query_count - 1 {
if i < query_count - 1 {
query_repeat_text.push_str("\n ");
}
}
@ -197,12 +210,9 @@ impl ProofSystem<Bn128Field> for GM17 {
)
}
fn verify(vk: String, proof: String) -> bool {
let map = parse_vk(vk).unwrap();
let vk_raw = hex::decode(map.get("vk.raw").unwrap()).unwrap();
let proof = Proof::<GM17ProofPoints>::from_str(proof.as_str());
let proof_raw = hex::decode(proof.raw).unwrap();
fn verify(vk: VerificationKey, proof: Proof<ProofPoints>) -> bool {
let vk_raw = hex::decode(vk.raw.clone()).unwrap();
let proof_raw = hex::decode(proof.raw.clone()).unwrap();
let public_inputs: Vec<_> = proof
.inputs
@ -219,7 +229,7 @@ impl ProofSystem<Bn128Field> for GM17 {
let mut proof_buffer = Buffer::from_vec(&proof_raw);
unsafe {
let ans = gm17_verify(
let ans = gm17_bn128_verify(
&mut vk_buffer as *mut _,
&mut proof_buffer as *mut _,
public_inputs_arr[0].as_ptr(),

View file

@ -1,3 +1,7 @@
mod ffi;
pub mod gm17;
pub mod pghr13;
use flat_absy::FlatVariable;
use ir::{self, Statement};
use std::cmp::max;
@ -293,7 +297,7 @@ pub fn r1cs_program<T: Field>(
let mut variables_list = vec![FlatVariable::new(0); variables.len()];
for (k, v) in variables.drain() {
assert_eq!(variables_list[v], FlatVariable::new(0));
std::mem::replace(&mut variables_list[v], k);
variables_list[v] = k;
}
(variables_list, private_inputs_offset, a, b, c)
}

View file

@ -1,14 +1,10 @@
use ir;
use proof_system::bn128::utils::ffi::{Buffer, ProofResult, SetupResult};
use proof_system::bn128::utils::libsnark::{
prepare_generate_proof, prepare_public_inputs, prepare_setup,
};
use proof_system::bn128::utils::parser::parse_vk;
use proof_system::bn128::utils::solidity::{
use proof_system::libsnark::ffi::{Buffer, ProofResult, SetupResult};
use proof_system::libsnark::{prepare_generate_proof, prepare_public_inputs, prepare_setup};
use proof_system::solidity::{
SOLIDITY_G2_ADDITION_LIB, SOLIDITY_PAIRING_LIB, SOLIDITY_PAIRING_LIB_V2,
};
use proof_system::bn128::{G1PairingPoint, G2PairingPoint, Proof};
use proof_system::{ProofSystem, SetupKeypair, SolidityAbi};
use proof_system::{G1Affine, G2Affine, Proof, ProofSystem, SetupKeypair, SolidityAbi};
use regex::Regex;
use zokrates_field::Bn128Field;
@ -17,19 +13,32 @@ use zokrates_field::Field;
pub struct PGHR13 {}
#[derive(Serialize, Deserialize)]
pub struct PGHR13ProofPoints {
a: G1PairingPoint,
a_p: G1PairingPoint,
b: G2PairingPoint,
b_p: G1PairingPoint,
c: G1PairingPoint,
c_p: G1PairingPoint,
h: G1PairingPoint,
k: G1PairingPoint,
pub struct VerificationKey {
a: G2Affine,
b: G1Affine,
c: G2Affine,
gamma: G2Affine,
gamma_beta_1: G1Affine,
gamma_beta_2: G2Affine,
z: G2Affine,
ic: Vec<G1Affine>,
raw: String,
}
#[derive(Serialize, Deserialize)]
pub struct ProofPoints {
a: G1Affine,
a_p: G1Affine,
b: G2Affine,
b_p: G1Affine,
c: G1Affine,
c_p: G1Affine,
h: G1Affine,
k: G1Affine,
}
extern "C" {
fn pghr13_setup(
fn pghr13_bn128_setup(
a: *const u8,
b: *const u8,
c: *const u8,
@ -41,7 +50,7 @@ extern "C" {
inputs: i32,
) -> SetupResult;
fn pghr13_generate_proof(
fn pghr13_bn128_generate_proof(
pk_buf: *mut Buffer,
public_query_inputs: *const u8,
public_query_inputs_length: i32,
@ -49,7 +58,7 @@ extern "C" {
private_inputs_length: i32,
) -> ProofResult;
fn pghr13_verify(
fn pghr13_bn128_verify(
vk_buf: *mut Buffer,
proof_buf: *mut Buffer,
public_inputs: *const u8,
@ -58,12 +67,15 @@ extern "C" {
}
impl ProofSystem<Bn128Field> for PGHR13 {
fn setup(program: ir::Prog<Bn128Field>) -> SetupKeypair {
type VerificationKey = VerificationKey;
type ProofPoints = ProofPoints;
fn setup(program: ir::Prog<Bn128Field>) -> SetupKeypair<VerificationKey> {
let (a_arr, b_arr, c_arr, a_vec, b_vec, c_vec, num_constraints, num_variables, num_inputs) =
prepare_setup(program);
let keypair = unsafe {
let result: SetupResult = pghr13_setup(
let result: SetupResult = pghr13_bn128_setup(
a_arr.as_ptr(),
b_arr.as_ptr(),
c_arr.as_ptr(),
@ -88,21 +100,22 @@ impl ProofSystem<Bn128Field> for PGHR13 {
(vk, pk)
};
SetupKeypair::from(String::from_utf8(keypair.0).unwrap(), keypair.1)
let vk = serde_json::from_str(String::from_utf8(keypair.0).unwrap().as_str()).unwrap();
SetupKeypair::new(vk, keypair.1)
}
fn generate_proof(
program: ir::Prog<Bn128Field>,
witness: ir::Witness<Bn128Field>,
proving_key: Vec<u8>,
) -> String {
) -> Proof<ProofPoints> {
let (public_inputs_arr, public_inputs_length, private_inputs_arr, private_inputs_length) =
prepare_generate_proof(program, witness);
let mut pk_buf = Buffer::from_vec(&proving_key);
let proof_vec = unsafe {
let result = pghr13_generate_proof(
let proof = unsafe {
let result = pghr13_bn128_generate_proof(
&mut pk_buf as *mut _,
public_inputs_arr[0].as_ptr(),
public_inputs_length as i32,
@ -112,7 +125,7 @@ impl ProofSystem<Bn128Field> for PGHR13 {
pk_buf.drop(); // drop the buffer manually
let proof_vec: Vec<u8> =
let proof: Vec<u8> =
std::slice::from_raw_parts(result.proof.data, result.proof.length as usize)
.to_vec();
@ -120,14 +133,13 @@ impl ProofSystem<Bn128Field> for PGHR13 {
// free the memory.
result.proof.free();
proof_vec
proof
};
String::from_utf8(proof_vec).unwrap()
serde_json::from_str(String::from_utf8(proof).unwrap().as_str()).unwrap()
}
fn export_solidity_verifier(vk: String, abi: SolidityAbi) -> String {
let vk_map = parse_vk(vk).unwrap();
fn export_solidity_verifier(vk: VerificationKey, abi: SolidityAbi) -> String {
let (mut template_text, solidity_pairing_lib) = match abi {
SolidityAbi::V1 => (
String::from(CONTRACT_TEMPLATE),
@ -145,23 +157,35 @@ impl ProofSystem<Bn128Field> for PGHR13 {
let vk_ic_repeat_regex = Regex::new(r#"(<%vk_ic_pts%>)"#).unwrap();
let vk_input_len_regex = Regex::new(r#"(<%vk_input_length%>)"#).unwrap();
let keys = vec![
"vk.a",
"vk.b",
"vk.c",
"vk.gamma",
"vk.gamma_beta_1",
"vk.gamma_beta_2",
"vk.z",
];
template_text = vk_regex
.replace(template_text.as_str(), vk.a.to_string().as_str())
.into_owned();
for key in keys.iter() {
template_text = vk_regex
.replace(template_text.as_str(), vk_map.get(*key).unwrap().as_str())
.into_owned();
}
template_text = vk_regex
.replace(template_text.as_str(), vk.b.to_string().as_str())
.into_owned();
let ic_count: usize = vk_map.get("vk.ic.len()").unwrap().parse().unwrap();
template_text = vk_regex
.replace(template_text.as_str(), vk.c.to_string().as_str())
.into_owned();
template_text = vk_regex
.replace(template_text.as_str(), vk.gamma.to_string().as_str())
.into_owned();
template_text = vk_regex
.replace(template_text.as_str(), vk.gamma_beta_1.to_string().as_str())
.into_owned();
template_text = vk_regex
.replace(template_text.as_str(), vk.gamma_beta_2.to_string().as_str())
.into_owned();
template_text = vk_regex
.replace(template_text.as_str(), vk.z.to_string().as_str())
.into_owned();
let ic_count: usize = vk.ic.len();
template_text = vk_ic_len_regex
.replace(template_text.as_str(), format!("{}", ic_count).as_str())
.into_owned();
@ -171,19 +195,16 @@ impl ProofSystem<Bn128Field> for PGHR13 {
.into_owned();
let mut ic_repeat_text = String::new();
for x in 0..ic_count {
for (i, g1) in vk.ic.iter().enumerate() {
ic_repeat_text.push_str(
format!(
"vk.ic[{}] = Pairing.G1Point({});",
x,
vk_map
.get(format!("vk.ic[{}]", x).as_str())
.unwrap()
.as_str()
i,
g1.to_string().as_str()
)
.as_str(),
);
if x < ic_count - 1 {
if i < ic_count - 1 {
ic_repeat_text.push_str("\n ");
}
}
@ -201,12 +222,9 @@ impl ProofSystem<Bn128Field> for PGHR13 {
)
}
fn verify(vk: String, proof: String) -> bool {
let map = parse_vk(vk).unwrap();
let vk_raw = hex::decode(map.get("vk.raw").unwrap()).unwrap();
let proof = Proof::<PGHR13ProofPoints>::from_str(proof.as_str());
let proof_raw = hex::decode(proof.raw).unwrap();
fn verify(vk: VerificationKey, proof: Proof<ProofPoints>) -> bool {
let vk_raw = hex::decode(vk.raw.clone()).unwrap();
let proof_raw = hex::decode(proof.raw.clone()).unwrap();
let public_inputs: Vec<_> = proof
.inputs
@ -223,7 +241,7 @@ impl ProofSystem<Bn128Field> for PGHR13 {
let mut proof_buffer = Buffer::from_vec(&proof_raw);
unsafe {
let ans = pghr13_verify(
let ans = pghr13_bn128_verify(
&mut vk_buffer as *mut _,
&mut proof_buffer as *mut _,
public_inputs_arr[0].as_ptr(),

View file

@ -1,24 +1,24 @@
mod bn128;
pub mod bellman;
#[cfg(feature = "libsnark")]
pub mod libsnark;
pub use self::bn128::G16;
#[cfg(feature = "libsnark")]
pub use self::bn128::GM17;
#[cfg(feature = "libsnark")]
pub use self::bn128::PGHR13;
mod solidity;
use crate::ir;
use serde::de::DeserializeOwned;
use serde::Serialize;
use zokrates_field::Field;
// We only need to serialize this struct, there is no need for deserialization as keys are
// used separately in other use cases
#[derive(Serialize)]
pub struct SetupKeypair {
pub vk: String,
pub struct SetupKeypair<V> {
pub vk: V,
pub pk: Vec<u8>,
}
impl SetupKeypair {
pub fn from(vk: String, pk: Vec<u8>) -> SetupKeypair {
impl<V: Serialize + DeserializeOwned> SetupKeypair<V> {
pub fn new(vk: V, pk: Vec<u8>) -> SetupKeypair<V> {
SetupKeypair { vk, pk }
}
}
@ -38,16 +38,54 @@ impl SolidityAbi {
}
}
pub trait ProofSystem<T: Field> {
fn setup(program: ir::Prog<T>) -> SetupKeypair;
#[derive(Serialize, Deserialize)]
pub struct Proof<T> {
proof: T,
inputs: Vec<String>,
raw: String,
}
impl<T: Serialize + DeserializeOwned> Proof<T> {
fn new(proof: T, inputs: Vec<String>, raw: String) -> Self {
Proof { proof, inputs, raw }
}
}
#[derive(Serialize, Deserialize)]
pub struct G1Affine(String, String);
#[derive(Serialize, Deserialize)]
pub struct G2Affine(G1Affine, G1Affine);
impl ToString for G1Affine {
fn to_string(&self) -> String {
format!("{}, {}", self.0, self.1)
}
}
impl ToString for G2Affine {
fn to_string(&self) -> String {
format!("[{}], [{}]", self.0.to_string(), self.1.to_string())
}
}
pub trait ProofSystem<T: Field>
where
Self::VerificationKey: Serialize + DeserializeOwned,
Self::ProofPoints: Serialize + DeserializeOwned,
{
type VerificationKey;
type ProofPoints;
fn setup(program: ir::Prog<T>) -> SetupKeypair<Self::VerificationKey>;
fn generate_proof(
program: ir::Prog<T>,
witness: ir::Witness<T>,
proving_key: Vec<u8>,
) -> String;
) -> Proof<Self::ProofPoints>;
fn export_solidity_verifier(vk: String, abi: SolidityAbi) -> String;
fn export_solidity_verifier(vk: Self::VerificationKey, abi: SolidityAbi) -> String;
fn verify(vk: String, proof: String) -> bool;
fn verify(vk: Self::VerificationKey, proof: Proof<Self::ProofPoints>) -> bool;
}

View file

@ -5,7 +5,7 @@ extern crate zokrates_field;
use std::io;
use zokrates_common::Resolver;
use zokrates_core::{
compile::{compile, CompilationArtifacts},
compile::{compile, CompilationArtifacts, CompileConfig},
ir::Interpreter,
};
use zokrates_field::Bn128Field;
@ -28,6 +28,7 @@ fn out_of_range() {
source,
"./path/to/file".into(),
None::<&dyn Resolver<io::Error>>,
&CompileConfig::default(),
)
.unwrap();

View file

@ -9,7 +9,7 @@ use zokrates_core::ir::{Function, Interpreter, Prog, Statement};
use zokrates_core::proof_system::ProofSystem;
use zokrates_field::Bn128Field;
use zokrates_core::proof_system::G16;
use zokrates_core::proof_system::bellman::groth16::G16;
#[wasm_bindgen_test]
fn generate_proof() {

View file

@ -1,5 +1,30 @@
declare module 'zokrates-js' {
export type G1Affine = [string, string];
export type G2Affine = [G1Affine, G1Affine];
export type ProvingKey = Uint8Array;
export interface VerificationKey {
alpha: G1Affine,
beta: G2Affine,
gamma: G2Affine,
delta: G2Affine,
gamma_abc: G1Affine[],
raw: string,
}
export interface ProofPoints {
a: G1Affine,
b: G2Affine,
c: G1Affine
}
export interface Proof {
proof: ProofPoints,
inputs: string[],
raw: string
}
export interface ResolverResult {
source: string,
location: string
@ -16,8 +41,8 @@ declare module 'zokrates-js' {
}
export interface SetupKeypair {
vk: string,
pk: Uint8Array,
vk: VerificationKey,
pk: ProvingKey,
}
export type SolidityAbi = "v1" | "v2";
@ -27,8 +52,8 @@ declare module 'zokrates-js' {
compile(source: string, location: string, callback: ResolveCallback): CompilationArtifacts;
setup(program: Uint8Array): SetupKeypair;
computeWitness(artifacts: CompilationArtifacts, args: any[]): ComputationResult;
exportSolidityVerifier(verifyingKey: string, abi: SolidityAbi): string;
generateProof(program: Uint8Array, witness: string, provingKey: Uint8Array): string;
exportSolidityVerifier(verifyingKey: VerificationKey, abi: SolidityAbi): string;
generateProof(program: Uint8Array, witness: string, provingKey: Uint8Array): Proof;
}
export function initialize(): Promise<ZoKratesProvider>;

View file

@ -5,10 +5,13 @@ use std::path::PathBuf;
use wasm_bindgen::prelude::*;
use zokrates_abi::{parse_strict, Decode, Encode, Inputs};
use zokrates_common::Resolver;
use zokrates_core::compile::{compile as core_compile, CompilationArtifacts, CompileError};
use zokrates_core::compile::{
compile as core_compile, CompilationArtifacts, CompileConfig, CompileError,
};
use zokrates_core::imports::Error;
use zokrates_core::ir;
use zokrates_core::proof_system::{self, ProofSystem, SolidityAbi};
use zokrates_core::proof_system::{ProofSystem, SolidityAbi};
use zokrates_core::proof_system::bellman::groth16::G16;
use zokrates_core::typed_absy::abi::Abi;
use zokrates_core::typed_absy::types::Signature;
use zokrates_field::Bn128Field;
@ -104,6 +107,7 @@ pub fn compile(
source.as_string().unwrap(),
PathBuf::from(location.as_string().unwrap()),
Some(&resolver),
&CompileConfig::default().with_is_release(true),
)
.map_err(|ce| {
JsValue::from_str(&format!(
@ -159,7 +163,7 @@ pub fn compute_witness(artifacts: JsValue, args: JsValue) -> Result<JsValue, JsV
pub fn setup(program: JsValue) -> Result<JsValue, JsValue> {
let input: Vec<u8> = program.into_serde().unwrap();
let program_flattened = deserialize_program(&input)?;
let keypair = proof_system::G16::setup(program_flattened);
let keypair = G16::setup(program_flattened);
Ok(JsValue::from_serde(&keypair).unwrap())
}
@ -168,8 +172,8 @@ pub fn export_solidity_verifier(vk: JsValue, abi_version: JsValue) -> Result<JsV
let abi_version = SolidityAbi::from(abi_version.as_string().unwrap().as_str())
.map_err(|err| JsValue::from_str(err))?;
let verifier = <proof_system::G16 as ProofSystem<Bn128Field>>::export_solidity_verifier(
vk.as_string().unwrap(),
let verifier = <G16 as ProofSystem<Bn128Field>>::export_solidity_verifier(
vk.into_serde().unwrap(),
abi_version,
);
@ -186,9 +190,9 @@ pub fn generate_proof(program: JsValue, witness: JsValue, pk: JsValue) -> Result
.map_err(|err| JsValue::from_str(&format!("Could not read witness: {}", err)))?;
let proving_key: Vec<u8> = pk.into_serde().unwrap();
let proof = proof_system::G16::generate_proof(program_flattened, ir_witness, proving_key);
let proof = G16::generate_proof(program_flattened, ir_witness, proving_key);
Ok(JsValue::from_str(proof.as_str()))
Ok(JsValue::from_serde(&proof).unwrap())
}
#[wasm_bindgen(start)]

View file

@ -83,7 +83,7 @@ fn compare<T: Field>(result: ir::ExecutionResult<T>, expected: TestResult) -> Re
}
use std::io::{BufReader, Read};
use zokrates_core::compile::compile;
use zokrates_core::compile::{compile, CompileConfig};
use zokrates_fs_resolver::FileSystemResolver;
pub fn test_inner(test_path: &str) {
@ -104,7 +104,13 @@ fn compile_and_run<T: Field>(t: Tests) {
let code = std::fs::read_to_string(&t.entry_point).unwrap();
let resolver = FileSystemResolver::new();
let artifacts = compile::<T, _>(code, t.entry_point.clone(), Some(&resolver)).unwrap();
let artifacts = compile::<T, _>(
code,
t.entry_point.clone(),
Some(&resolver),
&CompileConfig::default().with_is_release(true),
)
.unwrap();
let bin = artifacts.prog();