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

Merge pull request #1103 from nirvantyagi/marlin-solidity-verifier

Marlin solidity verifier
This commit is contained in:
Thibaut Schaeffer 2022-04-11 10:41:05 +02:00 committed by GitHub
commit 68daa381e8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
48 changed files with 3335 additions and 3692 deletions

View file

@ -27,7 +27,7 @@ jobs:
test:
docker:
- image: zokrates/env:latest
resource_class: large
resource_class: xlarge
steps:
- checkout
- run:
@ -40,9 +40,11 @@ jobs:
command: cargo fmt --all -- --check
- run:
name: Run clippy
command: cargo clippy -- -D warnings
no_output_timeout: 1h
command: cargo clippy -j 4 -- -D warnings
- run:
name: Run tests
no_output_timeout: 1h
command: WITH_LIBSNARK=1 RUSTFLAGS="-D warnings" ./test.sh
- save-sccache-cache
cpp_format:

1200
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -10,6 +10,7 @@ members = [
"zokrates_abi",
"zokrates_test",
"zokrates_core_test",
"zokrates_solidity_test",
]
exclude = ["zokrates_js"]
exclude = ["zokrates_js"]

View file

@ -0,0 +1 @@
Output structured data for Marlin artifacts

View file

@ -0,0 +1 @@
Add support for EVM verification of the Marlin proof system

View file

@ -1 +1 @@
Handle unconstrained variables gracefully
Handle unconstrained variables gracefully

View file

@ -4,7 +4,7 @@
set -e
if [ -n "$WITH_LIBSNARK" ]; then
cargo test --release --package zokrates_cli --features="libsnark" -- --ignored
cargo test -j 4 --release --package zokrates_cli --features="libsnark" -- --ignored
else
cargo test --release --package zokrates_cli -- --ignored
cargo test -j 4 --release --package zokrates_cli -- --ignored
fi

View file

@ -5,8 +5,8 @@ set -e
if [ -n "$WITH_LIBSNARK" ]; then
# run specifically the libsnark tests inside zokrates_core
cargo test --release --package zokrates_core --features="libsnark" libsnark -- --test-threads=1
cargo test -j 4 --release --package zokrates_core --features="libsnark" libsnark -- --test-threads=1
fi
# run all tests without libsnark on
cargo test --release
cargo test -j 4 --release

View file

@ -9,4 +9,4 @@ zokrates_field = { version = "0.5", path = "../zokrates_field", default-features
zokrates_core = { version = "0.6", path = "../zokrates_core", default-features = false }
serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
serde_json = { version = "1.0", features = ["preserve_order"] }

View file

@ -23,12 +23,13 @@ zokrates_abi = { version = "0.1", path = "../zokrates_abi" }
zokrates_core = { version = "0.6", path = "../zokrates_core", default-features = false }
typed-arena = "1.4.1"
zokrates_fs_resolver = { version = "0.5", path = "../zokrates_fs_resolver"}
serde_json = "1.0"
serde_json = { version = "1.0", features = ["preserve_order"] }
serde = { version = "1.0", features = ["derive"] }
dirs = "3.0.1"
lazy_static = "1.4.0"
byteorder = "1"
rand = "0.4"
rand_0_4 = { version = "0.4", package = "rand" }
rand_0_8 = { version = "0.8", package = "rand" }
hex = "0.3.1"
blake2 = "0.8.1"
sha2 = "0.10.0"
@ -37,6 +38,9 @@ sha2 = "0.10.0"
glob = "0.2.11"
assert_cli = "0.5"
tempdir = "0.3"
zokrates_solidity_test = { version = "0.1", path = "../zokrates_solidity_test", default-features = false }
ethabi = "17.0.0"
primitive-types = { version = "0.11", features = ["rlp"] }
fs_extra = "1.1.0"
[build-dependencies]

View file

@ -1,15 +0,0 @@
use fs_extra::copy_items;
use fs_extra::dir::CopyOptions;
use std::env;
fn main() {
// export js test folder to OUT_DIR
export_stdlib();
}
fn export_stdlib() {
let out_dir = env::var("OUT_DIR").unwrap();
let mut options = CopyOptions::new();
options.overwrite = true;
copy_items(&["tests/contract"], out_dir, &options).unwrap();
}

View file

@ -71,6 +71,9 @@ pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> {
(CurveParameter::Bn128, SchemeParameter::PGHR13) => {
cli_export_verifier::<Bn128Field, PGHR13>(sub_matches)
}
(CurveParameter::Bn128, SchemeParameter::MARLIN) => {
cli_export_verifier::<Bn128Field, Marlin>(sub_matches)
}
_ => Err(format!("Could not export verifier with given parameters (curve: {}, scheme: {}): not supported", curve, scheme))
}
}

View file

