1
0
Fork 0
mirror of synced 2025-09-24 04:40:05 +00:00
This commit is contained in:
dark64 2019-10-30 00:08:39 +01:00
parent 3993732a1f
commit e7c1a0e6d7
10 changed files with 555 additions and 165 deletions

View file

@ -46,4 +46,4 @@ assert_cli = "0.5"
[build-dependencies]
cc = { version = "1.0", features = ["parallel"], optional = true }
cmake = { version = "0.1.31", optional = true }
git2 = { version = "0.8.0", optional = true }
git2 = { version = "0.8.0", optional = true }

View file

@ -14,11 +14,12 @@ fn main() {
use std::path::PathBuf;
// fetch libsnark source
const LIBSNARK_URL: &'static str = "https://github.com/scipr-lab/libsnark.git";
const LIBSNARK_COMMIT: &'static str = "f7c87b88744ecfd008126d415494d9b34c4c1b20";
let libsnark_source_path = &PathBuf::from(env::var("OUT_DIR").unwrap()).join("LIBSNARK");
let out_path = env::var("OUT_DIR").unwrap();
let libsnark_source_path = &PathBuf::from(out_path.clone()).join("libsnark");
let libsnark_wrapper_path = &PathBuf::from(out_path.clone()).join("libsnark-wrapper.a");
let repo = Repository::open(libsnark_source_path).unwrap_or_else(|_| {
remove_dir(libsnark_source_path).ok();
@ -36,7 +37,6 @@ fn main() {
}
// build libsnark
let libsnark = cmake::Config::new(libsnark_source_path)
.define("WITH_PROCPS", "OFF")
.define("CURVE", "ALT_BN128")
@ -46,7 +46,6 @@ fn main() {
.build();
// build backends
cc::Build::new()
.cpp(true)
.debug(cfg!(debug_assertions))
@ -58,12 +57,10 @@ fn main() {
.file("lib/util.cpp")
.file("lib/gm17.cpp")
.file("lib/pghr13.cpp")
.compile("libwraplibsnark.a");
.compile("libsnark-wrapper.a");
println!(
"cargo:rustc-link-search=native={}",
libsnark.join("lib").display()
);
println!("cargo:rustc-link-search={}", libsnark_wrapper_path.display());
println!("cargo:rustc-link-search=native={}", libsnark.join("lib").display());
println!("cargo:rustc-link-lib=gmp");
println!("cargo:rustc-link-lib=gmpxx");

View file

@ -7,8 +7,6 @@
#include "util.hpp"
#include "gm17.hpp"
#include <fstream>
#include <iostream>
#include <cassert>
#include <iomanip>
@ -22,104 +20,89 @@ typedef long integer_coeff_t;
using namespace std;
using namespace libsnark;
namespace gm17 {
//takes input and puts it into constraint system
r1cs_se_ppzksnark_constraint_system<libff::alt_bn128_pp> createConstraintSystem(const uint8_t* A, const uint8_t* B, const uint8_t* C, int A_len, int B_len, int C_len, int constraints, int variables, int inputs)
namespace gm17
{
r1cs_se_ppzksnark_constraint_system<libff::alt_bn128_pp> cs;
cs.primary_input_size = inputs;
cs.auxiliary_input_size = variables - inputs - 1; // ~one not included
cout << "num variables: " << variables <<endl;
cout << "num constraints: " << constraints <<endl;
cout << "num inputs: " << inputs <<endl;
struct VariableValueMapping {
int constraint_id;
int variable_id;
uint8_t variable_value[32];
};
const VariableValueMapping* A_vvmap = (VariableValueMapping*) A;
const VariableValueMapping* B_vvmap = (VariableValueMapping*) B;
const VariableValueMapping* C_vvmap = (VariableValueMapping*) C;
int A_id = 0;
int B_id = 0;
int C_id = 0;
libff::alt_bn128_pp::init_public_params();
for (int row = 0; row < constraints; row++) {
linear_combination<libff::Fr<libff::alt_bn128_pp> > lin_comb_A, lin_comb_B, lin_comb_C;
while (A_id < A_len && A_vvmap[A_id].constraint_id == row) {
libff::bigint<libff::alt_bn128_r_limbs> value = libsnarkBigintFromBytes(A_vvmap[A_id].variable_value);
if (!value.is_zero())
lin_comb_A.add_term(A_vvmap[A_id].variable_id, value);
A_id++;
}
while (B_id < B_len && B_vvmap[B_id].constraint_id == row) {
libff::bigint<libff::alt_bn128_r_limbs> value = libsnarkBigintFromBytes(B_vvmap[B_id].variable_value);
if (!value.is_zero())
lin_comb_B.add_term(B_vvmap[B_id].variable_id, value);
B_id++;
}
while (C_id < C_len && C_vvmap[C_id].constraint_id == row) {
libff::bigint<libff::alt_bn128_r_limbs> value = libsnarkBigintFromBytes(C_vvmap[C_id].variable_value);
if (!value.is_zero())
lin_comb_C.add_term(C_vvmap[C_id].variable_id, value);
C_id++;
}
cs.add_constraint(r1cs_constraint<libff::Fr<libff::alt_bn128_pp> >(lin_comb_A, lin_comb_B, lin_comb_C));
}
return cs;
}
// keypair generateKeypair(constraints)
r1cs_se_ppzksnark_keypair<libff::alt_bn128_pp> generateKeypair(const r1cs_se_ppzksnark_constraint_system<libff::alt_bn128_pp> &cs){
// from r1cs_se_ppzksnark.hpp
return r1cs_se_ppzksnark_generator<libff::alt_bn128_pp>(cs);
}
void serializeProvingKeyToFile(r1cs_se_ppzksnark_proving_key<libff::alt_bn128_pp> pk, const char* pk_path){
writeToFile(pk_path, pk);
}
r1cs_se_ppzksnark_proving_key<libff::alt_bn128_pp> deserializeProvingKeyFromFile(const char* pk_path){
return loadFromFile<r1cs_se_ppzksnark_proving_key<libff::alt_bn128_pp>>(pk_path);
}
void serializeVerificationKeyToFile(r1cs_se_ppzksnark_verification_key<libff::alt_bn128_pp> vk, const char* vk_path){
std::stringstream ss;
unsigned queryLength = vk.query.size();
ss << "\t\tvk.h = " << outputPointG2AffineAsHex(vk.H) << endl;
ss << "\t\tvk.g_alpha = " << outputPointG1AffineAsHex(vk.G_alpha) << endl;
ss << "\t\tvk.h_beta = " << outputPointG2AffineAsHex(vk.H_beta) << endl;
ss << "\t\tvk.g_gamma = " << outputPointG1AffineAsHex(vk.G_gamma) << endl;
ss << "\t\tvk.h_gamma = " << outputPointG2AffineAsHex(vk.H_gamma) << endl;
ss << "\t\tvk.query.len() = " << queryLength << endl;
for (size_t i = 0; i < queryLength; ++i)
//takes input and puts it into constraint system
r1cs_se_ppzksnark_constraint_system<libff::alt_bn128_pp> createConstraintSystem(const uint8_t* A, const uint8_t* B, const uint8_t* C, int A_len, int B_len, int C_len, int constraints, int variables, int inputs)
{
auto vkqueryi = outputPointG1AffineAsHex(vk.query[i]);
ss << "\t\tvk.query[" << i << "] = " << vkqueryi << endl;
r1cs_se_ppzksnark_constraint_system<libff::alt_bn128_pp> cs;
cs.primary_input_size = inputs;
cs.auxiliary_input_size = variables - inputs - 1; // ~one not included
cout << "num variables: " << variables <<endl;
cout << "num constraints: " << constraints <<endl;
cout << "num inputs: " << inputs <<endl;
struct VariableValueMapping {
int constraint_id;
int variable_id;
uint8_t variable_value[32];
};
const VariableValueMapping* A_vvmap = (VariableValueMapping*) A;
const VariableValueMapping* B_vvmap = (VariableValueMapping*) B;
const VariableValueMapping* C_vvmap = (VariableValueMapping*) C;
int A_id = 0;
int B_id = 0;
int C_id = 0;
libff::alt_bn128_pp::init_public_params();
for (int row = 0; row < constraints; row++) {
linear_combination<libff::Fr<libff::alt_bn128_pp> > lin_comb_A, lin_comb_B, lin_comb_C;
while (A_id < A_len && A_vvmap[A_id].constraint_id == row) {
libff::bigint<libff::alt_bn128_r_limbs> value = libsnarkBigintFromBytes(A_vvmap[A_id].variable_value);
if (!value.is_zero())
lin_comb_A.add_term(A_vvmap[A_id].variable_id, value);
A_id++;
}
while (B_id < B_len && B_vvmap[B_id].constraint_id == row) {
libff::bigint<libff::alt_bn128_r_limbs> value = libsnarkBigintFromBytes(B_vvmap[B_id].variable_value);
if (!value.is_zero())
lin_comb_B.add_term(B_vvmap[B_id].variable_id, value);
B_id++;
}
while (C_id < C_len && C_vvmap[C_id].constraint_id == row) {
libff::bigint<libff::alt_bn128_r_limbs> value = libsnarkBigintFromBytes(C_vvmap[C_id].variable_value);
if (!value.is_zero())
lin_comb_C.add_term(C_vvmap[C_id].variable_id, value);
C_id++;
}
cs.add_constraint(r1cs_constraint<libff::Fr<libff::alt_bn128_pp> >(lin_comb_A, lin_comb_B, lin_comb_C));
}
return cs;
}
std::ofstream fh;
fh.open(vk_path, std::ios::binary);
ss.rdbuf()->pubseekpos(0, std::ios_base::out);
fh << ss.rdbuf();
fh.flush();
fh.close();
}
// keypair generateKeypair(constraints)
r1cs_se_ppzksnark_keypair<libff::alt_bn128_pp> generateKeypair(const r1cs_se_ppzksnark_constraint_system<libff::alt_bn128_pp> &cs)
{
// from r1cs_se_ppzksnark.hpp
return r1cs_se_ppzksnark_generator<libff::alt_bn128_pp>(cs);
}
void exportProof(r1cs_se_ppzksnark_proof<libff::alt_bn128_pp> proof, const char* proof_path, const uint8_t* public_inputs,
int public_inputs_length){
//create JSON file
std::string serializeVerificationKey(r1cs_se_ppzksnark_verification_key<libff::alt_bn128_pp>* vk)
{
std::stringstream ss;
unsigned queryLength = vk->query.size();
ss << "\t\tvk.h = " << outputPointG2AffineAsHex(vk->H) << endl;
ss << "\t\tvk.g_alpha = " << outputPointG1AffineAsHex(vk->G_alpha) << endl;
ss << "\t\tvk.h_beta = " << outputPointG2AffineAsHex(vk->H_beta) << endl;
ss << "\t\tvk.g_gamma = " << outputPointG1AffineAsHex(vk->G_gamma) << endl;
ss << "\t\tvk.h_gamma = " << outputPointG2AffineAsHex(vk->H_gamma) << endl;
ss << "\t\tvk.query.len() = " << queryLength << endl;
for (size_t i = 0; i < queryLength; ++i)
{
auto vkqueryi = outputPointG1AffineAsHex(vk->query[i]);
ss << "\t\tvk.query[" << i << "] = " << vkqueryi << endl;
}
return ss.str();
}
std::string exportProof(r1cs_se_ppzksnark_proof<libff::alt_bn128_pp> proof, const uint8_t* public_inputs, int public_inputs_length)
{
std::stringstream ss;
ss << "{" << "\n";
ss << "\t\"proof\":" << "\n";
@ -140,15 +123,11 @@ void exportProof(r1cs_se_ppzksnark_proof<libff::alt_bn128_pp> proof, const char*
}
ss << "]" << "\n";
ss << "}" << "\n";
std::string s = ss.str();
//write json string to proof_path
writeToFile(proof_path, s);
return ss.str();
}
}
}
bool _gm17_setup(const uint8_t* A, const uint8_t* B, const uint8_t* C, int A_len, int B_len, int C_len, int constraints, int variables, int inputs, const char* pk_path, const char* vk_path)
void _gm17_setup(const uint8_t* A, const uint8_t* B, const uint8_t* C, int A_len, int B_len, int C_len, int constraints, int variables, int inputs, buffer_t* pk_buf, buffer_t* vk_buf)
{
libff::inhibit_profiling_info = true;
libff::inhibit_profiling_counters = true;
@ -165,21 +144,24 @@ bool _gm17_setup(const uint8_t* A, const uint8_t* B, const uint8_t* C, int A_len
// create keypair
auto keypair = r1cs_se_ppzksnark_generator<libff::alt_bn128_pp>(cs);
// Export vk and pk to files
gm17::serializeProvingKeyToFile(keypair.pk, pk_path);
gm17::serializeVerificationKeyToFile(keypair.vk, vk_path);
memcpy(pk_buf->data, &keypair.pk, sizeof(r1cs_se_ppzksnark_proving_key<libff::alt_bn128_pp>));
return true;
auto vk = gm17::serializeVerificationKey(&keypair.vk);
vk.copy((char*)vk_buf->data, vk_buf->size);
}
bool _gm17_generate_proof(const char* pk_path, const char* proof_path, const uint8_t* public_inputs, int public_inputs_length, const uint8_t* private_inputs, int private_inputs_length)
void _gm17_generate_proof(const buffer_t* pk_buf, const uint8_t* public_inputs, int public_inputs_length, const uint8_t* private_inputs, int private_inputs_length, buffer_t* proof_buf)
{
libff::inhibit_profiling_info = true;
libff::inhibit_profiling_counters = true;
//initialize curve parameters
libff::alt_bn128_pp::init_public_params();
auto pk = gm17::deserializeProvingKeyFromFile(pk_path);
r1cs_se_ppzksnark_proving_key<libff::alt_bn128_pp> pk;
memcpy(&pk, pk_buf->data, sizeof(pk));
// auto pk = reinterpret_cast<const r1cs_se_ppzksnark_proving_key<libff::alt_bn128_pp>&>(pk_buf->data);
// assign variables based on witness values, excludes ~one
r1cs_variable_assignment<libff::Fr<libff::alt_bn128_pp> > full_variable_assignment;
@ -202,9 +184,7 @@ bool _gm17_generate_proof(const char* pk_path, const char* proof_path, const uin
// Proof Generation
auto proof = r1cs_se_ppzksnark_prover<libff::alt_bn128_pp>(pk, primary_input, auxiliary_input);
auto result = gm17::exportProof(proof, public_inputs, public_inputs_length);
gm17::exportProof(proof, proof_path, public_inputs, public_inputs_length);
return true;
}
result.copy((char*)proof_buf->data, proof_buf->size);
}

View file

@ -14,26 +14,31 @@ extern "C" {
#include <stdbool.h>
#include <stdint.h>
bool _gm17_setup(const uint8_t* A,
const uint8_t* B,
const uint8_t* C,
int A_len,
int B_len,
int C_len,
int constraints,
int variables,
int inputs,
const char* pk_path,
const char* vk_path
);
struct buffer_t {
uint8_t* data;
size_t size;
};
bool _gm17_generate_proof(const char* pk_path,
const char* proof_path,
const uint8_t* public_inputs,
int public_inputs_length,
const uint8_t* private_inputs,
int private_inputs_length
);
void _gm17_setup(const uint8_t* A,
const uint8_t* B,
const uint8_t* C,
int A_len,
int B_len,
int C_len,
int constraints,
int variables,
int inputs,
buffer_t* pk_buf,
buffer_t* vk_buf
);
void _gm17_generate_proof(const buffer_t* pk_buf,
const uint8_t* public_inputs,
int public_inputs_length,
const uint8_t* private_inputs,
int private_inputs_length,
buffer_t* proof_buf
);
#ifdef __cplusplus
} // extern "C"

View file

@ -0,0 +1,35 @@
extern crate zokrates_core;
extern crate zokrates_field;
use zokrates_core::flat_absy::FlatVariable;
use zokrates_core::ir::*;
use zokrates_core::typed_absy::types::{Signature, Type};
use zokrates_field::field::FieldPrime;
use zokrates_core::proof_system::{self, ProofSystem};
fn main() {
let program: Prog<FieldPrime> = Prog {
main: Function {
id: String::from("main"),
arguments: vec![FlatVariable::new(0)],
returns: vec![FlatVariable::public(0)],
statements: vec![Statement::Constraint(
FlatVariable::new(0).into(),
FlatVariable::public(0).into(),
)],
},
private: vec![false],
signature: Signature::new()
.inputs(vec![Type::FieldElement])
.outputs(vec![Type::FieldElement]),
};
let result: (String, Vec<u8>) = proof_system::GM17{}.setup(program.clone());
let witness = program
.clone()
.execute(&vec![FieldPrime::from(42)])
.unwrap();
println!("\n{}", result.0.as_str());
println!("\n{:?}", result.1);
}

View file

@ -40,4 +40,4 @@ pub mod compile;
pub mod flat_absy;
pub mod ir;
pub mod proof_system;
pub mod typed_absy;
pub mod typed_absy;

View file

@ -0,0 +1,384 @@
extern crate libc;
use self::libc::{c_char, c_int, size_t};
use std::{mem};
use ir;
use proof_system::bn128::utils::libsnark::{prepare_generate_proof, prepare_setup};
use proof_system::bn128::utils::solidity::{
SOLIDITY_G2_ADDITION_LIB, SOLIDITY_PAIRING_LIB, SOLIDITY_PAIRING_LIB_V2,
};
use proof_system::ProofSystem;
use regex::Regex;
use zokrates_field::field::FieldPrime;
pub struct GM17 {}
impl GM17 {
pub fn new() -> GM17 {
GM17 {}
}
}
#[repr(C)]
struct Buffer {
data: *mut u8,
size: size_t
}
impl Buffer {
fn alloc(size: usize) -> Buffer {
unsafe {
let mut buf: Vec<u8> = Vec::with_capacity(size);
let ptr = buf.as_mut_ptr();
mem::forget(buf);
Buffer {
data: ptr,
size: size as size_t
}
}
}
fn from_vec(v: &Vec<u8>) -> Buffer {
Buffer {
data: v.as_ptr() as *mut u8,
size: v.len(),
}
}
fn from_raw_vec(v: &[u8]) -> Buffer {
Buffer {
data: v.as_ptr() as *mut u8,
size: v.len(),
}
}
fn into_vec(self) -> Vec<u8> {
unsafe {
Vec::from_raw_parts(self.data, self.size, self.size)
}
}
}
extern "C" {
fn _gm17_setup(
A: *const u8,
B: *const u8,
C: *const u8,
A_len: c_int,
B_len: c_int,
C_len: c_int,
constraints: c_int,
variables: c_int,
inputs: c_int,
pk_buf: *mut Buffer,
vk_buf: *mut Buffer,
);
fn _gm17_generate_proof(
pk_buf: *const Buffer,
publquery_inputs: *const u8,
publquery_inputs_length: c_int,
private_inputs: *const u8,
private_inputs_length: c_int,
proof_buf: *mut Buffer
);
}
impl ProofSystem for GM17 {
fn setup(&self, program: ir::Prog<FieldPrime>) -> (String, Vec<u8>) {
let (
a_arr,
b_arr,
c_arr,
a_vec,
b_vec,
c_vec,
num_constraints,
num_variables,
num_inputs
) = prepare_setup(program);
let mut pk_buffer = Buffer::alloc(2048);
let mut vk_buffer = Buffer::alloc(2048);
unsafe {
_gm17_setup(
a_arr.as_ptr(),
b_arr.as_ptr(),
c_arr.as_ptr(),
a_vec.len() as i32,
b_vec.len() as i32,
c_vec.len() as i32,
num_constraints as i32,
num_variables as i32,
num_inputs as i32,
&mut pk_buffer as *mut _,
&mut vk_buffer as *mut _
)
};
let vk = unsafe { String::from_raw_parts(vk_buffer.data, vk_buffer.size, vk_buffer.size) };
let pk = pk_buffer.into_vec();
(vk, pk)
}
fn generate_proof(
&self,
program: ir::Prog<FieldPrime>,
witness: ir::Witness<FieldPrime>,
proving_key: &[u8],
) -> String {
String::new()
// let (
// public_inputs_arr,
// public_inputs_length,
// private_inputs_arr,
// private_inputs_length,
// ) = prepare_generate_proof(program, witness);
// let pk_vec: Vec<u8> = Vec::from(proving_key);
// let pk_buf = Buffer::from_vec(&pk_vec);
// let mut proof_buf = Buffer::alloc(4096);
// unsafe {
// _gm17_generate_proof(
// &pk_buf as *const _,
// public_inputs_arr[0].as_ptr(),
// public_inputs_length as c_int,
// private_inputs_arr[0].as_ptr(),
// private_inputs_length as c_int,
// &mut proof_buf as *mut _
// );
// String::from_raw_parts(proof_buf.data, proof_buf.size, proof_buf.size)
// }
}
fn export_solidity_verifier(&self, vk: String, is_abiv2: bool) -> String {
let mut lines = vk.lines();
let (mut template_text, solidity_pairing_lib) = if is_abiv2 {
(
String::from(CONTRACT_TEMPLATE_V2),
String::from(SOLIDITY_PAIRING_LIB_V2),
)
} else {
(
String::from(CONTRACT_TEMPLATE),
String::from(SOLIDITY_PAIRING_LIB),
)
};
let query_template = String::from("vk.query[index] = Pairing.G1Point(points);"); //copy this for each entry
//replace things in template
let vk_regex = Regex::new(r#"(<%vk_[^i%]*%>)"#).unwrap();
let vk_query_len_regex = Regex::new(r#"(<%vk_query_length%>)"#).unwrap();
let vk_query_index_regex = Regex::new(r#"index"#).unwrap();
let vk_query_points_regex = Regex::new(r#"points"#).unwrap();
let vk_query_repeat_regex = Regex::new(r#"(<%vk_query_pts%>)"#).unwrap();
let vk_input_len_regex = Regex::new(r#"(<%vk_input_length%>)"#).unwrap();
for _ in 0..5 {
let current_line: &str = lines
.next()
.expect("Unexpected end of file in verification key!");
let current_line_split: Vec<&str> = current_line.split("=").collect();
assert_eq!(current_line_split.len(), 2);
template_text = vk_regex
.replace(template_text.as_str(), current_line_split[1].trim())
.into_owned();
}
let current_line: &str = lines
.next()
.expect("Unexpected end of file in verification key!");
let current_line_split: Vec<&str> = current_line.split("=").collect();
assert_eq!(current_line_split.len(), 2);
let query_count: i32 = current_line_split[1].trim().parse().unwrap();
template_text = vk_query_len_regex
.replace(
template_text.as_str(),
format!("{}", query_count).as_str()
)
.into_owned();
template_text = vk_input_len_regex
.replace(
template_text.as_str(),
format!("{}", query_count - 1).as_str(),
)
.into_owned();
let mut query_repeat_text = String::new();
for x in 0..query_count {
let mut curr_template = query_template.clone();
let current_line: &str = lines
.next()
.expect("Unexpected end of file in verification key!");
let current_line_split: Vec<&str> = current_line.split("=").collect();
assert_eq!(current_line_split.len(), 2);
curr_template = vk_query_index_regex
.replace(curr_template.as_str(), format!("{}", x).as_str())
.into_owned();
curr_template = vk_query_points_regex
.replace(curr_template.as_str(), current_line_split[1].trim())
.into_owned();
query_repeat_text.push_str(curr_template.as_str());
if x < query_count - 1 {
query_repeat_text.push_str("\n ");
}
}
template_text = vk_query_repeat_regex
.replace(template_text.as_str(), query_repeat_text.as_str())
.into_owned();
let re = Regex::new(r"(?P<v>0[xX][0-9a-fA-F]{64})").unwrap();
template_text = re.replace_all(&template_text, "uint256($v)").to_string();
format!(
"{}{}{}",
SOLIDITY_G2_ADDITION_LIB, solidity_pairing_lib, template_text
)
}
}
const CONTRACT_TEMPLATE_V2: &str = r#"
contract Verifier {
using Pairing for *;
struct VerifyingKey {
Pairing.G2Point h;
Pairing.G1Point g_alpha;
Pairing.G2Point h_beta;
Pairing.G1Point g_gamma;
Pairing.G2Point h_gamma;
Pairing.G1Point[] query;
}
struct Proof {
Pairing.G1Point a;
Pairing.G2Point b;
Pairing.G1Point c;
}
function verifyingKey() pure internal returns (VerifyingKey memory vk) {
vk.h= Pairing.G2Point(<%vk_h%>);
vk.g_alpha = Pairing.G1Point(<%vk_g_alpha%>);
vk.h_beta = Pairing.G2Point(<%vk_h_beta%>);
vk.g_gamma = Pairing.G1Point(<%vk_g_gamma%>);
vk.h_gamma = Pairing.G2Point(<%vk_h_gamma%>);
vk.query = new Pairing.G1Point[](<%vk_query_length%>);
<%vk_query_pts%>
}
function verify(uint[] memory input, Proof memory proof) internal returns (uint) {
uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
VerifyingKey memory vk = verifyingKey();
require(input.length + 1 == vk.query.length);
// Compute the linear combination vk_x
Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0);
for (uint i = 0; i < input.length; i++) {
require(input[i] < snark_scalar_field);
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.query[i + 1], input[i]));
}
vk_x = Pairing.addition(vk_x, vk.query[0]);
/**
* e(A*G^{alpha}, B*H^{beta}) = e(G^{alpha}, H^{beta}) * e(G^{psi}, H^{gamma})
* * e(C, H)
* where psi = \sum_{i=0}^l input_i pvk.query[i]
*/
if (!Pairing.pairingProd4(vk.g_alpha, vk.h_beta, vk_x, vk.h_gamma, proof.c, vk.h, Pairing.negate(Pairing.addition(proof.a, vk.g_alpha)), Pairing.addition(proof.b, vk.h_beta))) return 1;
/**
* e(A, H^{gamma}) = e(G^{gamma}, B)
*/
if (!Pairing.pairingProd2(proof.a, vk.h_gamma, Pairing.negate(vk.g_gamma), proof.b)) return 2;
return 0;
}
event Verified(string s);
function verifyTx(
Proof memory proof,
uint[<%vk_input_length%>] memory input
) public returns (bool r) {
uint[] memory inputValues = new uint[](input.length);
for(uint i = 0; i < input.length; i++){
inputValues[i] = input[i];
}
if (verify(inputValues, proof) == 0) {
emit Verified("Transaction successfully verified.");
return true;
} else {
return false;
}
}
}
"#;
const CONTRACT_TEMPLATE: &str = r#"
contract Verifier {
using Pairing for *;
struct VerifyingKey {
Pairing.G2Point h;
Pairing.G1Point g_alpha;
Pairing.G2Point h_beta;
Pairing.G1Point g_gamma;
Pairing.G2Point h_gamma;
Pairing.G1Point[] query;
}
struct Proof {
Pairing.G1Point a;
Pairing.G2Point b;
Pairing.G1Point c;
}
function verifyingKey() pure internal returns (VerifyingKey memory vk) {
vk.h = Pairing.G2Point(<%vk_h%>);
vk.g_alpha = Pairing.G1Point(<%vk_g_alpha%>);
vk.h_beta = Pairing.G2Point(<%vk_h_beta%>);
vk.g_gamma = Pairing.G1Point(<%vk_g_gamma%>);
vk.h_gamma = Pairing.G2Point(<%vk_h_gamma%>);
vk.query = new Pairing.G1Point[](<%vk_query_length%>);
<%vk_query_pts%>
}
function verify(uint[] memory input, Proof memory proof) internal returns (uint) {
uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
VerifyingKey memory vk = verifyingKey();
require(input.length + 1 == vk.query.length);
// Compute the linear combination vk_x
Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0);
for (uint i = 0; i < input.length; i++) {
require(input[i] < snark_scalar_field);
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.query[i + 1], input[i]));
}
vk_x = Pairing.addition(vk_x, vk.query[0]);
/**
* e(A*G^{alpha}, B*H^{beta}) = e(G^{alpha}, H^{beta}) * e(G^{psi}, H^{gamma})
* * e(C, H)
* where psi = \sum_{i=0}^l input_i pvk.query[i]
*/
if (!Pairing.pairingProd4(vk.g_alpha, vk.h_beta, vk_x, vk.h_gamma, proof.c, vk.h, Pairing.negate(Pairing.addition(proof.a, vk.g_alpha)), Pairing.addition(proof.b, vk.h_beta))) return 1;
/**
* e(A, H^{gamma}) = e(G^{gamma}, b)
*/
if (!Pairing.pairingProd2(proof.a, vk.h_gamma, Pairing.negate(vk.g_gamma), proof.b)) return 2;
return 0;
}
event Verified(string s);
function verifyTx(
uint[2] memory a,
uint[2][2] memory b,
uint[2] memory c,
uint[<%vk_input_length%>] memory input
) public returns (bool r) {
Proof memory proof;
proof.a = Pairing.G1Point(a[0], a[1]);
proof.b = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
proof.c = Pairing.G1Point(c[0], c[1]);
uint[] memory inputValues = new uint[](input.length);
for(uint i = 0; i < input.length; i++){
inputValues[i] = input[i];
}
if (verify(inputValues, proof) == 0) {
emit Verified("Transaction successfully verified.");
return true;
} else {
return false;
}
}
}
"#;

View file

@ -1,4 +1,8 @@
mod g16;
#[cfg(feature = "libsnark")]
mod gm17;
mod utils;
pub use self::g16::G16;
#[cfg(feature = "libsnark")]
pub use self::gm17::GM17;

View file

@ -17,9 +17,7 @@ fn vec_as_u8_32_array(vec: &Vec<u8>) -> [u8; 32] {
// proof-system-independent preparation for the setup phase
pub fn prepare_setup<T: Field>(
program: ir::Prog<T>,
pk_path: &str,
vk_path: &str,
program: ir::Prog<T>
) -> (
Vec<u8>,
Vec<u8>,
@ -29,9 +27,7 @@ pub fn prepare_setup<T: Field>(
Vec<(i32, i32, [u8; 32])>,
usize,
usize,
usize,
CString,
CString,
usize
) {
// transform to R1CS
let (variables, public_variables_count, a, b, c) = r1cs_program(program);
@ -129,10 +125,6 @@ pub fn prepare_setup<T: Field>(
}
}
// convert String slices to 'CString's
let pk_path_cstring = CString::new(pk_path).unwrap();
let vk_path_cstring = CString::new(vk_path).unwrap();
(
a_arr,
b_arr,
@ -142,9 +134,7 @@ pub fn prepare_setup<T: Field>(
c_vec,
num_constraints,
num_variables,
num_inputs,
pk_path_cstring,
vk_path_cstring,
num_inputs
)
}
@ -152,9 +142,7 @@ pub fn prepare_setup<T: Field>(
pub fn prepare_generate_proof<T: Field>(
program: ir::Prog<T>,
witness: ir::Witness<T>,
pk_path: &str,
proof_path: &str,
) -> (CString, CString, Vec<[u8; 32]>, usize, Vec<[u8; 32]>, usize) {
) -> (Vec<[u8; 32]>, usize, Vec<[u8; 32]>, usize) {
// recover variable order from the program
let (variables, public_variables_count, _, _, _) = r1cs_program(program);
@ -164,9 +152,6 @@ pub fn prepare_generate_proof<T: Field>(
let mut public_inputs: Vec<_> = witness.clone();
let private_inputs: Vec<_> = public_inputs.split_off(public_variables_count);
let pk_path_cstring = CString::new(pk_path).unwrap();
let proof_path_cstring = CString::new(proof_path).unwrap();
let public_inputs_length = public_inputs.len();
let private_inputs_length = private_inputs.len();
@ -183,12 +168,10 @@ pub fn prepare_generate_proof<T: Field>(
}
(
pk_path_cstring,
proof_path_cstring,
public_inputs_arr,
public_inputs_length,
private_inputs_arr,
private_inputs_length,
private_inputs_length
)
}

View file

@ -3,6 +3,8 @@ mod bn128;
use zokrates_field::field::FieldPrime;
pub use self::bn128::G16;
#[cfg(feature = "libsnark")]
pub use self::bn128::GM17;
use crate::ir;