wip
This commit is contained in:
parent
3993732a1f
commit
e7c1a0e6d7
10 changed files with 555 additions and 165 deletions
|
@ -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 }
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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"
|
||||
|
|
35
zokrates_core/src/bin/bin.rs
Normal file
35
zokrates_core/src/bin/bin.rs
Normal 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);
|
||||
}
|
|
@ -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;
|
384
zokrates_core/src/proof_system/bn128/gm17.rs
Normal file
384
zokrates_core/src/proof_system/bn128/gm17.rs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
"#;
|
|
@ -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;
|
|
@ -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
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in a new issue