@ -53,9 +53,6 @@ fn cli_inspect<T: Field, I: Iterator<Item = ir::Statement<T>>>(
let curve = format!("{:<17} {}", "curve:", T::name());
let constraint_count = format!("{:<17} {}", "constraint_count:", ir_prog.constraint_count());
println!("{}", curve);
println!("{}", constraint_count);
if sub_matches.is_present("ztf") {
let output_path =
PathBuf::from(sub_matches.value_of("input").unwrap()).with_extension("ztf");

View file

@ -87,8 +87,8 @@ fn cli_mpc_beacon<T: Field + BellmanFieldExtensions, S: MpcScheme<T>, B: MpcBack
// Create an RNG based on the outcome of the random beacon
let mut rng = {
use byteorder::{BigEndian, ReadBytesExt};
use rand::chacha::ChaChaRng;
use rand::SeedableRng;
use rand_0_4::chacha::ChaChaRng;
use rand_0_4::SeedableRng;
use sha2::{Digest, Sha256};
// The hash used for the beacon

View file

@ -76,8 +76,8 @@ pub fn cli_mpc_contribute<
let mut rng = {
use blake2::{Blake2b, Digest};
use byteorder::{BigEndian, ReadBytesExt};
use rand::chacha::ChaChaRng;
use rand::{OsRng, Rng, SeedableRng};
use rand_0_4::chacha::ChaChaRng;
use rand_0_4::{OsRng, Rng, SeedableRng};
let h = {
let mut system_rng = OsRng::new().unwrap();

View file

@ -1,8 +1,13 @@
use crate::constants::JSON_PROOF_PATH;
use crate::constants::{self, JSON_PROOF_PATH};
use crate::helpers::{CurveParameter, SchemeParameter};
use clap::{App, Arg, ArgMatches, SubCommand};
use serde_json::Value;
use std::convert::TryInto;
use std::fs::File;
use std::path::Path;
use zokrates_core::proof_system::{
Marlin, Proof, SolidityCompatibleField, SolidityCompatibleScheme, G16, GM17, PGHR13,
};
use zokrates_field::Bn128Field;
pub fn subcommand() -> App<'static, 'static> {
SubCommand::with_name("print-proof")
@ -25,41 +30,93 @@ pub fn subcommand() -> App<'static, 'static> {
.help("Format in which the proof should be printed")
.takes_value(true)
.possible_values(&["remix", "json"])
.required(true),
.required(true)
.default_value("remix"),
)
.arg(
Arg::with_name("proving-scheme")
.short("s")
.long("proving-scheme")
.help("Proving scheme the proof was created with")
.value_name("FILE")
.takes_value(true)
.required(false)
.possible_values(constants::SCHEMES)
.default_value(constants::G16),
)
.arg(
Arg::with_name("curve")
.short("c")
.long("curve")
.help("Curve to be used in the verification")
.takes_value(true)
.required(false)
.possible_values(constants::CURVES)
.default_value(constants::BN128),
)
}
pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> {
let curve = sub_matches.value_of("curve").unwrap();
let scheme = sub_matches.value_of("proving-scheme").unwrap();
let parameters: (CurveParameter, SchemeParameter) =
(curve.try_into().unwrap(), scheme.try_into().unwrap());
match parameters {
(CurveParameter::Bn128, SchemeParameter::PGHR13) => {
cli_print_proof::<Bn128Field, PGHR13>(sub_matches)
}
(CurveParameter::Bn128, SchemeParameter::G16) => {
cli_print_proof::<Bn128Field, G16>(sub_matches)
}
(CurveParameter::Bn128, SchemeParameter::GM17) => {
cli_print_proof::<Bn128Field, GM17>(sub_matches)
}
(CurveParameter::Bn128, SchemeParameter::MARLIN) => {
cli_print_proof::<Bn128Field, Marlin>(sub_matches)
}
_ => Err(format!("Could not print proof with given parameters (curve: {}, scheme: {}): only bn128 is supported", curve, scheme))
}
}
fn cli_print_proof<T: SolidityCompatibleField, S: SolidityCompatibleScheme<T>>(
sub_matches: &ArgMatches,
) -> Result<(), String> {
let format = sub_matches.value_of("format").unwrap();
let path = Path::new(sub_matches.value_of("proof-path").unwrap());
let file =
File::open(&path).map_err(|why| format!("Couldn't open {}: {}", path.display(), why))?;
let proof_object: Value = serde_json::from_reader(file).map_err(|why| format!("{:?}", why))?;
let proof: Proof<T, S> = serde_json::from_reader(file).map_err(|why| format!("{:?}", why))?;
let inputs = serde_json::to_value(&proof.inputs).unwrap();
let res = S::Proof::from(proof.proof);
let proof_object = serde_json::to_value(&res).unwrap();
match format {
"json" => {
println!("~~~~~~~~ Copy the output below for valid ABIv2 format ~~~~~~~~");
println!();
print!("{}", proof_object["proof"]);
print!("{}", proof_object);
print!(",");
println!("{}", proof_object["inputs"]);
print!("{}", inputs);
println!();
println!("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
}
"remix" => {
println!("~~~~~~~~ Copy the output below for valid ABIv1 format ~~~~~~~~");
print!(
"[{}]",
proof_object
.as_object()
.unwrap()
.iter()
.map(|(_, value)| value.to_string())
.collect::<Vec<_>>()
.join(", ")
);
print!(",");
print!("{}", inputs);
println!();
for (_, value) in proof_object["proof"].as_object().unwrap().iter() {
print!("{}", value);
print!(",");
}
println!("{}", proof_object["inputs"]);
println!();
println!("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
}
_ => unreachable!(),
}

View file

@ -1 +0,0 @@
node_modules

File diff suppressed because it is too large Load diff

View file

@ -1,15 +0,0 @@
{
"name": "zokrates-solidity-tester",
"version": "1.0.0",
"description": "",
"main": "test.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Paul Etscheit",
"license": "LGPL-3.0-only",
"dependencies": {
"solc": "0.8.0",
"web3": "^1.0.0"
}
}

View file

@ -1,160 +0,0 @@
var fs = require("fs");
let Web3 = require('web3');
const solc = require('solc');
const contractPath = process.argv[2]
const proofPath = process.argv[3]
const format = process.argv[4]
const web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545'));
const source = fs.readFileSync(contractPath, 'UTF-8');
let jsonContractSource = {
language: 'Solidity',
sources: {
[contractPath]: {
content: source,
},
},
settings: {
optimizer: {
enabled: true
},
outputSelection: {
[contractPath]: {
"Verifier": ['abi', "evm.bytecode"],
},
},
},
};
(async () => {
const accounts = await web3.eth.getAccounts();
// The BN256G2 library needs to be deployed and linked separately
// because it has `public` functions.
// This is not needed for the Pairing library because all its functions
// are `internal` and therefore are compiled into the contract that uses it.
if (format == "gm17") {
let library = await deployLibrary();
jsonContractSource.settings.libraries = {
[contractPath]: {
BN256G2: library["_address"]
}
}
}
// -----Compile contract-----
let jsonInterface = JSON.parse(solc.compile(JSON.stringify(jsonContractSource)));
console.log(jsonInterface);
let abi = jsonInterface.contracts[contractPath]["Verifier"].abi;
let bytecode = jsonInterface.contracts[contractPath]["Verifier"].evm.bytecode;
let contract = new web3.eth.Contract(abi)
.deploy({
data: '0x' + bytecode.object
})
.send({
from: accounts[0],
gas: '2000000'
})
.on('receipt', (tx) => {
if (tx.status == true) {
console.log("Contract Deployed! Gas used: " + tx.gasUsed);
}
})
.then(newContractInstance => {
contract = newContractInstance;
Promise.all([makeTransaction(accounts[0], true), makeTransaction(accounts[0], false)]);
})
.catch(err => {
console.log(err);
process.exit(1);
});
function makeTransaction(account, correct) {
let proof = getProof(correct);
function handleReceipt(tx) {
if (tx.status == true && !correct) {
console.log("Verification has been successful with invalid proof data! THIS IS A BUG");
process.exit(1);
}
if (tx.status == true) {
console.log("Correct proof works! Gas used: " + tx.gasUsed);
}
}
function handleError(err, correct) {
if (!correct) {
console.log("False proof not verified! Success");
} else {
console.log(err);
process.exit(1);
}
}
verifyTx(proof, account, correct).on('receipt', handleReceipt)
.catch(handleError);
}
function verifyTx(proof, account, correct) {
var args = proof[0];
args = proof[1].length > 0 ? [args, proof[1]] : [args];
return contract.methods.verifyTx(...args).send({
from: account,
gas: 5000000
});
}
function getProof(correct) {
let json = JSON.parse(fs.readFileSync(proofPath));
let inputs = json["inputs"];
let proof = json["proof"];
//falsifies proof to check if verification fails
if (!correct) {
proof["a"][0] = "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
}
return [Object.values(proof), Object.values(inputs)];
}
//function used for deploying BN256G2 Library, used for gm17 only
function deployLibrary() {
let jsonContractSourceBin = JSON.stringify({
language: 'Solidity',
sources: {
["BN256G2"]: {
content: source,
},
},
settings: {
optimizer: {
enabled: true
},
outputSelection: {
'*': {
'*': ['abi', "evm.bytecode"],
},
},
},
});
let jsonInterfaceBin = JSON.parse(solc.compile(jsonContractSourceBin));
let abiLib = jsonInterfaceBin.contracts["BN256G2"]["BN256G2"].abi;
let bytecodeLib = jsonInterfaceBin.contracts["BN256G2"]['BN256G2'].evm.bytecode;
return new web3.eth.Contract(abiLib)
.deploy({
data: '0x' + bytecodeLib.object
})
.send({
from: accounts[0],
gas: '2000000'
})
.on('receipt', (tx) => {
if (tx.status == false) {
console.log("Library couldn't be deployed");
process.exit(1);
}
});
}
})();

View file

@ -1,11 +1,16 @@
extern crate assert_cli;
extern crate ethabi;
extern crate primitive_types;
extern crate rand_0_4;
extern crate rand_0_8;
extern crate serde_json;
extern crate zokrates_solidity_test;
#[cfg(test)]
mod integration {
use fs_extra::copy_items;
use fs_extra::dir::CopyOptions;
use primitive_types::U256;
use serde_json::from_reader;
use std::fs;
use std::fs::File;
@ -14,7 +19,12 @@ mod integration {
use std::path::Path;
use tempdir::TempDir;
use zokrates_abi::{parse_strict, Encode};
use zokrates_core::proof_system::{
to_token::ToToken, Marlin, Proof, SolidityCompatibleScheme, G16, GM17, PGHR13,
SOLIDITY_G2_ADDITION_LIB,
};
use zokrates_core::typed_absy::abi::Abi;
use zokrates_field::Bn128Field;
macro_rules! map(
{
@ -30,8 +40,23 @@ mod integration {
#[test]
#[ignore]
fn test_compile_and_witness_dir() {
// install nodejs dependencies for the verification contract tester
install_nodejs_deps();
let global_dir = TempDir::new("global").unwrap();
let global_base = global_dir.path();
let universal_setup_path = global_base.join("universal_setup.dat");
// GENERATE A UNIVERSAL SETUP
assert_cli::Assert::main_binary()
.with_args(&[
"universal-setup",
"--size",
"10",
"--proving-scheme",
"marlin",
"--universal-setup-path",
universal_setup_path.to_str().unwrap(),
])
.succeeds()
.unwrap();
let dir = Path::new("./tests/code");
assert!(dir.is_dir());
@ -44,32 +69,26 @@ mod integration {
let prog = dir.join(program_name).with_extension("zok");
let witness = dir.join(program_name).with_extension("expected.witness");
let json_input = dir.join(program_name).with_extension("arguments.json");
test_compile_and_witness(
program_name.to_str().unwrap(),
&prog,
&json_input,
&witness,
global_base,
);
}
}
}
fn install_nodejs_deps() {
let out_dir = concat!(env!("OUT_DIR"), "/contract");
assert_cli::Assert::command(&["npm", "install"])
.current_dir(out_dir)
.succeeds()
.unwrap();
}
fn test_compile_and_witness(
program_name: &str,
program_path: &Path,
inputs_path: &Path,
expected_witness_path: &Path,
global_path: &Path,
) {
let tmp_dir = TempDir::new(".tmp").unwrap();
let tmp_dir = TempDir::new(program_name).unwrap();
let tmp_base = tmp_dir.path();
let test_case_path = tmp_base.join(program_name);
let flattened_path = tmp_base.join(program_name).join("out");
@ -77,6 +96,7 @@ mod integration {
let witness_path = tmp_base.join(program_name).join("witness");
let inline_witness_path = tmp_base.join(program_name).join("inline_witness");
let proof_path = tmp_base.join(program_name).join("proof.json");
let universal_setup_path = global_path.join("universal_setup.dat");
let verification_key_path = tmp_base
.join(program_name)
.join("verification")
@ -97,7 +117,6 @@ mod integration {
// prepare compile arguments
let compile = vec![
"../target/release/zokrates",
"compile",
"-i",
program_path.to_str().unwrap(),
@ -110,12 +129,13 @@ mod integration {
];
// compile
assert_cli::Assert::command(&compile).succeeds().unwrap();
assert_cli::Assert::main_binary()
.with_args(&compile)
.succeeds()
.unwrap();
// COMPUTE_WITNESS
let compute = vec![
"../target/release/zokrates",
"compute-witness",
"-i",
flattened_path.to_str().unwrap(),
@ -130,7 +150,8 @@ mod integration {
// run witness-computation for ABI-encoded inputs through stdin
let json_input_str = fs::read_to_string(inputs_path).unwrap();
assert_cli::Assert::command(&compute)
assert_cli::Assert::main_binary()
.with_args(&compute)
.stdin(&json_input_str)
.succeeds()
.unwrap();
@ -162,7 +183,6 @@ mod integration {
.collect();
let mut compute_inline = vec![
"../target/release/zokrates",
"compute-witness",
"-i",
flattened_path.to_str().unwrap(),
@ -178,7 +198,8 @@ mod integration {
}
}
assert_cli::Assert::command(&compute_inline)
assert_cli::Assert::main_binary()
.with_args(&compute_inline)
.succeeds()
.unwrap();
@ -225,81 +246,71 @@ mod integration {
"ark" => vec!["g16", "gm17", "marlin"]
};
// GENERATE A UNIVERSAL SETUP
assert_cli::Assert::command(&[
"../target/release/zokrates",
"universal-setup",
"--size",
"15",
"--proving-scheme",
"marlin",
])
.succeeds()
.unwrap();
for (backend, schemes) in backends {
for scheme in &schemes {
println!("test with {}, {}", backend, scheme);
// SETUP
let 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()
.stdout()
.doesnt_contain("This program is too small to generate a setup with Marlin")
.execute();
let setup = assert_cli::Assert::main_binary()
.with_args(&[
"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,
"--universal-setup-path",
universal_setup_path.to_str().unwrap(),
])
.succeeds()
.stdout()
.doesnt_contain("This program is too small to generate a setup with Marlin")
.execute();
if setup.is_ok() {
// 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();
assert_cli::Assert::main_binary()
.with_args(&[
"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();
// CLI VERIFICATION
assert_cli::Assert::command(&[
"../target/release/zokrates",
"verify",
"--backend",
backend,
"--proving-scheme",
scheme,
"-j",
proof_path.to_str().unwrap(),
"-v",
verification_key_path.to_str().unwrap(),
])
.succeeds()
.unwrap();
assert_cli::Assert::main_binary()
.with_args(&[
"verify",
"--backend",
backend,
"--proving-scheme",
scheme,
"-j",
proof_path.to_str().unwrap(),
"-v",
verification_key_path.to_str().unwrap(),
])
.succeeds()
.unwrap();
if scheme != &"marlin" {
// EXPORT-VERIFIER
assert_cli::Assert::command(&[
"../target/release/zokrates",
// EXPORT-VERIFIER
assert_cli::Assert::main_binary()
.with_args(&[
"export-verifier",
"-i",
verification_key_path.to_str().unwrap(),
@ -311,29 +322,158 @@ mod integration {
.succeeds()
.unwrap();
// TEST VERIFIER
assert_cli::Assert::command(&[
"node",
"test.js",
verification_contract_path.to_str().unwrap(),
proof_path.to_str().unwrap(),
scheme,
])
.current_dir(concat!(env!("OUT_DIR"), "/contract"))
.succeeds()
.unwrap();
// TEST VERIFIER
// Get the contract
let contract_str =
std::fs::read_to_string(verification_contract_path.to_str().unwrap())
.unwrap();
match *scheme {
"marlin" => {
// Get the proof
let proof: Proof<Bn128Field, Marlin> = serde_json::from_reader(
File::open(proof_path.to_str().unwrap()).unwrap(),
)
.unwrap();
test_solidity_verifier(contract_str, proof);
}
"g16" => {
// Get the proof
let proof: Proof<Bn128Field, G16> = serde_json::from_reader(
File::open(proof_path.to_str().unwrap()).unwrap(),
)
.unwrap();
test_solidity_verifier(contract_str, proof);
}
"gm17" => {
// Get the proof
let proof: Proof<Bn128Field, GM17> = serde_json::from_reader(
File::open(proof_path.to_str().unwrap()).unwrap(),
)
.unwrap();
test_solidity_verifier(contract_str, proof);
}
"pghr13" => {
// Get the proof
let proof: Proof<Bn128Field, PGHR13> = serde_json::from_reader(
File::open(proof_path.to_str().unwrap()).unwrap(),
)
.unwrap();
test_solidity_verifier(contract_str, proof);
}
_ => unreachable!(),
}
}
}
}
}
fn test_solidity_verifier<S: SolidityCompatibleScheme<Bn128Field> + ToToken<Bn128Field>>(
src: String,
proof: Proof<Bn128Field, S>,
) {
use ethabi::Token;
use rand_0_8::{rngs::StdRng, SeedableRng};
use zokrates_solidity_test::{address::*, contract::*, evm::*, to_be_bytes};
// Setup EVM
let mut rng = StdRng::from_seed([0; 32]);
let mut evm = Evm::default();
let deployer = Address::random(&mut rng);
evm.create_account(&deployer, 0);
// Compile lib
let g2_lib =
Contract::compile_from_src_string(&SOLIDITY_G2_ADDITION_LIB, "BN256G2", true, &[])
.unwrap();
// Deploy lib
let create_result = evm
.deploy(g2_lib.encode_create_contract_bytes(&[]).unwrap(), &deployer)
.unwrap();
let lib_addr = create_result.addr.clone();
// Compile contract
let contract = Contract::compile_from_src_string(
&src,
"Verifier",
true,
&[("BN256G2", lib_addr.as_token())],
)
.unwrap();
// Deploy contract
let create_result = evm
.deploy(
contract.encode_create_contract_bytes(&[]).unwrap(),
&deployer,
)
.unwrap();
let contract_addr = create_result.addr.clone();
// convert to the solidity proof format
let solidity_proof = S::Proof::from(proof.proof);
// convert to tokens to build a call
let proof_token = S::to_token(solidity_proof.clone());
let input_token = Token::FixedArray(
proof
.inputs
.iter()
.map(|s| {
let bytes = hex::decode(s.trim_start_matches("0x")).unwrap();
debug_assert_eq!(bytes.len(), 32);
Token::Uint(U256::from(&bytes[..]))
})
.collect::<Vec<_>>(),
);
let inputs = [proof_token, input_token.clone()];
// Call verify function on contract
let result = evm
.call(
contract
.encode_call_contract_bytes("verifyTx", &inputs)
.unwrap(),
&contract_addr,
&deployer,
)
.unwrap();
assert_eq!(&result.out, &to_be_bytes(&U256::from(1)));
// modify the proof
let modified_solidity_proof = S::modify(solidity_proof.clone());
let modified_proof_token = S::to_token(modified_solidity_proof.clone());
let inputs = [modified_proof_token, input_token.clone()];
// Call verify function on contract
let result = evm
.call(
contract
.encode_call_contract_bytes("verifyTx", &inputs)
.unwrap(),
&contract_addr,
&deployer,
)
.unwrap();
assert_eq!(result.op_out, Return::InvalidOpcode);
}
fn test_compile_and_smtlib2(
program_name: &str,
program_path: &Path,
expected_smtlib2_path: &Path,
) {
let tmp_dir = TempDir::new(".tmp").unwrap();
let tmp_dir = TempDir::new(program_name).unwrap();
let tmp_base = tmp_dir.path();
let test_case_path = tmp_base.join(program_name);
let flattened_path = tmp_base.join(program_name).join("out");
@ -346,7 +486,6 @@ mod integration {
// prepare compile arguments
let compile = vec![
"../target/release/zokrates",
"compile",
"-i",
program_path.to_str().unwrap(),
@ -357,11 +496,13 @@ mod integration {
];
// compile
assert_cli::Assert::command(&compile).succeeds().unwrap();
assert_cli::Assert::main_binary()
.with_args(&compile)
.succeeds()
.unwrap();
// prepare generate-smtlib2 arguments
let gen = vec![
"../target/release/zokrates",
"generate-smtlib2",
"-i",
flattened_path.to_str().unwrap(),
@ -370,7 +511,10 @@ mod integration {
];
// generate-smtlib2
assert_cli::Assert::command(&gen).succeeds().unwrap();
assert_cli::Assert::main_binary()
.with_args(&gen)
.succeeds()
.unwrap();
// load the expected smtlib2
let mut expected_smtlib2_file = File::open(&expected_smtlib2_path).unwrap();

View file

@ -13,7 +13,7 @@ libsnark = ["cc", "cmake"]
bellman = ["bellman_ce", "pairing_ce", "ff_ce", "zokrates_field/bellman"]
wasm = ["bellman_ce/nolog", "bellman_ce/wasm"]
multicore = ["bellman_ce/multicore", "phase2/multicore"]
ark = ["ark-ff", "ark-ec", "ark-bn254", "ark-bls12-377", "ark-bw6-761", "ark-gm17", "ark-groth16", "ark-crypto-primitives", "ark-serialize", "ark-relations", "ark-marlin", "ark-poly", "ark-poly-commit", "sha2"]
ark = ["ark-ff", "ark-ec", "ark-bn254", "ark-bls12-377", "ark-bw6-761", "ark-gm17", "ark-groth16", "ark-crypto-primitives", "ark-serialize", "ark-relations", "ark-marlin", "ark-poly", "ark-poly-commit", "sha3", "digest" ]
[dependencies]
log = "0.4"
@ -25,7 +25,7 @@ typed-arena = "1.4.1"
reduce = "0.1.1"
# serialization and deserialization
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
serde_json = { version = "1.0", features = ["preserve_order"] }
serde_cbor = "0.11.2"
hex = "0.4.2"
regex = "0.2"
@ -33,9 +33,9 @@ zokrates_field = { version = "0.5.0", path = "../zokrates_field", default-featur
zokrates_pest_ast = { version = "0.2.0", path = "../zokrates_pest_ast" }
zokrates_common = { path = "../zokrates_common" }
zokrates_embed = { version = "0.1.0", path = "../zokrates_embed" }
getrandom = { version = "0.2", features = ["js"] }
getrandom = { version = "0.2", features = ["js", "wasm-bindgen"] }
rand_0_4 = { version = "0.4", package = "rand" }
rand_0_7 = { version = "0.7", package = "rand", features = ["wasm-bindgen"] }
rand_0_8 = { version = "0.8", package = "rand" }
csv = "1"
phase2 = { git = "https://github.com/Zokrates/phase2", default-features = false }
@ -45,20 +45,23 @@ pairing_ce = { version = "^0.21", optional = true }
ff_ce = { version = "^0.9", optional = true }
# ark
ark-ff = { version = "^0.2.0", default-features = false, optional = true }
ark-ec = { version = "^0.2.0", default-features = false, optional = true }
ark-bn254 = { version = "^0.2.0", features = ["curve"], default-features = false, optional = true }
ark-bls12-377 = { version = "^0.2.0", features = ["curve"], default-features = false, optional = true }
ark-bw6-761 = { version = "^0.2.0", default-features = false, optional = true }
ark-gm17 = { version = "^0.2.0", default-features = false, optional = true }
ark-groth16 = { version = "^0.2.0", default-features = false, optional = true }
ark-serialize = { version = "^0.2.0", default-features = false, optional = true }
ark-relations = { version = "^0.2.0", default-features = false, optional = true }
ark-marlin = { version = "^0.2.0", default-features = false, optional = true }
ark-poly = { version = "^0.2.0", default-features = false, optional = true }
ark-poly-commit = { version = "^0.2.0", default-features = false, optional = true }
ark-crypto-primitives = { version = "^0.2.0", default-features = false, optional = true }
sha2 = { version = "0.9.3", optional = true }
ark-ff = { version = "^0.3.0", default-features = false, optional = true }
ark-ec = { version = "^0.3.0", default-features = false, optional = true }
ark-bn254 = { version = "^0.3.0", features = ["curve"], default-features = false, optional = true }
ark-bls12-377 = { version = "^0.3.0", features = ["curve"], default-features = false, optional = true }
ark-bw6-761 = { version = "^0.3.0", default-features = false, optional = true }
ark-gm17 = { version = "^0.3.0", default-features = false, optional = true }
ark-groth16 = { version = "^0.3.0", default-features = false, optional = true }
ark-serialize = { version = "^0.3.0", default-features = false, optional = true }
ark-relations = { version = "^0.3.0", default-features = false, optional = true }
ark-marlin = { git = "https://github.com/arkworks-rs/marlin", rev = "63cfd82", default-features = false, optional = true }
ark-poly = { version = "^0.3.0", default-features = false, optional = true }
ark-poly-commit = { version = "^0.3.0", default-features = false, optional = true }
ark-crypto-primitives = { version = "^0.3.0", default-features = false, optional = true }
sha3 = { version = "0.9", optional = true }
digest = { version = "0.9", optional = true }
ethabi = "17.0.0"
primitive-types = { version = "0.11", features = ["rlp"] }
[dev-dependencies]
wasm-bindgen-test = "^0.3.0"

View file

@ -103,6 +103,10 @@ impl<T, I: IntoIterator<Item = Statement<T>>> ProgIterator<T, I> {
pub fn returns(&self) -> Vec<FlatVariable> {
(0..self.return_count).map(FlatVariable::public).collect()
}
pub fn public_count(&self) -> usize {
self.arguments.iter().filter(|a| !a.private).count() + self.return_count
}
}
impl<T: Field, I: IntoIterator<Item = Statement<T>>> ProgIterator<T, I> {

View file

@ -14,7 +14,7 @@ use crate::proof_system::gm17::{ProofPoints, VerificationKey, GM17};
use crate::proof_system::{Backend, NonUniversalBackend, Proof, SetupKeypair};
use crate::proof_system::{NotBw6_761Field, Scheme};
use ark_bw6_761::BW6_761;
use rand_0_7::SeedableRng;
use rand_0_8::{rngs::StdRng, SeedableRng};
impl<T: Field + ArkFieldExtensions + NotBw6_761Field> NonUniversalBackend<T, GM17> for Ark {
fn setup<I: IntoIterator<Item = Statement<T>>>(
@ -22,7 +22,7 @@ impl<T: Field + ArkFieldExtensions + NotBw6_761Field> NonUniversalBackend<T, GM1
) -> SetupKeypair<<GM17 as Scheme<T>>::VerificationKey> {
let computation = Computation::without_witness(program);
let rng = &mut rand_0_7::rngs::StdRng::from_entropy();
let rng = &mut StdRng::from_entropy();
let (pk, vk) = ArkGM17::<T::ArkEngine>::circuit_specific_setup(computation, rng).unwrap();
let mut pk_vec: Vec<u8> = Vec::new();
@ -46,7 +46,7 @@ impl<T: Field + ArkFieldExtensions + NotBw6_761Field> Backend<T, GM17> for Ark {
program: ProgIterator<T, I>,
witness: Witness<T>,
proving_key: Vec<u8>,
) -> Proof<<GM17 as Scheme<T>>::ProofPoints> {
) -> Proof<T, GM17> {
let computation = Computation::with_witness(program, witness);
let inputs = computation
@ -60,7 +60,7 @@ impl<T: Field + ArkFieldExtensions + NotBw6_761Field> Backend<T, GM17> for Ark {
)
.unwrap();
let rng = &mut rand_0_7::rngs::StdRng::from_entropy();
let rng = &mut StdRng::from_entropy();
let proof = ArkGM17::<T::ArkEngine>::prove(&pk, computation, rng).unwrap();
let proof_points = ProofPoints {
@ -72,10 +72,7 @@ impl<T: Field + ArkFieldExtensions + NotBw6_761Field> Backend<T, GM17> for Ark {
Proof::new(proof_points, inputs)
}
fn verify(
vk: <GM17 as Scheme<T>>::VerificationKey,
proof: Proof<<GM17 as Scheme<T>>::ProofPoints>,
) -> bool {
fn verify(vk: <GM17 as Scheme<T>>::VerificationKey, proof: Proof<T, GM17>) -> bool {
let vk = VerifyingKey {
h_g2: serialization::to_g2::<T>(vk.h),
g_alpha_g1: serialization::to_g1::<T>(vk.g_alpha),
@ -118,7 +115,7 @@ impl NonUniversalBackend<Bw6_761Field, GM17> for Ark {
) -> SetupKeypair<<GM17 as Scheme<Bw6_761Field>>::VerificationKey> {
let computation = Computation::without_witness(program);
let rng = &mut rand_0_7::rngs::StdRng::from_entropy();
let rng = &mut StdRng::from_entropy();
let (pk, vk) = ArkGM17::<BW6_761>::circuit_specific_setup(computation, rng).unwrap();
let mut pk_vec: Vec<u8> = Vec::new();
@ -142,7 +139,7 @@ impl Backend<Bw6_761Field, GM17> for Ark {
program: ProgIterator<Bw6_761Field, I>,
witness: Witness<Bw6_761Field>,
proving_key: Vec<u8>,
) -> Proof<<GM17 as Scheme<Bw6_761Field>>::ProofPoints> {
) -> Proof<Bw6_761Field, GM17> {
let computation = Computation::with_witness(program, witness);
let inputs = computation
@ -157,7 +154,7 @@ impl Backend<Bw6_761Field, GM17> for Ark {
)
.unwrap();
let rng = &mut rand_0_7::rngs::StdRng::from_entropy();
let rng = &mut StdRng::from_entropy();
let proof = ArkGM17::<BW6_761>::prove(&pk, computation, rng).unwrap();
let proof_points = ProofPoints {
@ -171,7 +168,7 @@ impl Backend<Bw6_761Field, GM17> for Ark {
fn verify(
vk: <GM17 as Scheme<Bw6_761Field>>::VerificationKey,
proof: Proof<<GM17 as Scheme<Bw6_761Field>>::ProofPoints>,
proof: Proof<Bw6_761Field, GM17>,
) -> bool {
let vk = VerifyingKey {
h_g2: serialization::to_g2_fq::<Bw6_761Field>(vk.h),

View file

@ -15,7 +15,7 @@ use crate::proof_system::ark::{parse_g1, parse_g2};
use crate::proof_system::groth16::{ProofPoints, VerificationKey, G16};
use crate::proof_system::Scheme;
use ark_bw6_761::BW6_761;
use rand_0_7::SeedableRng;
use rand_0_8::{rngs::StdRng, SeedableRng};
const G16_WARNING: &str = "WARNING: You are using the G16 scheme which is subject to malleability. See zokrates.github.io/toolbox/proving_schemes.html#g16-malleability for implications.";
@ -24,7 +24,7 @@ impl<T: Field + ArkFieldExtensions + NotBw6_761Field> Backend<T, G16> for Ark {
program: ProgIterator<T, I>,
witness: Witness<T>,
proving_key: Vec<u8>,
) -> Proof<<G16 as Scheme<T>>::ProofPoints> {
) -> Proof<T, G16> {
println!("{}", G16_WARNING);
let computation = Computation::with_witness(program, witness);
@ -40,7 +40,7 @@ impl<T: Field + ArkFieldExtensions + NotBw6_761Field> Backend<T, G16> for Ark {
)
.unwrap();
let rng = &mut rand_0_7::rngs::StdRng::from_entropy();
let rng = &mut StdRng::from_entropy();
let proof = Groth16::<T::ArkEngine>::prove(&pk, computation, rng).unwrap();
let proof_points = ProofPoints {
@ -52,10 +52,7 @@ impl<T: Field + ArkFieldExtensions + NotBw6_761Field> Backend<T, G16> for Ark {
Proof::new(proof_points, inputs)
}
fn verify(
vk: <G16 as Scheme<T>>::VerificationKey,
proof: Proof<<G16 as Scheme<T>>::ProofPoints>,
) -> bool {
fn verify(vk: <G16 as Scheme<T>>::VerificationKey, proof: Proof<T, G16>) -> bool {
let vk = VerifyingKey {
alpha_g1: serialization::to_g1::<T>(vk.alpha),
beta_g2: serialization::to_g2::<T>(vk.beta),
@ -97,7 +94,7 @@ impl<T: Field + ArkFieldExtensions + NotBw6_761Field> NonUniversalBackend<T, G16
let computation = Computation::without_witness(program);
let rng = &mut rand_0_7::rngs::StdRng::from_entropy();
let rng = &mut StdRng::from_entropy();
let (pk, vk) = Groth16::<T::ArkEngine>::circuit_specific_setup(computation, rng).unwrap();
let mut pk_vec: Vec<u8> = Vec::new();
@ -120,7 +117,7 @@ impl Backend<Bw6_761Field, G16> for Ark {
program: ProgIterator<Bw6_761Field, I>,
witness: Witness<Bw6_761Field>,
proving_key: Vec<u8>,
) -> Proof<<G16 as Scheme<Bw6_761Field>>::ProofPoints> {
) -> Proof<Bw6_761Field, G16> {
println!("{}", G16_WARNING);
let computation = Computation::with_witness(program, witness);
@ -134,7 +131,7 @@ impl Backend<Bw6_761Field, G16> for Ark {
let pk =
ProvingKey::<BW6_761>::deserialize_uncompressed(&mut proving_key.as_slice()).unwrap();
let rng = &mut rand_0_7::rngs::StdRng::from_entropy();
let rng = &mut StdRng::from_entropy();
let proof = Groth16::<BW6_761>::prove(&pk, computation, rng).unwrap();
let proof_points = ProofPoints {
@ -148,7 +145,7 @@ impl Backend<Bw6_761Field, G16> for Ark {
fn verify(
vk: <G16 as Scheme<Bw6_761Field>>::VerificationKey,
proof: Proof<<G16 as Scheme<Bw6_761Field>>::ProofPoints>,
proof: Proof<Bw6_761Field, G16>,
) -> bool {
let vk = VerifyingKey {
alpha_g1: serialization::to_g1::<Bw6_761Field>(vk.alpha),
@ -191,7 +188,7 @@ impl NonUniversalBackend<Bw6_761Field, G16> for Ark {
let computation = Computation::without_witness(program);
let rng = &mut rand_0_7::rngs::StdRng::from_entropy();
let rng = &mut StdRng::from_entropy();
let (pk, vk) = Groth16::<BW6_761>::circuit_specific_setup(computation, rng).unwrap();
let mut pk_vec: Vec<u8> = Vec::new();

View file

@ -1,40 +1,129 @@
use ark_marlin::{IndexProverKey, IndexVerifierKey, Proof as ArkProof};
use ark_marlin::{
ahp::indexer::IndexInfo, ahp::prover::ProverMsg, rng::FiatShamirRng, IndexProverKey,
IndexVerifierKey, Proof as ArkProof,
};
use ark_marlin::Marlin as ArkMarlin;
use ark_ec::PairingEngine;
use ark_ff::{to_bytes, FftField, FromBytes, ToBytes};
use ark_poly::univariate::DensePolynomial;
use ark_poly_commit::marlin_pc::MarlinKZG10;
use ark_poly_commit::{
data_structures::BatchLCProof,
kzg10::Commitment as KZG10Commitment,
kzg10::Proof as KZG10Proof,
kzg10::VerifierKey as KZG10VerifierKey,
marlin_pc::{Commitment, MarlinKZG10, VerifierKey},
};
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use sha2::Sha256;
use digest::Digest;
use rand_0_8::{Error, RngCore, SeedableRng};
use sha3::Keccak256;
use std::marker::PhantomData;
use zokrates_field::{ArkFieldExtensions, Field};
use crate::ir::{ProgIterator, Statement, Witness};
use crate::proof_system::ark::parse_fr;
use crate::proof_system::ark::Ark;
use crate::proof_system::ark::Computation;
use crate::proof_system::marlin::{self, ProofPoints, VerificationKey};
use crate::proof_system::ark::{parse_fr, parse_g1, parse_g2, serialization};
use crate::proof_system::marlin::{self, KZGVerifierKey, ProofPoints, VerificationKey};
use crate::proof_system::Scheme;
use crate::proof_system::{Backend, Proof, SetupKeypair, UniversalBackend};
const MINIMUM_CONSTRAINT_COUNT: usize = 2;
/// Simple hash-based Fiat-Shamir RNG that allows for efficient solidity verification.
pub struct HashFiatShamirRng<D: Digest> {
seed: [u8; 32],
ctr: u32,
digest: PhantomData<D>,
}
impl<D: Digest> RngCore for HashFiatShamirRng<D> {
fn next_u32(&mut self) -> u32 {
let mut bytes = [0; 4];
self.fill_bytes(&mut bytes);
u32::from_be_bytes(bytes)
}
fn next_u64(&mut self) -> u64 {
let mut bytes = [0; 8];
self.fill_bytes(&mut bytes);
u64::from_be_bytes(bytes)
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
let bytes_per_hash = D::output_size();
let n_hashes = (dest.len() - 1) / bytes_per_hash + 1;
let mut seed_ctr = self.seed.to_vec();
for i in 0..n_hashes {
seed_ctr.extend_from_slice(&self.ctr.to_be_bytes());
let mut h = D::digest(&seed_ctr).to_vec();
h.reverse(); // Switch to big endian representation for solidity translation
let len = dest.len();
if i * bytes_per_hash + bytes_per_hash >= len {
dest[i * bytes_per_hash..]
.copy_from_slice(&h.as_slice()[..len - i * bytes_per_hash]);
} else {
dest[i * bytes_per_hash..i * bytes_per_hash + bytes_per_hash]
.copy_from_slice(h.as_slice());
}
self.ctr += 1;
seed_ctr.truncate(seed_ctr.len() - 4);
}
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
self.fill_bytes(dest);
Ok(())
}
}
impl<D: Digest> FiatShamirRng for HashFiatShamirRng<D> {
fn initialize<'a, T: 'a + ToBytes>(initial_input: &'a T) -> Self {
let mut bytes = Vec::new();
initial_input
.write(&mut bytes)
.expect("failed to convert to bytes");
let seed = FromBytes::read(D::digest(&bytes).as_ref()).expect("failed to get [u8; 32]");
Self {
seed,
ctr: 0,
digest: PhantomData,
}
}
fn absorb<'a, T: 'a + ToBytes>(&mut self, new_input: &'a T) {
let mut bytes = Vec::new();
new_input
.write(&mut bytes)
.expect("failed to convert to bytes");
bytes.extend_from_slice(&self.seed);
self.seed = FromBytes::read(D::digest(&bytes).as_ref()).expect("failed to get [u8; 32]");
self.ctr = 0;
}
}
type PCInst<T> = MarlinKZG10<
<T as ArkFieldExtensions>::ArkEngine,
DensePolynomial<<<T as ArkFieldExtensions>::ArkEngine as PairingEngine>::Fr>,
>;
type MarlinInst<T> = ArkMarlin<
<<T as ArkFieldExtensions>::ArkEngine as PairingEngine>::Fr,
PCInst<T>,
HashFiatShamirRng<Keccak256>,
>;
impl<T: Field + ArkFieldExtensions> UniversalBackend<T, marlin::Marlin> for Ark {
fn universal_setup(size: u32) -> Vec<u8> {
use rand_0_7::SeedableRng;
let rng = &mut rand_0_8::rngs::StdRng::from_entropy();
let rng = &mut rand_0_7::rngs::StdRng::from_entropy();
let srs = ArkMarlin::<
<<T as ArkFieldExtensions>::ArkEngine as PairingEngine>::Fr,
MarlinKZG10<
T::ArkEngine,
DensePolynomial<<<T as ArkFieldExtensions>::ArkEngine as PairingEngine>::Fr>,
>,
Sha256,
>::universal_setup(
2usize.pow(size), 2usize.pow(size), 2usize.pow(size), rng
let srs = MarlinInst::<T>::universal_setup(
2usize.pow(size),
2usize.pow(size),
2usize.pow(size),
rng,
)
.unwrap();
@ -55,6 +144,8 @@ impl<T: Field + ArkFieldExtensions> UniversalBackend<T, marlin::Marlin> for Ark
return Err(format!("Programs must have a least {} constraints. This program is too small to generate a setup with Marlin, see [this issue](https://github.com/arkworks-rs/marlin/issues/79)", MINIMUM_CONSTRAINT_COUNT));
}
let num_public_inputs = program.public_count();
let computation = Computation::without_witness(program);
let srs = ark_marlin::UniversalSRS::<
@ -66,14 +157,7 @@ impl<T: Field + ArkFieldExtensions> UniversalBackend<T, marlin::Marlin> for Ark
>::deserialize(&mut srs.as_slice())
.unwrap();
let (pk, vk) = ArkMarlin::<
<<T as ArkFieldExtensions>::ArkEngine as PairingEngine>::Fr,
MarlinKZG10<
T::ArkEngine,
DensePolynomial<<<T as ArkFieldExtensions>::ArkEngine as PairingEngine>::Fr>,
>,
Sha256,
>::index(&srs, computation)
let (pk, vk) = MarlinInst::<T>::index(&srs, computation)
.map_err(|e| match e {
ark_marlin::Error::IndexTooLarge => String::from("The universal setup is too small for this program, please provide a larger universal setup"),
_ => String::from("Unknown error specializing the universal setup for this program")
@ -82,11 +166,44 @@ impl<T: Field + ArkFieldExtensions> UniversalBackend<T, marlin::Marlin> for Ark
let mut serialized_pk: Vec<u8> = Vec::new();
pk.serialize_uncompressed(&mut serialized_pk).unwrap();
let mut serialized_vk: Vec<u8> = Vec::new();
vk.serialize_uncompressed(&mut serialized_vk).unwrap();
// Precompute some useful values for solidity contract
let fs_seed = to_bytes![&MarlinInst::<T>::PROTOCOL_NAME, &vk].unwrap();
let x_root_of_unity =
<<T as ArkFieldExtensions>::ArkEngine as PairingEngine>::Fr::get_root_of_unity(
vk.index_info.num_instance_variables,
)
.unwrap();
Ok(SetupKeypair::new(
VerificationKey { raw: serialized_vk },
VerificationKey {
fs_seed,
x_root_of_unity: parse_fr::<T>(&x_root_of_unity),
index_comms: vk
.index_comms
.into_iter()
.map(|c| (parse_g1::<T>(&c.comm.0), None))
.collect(),
num_public_inputs,
num_constraints: vk.index_info.num_constraints,
num_non_zero: vk.index_info.num_non_zero,
num_instance_variables: vk.index_info.num_instance_variables,
num_variables: vk.index_info.num_variables,
vk: KZGVerifierKey {
g: parse_g1::<T>(&vk.verifier_key.vk.g),
gamma_g: parse_g1::<T>(&vk.verifier_key.vk.gamma_g),
h: parse_g2::<T>(&vk.verifier_key.vk.h),
beta_h: parse_g2::<T>(&vk.verifier_key.vk.beta_h),
},
max_degree: vk.verifier_key.max_degree,
supported_degree: vk.verifier_key.supported_degree,
degree_bounds_and_shift_powers: vk.verifier_key.degree_bounds_and_shift_powers.map(
|vk| {
vk.into_iter()
.map(|(bound, pow)| (bound, parse_g1::<T>(&pow)))
.collect()
},
),
},
serialized_pk,
))
}
@ -97,12 +214,10 @@ impl<T: Field + ArkFieldExtensions> Backend<T, marlin::Marlin> for Ark {
program: ProgIterator<T, I>,
witness: Witness<T>,
proving_key: Vec<u8>,
) -> Proof<<marlin::Marlin as Scheme<T>>::ProofPoints> {
) -> Proof<T, marlin::Marlin> {
let computation = Computation::with_witness(program, witness);
use rand_0_7::SeedableRng;
let rng = &mut rand_0_7::rngs::StdRng::from_entropy();
let rng = &mut rand_0_8::rngs::StdRng::from_entropy();
let pk = IndexProverKey::<
<<T as ArkFieldExtensions>::ArkEngine as PairingEngine>::Fr,
@ -113,28 +228,40 @@ impl<T: Field + ArkFieldExtensions> Backend<T, marlin::Marlin> for Ark {
>::deserialize_uncompressed(&mut proving_key.as_slice())
.unwrap();
let inputs = computation
.public_inputs_values()
.iter()
.map(parse_fr::<T>)
.collect::<Vec<_>>();
let public_inputs = computation.public_inputs_values();
let proof = ArkMarlin::<
<<T as ArkFieldExtensions>::ArkEngine as PairingEngine>::Fr,
MarlinKZG10<
T::ArkEngine,
DensePolynomial<<<T as ArkFieldExtensions>::ArkEngine as PairingEngine>::Fr>,
>,
Sha256,
>::prove(&pk, computation, rng)
.unwrap();
let inputs = public_inputs.iter().map(parse_fr::<T>).collect::<Vec<_>>();
let mut serialized_proof: Vec<u8> = Vec::new();
proof.serialize_uncompressed(&mut serialized_proof).unwrap();
let proof = MarlinInst::<T>::prove(&pk, computation, rng).unwrap();
assert!(proof.pc_proof.evals.is_none());
Proof::new(
ProofPoints {
raw: serialized_proof,
commitments: proof
.commitments
.into_iter()
.map(|r| {
r.into_iter()
.map(|c| {
(
parse_g1::<T>(&c.comm.0),
c.shifted_comm
.map(|shifted_comm| parse_g1::<T>(&shifted_comm.0)),
)
})
.collect()
})
.collect(),
evaluations: proof
.evaluations
.into_iter()
.map(|e| parse_fr::<T>(&e))
.collect(),
pc_lc_opening_1: parse_g1::<T>(&proof.pc_proof.proof[0].w),
pc_lc_opening_1_degree: parse_fr::<T>(&proof.pc_proof.proof[0].random_v.unwrap()),
pc_lc_opening_2: parse_g1::<T>(&proof.pc_proof.proof[1].w),
prover_messages_count: proof.prover_messages.len(),
},
inputs,
)
@ -142,7 +269,7 @@ impl<T: Field + ArkFieldExtensions> Backend<T, marlin::Marlin> for Ark {
fn verify(
vk: <marlin::Marlin as Scheme<T>>::VerificationKey,
proof: Proof<<marlin::Marlin as Scheme<T>>::ProofPoints>,
proof: Proof<T, marlin::Marlin>,
) -> bool {
let inputs: Vec<_> = proof
.inputs
@ -160,8 +287,54 @@ impl<T: Field + ArkFieldExtensions> Backend<T, marlin::Marlin> for Ark {
T::ArkEngine,
DensePolynomial<<<T as ArkFieldExtensions>::ArkEngine as PairingEngine>::Fr>,
>,
>::deserialize_uncompressed(&mut proof.proof.raw.as_slice())
.unwrap();
> {
commitments: proof
.proof
.commitments
.iter()
.map(|r| {
r.iter()
.map(|(c, shifted_comm)| Commitment {
comm: KZG10Commitment(serialization::to_g1::<T>(c.clone())),
shifted_comm: shifted_comm.clone().map(|shifted_comm| {
KZG10Commitment(serialization::to_g1::<T>(shifted_comm))
}),
})
.collect()
})
.collect(),
evaluations: proof
.proof
.evaluations
.into_iter()
.map(|v| {
T::try_from_str(v.trim_start_matches("0x"), 16)
.unwrap()
.into_ark()
})
.collect(),
prover_messages: vec![ProverMsg::EmptyMessage; proof.proof.prover_messages_count],
pc_proof: BatchLCProof {
proof: vec![
KZG10Proof {
w: serialization::to_g1::<T>(proof.proof.pc_lc_opening_1),
random_v: Some(
T::try_from_str(
proof.proof.pc_lc_opening_1_degree.trim_start_matches("0x"),
16,
)
.unwrap()
.into_ark(),
),
},
KZG10Proof {
w: serialization::to_g1::<T>(proof.proof.pc_lc_opening_2),
random_v: None,
},
],
evals: None,
},
};
let vk = IndexVerifierKey::<
<<T as ArkFieldExtensions>::ArkEngine as PairingEngine>::Fr,
@ -169,22 +342,45 @@ impl<T: Field + ArkFieldExtensions> Backend<T, marlin::Marlin> for Ark {
T::ArkEngine,
DensePolynomial<<<T as ArkFieldExtensions>::ArkEngine as PairingEngine>::Fr>,
>,
>::deserialize_uncompressed(&mut vk.raw.as_slice())
.unwrap();
> {
index_info: IndexInfo::new(
vk.num_variables,
vk.num_constraints,
vk.num_non_zero,
vk.num_instance_variables,
),
index_comms: vk
.index_comms
.into_iter()
.map(|(c, shifted_comm)| Commitment {
comm: KZG10Commitment(serialization::to_g1::<T>(c)),
shifted_comm: shifted_comm.map(|shifted_comm| {
KZG10Commitment(serialization::to_g1::<T>(shifted_comm))
}),
})
.collect(),
verifier_key: VerifierKey {
degree_bounds_and_shift_powers: vk.degree_bounds_and_shift_powers.map(|vk| {
vk.into_iter()
.map(|(bound, pow)| (bound, serialization::to_g1::<T>(pow)))
.collect()
}),
max_degree: vk.max_degree,
supported_degree: vk.supported_degree,
vk: KZG10VerifierKey {
g: serialization::to_g1::<T>(vk.vk.g),
gamma_g: serialization::to_g1::<T>(vk.vk.gamma_g),
h: serialization::to_g2::<T>(vk.vk.h.clone()),
beta_h: serialization::to_g2::<T>(vk.vk.beta_h.clone()),
prepared_h: serialization::to_g2::<T>(vk.vk.h).into(),
prepared_beta_h: serialization::to_g2::<T>(vk.vk.beta_h).into(),
},
},
};
use rand_0_7::SeedableRng;
let rng = &mut rand_0_8::rngs::StdRng::from_entropy();
let rng = &mut rand_0_7::rngs::StdRng::from_entropy();
ArkMarlin::<
<<T as ArkFieldExtensions>::ArkEngine as PairingEngine>::Fr,
MarlinKZG10<
T::ArkEngine,
DensePolynomial<<<T as ArkFieldExtensions>::ArkEngine as PairingEngine>::Fr>,
>,
Sha256,
>::verify(&vk, &inputs, &proof, rng)
.unwrap()
MarlinInst::<T>::verify(&vk, &inputs, &proof, rng).unwrap()
}
}

View file

@ -25,7 +25,7 @@ impl<T: Field + BellmanFieldExtensions> Backend<T, G16> for Bellman {
program: ProgIterator<T, I>,
witness: Witness<T>,
proving_key: Vec<u8>,
) -> Proof<<G16 as Scheme<T>>::ProofPoints> {
) -> Proof<T, G16> {
println!("{}", G16_WARNING);
let computation = Computation::with_witness(program, witness);
@ -47,10 +47,7 @@ impl<T: Field + BellmanFieldExtensions> Backend<T, G16> for Bellman {
Proof::new(proof_points, public_inputs)
}
fn verify(
vk: <G16 as Scheme<T>>::VerificationKey,
proof: Proof<<G16 as Scheme<T>>::ProofPoints>,
) -> bool {
fn verify(vk: <G16 as Scheme<T>>::VerificationKey, proof: Proof<T, G16>) -> bool {
let vk = VerifyingKey {
alpha_g1: serialization::to_g1::<T>(vk.alpha),
beta_g1: <T::BellmanEngine as Engine>::G1Affine::one(), // not used during verification

View file

@ -43,7 +43,7 @@ impl Backend<Bn128Field, GM17> for Libsnark {
program: ProgIterator<Bn128Field, I>,
witness: Witness<Bn128Field>,
proving_key: Vec<u8>,
) -> Proof<<GM17 as Scheme<Bn128Field>>::ProofPoints> {
) -> Proof<Bn128Field, GM17> {
let program = program.collect();
let (public_inputs_arr, public_inputs_length, private_inputs_arr, private_inputs_length) =
@ -86,7 +86,7 @@ impl Backend<Bn128Field, GM17> for Libsnark {
fn verify(
vk: <GM17 as Scheme<Bn128Field>>::VerificationKey,
proof: Proof<<GM17 as Scheme<Bn128Field>>::ProofPoints>,
proof: Proof<Bn128Field, GM17>,
) -> bool {
let vk_buffer = vec![];
let mut vk_writer = BufWriter::new(vk_buffer);

View file

@ -46,7 +46,7 @@ impl Backend<Bn128Field, PGHR13> for Libsnark {
program: ProgIterator<Bn128Field, I>,
witness: Witness<Bn128Field>,
proving_key: Vec<u8>,
) -> Proof<<PGHR13 as Scheme<Bn128Field>>::ProofPoints> {
) -> Proof<Bn128Field, PGHR13> {
let program = program.collect();
let (public_inputs_arr, public_inputs_length, private_inputs_arr, private_inputs_length) =
@ -104,7 +104,7 @@ impl Backend<Bn128Field, PGHR13> for Libsnark {
fn verify(
vk: <PGHR13 as Scheme<Bn128Field>>::VerificationKey,
proof: Proof<<PGHR13 as Scheme<Bn128Field>>::ProofPoints>,
proof: Proof<Bn128Field, PGHR13>,
) -> bool {
let vk_buffer = vec![];
let mut vk_writer = BufWriter::new(vk_buffer);

View file

@ -5,6 +5,8 @@ pub mod bellman;
#[cfg(feature = "libsnark")]
pub mod libsnark;
pub mod to_token;
mod scheme;
mod solidity;
@ -43,14 +45,14 @@ impl<V: Serialize + DeserializeOwned> SetupKeypair<V> {
}
#[derive(Serialize, Deserialize)]
pub struct Proof<T> {
pub proof: T,
pub inputs: Vec<String>,
pub struct Proof<T: Field, S: Scheme<T>> {
pub proof: S::ProofPoints,
pub inputs: Vec<Fr>,
}
#[allow(dead_code)]
impl<T: Serialize + DeserializeOwned> Proof<T> {
fn new(proof: T, inputs: Vec<String>) -> Self {
impl<T: Field, S: Scheme<T>> Proof<T, S> {
fn new(proof: S::ProofPoints, inputs: Vec<String>) -> Self {
Proof { proof, inputs }
}
}
@ -59,15 +61,15 @@ pub type Fr = String;
pub type Fq = String;
pub type Fq2 = (String, String);
#[derive(Serialize, Deserialize)]
pub struct G1Affine(Fq, Fq);
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct G1Affine(pub Fq, pub Fq);
// When G2 is defined on Fq2 field
#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize, Clone)]
pub struct G2Affine(Fq2, Fq2);
// When G2 is defined on a Fq field (BW6_761 curve)
#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize, Clone)]
pub struct G2AffineFq(Fq, Fq);
impl ToString for G1Affine {
@ -98,9 +100,9 @@ pub trait Backend<T: Field, S: Scheme<T>> {
program: ir::ProgIterator<T, I>,
witness: ir::Witness<T>,
proving_key: Vec<u8>,
) -> Proof<S::ProofPoints>;
) -> Proof<T, S>;
fn verify(vk: S::VerificationKey, proof: Proof<S::ProofPoints>) -> bool;
fn verify(vk: S::VerificationKey, proof: Proof<T, S>) -> bool;
}
pub trait NonUniversalBackend<T: Field, S: NonUniversalScheme<T>>: Backend<T, S> {
fn setup<I: IntoIterator<Item = ir::Statement<T>>>(

View file

@ -11,7 +11,7 @@ use zokrates_field::{Bw6_761Field, Field};
#[allow(clippy::upper_case_acronyms)]
pub struct GM17;
#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize, Clone)]
pub struct ProofPoints<G1, G2> {
pub a: G1,
pub b: G2,
@ -43,6 +43,8 @@ impl Scheme<Bw6_761Field> for GM17 {
}
impl<T: SolidityCompatibleField + NotBw6_761Field> SolidityCompatibleScheme<T> for GM17 {
type Proof = Self::ProofPoints;
fn export_solidity_verifier(vk: <GM17 as Scheme<T>>::VerificationKey) -> String {
let (mut template_text, solidity_pairing_lib) =
(String::from(CONTRACT_TEMPLATE), solidity_pairing_lib(true));

View file

@ -9,7 +9,7 @@ use zokrates_field::Field;
pub struct G16;
#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize, Clone)]
pub struct ProofPoints<G1, G2> {
pub a: G1,
pub b: G2,
@ -34,6 +34,8 @@ impl<T: Field> NonUniversalScheme<T> for G16 {}
impl<T: Field> MpcScheme<T> for G16 {}
impl<T: SolidityCompatibleField> SolidityCompatibleScheme<T> for G16 {
type Proof = Self::ProofPoints;
fn export_solidity_verifier(vk: <G16 as Scheme<T>>::VerificationKey) -> String {
let (mut template_text, solidity_pairing_lib_sans_bn256g2) =
(String::from(CONTRACT_TEMPLATE), solidity_pairing_lib(false));

View file

@ -1,23 +1,682 @@
use crate::proof_system::scheme::{Scheme, UniversalScheme};
use crate::proof_system::solidity::{
solidity_pairing_lib, SolidityCompatibleField, SolidityCompatibleScheme,
};
use crate::proof_system::{Fr, G1Affine, G2Affine, NotBw6_761Field};
use serde::{Deserialize, Serialize};
use zokrates_field::Field;
#[allow(clippy::upper_case_acronyms)]
pub struct Marlin;
#[derive(Serialize, Deserialize)]
pub struct ProofPoints {
pub raw: Vec<u8>,
pub struct ProofPoints<Fr, G1> {
pub commitments: Vec<Vec<(G1, Option<G1>)>>,
pub evaluations: Vec<Fr>,
pub pc_lc_opening_1: G1,
pub pc_lc_opening_1_degree: Fr,
pub pc_lc_opening_2: G1,
pub prover_messages_count: usize,
}
#[derive(Serialize, Deserialize, Clone)]
pub struct SolidityProof<Fr, G1> {
pub comms_1: Vec<G1>,
pub comms_2: Vec<G1>,
pub degree_bound_comms_2_g1: G1,
pub comms_3: Vec<G1>,
pub degree_bound_comms_3_g2: G1,
pub evals: Vec<Fr>,
pub batch_lc_proof_1: G1,
pub batch_lc_proof_1_r: Fr,
pub batch_lc_proof_2: G1,
}
impl<Fr: Clone, G1: Clone> From<ProofPoints<Fr, G1>> for SolidityProof<Fr, G1> {
fn from(p: ProofPoints<Fr, G1>) -> Self {
SolidityProof {
comms_1: p.commitments[0].clone().into_iter().map(|x| x.0).collect(),
comms_2: p.commitments[1].clone().into_iter().map(|x| x.0).collect(),
degree_bound_comms_2_g1: p.commitments[1][1].1.clone().unwrap(),
comms_3: p.commitments[2].clone().into_iter().map(|x| x.0).collect(),
degree_bound_comms_3_g2: p.commitments[2][0].1.clone().unwrap(),
evals: p.evaluations,
batch_lc_proof_1: p.pc_lc_opening_1,
batch_lc_proof_1_r: p.pc_lc_opening_1_degree,
batch_lc_proof_2: p.pc_lc_opening_2,
}
}
}
#[derive(Serialize, Deserialize)]
pub struct VerificationKey {
pub raw: Vec<u8>,
pub struct KZGVerifierKey<G1, G2> {
/// The generator of G1.
pub g: G1,
/// The generator of G1 that is used for making a commitment hiding.
pub gamma_g: G1,
/// The generator of G2.
pub h: G2,
/// \beta times the above generator of G2.
pub beta_h: G2,
}
#[derive(Serialize, Deserialize)]
pub struct VerificationKey<Fr, G1, G2> {
// Useful values to precompute for solidity contract
pub fs_seed: Vec<u8>,
pub x_root_of_unity: Fr,
pub num_public_inputs: usize,
// index_info
pub num_variables: usize,
pub num_constraints: usize,
pub num_non_zero: usize,
pub num_instance_variables: usize,
// index comms
pub index_comms: Vec<(G1, Option<G1>)>,
// verifier key
pub vk: KZGVerifierKey<G1, G2>,
pub max_degree: usize,
pub supported_degree: usize,
pub degree_bounds_and_shift_powers: Option<Vec<(usize, G1)>>,
}
impl<T: Field> Scheme<T> for Marlin {
type VerificationKey = VerificationKey;
type ProofPoints = ProofPoints;
type VerificationKey = VerificationKey<Fr, G1Affine, G2Affine>;
type ProofPoints = ProofPoints<Fr, G1Affine>;
}
impl<T: Field> UniversalScheme<T> for Marlin {}
impl<T: SolidityCompatibleField + NotBw6_761Field> SolidityCompatibleScheme<T> for Marlin {
type Proof = SolidityProof<Fr, G1Affine>;
fn export_solidity_verifier(vk: <Marlin as Scheme<T>>::VerificationKey) -> String {
let (template, solidity_pairing_lib) =
(String::from(CONTRACT_TEMPLATE), solidity_pairing_lib(false));
// Replace public parameters in template
let src = template
.replace(
"<%vk_index_comms_length%>",
&vk.index_comms.len().to_string(),
)
.replace("<%vk_populate_index_comms%>", &{
let mut populate_index_comms = String::new();
for (i, (g, _)) in vk.index_comms.iter().enumerate() {
populate_index_comms.push_str(&format!(
"vk.index_comms[{}] = Pairing.G1Point({});",
i,
&g.to_string()
));
if i < vk.index_comms.len() - 1 {
populate_index_comms.push_str("\n ");
}
}
populate_index_comms
})
.replace("<%vk_kzg_g%>", &vk.vk.g.to_string())
.replace("<%vk_kzg_gamma_g%>", &vk.vk.gamma_g.to_string())
.replace("<%vk_kzg_h%>", &vk.vk.h.to_string())
.replace("<%vk_kzg_beta_h%>", &vk.vk.beta_h.to_string())
.replace(
"<%vk_degree_bounds_length%>",
&vk.degree_bounds_and_shift_powers
.as_ref()
.unwrap()
.len()
.to_string(),
)
.replace("<%vk_g1_shift%>", &{
let h_domain_size = if vk.num_constraints.is_power_of_two() {
vk.num_constraints
} else {
vk.num_constraints.next_power_of_two()
};
vk.degree_bounds_and_shift_powers
.as_ref()
.unwrap()
.iter()
.find(|(b, _)| *b == h_domain_size - 2)
.unwrap()
.1
.to_string()
})
.replace("<%vk_g2_shift%>", &{
let k_domain_size = if vk.num_non_zero.is_power_of_two() {
vk.num_non_zero
} else {
vk.num_non_zero.next_power_of_two()
};
vk.degree_bounds_and_shift_powers
.as_ref()
.unwrap()
.iter()
.find(|(b, _)| *b == k_domain_size - 2)
.unwrap()
.1
.to_string()
})
.replace("<%fs_init_seed_len%>", &(vk.fs_seed.len() / 32).to_string())
.replace("<%fs_init_seed_overflow_len%>", &{
let seed_len_in_32_byte_words = vk.fs_seed.len() / 32;
let seed_len_overflow_in_bytes =
vk.fs_seed.len() - (seed_len_in_32_byte_words * 32);
seed_len_overflow_in_bytes.to_string()
})
.replace("<%fs_populate_init_seed%>", &{
let mut populate_init_seed = String::new();
for i in 0..vk.fs_seed.len() / 32 {
let word_32_bytes = hex::encode(&vk.fs_seed[i * 32..i * 32 + 32]);
populate_init_seed
.push_str(&format!("init_seed[{}] = 0x{};", i, &word_32_bytes));
if i < vk.fs_seed.len() / 32 - 1 {
populate_init_seed.push_str("\n ");
}
}
populate_init_seed
})
.replace("<%fs_init_seed_overflow%>", &{
let seed_len_in_32_byte_words = vk.fs_seed.len() / 32;
format!(
"0x{}",
hex::encode(&vk.fs_seed[seed_len_in_32_byte_words * 32..])
)
})
.replace("<%h_domain_size%>", &{
let size = if vk.num_constraints.is_power_of_two() {
vk.num_constraints as u64
} else {
vk.num_constraints.next_power_of_two() as u64
};
size.to_string()
})
.replace("<%k_domain_size%>", &{
let size = if vk.num_non_zero.is_power_of_two() {
vk.num_non_zero as u64
} else {
vk.num_non_zero.next_power_of_two() as u64
};
size.to_string()
})
.replace("<%x_domain_size%>", &{
let x = vk.num_instance_variables;
let size = if x.is_power_of_two() {
x as u64
} else {
x.next_power_of_two() as u64
};
size.to_string()
})
.replace("<%pub_padded_size%>", &{
let x = vk.num_instance_variables;
let size = if x.is_power_of_two() {
x as u64
} else {
x.next_power_of_two() as u64
};
(size - 1).to_string()
})
.replace(
"<%num_instance_variables%>",
&vk.num_instance_variables.to_string(),
)
.replace("<%num_public_inputs%>", &vk.num_public_inputs.to_string())
.replace("<%x_root%>", &vk.x_root_of_unity.to_string())
.replace(
"<%f_mod%>",
"0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001",
)
.replace(
"<%f_r%>",
"0x0e0a77c19a07df2f666ea36f7879462e36fc76959f60cd29ac96341c4ffffffb",
)
.replace("<%f_inv%>", "0xc2e1f593efffffff");
format!("{}{}", solidity_pairing_lib, src)
}
}
const CONTRACT_TEMPLATE: &str = r#"
contract Verifier {
using Pairing for *;
struct KZGVerifierKey {
Pairing.G1Point g;
Pairing.G1Point gamma_g;
Pairing.G2Point h;
Pairing.G2Point beta_h;
}
struct VerifierKey {
// index commitments
Pairing.G1Point[] index_comms;
// verifier key
KZGVerifierKey vk;
Pairing.G1Point g1_shift;
Pairing.G1Point g2_shift;
}
struct Proof {
Pairing.G1Point[] comms_1;
Pairing.G1Point[] comms_2;
Pairing.G1Point degree_bound_comms_2_g1;
Pairing.G1Point[] comms_3;
Pairing.G1Point degree_bound_comms_3_g2;
uint256[] evals;
Pairing.G1Point batch_lc_proof_1;
uint256 batch_lc_proof_1_r;
Pairing.G1Point batch_lc_proof_2;
}
function verifierKey() internal pure returns (VerifierKey memory vk) {
vk.index_comms = new Pairing.G1Point[](<%vk_index_comms_length%>);
<%vk_populate_index_comms%>
vk.vk.g = Pairing.G1Point(<%vk_kzg_g%>);
vk.vk.gamma_g = Pairing.G1Point(<%vk_kzg_gamma_g%>);
vk.vk.h = Pairing.G2Point(<%vk_kzg_h%>);
vk.vk.beta_h = Pairing.G2Point(<%vk_kzg_beta_h%>);
vk.g1_shift = Pairing.G1Point(<%vk_g1_shift%>);
vk.g2_shift = Pairing.G1Point(<%vk_g2_shift%>);
}
function verifyTx(Proof memory proof, uint256[<%num_public_inputs%>] memory input) public view returns (bool) {
uint256[<%pub_padded_size%>] memory input_padded;
for (uint i = 0; i < input.length; i++) {
input_padded[i] = input[i];
}
return verifyTxAux(input_padded, proof);
}
function verifyTxAux(uint256[<%pub_padded_size%>] memory input, Proof memory proof) internal view returns (bool) {
VerifierKey memory vk = verifierKey();
for (uint i = 0; i < input.length; i++) {
require(input[i] < <%f_mod%>);
}
bytes32 fs_seed;
uint32 ctr;
{
bytes32[<%fs_init_seed_len%>] memory init_seed;
<%fs_populate_init_seed%>
bytes<%fs_init_seed_overflow_len%> init_seed_overflow = <%fs_init_seed_overflow%>;
uint256[<%pub_padded_size%>] memory input_reverse;
for (uint i = 0; i < input.length; i++) {
input_reverse[i] = be_to_le(input[i]);
}
fs_seed = keccak256(abi.encodePacked(init_seed, init_seed_overflow, input_reverse));
}
{
ctr = 0;
uint8 one = 1;
uint8 zero = 0;
uint256[2] memory empty = [0, be_to_le(1)];
fs_seed = keccak256(abi.encodePacked(
abi.encodePacked(
be_to_le(proof.comms_1[0].X), be_to_le(proof.comms_1[0].Y), zero,
zero,
empty, one
),
abi.encodePacked(
be_to_le(proof.comms_1[1].X), be_to_le(proof.comms_1[1].Y), zero,
zero,
empty, one
),
abi.encodePacked(
be_to_le(proof.comms_1[2].X), be_to_le(proof.comms_1[2].Y), zero,
zero,
empty, one
),
abi.encodePacked(
be_to_le(proof.comms_1[3].X), be_to_le(proof.comms_1[3].Y), zero,
zero,
empty, one
),
fs_seed
));
}
uint256[7] memory challenges;
{
uint256 f;
(f, ctr) = sample_field(fs_seed, ctr);
while (eval_vanishing_poly(f, <%h_domain_size%>) == 0) {
(f, ctr) = sample_field(fs_seed, ctr);
}
challenges[0] = montgomery_reduction(f);
(f, ctr) = sample_field(fs_seed, ctr);
challenges[1] = montgomery_reduction(f);
(f, ctr) = sample_field(fs_seed, ctr);
challenges[2] = montgomery_reduction(f);
(f, ctr) = sample_field(fs_seed, ctr);
challenges[3] = montgomery_reduction(f);
}
{
ctr = 0;
uint8 one = 1;
uint8 zero = 0;
uint256[2] memory empty = [0, be_to_le(1)];
fs_seed = keccak256(abi.encodePacked(
abi.encodePacked(
be_to_le(proof.comms_2[0].X), be_to_le(proof.comms_2[0].Y), zero,
zero,
empty, one
),
abi.encodePacked(
be_to_le(proof.comms_2[1].X), be_to_le(proof.comms_2[1].Y), zero,
one,
be_to_le(proof.degree_bound_comms_2_g1.X), be_to_le(proof.degree_bound_comms_2_g1.Y), zero
),
abi.encodePacked(
be_to_le(proof.comms_2[2].X), be_to_le(proof.comms_2[2].Y), zero,
zero,
empty, one
),
fs_seed
));
}
{
uint256 f;
(f, ctr) = sample_field(fs_seed, ctr);
while (eval_vanishing_poly(f, <%h_domain_size%>) == 0) {
(f, ctr) = sample_field(fs_seed, ctr);
}
challenges[4] = montgomery_reduction(f);
}
{
ctr = 0;
uint8 one = 1;
uint8 zero = 0;
uint256[2] memory empty = [0, be_to_le(1)];
fs_seed = keccak256(abi.encodePacked(
abi.encodePacked(
be_to_le(proof.comms_3[0].X), be_to_le(proof.comms_3[0].Y), zero,
one,
be_to_le(proof.degree_bound_comms_3_g2.X), be_to_le(proof.degree_bound_comms_3_g2.Y), zero
),
abi.encodePacked(
be_to_le(proof.comms_3[1].X), be_to_le(proof.comms_3[1].Y), zero,
zero,
empty, one
),
fs_seed
));
}
{
uint256 f;
(f, ctr) = sample_field(fs_seed, ctr);
challenges[5] = montgomery_reduction(f);
}
{
ctr = 0;
uint256[] memory evals_reverse = new uint256[](proof.evals.length);
for (uint i = 0; i < proof.evals.length; i++) {
evals_reverse[i] = be_to_le(proof.evals[i]);
}
fs_seed = keccak256(abi.encodePacked(evals_reverse, fs_seed));
}
{
uint256 f;
(f, ctr) = sample_field_128(fs_seed, ctr);
challenges[6] = f;
}
Pairing.G1Point[2] memory combined_comm;
uint256[2] memory combined_eval;
{
uint256[6] memory intermediate_evals;
intermediate_evals[0] = eval_unnormalized_bivariate_lagrange_poly(
challenges[0],
challenges[4],
<%h_domain_size%>
);
intermediate_evals[1] = eval_vanishing_poly(challenges[0], <%h_domain_size%>);
intermediate_evals[2] = eval_vanishing_poly(challenges[4], <%h_domain_size%>);
intermediate_evals[3] = eval_vanishing_poly(challenges[4], <%x_domain_size%>);
{
uint256[<%x_domain_size%>] memory lagrange_coeffs = eval_all_lagrange_coeffs_x_domain(challenges[4]);
intermediate_evals[4] = lagrange_coeffs[0];
for (uint i = 1; i < lagrange_coeffs.length; i++) {
intermediate_evals[4] = addmod(intermediate_evals[4], mulmod(lagrange_coeffs[i], input[i-1], <%f_mod%>), <%f_mod%>);
}
}
intermediate_evals[5] = eval_vanishing_poly(challenges[5], <%k_domain_size%>);
{
// beta commitments: g_1, outer_sc, t, z_b
uint256[4] memory beta_evals;
Pairing.G1Point[4] memory beta_commitments;
beta_evals[0] = proof.evals[0];
beta_evals[2] = proof.evals[2];
beta_evals[3] = proof.evals[3];
beta_commitments[0] = proof.comms_2[1];
beta_commitments[2] = proof.comms_2[0];
beta_commitments[3] = proof.comms_1[2];
{
// outer sum check: mask_poly, z_a, 1, w, 1, h_1, 1
uint256[7] memory outer_sc_coeffs;
outer_sc_coeffs[0] = 1;
outer_sc_coeffs[1] = mulmod(intermediate_evals[0], addmod(challenges[1], mulmod(challenges[3], proof.evals[3], <%f_mod%>), <%f_mod%>), <%f_mod%>);
outer_sc_coeffs[2] = mulmod(intermediate_evals[0], mulmod(challenges[2], proof.evals[3], <%f_mod%>), <%f_mod%>);
outer_sc_coeffs[3] = mulmod(intermediate_evals[3], submod(0, proof.evals[2], <%f_mod%>), <%f_mod%>);
outer_sc_coeffs[4] = mulmod(intermediate_evals[4], submod(0, proof.evals[2], <%f_mod%>), <%f_mod%>);
outer_sc_coeffs[5] = submod(0, intermediate_evals[2], <%f_mod%>);
outer_sc_coeffs[6] = mulmod(proof.evals[0], submod(0, challenges[4], <%f_mod%>), <%f_mod%>);
beta_commitments[1] = proof.comms_1[3];
beta_commitments[1] = beta_commitments[1].addition(proof.comms_1[1].scalar_mul(outer_sc_coeffs[1]));
beta_commitments[1] = beta_commitments[1].addition(proof.comms_1[0].scalar_mul(outer_sc_coeffs[3]));
beta_commitments[1] = beta_commitments[1].addition(proof.comms_2[2].scalar_mul(outer_sc_coeffs[5]));
beta_evals[1] = submod(beta_evals[1], outer_sc_coeffs[2], <%f_mod%>);
beta_evals[1] = submod(beta_evals[1], outer_sc_coeffs[4], <%f_mod%>);
beta_evals[1] = submod(beta_evals[1], outer_sc_coeffs[6], <%f_mod%>);
}
{
combined_comm[0] = beta_commitments[0];
combined_eval[0] = beta_evals[0];
uint256 beta_opening_challenge = challenges[6];
{
Pairing.G1Point memory tmp = proof.degree_bound_comms_2_g1.addition(vk.g1_shift.scalar_mul(beta_evals[0]).negate());
tmp = tmp.scalar_mul(beta_opening_challenge);
combined_comm[0] = combined_comm[0].addition(tmp);
}
beta_opening_challenge = mulmod(beta_opening_challenge, challenges[6], <%f_mod%>);
combined_comm[0] = combined_comm[0].addition(beta_commitments[1].scalar_mul(beta_opening_challenge));
combined_eval[0] = addmod(combined_eval[0], mulmod(beta_evals[1], beta_opening_challenge, <%f_mod%>), <%f_mod%>);
beta_opening_challenge = mulmod(beta_opening_challenge, challenges[6], <%f_mod%>);
combined_comm[0] = combined_comm[0].addition(beta_commitments[2].scalar_mul(beta_opening_challenge));
combined_eval[0] = addmod(combined_eval[0], mulmod(beta_evals[2], beta_opening_challenge, <%f_mod%>), <%f_mod%>);
beta_opening_challenge = mulmod(beta_opening_challenge, challenges[6], <%f_mod%>);
combined_comm[0] = combined_comm[0].addition(beta_commitments[3].scalar_mul(beta_opening_challenge));
combined_eval[0] = addmod(combined_eval[0], mulmod(beta_evals[3], beta_opening_challenge, <%f_mod%>), <%f_mod%>);
}
}
{
// gamma commitments: g_2, inner_sc
uint256[2] memory gamma_evals;
Pairing.G1Point[2] memory gamma_commitments;
gamma_evals[0] = proof.evals[1];
gamma_commitments[0] = proof.comms_3[0];
{
// inner sum check: a_val, b_val, c_val, 1, row, col, row_col, h_2
uint256[8] memory inner_sc_coeffs;
{
uint256 a_poly_coeff = mulmod(intermediate_evals[1], intermediate_evals[2], <%f_mod%>);
inner_sc_coeffs[0] = mulmod(challenges[1], a_poly_coeff, <%f_mod%>);
inner_sc_coeffs[1] = mulmod(challenges[2], a_poly_coeff, <%f_mod%>);
inner_sc_coeffs[2] = mulmod(challenges[3], a_poly_coeff, <%f_mod%>);
}
{
uint256 b_poly_coeff = mulmod(challenges[5], proof.evals[1], <%f_mod%>);
b_poly_coeff = addmod(b_poly_coeff, mulmod(proof.evals[2], inverse(<%k_domain_size%>), <%f_mod%>), <%f_mod%>);
inner_sc_coeffs[3] = mulmod(b_poly_coeff, submod(0, mulmod(challenges[4], challenges[0], <%f_mod%>), <%f_mod%>), <%f_mod%>);
inner_sc_coeffs[4] = mulmod(b_poly_coeff, challenges[0], <%f_mod%>);
inner_sc_coeffs[5] = mulmod(b_poly_coeff, challenges[4], <%f_mod%>);
inner_sc_coeffs[6] = submod(0, b_poly_coeff, <%f_mod%>);
}
inner_sc_coeffs[7] = submod(0, intermediate_evals[5], <%f_mod%>);
gamma_commitments[1] = vk.index_comms[2].scalar_mul(inner_sc_coeffs[0]);
gamma_commitments[1] = gamma_commitments[1].addition(vk.index_comms[3].scalar_mul(inner_sc_coeffs[1]));
gamma_commitments[1] = gamma_commitments[1].addition(vk.index_comms[4].scalar_mul(inner_sc_coeffs[2]));
gamma_commitments[1] = gamma_commitments[1].addition(vk.index_comms[0].scalar_mul(inner_sc_coeffs[4]));
gamma_commitments[1] = gamma_commitments[1].addition(vk.index_comms[1].scalar_mul(inner_sc_coeffs[5]));
gamma_commitments[1] = gamma_commitments[1].addition(vk.index_comms[5].scalar_mul(inner_sc_coeffs[6]));
gamma_commitments[1] = gamma_commitments[1].addition(proof.comms_3[1].scalar_mul(inner_sc_coeffs[7]));
gamma_evals[1] = submod(0, inner_sc_coeffs[3], <%f_mod%>);
}
{
combined_comm[1] = gamma_commitments[0];
combined_eval[1] = gamma_evals[0];
uint256 gamma_opening_challenge = challenges[6];
{
Pairing.G1Point memory tmp = proof.degree_bound_comms_3_g2.addition(vk.g2_shift.scalar_mul(gamma_evals[0]).negate());
tmp = tmp.scalar_mul(gamma_opening_challenge);
combined_comm[1] = combined_comm[1].addition(tmp);
}
gamma_opening_challenge = mulmod(gamma_opening_challenge, challenges[6], <%f_mod%>);
combined_comm[1] = combined_comm[1].addition(gamma_commitments[1].scalar_mul(gamma_opening_challenge));
combined_eval[1] = addmod(combined_eval[1], mulmod(gamma_evals[1], gamma_opening_challenge, <%f_mod%>), <%f_mod%>);
}
}
}
// Final pairing check
uint256 r = uint256(keccak256(abi.encodePacked(combined_comm[0].X, combined_comm[0].Y, combined_comm[1].X, combined_comm[1].Y, fs_seed)));
Pairing.G1Point memory c_final;
{
Pairing.G1Point[2] memory c;
c[0] = combined_comm[0].addition(proof.batch_lc_proof_1.scalar_mul(challenges[4]));
c[1] = combined_comm[1].addition(proof.batch_lc_proof_2.scalar_mul(challenges[5]));
c_final = c[0].addition(c[1].scalar_mul(r));
}
Pairing.G1Point memory w_final = proof.batch_lc_proof_1.addition(proof.batch_lc_proof_2.scalar_mul(r));
uint256 g_mul_final = addmod(combined_eval[0], mulmod(combined_eval[1], r, <%f_mod%>), <%f_mod%>);
c_final = c_final.addition(vk.vk.g.scalar_mul(g_mul_final).negate());
c_final = c_final.addition(vk.vk.gamma_g.scalar_mul(proof.batch_lc_proof_1_r).negate());
bool valid = Pairing.pairingProd2(w_final.negate(), vk.vk.beta_h, c_final, vk.vk.h);
return valid;
}
function be_to_le(uint256 input) internal pure returns (uint256 v) {
v = input;
// swap bytes
v = ((v & 0xFF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00) >> 8) |
((v & 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) << 8);
// swap 2-byte long pairs
v = ((v & 0xFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000) >> 16) |
((v & 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) << 16);
// swap 4-byte long pairs
v = ((v & 0xFFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000) >> 32) |
((v & 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) << 32);
// swap 8-byte long pairs
v = ((v & 0xFFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF0000000000000000) >> 64) |
((v & 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) << 64);
// swap 16-byte long pairs
v = (v >> 128) | (v << 128);
}
function sample_field(bytes32 fs_seed, uint32 ctr) internal pure returns (uint256, uint32) {
// https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/fp/mod.rs#L561
while (true) {
uint256 v;
for (uint i = 0; i < 4; i++) {
v |= (uint256(keccak256(abi.encodePacked(fs_seed, ctr))) & uint256(0xFFFFFFFFFFFFFFFF)) << ((3-i) * 64);
ctr += 1;
}
v = be_to_le(v);
v &= (1 << 254) - 1;
if (v < <%f_mod%>) {
return (v, ctr);
}
}
}
function sample_field_128(bytes32 fs_seed, uint32 ctr) internal pure returns (uint256, uint32) {
// https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/fp/mod.rs#L561
uint256 v;
for (uint i = 0; i < 2; i++) {
v |= (uint256(keccak256(abi.encodePacked(fs_seed, ctr))) & uint256(0xFFFFFFFFFFFFFFFF)) << ((3-i) * 64);
ctr += 1;
}
v = be_to_le(v);
return (v, ctr);
}
function montgomery_reduction(uint256 r) internal pure returns (uint256 v) {
uint256[4] memory limbs;
uint256[4] memory mod_limbs;
for (uint i = 0; i < 4; i++) {
limbs[i] = (r >> (i * 64)) & uint256(0xFFFFFFFFFFFFFFFF);
mod_limbs[i] = (<%f_mod%> >> (i * 64)) & uint256(0xFFFFFFFFFFFFFFFF);
}
// Montgomery Reduction
for (uint i = 0; i < 4; i++) {
uint256 k = mulmod(limbs[i], <%f_inv%>, 1 << 64);
uint256 carry = 0;
carry = (limbs[i] + (k * mod_limbs[0]) + carry) >> 64;
for (uint j = 0; j < 4; j++) {
uint256 tmp = limbs[(i + j) % 4] + (k * mod_limbs[j]) + carry;
limbs[(i + j) % 4] = tmp & uint256(0xFFFFFFFFFFFFFFFF);
carry = tmp >> 64;
}
limbs[i % 4] = carry;
}
for (uint i = 0; i < 4; i++) {
v |= (limbs[i] & uint256(0xFFFFFFFFFFFFFFFF)) << (i * 64);
}
}
function submod(uint256 a, uint256 b, uint256 n) internal pure returns (uint256) {
return addmod(a, n - b, n);
}
function expmod(uint256 _base, uint256 _exponent, uint256 _modulus) internal view returns (uint256 retval){
bool success;
uint256[1] memory output;
uint[6] memory input;
input[0] = 0x20; // baseLen = new(big.Int).SetBytes(getData(input, 0, 32))
input[1] = 0x20; // expLen = new(big.Int).SetBytes(getData(input, 32, 32))
input[2] = 0x20; // modLen = new(big.Int).SetBytes(getData(input, 64, 32))
input[3] = _base;
input[4] = _exponent;
input[5] = _modulus;
assembly {
success := staticcall(sub(gas(), 2000), 5, input, 0xc0, output, 0x20)
// Use "invalid" to make gas estimation work
switch success case 0 { invalid() }
}
require(success);
return output[0];
}
function inverse(uint256 a) internal view returns (uint256){
return expmod(a, <%f_mod%> - 2, <%f_mod%>);
}
function eval_vanishing_poly(uint256 x, uint256 domain_size) internal view returns (uint256){
return submod(expmod(x, domain_size, <%f_mod%>), 1, <%f_mod%>);
}
function eval_unnormalized_bivariate_lagrange_poly(uint256 x, uint256 y, uint256 domain_size) internal view returns (uint256){
require(x != y);
uint256 tmp = submod(eval_vanishing_poly(x, domain_size), eval_vanishing_poly(y, domain_size), <%f_mod%>);
return mulmod(tmp, inverse(submod(x, y, <%f_mod%>)), <%f_mod%>);
}
function eval_all_lagrange_coeffs_x_domain(uint256 x) internal view returns (uint256[<%x_domain_size%>] memory){
uint256[<%x_domain_size%>] memory coeffs;
uint256 domain_size = <%x_domain_size%>;
uint256 root = <%x_root%>;
uint256 v_at_x = eval_vanishing_poly(x, domain_size);
uint256 root_inv = inverse(root);
if (v_at_x == 0) {
uint256 omega_i = 1;
for (uint i = 0; i < domain_size; i++) {
if (omega_i == x) {
coeffs[i] = 1;
return coeffs;
}
omega_i = mulmod(omega_i, root, <%f_mod%>);
}
} else {
uint256 l_i = mulmod(inverse(v_at_x), domain_size, <%f_mod%>);
uint256 neg_elem = 1;
for (uint i = 0; i < domain_size; i++) {
coeffs[i] = mulmod(submod(x, neg_elem, <%f_mod%>), l_i, <%f_mod%>);
coeffs[i] = inverse(coeffs[i]);
l_i = mulmod(l_i, root_inv, <%f_mod%>);
neg_elem = mulmod(neg_elem, root, <%f_mod%>);
}
return coeffs;
}
}
}
"#;

View file

@ -8,7 +8,7 @@ use zokrates_field::Field;
#[allow(clippy::upper_case_acronyms)]
pub struct PGHR13;
#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize, Clone)]
pub struct ProofPoints<G1, G2> {
pub a: G1,
pub a_p: G1,
@ -40,6 +40,8 @@ impl<T: Field> Scheme<T> for PGHR13 {
impl<T: Field> NonUniversalScheme<T> for PGHR13 {}
impl<T: SolidityCompatibleField> SolidityCompatibleScheme<T> for PGHR13 {
type Proof = Self::ProofPoints;
fn export_solidity_verifier(vk: <PGHR13 as Scheme<T>>::VerificationKey) -> String {
let (mut template_text, solidity_pairing_lib) =
(String::from(CONTRACT_TEMPLATE), solidity_pairing_lib(false));

View file

@ -1,10 +1,12 @@
use crate::proof_system::Scheme;
use serde::{de::DeserializeOwned, Serialize};
use zokrates_field::{Bn128Field, Field};
pub trait SolidityCompatibleField: Field {}
impl SolidityCompatibleField for Bn128Field {}
pub trait SolidityCompatibleScheme<T: SolidityCompatibleField>: Scheme<T> {
type Proof: From<Self::ProofPoints> + Serialize + DeserializeOwned + Clone;
fn export_solidity_verifier(vk: Self::VerificationKey) -> String;
}

View file

@ -0,0 +1,239 @@
use ethabi::Token;
use primitive_types::U256;
use super::{
Fr, G1Affine, G2Affine, Marlin, NotBw6_761Field, SolidityCompatibleField,
SolidityCompatibleScheme, G16, GM17, PGHR13,
};
/// Helper methods for parsing group structure
pub fn encode_g1_element(g: &G1Affine) -> (U256, U256) {
(
U256::from(&hex::decode(&g.0.trim_start_matches("0x")).unwrap()[..]),
U256::from(&hex::decode(&g.1.trim_start_matches("0x")).unwrap()[..]),
)
}
pub fn encode_g2_element(g: &G2Affine) -> ((U256, U256), (U256, U256)) {
(
(
U256::from(&hex::decode(&g.0 .0.trim_start_matches("0x")).unwrap()[..]),
U256::from(&hex::decode(&g.0 .1.trim_start_matches("0x")).unwrap()[..]),
),
(
U256::from(&hex::decode(&g.1 .0.trim_start_matches("0x")).unwrap()[..]),
U256::from(&hex::decode(&g.1 .1.trim_start_matches("0x")).unwrap()[..]),
),
)
}
pub fn encode_fr_element(f: &Fr) -> U256 {
U256::from(&hex::decode(&f.trim_start_matches("0x")).unwrap()[..])
}
pub trait ToToken<T: SolidityCompatibleField>: SolidityCompatibleScheme<T> {
fn to_token(proof: Self::Proof) -> ethabi::Token;
fn modify(proof: Self::Proof) -> Self::Proof;
}
impl<T: SolidityCompatibleField> ToToken<T> for PGHR13 {
fn to_token(proof: Self::Proof) -> Token {
let a = {
let (x, y) = encode_g1_element(&proof.a);
Token::Tuple(vec![Token::Uint(x), Token::Uint(y)])
};
let a_p = {
let (x, y) = encode_g1_element(&proof.a_p);
Token::Tuple(vec![Token::Uint(x), Token::Uint(y)])
};
let b = {
let ((x0, y0), (x1, y1)) = encode_g2_element(&proof.b);
Token::Tuple(vec![
Token::FixedArray(vec![Token::Uint(x0), Token::Uint(y0)]),
Token::FixedArray(vec![Token::Uint(x1), Token::Uint(y1)]),
])
};
let b_p = {
let (x, y) = encode_g1_element(&proof.b_p);
Token::Tuple(vec![Token::Uint(x), Token::Uint(y)])
};
let c = {
let (x, y) = encode_g1_element(&proof.c);
Token::Tuple(vec![Token::Uint(x), Token::Uint(y)])
};
let c_p = {
let (x, y) = encode_g1_element(&proof.c_p);
Token::Tuple(vec![Token::Uint(x), Token::Uint(y)])
};
let h = {
let (x, y) = encode_g1_element(&proof.h);
Token::Tuple(vec![Token::Uint(x), Token::Uint(y)])
};
let k = {
let (x, y) = encode_g1_element(&proof.k);
Token::Tuple(vec![Token::Uint(x), Token::Uint(y)])
};
let proof_tokens = vec![a, a_p, b, b_p, c, c_p, h, k];
Token::Tuple(proof_tokens)
}
fn modify(mut proof: Self::Proof) -> Self::Proof {
proof.a.0 = "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".into();
proof
}
}
impl<T: SolidityCompatibleField> ToToken<T> for G16 {
fn to_token(proof: Self::Proof) -> Token {
let a = {
let (x, y) = encode_g1_element(&proof.a);
Token::Tuple(vec![Token::Uint(x), Token::Uint(y)])
};
let b = {
let ((x0, y0), (x1, y1)) = encode_g2_element(&proof.b);
Token::Tuple(vec![
Token::FixedArray(vec![Token::Uint(x0), Token::Uint(y0)]),
Token::FixedArray(vec![Token::Uint(x1), Token::Uint(y1)]),
])
};
let c = {
let (x, y) = encode_g1_element(&proof.c);
Token::Tuple(vec![Token::Uint(x), Token::Uint(y)])
};
let proof_tokens = vec![a, b, c];
Token::Tuple(proof_tokens)
}
fn modify(mut proof: Self::Proof) -> Self::Proof {
proof.a.0 = "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".into();
proof
}
}
impl<T: SolidityCompatibleField + NotBw6_761Field> ToToken<T> for GM17 {
fn to_token(proof: Self::Proof) -> Token {
let a = {
let (x, y) = encode_g1_element(&proof.a);
Token::Tuple(vec![Token::Uint(x), Token::Uint(y)])
};
let b = {
let ((x0, y0), (x1, y1)) = encode_g2_element(&proof.b);
Token::Tuple(vec![
Token::FixedArray(vec![Token::Uint(x0), Token::Uint(y0)]),
Token::FixedArray(vec![Token::Uint(x1), Token::Uint(y1)]),
])
};
let c = {
let (x, y) = encode_g1_element(&proof.c);
Token::Tuple(vec![Token::Uint(x), Token::Uint(y)])
};
let proof_tokens = vec![a, b, c];
Token::Tuple(proof_tokens)
}
fn modify(mut proof: Self::Proof) -> Self::Proof {
proof.a.0 = "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".into();
proof
}
}
impl<T: SolidityCompatibleField + NotBw6_761Field> ToToken<T> for Marlin {
fn to_token(proof: Self::Proof) -> Token {
let comms_1_token = Token::Array(
proof
.comms_1
.iter()
.map(encode_g1_element)
.map(|(x, y)| Token::Tuple(vec![Token::Uint(x), Token::Uint(y)]))
.collect(),
);
let comms_2_token = Token::Array(
proof
.comms_2
.iter()
.map(encode_g1_element)
.map(|(x, y)| Token::Tuple(vec![Token::Uint(x), Token::Uint(y)]))
.collect(),
);
let degree_bound_comms_2_g1_token = {
let (x, y) = encode_g1_element(&proof.degree_bound_comms_2_g1);
Token::Tuple(vec![Token::Uint(x), Token::Uint(y)])
};
let comms_3_token = Token::Array(
proof
.comms_3
.iter()
.map(encode_g1_element)
.map(|(x, y)| Token::Tuple(vec![Token::Uint(x), Token::Uint(y)]))
.collect(),
);
let degree_bound_comms_3_g2_token = {
let (x, y) = encode_g1_element(&proof.degree_bound_comms_3_g2);
Token::Tuple(vec![Token::Uint(x), Token::Uint(y)])
};
let evals_token = Token::Array(
proof
.evals
.into_iter()
.map(|f| encode_fr_element(&f))
.map(Token::Uint)
.collect::<Vec<_>>(),
);
let pc_lc_opening_1_token = {
let (x, y) = encode_g1_element(&proof.batch_lc_proof_1);
Token::Tuple(vec![Token::Uint(x), Token::Uint(y)])
};
let degree_bound_pc_lc_opening_1_token =
Token::Uint(encode_fr_element(&proof.batch_lc_proof_1_r));
let pc_lc_opening_2_token = {
let (x, y) = encode_g1_element(&proof.batch_lc_proof_2);
Token::Tuple(vec![Token::Uint(x), Token::Uint(y)])
};
let proof_tokens = vec![
comms_1_token,
comms_2_token,
degree_bound_comms_2_g1_token,
comms_3_token,
degree_bound_comms_3_g2_token,
evals_token,
pc_lc_opening_1_token,
degree_bound_pc_lc_opening_1_token,
pc_lc_opening_2_token,
];
Token::Tuple(proof_tokens)
}
fn modify(mut proof: Self::Proof) -> Self::Proof {
proof.degree_bound_comms_3_g2.0 =
"0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".into();
proof
}
}

View file

@ -13,12 +13,12 @@ multicore = ["bellman_ce/multicore", "sapling-crypto_ce/multicore"]
zokrates_field = { version = "0.5.0", path = "../zokrates_field", default-features = false }
bellman_ce = { version = "^0.3", default-features = false }
sapling-crypto_ce = { version = "^0.1", default-features = false }
ark-bls12-377 = { version = "^0.2.0", features = ["curve", "r1cs"], default-features = false }
ark-bw6-761 = { version = "^0.2.0", default-features = false }
ark-gm17 = { version = "^0.2.0", default-features = false, features = ["r1cs"] }
ark-relations = { version = "^0.2.0", default-features = false }
ark-crypto-primitives = { version = "^0.2.0", default-features = false, features = ["r1cs"] }
ark-r1cs-std = { version = "^0.2.0", default-features = false }
ark-std = { version = "^0.2.0", default-features = false }
ark-ec = { version = "^0.2.0", default-features = false }
ark-ff = { version = "^0.2.0", default-features = false}
ark-bls12-377 = { version = "^0.3.0", features = ["curve", "r1cs"], default-features = false }
ark-bw6-761 = { version = "^0.3.0", default-features = false }
ark-gm17 = { version = "^0.3.0", default-features = false, features = ["r1cs"] }
ark-relations = { version = "^0.3.0", default-features = false }
ark-crypto-primitives = { version = "^0.3.0", default-features = false, features = ["r1cs"] }
ark-r1cs-std = { version = "^0.3.0", default-features = false }
ark-std = { version = "^0.3.0", default-features = false }
ark-ec = { version = "^0.3.0", default-features = false }
ark-ff = { version = "^0.3.0", default-features = false}

View file

@ -13,7 +13,7 @@ serde = "1.0"
serde_derive = "1.0"
lazy_static = "1.4"
bincode = "0.8.0"
serde_json = "1.0"
serde_json = { version = "1.0", features = ["preserve_order"] }
sha2 = "0.8.0"
num-traits = { version = "0.2", default-features = false }
num-integer = { version = "0.1", default-features = false }
@ -22,13 +22,13 @@ num-integer = { version = "0.1", default-features = false }
bellman_ce = { version = "^0.3", default-features = false, optional = true }
# ark
ark-ec = { version = "^0.2.0", default-features = false }
ark-ff = { version = "^0.2.0", default-features = false }
ark-bn254 = { version = "^0.2.0", features = ["curve"], default-features = false }
ark-bls12-377 = { version = "^0.2.0", features = ["curve"], default-features = false }
ark-bls12-381 = { version = "^0.2.0", features = ["curve"], default-features = false }
ark-bw6-761 = { version = "^0.2.0", default-features = false }
ark-serialize = { version = "^0.2.0", default-features = false }
ark-ff = { version = "^0.3.0", default-features = false }
ark-ec = { version = "^0.3.0", default-features = false }
ark-bn254 = { version = "^0.3.0", features = ["curve"], default-features = false }
ark-bls12-377 = { version = "^0.3.0", features = ["curve"], default-features = false }
ark-bls12-381 = { version = "^0.3.0", features = ["curve"] }
ark-bw6-761 = { version = "^0.3.0", default-features = false }
ark-serialize = { version = "^0.3.0", default-features = false }
[dev-dependencies]
rand = "0.4"

531
zokrates_js/Cargo.lock generated
View file

@ -23,7 +23,7 @@ version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
dependencies = [
"getrandom 0.2.3",
"getrandom",
"once_cell",
"version_check",
]
@ -38,10 +38,19 @@ dependencies = [
]
[[package]]
name = "ark-bls12-377"
version = "0.2.0"
name = "aho-corasick"
version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb89b97424403ec9cc22a1df0db748dd7396c9ba5fb5c71a6f0e10ae1d1a7449"
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
dependencies = [
"memchr",
]
[[package]]
name = "ark-bls12-377"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc41c02c0d18a226947ee9ee023b1d957bdb6a68fc22ac296722935a9fef423c"
dependencies = [
"ark-ec",
"ark-ff",
@ -51,9 +60,9 @@ dependencies = [
[[package]]
name = "ark-bls12-381"
version = "0.2.0"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70e1c2ad76c4f725520440b981df3ce2d635f2baa1122750c757c0cf0f3d4b74"
checksum = "65be532f9dd1e98ad0150b037276cde464c6f371059e6dd02c0222395761f6aa"
dependencies = [
"ark-ec",
"ark-ff",
@ -62,9 +71,9 @@ dependencies = [
[[package]]
name = "ark-bn254"
version = "0.2.0"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ead066869de5e8cb2938123204d1572f09496b629e146a6f80fa8ec508446ba"
checksum = "ea691771ebbb28aea556c044e2e5c5227398d840cee0c34d4d20fa8eb2689e8c"
dependencies = [
"ark-ec",
"ark-ff",
@ -73,9 +82,9 @@ dependencies = [
[[package]]
name = "ark-bw6-761"
version = "0.2.0"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69ad8d74a8e083a59defc4a226a19759691337006d5c9397dbd793af9e406418"
checksum = "5abb465edcdee2bec3eff283e43f1c2414d1a4f6eaeb8e3de02aba3695d0520b"
dependencies = [
"ark-bls12-377",
"ark-ec",
@ -85,15 +94,16 @@ dependencies = [
[[package]]
name = "ark-crypto-primitives"
version = "0.2.0"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74b83a7e125e5c611e4a997123effb2f02e3fbc66531dd77751d3016ee920741"
checksum = "ff773c0ef8c655c98071d3026a63950798a66b2f45baef22d8334c1756f1bd18"
dependencies = [
"ark-ec",
"ark-ff",
"ark-nonnative-field",
"ark-r1cs-std",
"ark-relations",
"ark-serialize",
"ark-snark",
"ark-std",
"blake2",
@ -104,9 +114,9 @@ dependencies = [
[[package]]
name = "ark-ec"
version = "0.2.0"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c56006994f509d76fbce6f6ffe3108f7191b4f3754ecd00bbae7cac20ec05020"
checksum = "dea978406c4b1ca13c2db2373b05cc55429c3575b8b21f1b9ee859aa5b03dd42"
dependencies = [
"ark-ff",
"ark-serialize",
@ -118,25 +128,27 @@ dependencies = [
[[package]]
name = "ark-ff"
version = "0.2.0"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4d8802d40fce9212c5c09be08f75c4b3becc0c488e87f60fff787b01250ce33"
checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6"
dependencies = [
"ark-ff-asm",
"ark-ff-macros",
"ark-serialize",
"ark-std",
"derivative",
"num-bigint 0.4.2",
"num-traits 0.2.14",
"paste",
"rustc_version",
"zeroize",
]
[[package]]
name = "ark-ff-asm"
version = "0.2.0"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e8cb28c2137af1ef058aa59616db3f7df67dbb70bf2be4ee6920008cc30d98c"
checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44"
dependencies = [
"quote 1.0.10",
"syn 1.0.80",
@ -144,9 +156,9 @@ dependencies = [
[[package]]
name = "ark-ff-macros"
version = "0.2.0"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b9c256a93a10ed9708c16a517d6dcfaba3d215c0d7fab44d29a9affefb5eeb8"
checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20"
dependencies = [
"num-bigint 0.4.2",
"num-traits 0.2.14",
@ -156,9 +168,9 @@ dependencies = [
[[package]]
name = "ark-gm17"
version = "0.2.0"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c9085a6c89aa65178aa2718b2efb62fd7c4dc23fe25285204e30b56e4cbfcac"
checksum = "94713045868e99a606a89825ff5a901667ba707ad1966a32c7f3a4d4dbcc0e9a"
dependencies = [
"ark-crypto-primitives",
"ark-ec",
@ -174,9 +186,9 @@ dependencies = [
[[package]]
name = "ark-nonnative-field"
version = "0.2.0"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17887af156e9911d1dba5b30d49256d508f82f6a4f765a6fad8b5c637b700353"
checksum = "440ad4569974910adbeb84422b7e622b79e08d27142afd113785b7fcfb446186"
dependencies = [
"ark-ec",
"ark-ff",
@ -192,22 +204,22 @@ dependencies = [
[[package]]
name = "ark-poly"
version = "0.2.0"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72d6683d21645a2abb94034f6a14e708405e55d9597687952d54b2269922857a"
checksum = "7b0f78f47537c2f15706db7e98fe64cc1711dbf9def81218194e17239e53e5aa"
dependencies = [
"ark-ff",
"ark-serialize",
"ark-std",
"derivative",
"hashbrown",
"hashbrown 0.11.2",
]
[[package]]
name = "ark-r1cs-std"
version = "0.2.0"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a90fea2b84ae4443983d56540360ea004cab952292b7a6535798b6b9dcb7f41"
checksum = "22e8fdacb1931f238a0d866ced1e916a49d36de832fd8b83dc916b718ae72893"
dependencies = [
"ark-ec",
"ark-ff",
@ -221,9 +233,9 @@ dependencies = [
[[package]]
name = "ark-relations"
version = "0.2.0"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a42f124f8dfff2b0561143c0c7ea48d7f7dc8d2c4c1e87eca14a27430c653c0b"
checksum = "4cba4c1c99792a6834bd97f7fd76578ec2cd58d2afc5139a17e1d1bec65b38f6"
dependencies = [
"ark-ff",
"ark-std",
@ -232,19 +244,20 @@ dependencies = [
[[package]]
name = "ark-serialize"
version = "0.2.0"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3e9b59329dc9b92086b3dc619f31cef4a0c802f10829b575a3666d48a48387d"
checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671"
dependencies = [
"ark-serialize-derive",
"ark-std",
"digest 0.9.0",
]
[[package]]
name = "ark-serialize-derive"
version = "0.2.0"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ac3d78c750b01f5df5b2e76d106ed31487a93b3868f14a7f0eb3a74f45e1d8a"
checksum = "8dd4e5f0bf8285d5ed538d27fab7411f3e297908fd93c62195de8bee3f199e82"
dependencies = [
"proc-macro2 1.0.30",
"quote 1.0.10",
@ -253,9 +266,9 @@ dependencies = [
[[package]]
name = "ark-snark"
version = "0.2.0"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39da26432fe584b0010741299820145ec69180fe9ea18ddf96946932763624a1"
checksum = "0dc3dff1a5f67a9c0b34df32b079752d8dd17f1e9d06253da0453db6c1b7cc8a"
dependencies = [
"ark-ff",
"ark-relations",
@ -264,12 +277,12 @@ dependencies = [
[[package]]
name = "ark-std"
version = "0.2.0"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb5b856a29bea7b810858116a596beee3d20fc4c5aeb240e8e5a8bca4845a470"
checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c"
dependencies = [
"rand 0.7.3",
"rand_xorshift",
"num-traits 0.2.14",
"rand 0.8.5",
]
[[package]]
@ -281,6 +294,12 @@ dependencies = [
"nodrop",
]
[[package]]
name = "arrayvec"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
[[package]]
name = "autocfg"
version = "1.0.1"
@ -335,6 +354,18 @@ version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
[[package]]
name = "bitvec"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1489fcb93a5bb47da0462ca93ad252ad6af2145cce58d10d46a83931ba9f016b"
dependencies = [
"funty",
"radium",
"tap",
"wyz",
]
[[package]]
name = "blake2"
version = "0.9.2"
@ -352,7 +383,7 @@ version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400"
dependencies = [
"arrayvec",
"arrayvec 0.4.12",
"constant_time_eq",
]
@ -362,7 +393,7 @@ version = "0.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdc60350286c7c3db13b98e91dbe5c8b6830a6821bc20af5b0c310ce94d74915"
dependencies = [
"arrayvec",
"arrayvec 0.4.12",
"byteorder",
"constant_time_eq",
]
@ -379,6 +410,15 @@ dependencies = [
"generic-array 0.12.4",
]
[[package]]
name = "block-buffer"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324"
dependencies = [
"generic-array 0.14.4",
]
[[package]]
name = "block-padding"
version = "0.1.5"
@ -406,6 +446,12 @@ version = "3.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c"
[[package]]
name = "byte-slice-cast"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87c5fdd0166095e1d463fc6cc01aa8ce547ad77a4e84d42eb6762b084e28067e"
[[package]]
name = "byte-tools"
version = "0.3.1"
@ -418,6 +464,12 @@ version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "bytes"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
[[package]]
name = "cc"
version = "1.0.71"
@ -530,6 +582,16 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]]
name = "crypto-common"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8"
dependencies = [
"generic-array 0.14.4",
"typenum",
]
[[package]]
name = "crypto-mac"
version = "0.8.0"
@ -591,12 +653,66 @@ dependencies = [
"generic-array 0.14.4",
]
[[package]]
name = "digest"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506"
dependencies = [
"block-buffer 0.10.2",
"crypto-common",
]
[[package]]
name = "either"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
name = "ethabi"
version = "17.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b69517146dfab88e9238c00c724fd8e277951c3cc6f22b016d72f422a832213e"
dependencies = [
"ethereum-types",
"hex",
"once_cell",
"regex 1.5.5",
"serde",
"serde_json",
"sha3",
"thiserror",
"uint",
]
[[package]]
name = "ethbloom"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11da94e443c60508eb62cf256243a64da87304c2802ac2528847f79d750007ef"
dependencies = [
"crunchy",
"fixed-hash",
"impl-rlp",
"impl-serde",
"tiny-keccak",
]
[[package]]
name = "ethereum-types"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2827b94c556145446fcce834ca86b7abf0c39a805883fe20e72c5bfdb5a0dc6"
dependencies = [
"ethbloom",
"fixed-hash",
"impl-rlp",
"impl-serde",
"primitive-types",
"uint",
]
[[package]]
name = "failure"
version = "0.1.8"
@ -662,6 +778,18 @@ dependencies = [
"syn 1.0.80",
]
[[package]]
name = "fixed-hash"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c"
dependencies = [
"byteorder",
"rand 0.8.5",
"rustc-hex",
"static_assertions",
]
[[package]]
name = "from-pest"
version = "0.3.1"
@ -678,6 +806,12 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
[[package]]
name = "funty"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
[[package]]
name = "futures"
version = "0.3.17"
@ -775,17 +909,6 @@ dependencies = [
"version_check",
]
[[package]]
name = "getrandom"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
dependencies = [
"cfg-if 1.0.0",
"libc",
"wasi 0.9.0+wasi-snapshot-preview1",
]
[[package]]
name = "getrandom"
version = "0.2.3"
@ -795,7 +918,7 @@ dependencies = [
"cfg-if 1.0.0",
"js-sys",
"libc",
"wasi 0.10.2+wasi-snapshot-preview1",
"wasi",
"wasm-bindgen",
]
@ -811,6 +934,12 @@ version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
[[package]]
name = "hashbrown"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
[[package]]
name = "hashbrown"
version = "0.11.2"
@ -835,6 +964,54 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "impl-codec"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f"
dependencies = [
"parity-scale-codec",
]
[[package]]
name = "impl-rlp"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808"
dependencies = [
"rlp",
]
[[package]]
name = "impl-serde"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4551f042f3438e64dbd6226b20527fc84a6e1fe65688b58746a2f53623f25f5c"
dependencies = [
"serde",
]
[[package]]
name = "impl-trait-for-tuples"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb"
dependencies = [
"proc-macro2 1.0.30",
"quote 1.0.10",
"syn 1.0.80",
]
[[package]]
name = "indexmap"
version = "1.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3"
dependencies = [
"autocfg",
"hashbrown 0.9.1",
]
[[package]]
name = "itertools"
version = "0.7.11"
@ -859,6 +1036,12 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "keccak"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7"
[[package]]
name = "lazy_static"
version = "1.4.0"
@ -1017,9 +1200,9 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.8.0"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
[[package]]
name = "opaque-debug"
@ -1044,6 +1227,38 @@ dependencies = [
"rand 0.4.6",
]
[[package]]
name = "parity-scale-codec"
version = "3.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8b44461635bbb1a0300f100a841e571e7d919c81c73075ef5d152ffdb521066"
dependencies = [
"arrayvec 0.7.2",
"bitvec",
"byte-slice-cast",
"impl-trait-for-tuples",
"parity-scale-codec-derive",
"serde",
]
[[package]]
name = "parity-scale-codec-derive"
version = "3.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c45ed1f39709f5a89338fab50e59816b2e8815f5bb58276e7ddf9afd495f73f8"
dependencies = [
"proc-macro-crate",
"proc-macro2 1.0.30",
"quote 1.0.10",
"syn 1.0.80",
]
[[package]]
name = "paste"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc"
[[package]]
name = "pest"
version = "2.1.3"
@ -1110,7 +1325,7 @@ dependencies = [
"blake2-rfc",
"byteorder",
"crossbeam",
"getrandom 0.2.3",
"getrandom",
"num_cpus",
"pairing_ce",
"rand 0.4.6",
@ -1134,6 +1349,29 @@ version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3ca011bd0129ff4ae15cd04c4eef202cadf6c51c21e47aba319b4e0501db741"
[[package]]
name = "primitive-types"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e28720988bff275df1f51b171e1b2a18c30d194c4d2b61defdacecd625a5d94a"
dependencies = [
"fixed-hash",
"impl-codec",
"impl-rlp",
"impl-serde",
"uint",
]
[[package]]
name = "proc-macro-crate"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a"
dependencies = [
"thiserror",
"toml",
]
[[package]]
name = "proc-macro2"
version = "0.4.30"
@ -1170,6 +1408,12 @@ dependencies = [
"proc-macro2 1.0.30",
]
[[package]]
name = "radium"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
[[package]]
name = "rand"
version = "0.4.6"
@ -1185,25 +1429,23 @@ dependencies = [
[[package]]
name = "rand"
version = "0.7.3"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"getrandom 0.1.16",
"libc",
"rand_chacha",
"rand_core 0.5.1",
"rand_hc",
"rand_core 0.6.3",
]
[[package]]
name = "rand_chacha"
version = "0.2.2"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core 0.5.1",
"rand_core 0.6.3",
]
[[package]]
@ -1223,29 +1465,11 @@ checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
[[package]]
name = "rand_core"
version = "0.5.1"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
dependencies = [
"getrandom 0.1.16",
]
[[package]]
name = "rand_hc"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
dependencies = [
"rand_core 0.5.1",
]
[[package]]
name = "rand_xorshift"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8"
dependencies = [
"rand_core 0.5.1",
"getrandom",
]
[[package]]
@ -1269,13 +1493,24 @@ version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9329abc99e39129fcceabd24cf5d85b4671ef7c29c50e972bc5afe32438ec384"
dependencies = [
"aho-corasick",
"aho-corasick 0.6.10",
"memchr",
"regex-syntax",
"regex-syntax 0.5.6",
"thread_local",
"utf8-ranges",
]
[[package]]
name = "regex"
version = "1.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
dependencies = [
"aho-corasick 0.7.18",
"memchr",
"regex-syntax 0.6.25",
]
[[package]]
name = "regex-automata"
version = "0.1.10"
@ -1291,12 +1526,34 @@ dependencies = [
"ucd-util",
]
[[package]]
name = "regex-syntax"
version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]]
name = "rlp"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "999508abb0ae792aabed2460c45b89106d97fe4adac593bdaef433c2605847b5"
dependencies = [
"bytes",
"rustc-hex",
]
[[package]]
name = "rustc-demangle"
version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
[[package]]
name = "rustc-hex"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6"
[[package]]
name = "rustc_version"
version = "0.3.3"
@ -1389,6 +1646,7 @@ version = "1.0.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8"
dependencies = [
"indexmap",
"itoa",
"ryu",
"serde",
@ -1400,7 +1658,7 @@ version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df"
dependencies = [
"block-buffer",
"block-buffer 0.7.3",
"digest 0.8.1",
"fake-simd",
"opaque-debug 0.2.3",
@ -1412,12 +1670,22 @@ version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69"
dependencies = [
"block-buffer",
"block-buffer 0.7.3",
"digest 0.8.1",
"fake-simd",
"opaque-debug 0.2.3",
]
[[package]]
name = "sha3"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "881bf8156c87b6301fc5ca6b27f11eeb2761224c7081e69b409d5a1951a70c86"
dependencies = [
"digest 0.10.3",
"keccak",
]
[[package]]
name = "single"
version = "1.0.0"
@ -1433,6 +1701,12 @@ version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5"
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "subtle"
version = "2.4.1"
@ -1473,6 +1747,32 @@ dependencies = [
"unicode-xid 0.2.2",
]
[[package]]
name = "tap"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
[[package]]
name = "thiserror"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
dependencies = [
"proc-macro2 1.0.30",
"quote 1.0.10",
"syn 1.0.80",
]
[[package]]
name = "thread_local"
version = "0.3.6"
@ -1491,6 +1791,15 @@ dependencies = [
"crunchy",
]
[[package]]
name = "toml"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
dependencies = [
"serde",
]
[[package]]
name = "tracing"
version = "0.1.29"
@ -1544,6 +1853,18 @@ version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c85f514e095d348c279b1e5cd76795082cf15bd59b93207832abe0b1d8fed236"
[[package]]
name = "uint"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12f03af7ccf01dd611cc450a0d10dbc9b745770d096473e2faf0ca6e2d66d1e0"
dependencies = [
"byteorder",
"crunchy",
"hex",
"static_assertions",
]
[[package]]
name = "unicode-xid"
version = "0.1.0"
@ -1574,12 +1895,6 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"
@ -1674,6 +1989,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "wyz"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30b31594f29d27036c383b53b59ed3476874d518f0efb151b27a4c275141390e"
dependencies = [
"tap",
]
[[package]]
name = "zeroize"
version = "1.4.2"
@ -1712,13 +2036,14 @@ version = "0.1.0"
[[package]]
name = "zokrates_core"
version = "0.6.9"
version = "0.6.10"
dependencies = [
"bellman_ce",
"cfg-if 0.1.10",
"csv",
"ethabi",
"ff_ce 0.9.0",
"getrandom 0.2.3",
"getrandom",
"hex",
"lazy_static",
"log",
@ -1726,10 +2051,11 @@ dependencies = [
"num-bigint 0.2.6",
"pairing_ce",
"phase2",
"primitive-types",
"rand 0.4.6",
"rand 0.7.3",
"rand 0.8.5",
"reduce",
"regex",
"regex 0.2.11",
"serde",
"serde_cbor",
"serde_json",
@ -1783,9 +2109,10 @@ dependencies = [
[[package]]
name = "zokrates_js"
version = "1.0.38"
version = "1.0.39"
dependencies = [
"console_error_panic_hook",
"indexmap",
"js-sys",
"serde",
"serde_json",

View file

@ -10,11 +10,13 @@ crate-type = ["cdylib"]
[dependencies]
js-sys = "0.3.33"
serde = { version = "^1.0.59", features = ["derive"] }
serde_json = "1.0"
serde_json = { version = "1.0", features = ["preserve_order"] }
wasm-bindgen = { version = "0.2.46", features = ["serde-serialize"] }
typed-arena = "1.4.1"
zokrates_core = { path = "../zokrates_core", features = ["wasm", "bellman"], default-features = false }
zokrates_common = { path = "../zokrates_common" }
zokrates_field = { path = "../zokrates_field", features = ["bellman"] }
zokrates_abi = { path = "../zokrates_abi" }
console_error_panic_hook = "0.1.6"
console_error_panic_hook = "0.1.6"
indexmap = "~1.6.2" # see https://github.com/rustwasm/wasm-bindgen/issues/2770#issuecomment-1041102532

View file

@ -214,7 +214,7 @@ pub fn generate_proof(program: &[u8], witness: JsValue, pk: &[u8]) -> Result<JsV
#[wasm_bindgen]
pub fn verify(vk: JsValue, proof: JsValue) -> Result<JsValue, JsValue> {
let vk: <G16 as Scheme<Bn128Field>>::VerificationKey = vk.into_serde().unwrap();
let proof: Proof<<G16 as Scheme<Bn128Field>>::ProofPoints> = proof.into_serde().unwrap();
let proof: Proof<Bn128Field, G16> = proof.into_serde().unwrap();
let ans = <Bellman as Backend<Bn128Field, G16>>::verify(vk, proof);
Ok(JsValue::from_serde(&ans).unwrap())

View file

@ -0,0 +1,18 @@
[package]
name = "zokrates_solidity_test"
version = "0.1.0"
authors = ["Nirvan Tyagi <nirvan.tyagi@gmail.com>"]
edition = "2018"
# Modeled after the testing pipeline of the Fe project: https://github.com/ethereum/fe/
[dependencies]
ethabi = "17.0.0"
primitive-types = { version = "0.11", features = ["rlp"] }
hex = { version = "0.4" }
bytes = { version = "1.1", default-features = false }
serde_json = { version = "1.0" }
rand = { version = "0.8" }
revm = { git = "https://github.com/bluealloy/revm", version = "1.2" }
solc = { git = "https://github.com/g-r-a-n-t/solc-rust", rev = "52d4146" }

View file

@ -0,0 +1,18 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
contract SimpleStorage {
Var myVariable;
struct Var {
uint v;
}
function set(Var memory x) public {
myVariable = x;
}
function get() public view returns (uint) {
return myVariable.v;
}
}

View file

@ -0,0 +1,28 @@
use ethabi::token::Token;
use primitive_types::H160;
use rand::Rng;
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Address(pub H160);
impl Address {
pub fn random<R: Rng>(rng: &mut R) -> Self {
Self(H160(rng.gen()))
}
pub fn as_token(&self) -> Token {
Token::Address(self.0)
}
}
impl AsRef<H160> for Address {
fn as_ref(&self) -> &H160 {
&self.0
}
}
impl From<H160> for Address {
fn from(hash: H160) -> Self {
Self(hash)
}
}

View file

@ -0,0 +1,156 @@
use ethabi::{Contract as ContractAbi, Token};
use serde_json::{from_str, json};
use solc::compile;
use std::{fs::File, io::Read, path::Path};
use crate::{Error, EvmTestError};
#[derive(Clone)]
pub struct Contract {
pub binary: Vec<u8>,
pub abi: ContractAbi,
}
impl Contract {
pub fn new(binary: Vec<u8>, abi: ContractAbi) -> Self {
Self { binary, abi }
}
pub fn compile_from_solidity_file<P: AsRef<Path>>(
path: P,
contract_name: &str,
opt: bool,
) -> Result<Self, Error> {
// Load source file
let mut src_file = File::open(path)
.map_err(|_| Box::new(EvmTestError("src file open failed".to_string())))?;
let mut src = String::new();
src_file
.read_to_string(&mut src)
.map_err(|_| Box::new(EvmTestError("src file read failed".to_string())))?;
Self::compile_from_src_string(&src, contract_name, opt, &[])
}
pub fn compile_from_src_string(
src: &str,
contract_name: &str,
opt: bool,
libraries: &[(&str, Token)],
) -> Result<Self, Error> {
// Compile source file using solc
// Configuration: https://docs.soliditylang.org/en/v0.8.10/using-the-compiler.html
// TODO: Change output selection to only compile 'input' file
let solc_config = format!(
r#"
{{
"language": "Solidity",
"sources": {{ "input.sol": {{ "content": {} }} }},
"settings": {{
"optimizer": {{ "enabled": {} }},
"libraries": {{
"input.sol" : {{ {} }}
}},
"outputSelection": {{
"*": {{
"*": [
"evm.bytecode.object", "abi"
],
"": [ "*" ] }}
}}
}}
}}"#,
json!(src),
opt,
libraries
.iter()
.map(|(name, address)| format!("\"{}\": \"0x{}\"", name, address))
.collect::<Vec<_>>()
.join(",\n")
);
Self::compile_from_config(&solc_config, contract_name)
}
pub fn compile_from_config(config: &str, contract_name: &str) -> Result<Self, Error> {
// Compile source file using solc
// Configuration: https://docs.soliditylang.org/en/v0.8.10/using-the-compiler.html
let out = from_str::<serde_json::Value>(&compile(config))
.map_err(|_| Box::new(EvmTestError("solc compile failed".to_string())))?;
if out["errors"].is_array()
&& out["errors"]
.as_array()
.unwrap()
.iter()
.any(|e| e["severity"] == "error")
{
return Err(Box::new(EvmTestError(format!(
"solc compiled with errors: {}",
out["errors"]
))));
}
let binary = {
let hex_code = out["contracts"]["input.sol"][contract_name]["evm"]["bytecode"]
["object"]
.to_string()
.replace('\"', "");
hex::decode(&hex_code)
.map_err(|_| Box::new(EvmTestError("decode hex binary failed".to_string())))?
};
let abi = {
if out["contracts"]["input.sol"][contract_name]["abi"] == "null" {
return Err(Box::new(EvmTestError(
"solc compiled with null abi".to_string(),
)));
}
ContractAbi::load(
out["contracts"]["input.sol"][contract_name]["abi"]
.to_string()
.as_bytes(),
)
.map_err(|_| Box::new(EvmTestError("ethabi failed loading abi".to_string())))?
};
Ok(Contract { binary, abi })
}
pub fn encode_create_contract_bytes(&self, init: &[Token]) -> Result<Vec<u8>, Error> {
match &self.abi.constructor {
Some(constructor) => {
let binary = constructor
.encode_input(self.binary.clone(), init)
.map_err(|_| {
Box::new(EvmTestError(
"abi constructor failed to encode inputs".to_string(),
))
})?;
Ok(binary.to_vec())
}
None => Ok(self.binary.clone()),
}
}
pub fn encode_call_contract_bytes(
&self,
fn_name: &str,
input: &[Token],
) -> Result<Vec<u8>, Error> {
match self.abi.functions.get(fn_name) {
Some(f) => {
let call_binary = f[0].encode_input(input).map_err(|_| {
Box::new(EvmTestError(
"abi function failed to encode inputs".to_string(),
))
})?;
Ok(call_binary.to_vec())
}
None => Err(Box::new(EvmTestError(
"abi does not include function".to_string(),
))),
}
}
}

View file

@ -0,0 +1,123 @@
use primitive_types::U256;
pub use revm::Return;
use revm::{AccountInfo, InMemoryDB, Log, TransactOut, TransactTo, EVM};
use crate::{address::Address, Error, EvmTestError};
#[derive(Debug)]
pub struct CallResult {
pub op_out: Return,
pub out: Vec<u8>,
pub gas: u64,
pub log_out: Vec<Log>,
}
#[derive(Debug)]
pub struct CreateContractResult {
pub addr: Address,
pub gas: u64,
}
pub struct Evm {
vm: EVM<InMemoryDB>,
}
impl Default for Evm {
fn default() -> Self {
let mut vm = revm::new();
vm.database(InMemoryDB::default());
Self { vm }
}
}
impl Evm {
pub fn call(
&mut self,
input: Vec<u8>,
addr: &Address,
caller: &Address,
) -> Result<CallResult, Error> {
self.vm.env.tx.caller = *caller.as_ref();
self.vm.env.tx.transact_to = TransactTo::Call(*addr.as_ref());
self.vm.env.tx.data = input.into();
let (op_out, tx_out, gas, log_out) = self.vm.transact_commit();
let out = match tx_out {
TransactOut::Call(out) => Ok(out.to_vec()),
_ => Err(Box::new(EvmTestError(
"call contract function failed".to_string(),
))),
}?;
Ok(CallResult {
op_out,
out,
gas,
log_out,
})
}
pub fn deploy(
&mut self,
contract: Vec<u8>,
deployer: &Address,
) -> Result<CreateContractResult, Error> {
match self
.vm
.db()
.unwrap()
.cache()
.get_key_value(deployer.as_ref())
{
Some(_) => {
self.vm.env.tx.caller = *deployer.as_ref();
self.vm.env.tx.transact_to = TransactTo::create();
self.vm.env.tx.data = contract.into();
let (_, tx_out, gas, _) = self.vm.transact_commit();
let contract_address = match tx_out {
TransactOut::Create(_, Some(addr)) => Ok(Address(addr)),
_ => Err(Box::new(EvmTestError("create contract failed".to_string()))),
}?;
Ok(CreateContractResult {
addr: contract_address,
gas,
})
}
None => Err(Box::new(EvmTestError(
"deployer address not found".to_string(),
))),
}
}
pub fn create_account(&mut self, address: &Address, balance: impl Into<U256>) {
let acc = AccountInfo::from_balance(balance.into());
self.vm.db().unwrap().insert_cache(*address.as_ref(), acc);
}
pub fn set_account_balance(
&mut self,
address: &Address,
balance: impl Into<U256>,
) -> Result<(), Error> {
let mut acc = self
.vm
.db()
.unwrap()
.cache()
.get(address.as_ref())
.ok_or_else(|| Box::new(EvmTestError("account address not found".to_string())))?
.clone();
acc.balance = balance.into();
self.vm.db().unwrap().insert_cache(*address.as_ref(), acc);
Ok(())
}
pub fn balance_of(&mut self, address: &Address) -> U256 {
match self.vm.db().unwrap().cache().get(address.as_ref()) {
Some(acc) => acc.balance,
None => 0.into(),
}
}
pub fn get_account(&mut self, address: &Address) -> Option<AccountInfo> {
self.vm.db().unwrap().cache().get(address.as_ref()).cloned()
}
}

View file

@ -0,0 +1,104 @@
use primitive_types::U256;
use std::{
error::Error as ErrorTrait,
fmt::{self, Debug},
};
pub mod address;
pub mod contract;
pub mod evm;
pub type Error = Box<dyn ErrorTrait>;
#[derive(Debug)]
pub struct EvmTestError(String);
impl ErrorTrait for EvmTestError {
fn source(&self) -> Option<&(dyn ErrorTrait + 'static)> {
None
}
}
impl fmt::Display for EvmTestError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
pub fn to_be_bytes(n: &U256) -> [u8; 32] {
let mut input_bytes: [u8; 32] = [0; 32];
n.to_big_endian(&mut input_bytes);
input_bytes
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{address::Address, contract::Contract, evm::Evm};
use ethabi::Token;
use rand::{rngs::StdRng, SeedableRng};
#[test]
fn simple_storage_contract_test() {
let mut rng = StdRng::seed_from_u64(0u64);
// Compile contract
let contract_path = format!(
"{}/contracts/simple_storage.sol",
env!("CARGO_MANIFEST_DIR")
);
let contract =
Contract::compile_from_solidity_file(contract_path, "SimpleStorage", false).unwrap();
// Setup EVM
let mut evm = Evm::default();
let deployer = Address::random(&mut rng);
evm.create_account(&deployer, 0);
// Deploy contract
let create_result = evm
.deploy(
contract.encode_create_contract_bytes(&[]).unwrap(),
&deployer,
)
.unwrap();
let contract_addr = create_result.addr.clone();
println!("Contract deploy gas cost: {}", create_result.gas);
// Call get function on contract
let get_result = evm
.call(
contract.encode_call_contract_bytes("get", &[]).unwrap(),
&contract_addr,
&deployer,
)
.unwrap();
assert_eq!(&get_result.out, &to_be_bytes(&U256::from(0)));
// Call set function on contract
let _ = evm
.call(
contract
.encode_call_contract_bytes(
"set",
&[Token::Tuple(vec![Token::Uint(U256::from(40))])],
)
.unwrap(),
&contract_addr,
&deployer,
)
.unwrap();
// Call get function on contract
let get_result = evm
.call(
contract.encode_call_contract_bytes("get", &[]).unwrap(),
&contract_addr,
&deployer,
)
.unwrap();
assert_eq!(&get_result.out, &to_be_bytes(&U256::from(40)));
println!("{:?}", get_result);
}
}

View file

@ -11,7 +11,7 @@ zokrates_fs_resolver = { version = "0.5", path = "../zokrates_fs_resolver" }
zokrates_abi = { version = "0.1", path = "../zokrates_abi" }
serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
serde_json = { version = "1.0", features = ["preserve_order"] }
typed-arena = "1.4.1"
[lib]