Added r1cs ppzksnark proving scheme and some tests.
This commit is contained in:
parent
a66c21fe11
commit
fc1bdf2148
@ -8,6 +8,9 @@ name = "bellman"
|
|||||||
repository = "https://github.com/ebfull/bellman"
|
repository = "https://github.com/ebfull/bellman"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
rand = "0.3.12"
|
||||||
|
|
||||||
[dependencies.tinysnark]
|
[dependencies.tinysnark]
|
||||||
path = "tinysnark"
|
path = "tinysnark"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
|
11
src/main.rs
11
src/main.rs
@ -1,7 +1,16 @@
|
|||||||
extern crate tinysnark;
|
extern crate tinysnark;
|
||||||
|
extern crate rand;
|
||||||
|
|
||||||
|
use tinysnark::{Proof, Keypair, FieldT, LinearTerm, ConstraintSystem};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
tinysnark::init();
|
tinysnark::init();
|
||||||
|
|
||||||
tinysnark::test();
|
let mut cs = ConstraintSystem::new(1, 2);
|
||||||
|
cs.add_constraint(
|
||||||
|
&[LinearTerm{coeff: FieldT::one(), index: 2}],
|
||||||
|
&[LinearTerm{coeff: FieldT::one(), index: 3}],
|
||||||
|
&[LinearTerm{coeff: FieldT::one(), index: 1}]
|
||||||
|
);
|
||||||
|
assert!(cs.test(&[100.into()], &[10.into(), 10.into()]));
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
#![feature(box_syntax)]
|
#![feature(box_syntax)]
|
||||||
|
#![allow(improper_ctypes)]
|
||||||
//#![cfg_attr(test, feature(test))]
|
//#![cfg_attr(test, feature(test))]
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
|
||||||
mod arith;
|
mod arith;
|
||||||
|
mod r1cs;
|
||||||
|
|
||||||
pub use self::arith::*;
|
pub use self::arith::*;
|
||||||
|
pub use self::r1cs::*;
|
||||||
|
|
||||||
use std::sync::{Once, ONCE_INIT};
|
use std::sync::{Once, ONCE_INIT};
|
||||||
|
|
||||||
@ -13,7 +16,6 @@ static mut INITIALIZED: bool = false;
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn tinysnark_init_public_params();
|
fn tinysnark_init_public_params();
|
||||||
fn tinysnark_test();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
@ -27,16 +29,48 @@ pub fn is_initialized() -> bool {
|
|||||||
unsafe { INITIALIZED }
|
unsafe { INITIALIZED }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn test() {
|
|
||||||
unsafe { tinysnark_test(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
//extern crate test;
|
//extern crate test;
|
||||||
use super::{init, FieldT};
|
use super::{init, FieldT, Proof, Keypair, LinearTerm, ConstraintSystem};
|
||||||
//use self::test::Bencher;
|
//use self::test::Bencher;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_zk() {
|
||||||
|
init();
|
||||||
|
{
|
||||||
|
let mut cs = ConstraintSystem::new(1, 2);
|
||||||
|
// zkpok { (a, b) c = a * b }
|
||||||
|
cs.add_constraint(
|
||||||
|
&[LinearTerm{coeff: FieldT::one(), index: 2}],
|
||||||
|
&[LinearTerm{coeff: FieldT::one(), index: 3}],
|
||||||
|
&[LinearTerm{coeff: FieldT::one(), index: 1}]
|
||||||
|
);
|
||||||
|
assert!(cs.test(&[10.into()], &[5.into(), 2.into()]));
|
||||||
|
assert!(!cs.test(&[10.into()], &[6.into(), 2.into()]));
|
||||||
|
|
||||||
|
let kp = Keypair::new(&cs);
|
||||||
|
let proof = Proof::new(&kp, &cs, &[10.into()], &[5.into(), 2.into()]);
|
||||||
|
assert!(proof.verify(&kp, &cs, &[10.into()]));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let mut cs = ConstraintSystem::new(0, 1);
|
||||||
|
// simple boolean constraint
|
||||||
|
cs.add_constraint(
|
||||||
|
&[LinearTerm{coeff: FieldT::one(), index: 0}, LinearTerm{coeff: -FieldT::one(), index: 1}],
|
||||||
|
&[LinearTerm{coeff: FieldT::one(), index: 1}],
|
||||||
|
&[LinearTerm{coeff: FieldT::zero(), index: 0}]
|
||||||
|
);
|
||||||
|
assert!(cs.test(&[], &[1.into()]));
|
||||||
|
assert!(cs.test(&[], &[0.into()]));
|
||||||
|
assert!(!cs.test(&[], &[2.into()]));
|
||||||
|
|
||||||
|
let kp = Keypair::new(&cs);
|
||||||
|
let proof = Proof::new(&kp, &cs, &[], &[1.into()]);
|
||||||
|
assert!(proof.verify(&kp, &cs, &[]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_one() {
|
fn test_one() {
|
||||||
init();
|
init();
|
||||||
|
144
tinysnark/src/r1cs.rs
Normal file
144
tinysnark/src/r1cs.rs
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
use libc::{size_t};
|
||||||
|
use super::arith::FieldT;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
struct R1ConstraintSystem;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct LinearTerm {
|
||||||
|
pub coeff: FieldT,
|
||||||
|
pub index: size_t
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
fn tinysnark_new_r1cs(primary: size_t, aux: size_t) -> *mut R1ConstraintSystem;
|
||||||
|
fn tinysnark_drop_r1cs(cs: *mut R1ConstraintSystem);
|
||||||
|
fn tinysnark_satisfy_test(cs: *mut R1ConstraintSystem, primary: *const FieldT, aux: *const FieldT) -> bool;
|
||||||
|
fn tinysnark_add_constraint(cs: *mut R1ConstraintSystem,
|
||||||
|
a: *const LinearTerm,
|
||||||
|
a_len: size_t,
|
||||||
|
b: *const LinearTerm,
|
||||||
|
b_len: size_t,
|
||||||
|
c: *const LinearTerm,
|
||||||
|
c_len: size_t
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ConstraintSystem {
|
||||||
|
cs: *mut R1ConstraintSystem,
|
||||||
|
primary_size: usize,
|
||||||
|
aux_size: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for ConstraintSystem {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe { tinysnark_drop_r1cs(self.cs) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConstraintSystem {
|
||||||
|
pub fn new(primary_size: usize, aux_size: usize) -> ConstraintSystem {
|
||||||
|
ConstraintSystem {
|
||||||
|
cs: unsafe { tinysnark_new_r1cs(primary_size, aux_size) },
|
||||||
|
primary_size: primary_size,
|
||||||
|
aux_size: aux_size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_constraint(&mut self, a: &[LinearTerm], b: &[LinearTerm], c: &[LinearTerm])
|
||||||
|
{
|
||||||
|
unsafe {
|
||||||
|
tinysnark_add_constraint(
|
||||||
|
self.cs,
|
||||||
|
a.get_unchecked(0),
|
||||||
|
a.len(),
|
||||||
|
b.get_unchecked(0),
|
||||||
|
b.len(),
|
||||||
|
c.get_unchecked(0),
|
||||||
|
c.len()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn test(&mut self, primary: &[FieldT], aux: &[FieldT]) -> bool
|
||||||
|
{
|
||||||
|
assert_eq!(primary.len(), self.primary_size);
|
||||||
|
assert_eq!(aux.len(), self.aux_size);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
tinysnark_satisfy_test(self.cs, primary.get_unchecked(0), aux.get_unchecked(0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
struct R1CSKeypair;
|
||||||
|
|
||||||
|
pub struct Keypair {
|
||||||
|
kp: *mut R1CSKeypair
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Keypair {
|
||||||
|
pub fn new(constraint_system: &ConstraintSystem) -> Keypair {
|
||||||
|
Keypair {
|
||||||
|
kp: unsafe { tinysnark_gen_keypair(constraint_system.cs) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Keypair {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe { tinysnark_drop_keypair(self.kp) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
fn tinysnark_gen_keypair(cs: *mut R1ConstraintSystem) -> *mut R1CSKeypair;
|
||||||
|
fn tinysnark_drop_keypair(cs: *mut R1CSKeypair);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
struct R1CSProof;
|
||||||
|
|
||||||
|
pub struct Proof {
|
||||||
|
proof: *mut R1CSProof
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Proof {
|
||||||
|
pub fn new(keypair: &Keypair, constraint_system: &ConstraintSystem, primary: &[FieldT], aux: &[FieldT])
|
||||||
|
-> Proof
|
||||||
|
{
|
||||||
|
assert_eq!(primary.len(), constraint_system.primary_size);
|
||||||
|
assert_eq!(aux.len(), constraint_system.aux_size);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
Proof {
|
||||||
|
proof: tinysnark_gen_proof(keypair.kp, constraint_system.cs, primary.get_unchecked(0), aux.get_unchecked(0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verify(&self, keypair: &Keypair, constraint_system: &ConstraintSystem, primary: &[FieldT]) -> bool {
|
||||||
|
unsafe {
|
||||||
|
tinysnark_verify_proof(self.proof, keypair.kp, constraint_system.cs, primary.get_unchecked(0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Proof {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe { tinysnark_drop_proof(self.proof) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
fn tinysnark_gen_proof(keypair: *mut R1CSKeypair,
|
||||||
|
cs: *mut R1ConstraintSystem,
|
||||||
|
primary: *const FieldT,
|
||||||
|
aux: *const FieldT) -> *mut R1CSProof;
|
||||||
|
fn tinysnark_verify_proof(proof: *mut R1CSProof,
|
||||||
|
keypair: *mut R1CSKeypair,
|
||||||
|
cs: *mut R1ConstraintSystem,
|
||||||
|
primary: *const FieldT) -> bool;
|
||||||
|
fn tinysnark_drop_proof(proof: *mut R1CSProof);
|
||||||
|
}
|
@ -13,6 +13,126 @@ using namespace std;
|
|||||||
|
|
||||||
typedef Fr<default_r1cs_ppzksnark_pp> FieldT;
|
typedef Fr<default_r1cs_ppzksnark_pp> FieldT;
|
||||||
|
|
||||||
|
struct tinysnark_linear_term {
|
||||||
|
FieldT coeff;
|
||||||
|
size_t index;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern "C" void * tinysnark_gen_proof(void * kp, void * ics, FieldT* primary, FieldT* aux) {
|
||||||
|
r1cs_constraint_system<FieldT>* cs = static_cast<r1cs_constraint_system<FieldT>*>(ics);
|
||||||
|
r1cs_ppzksnark_keypair<default_r1cs_ppzksnark_pp>* keypair = static_cast<r1cs_ppzksnark_keypair<default_r1cs_ppzksnark_pp>*>(kp);
|
||||||
|
|
||||||
|
r1cs_primary_input<FieldT> primary_input(primary, primary+(cs->primary_input_size));
|
||||||
|
r1cs_auxiliary_input<FieldT> aux_input(aux, aux+(cs->auxiliary_input_size));
|
||||||
|
|
||||||
|
auto proof = new r1cs_ppzksnark_proof<default_r1cs_ppzksnark_pp>(
|
||||||
|
r1cs_ppzksnark_prover<default_r1cs_ppzksnark_pp>(keypair->pk, primary_input, aux_input)
|
||||||
|
);
|
||||||
|
|
||||||
|
return static_cast<void*>(std::move(proof));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" bool tinysnark_verify_proof(void * iproof, void * kp, void * ics, FieldT* primary) {
|
||||||
|
r1cs_ppzksnark_proof<default_r1cs_ppzksnark_pp>* proof = static_cast<r1cs_ppzksnark_proof<default_r1cs_ppzksnark_pp>*>(iproof);
|
||||||
|
r1cs_constraint_system<FieldT>* cs = static_cast<r1cs_constraint_system<FieldT>*>(ics);
|
||||||
|
r1cs_ppzksnark_keypair<default_r1cs_ppzksnark_pp>* keypair = static_cast<r1cs_ppzksnark_keypair<default_r1cs_ppzksnark_pp>*>(kp);
|
||||||
|
|
||||||
|
r1cs_primary_input<FieldT> primary_input(primary, primary+(cs->primary_input_size));
|
||||||
|
|
||||||
|
return r1cs_ppzksnark_verifier_strong_IC<default_r1cs_ppzksnark_pp>(keypair->vk, primary_input, *proof);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void * tinysnark_drop_proof(void * proof) {
|
||||||
|
r1cs_ppzksnark_proof<default_r1cs_ppzksnark_pp>* p = static_cast<r1cs_ppzksnark_proof<default_r1cs_ppzksnark_pp>*>(proof);
|
||||||
|
|
||||||
|
delete p;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void * tinysnark_gen_keypair(void * ics) {
|
||||||
|
r1cs_constraint_system<FieldT>* cs = static_cast<r1cs_constraint_system<FieldT>*>(ics);
|
||||||
|
|
||||||
|
auto keypair = new r1cs_ppzksnark_keypair<default_r1cs_ppzksnark_pp>(
|
||||||
|
r1cs_ppzksnark_generator<default_r1cs_ppzksnark_pp>(*cs)
|
||||||
|
);
|
||||||
|
|
||||||
|
return static_cast<void*>(std::move(keypair));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void * tinysnark_drop_keypair(void * kp) {
|
||||||
|
r1cs_ppzksnark_keypair<default_r1cs_ppzksnark_pp>* k = static_cast<r1cs_ppzksnark_keypair<default_r1cs_ppzksnark_pp>*>(kp);
|
||||||
|
|
||||||
|
delete k;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void * tinysnark_new_r1cs(size_t primary_size, size_t aux_size) {
|
||||||
|
auto cs = new r1cs_constraint_system<FieldT>();
|
||||||
|
|
||||||
|
cs->primary_input_size = primary_size;
|
||||||
|
cs->auxiliary_input_size = aux_size;
|
||||||
|
|
||||||
|
return static_cast<void*>(std::move(cs));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void tinysnark_drop_r1cs(void * ics) {
|
||||||
|
r1cs_constraint_system<FieldT>* cs = static_cast<r1cs_constraint_system<FieldT>*>(ics);
|
||||||
|
|
||||||
|
delete cs;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" bool tinysnark_satisfy_test(void * ics, FieldT* primary, FieldT* aux) {
|
||||||
|
r1cs_constraint_system<FieldT>* cs = static_cast<r1cs_constraint_system<FieldT>*>(ics);
|
||||||
|
|
||||||
|
r1cs_primary_input<FieldT> primary_input(primary, primary+(cs->primary_input_size));
|
||||||
|
r1cs_auxiliary_input<FieldT> aux_input(aux, aux+(cs->auxiliary_input_size));
|
||||||
|
|
||||||
|
return cs->is_valid() && cs->is_satisfied(primary_input, aux_input);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void * tinysnark_add_constraint(
|
||||||
|
void * ics,
|
||||||
|
tinysnark_linear_term * a_terms,
|
||||||
|
size_t a_terms_len,
|
||||||
|
tinysnark_linear_term * b_terms,
|
||||||
|
size_t b_terms_len,
|
||||||
|
tinysnark_linear_term * c_terms,
|
||||||
|
size_t c_terms_len
|
||||||
|
) {
|
||||||
|
r1cs_constraint_system<FieldT>* cs = static_cast<r1cs_constraint_system<FieldT>*>(ics);
|
||||||
|
|
||||||
|
std::vector<linear_term<FieldT>> a;
|
||||||
|
std::vector<linear_term<FieldT>> b;
|
||||||
|
std::vector<linear_term<FieldT>> c;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < a_terms_len; i++) {
|
||||||
|
FieldT coeff = a_terms[i].coeff;
|
||||||
|
size_t index = a_terms[i].index;
|
||||||
|
|
||||||
|
a.push_back(linear_term<FieldT>(variable<FieldT>(index), coeff));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < b_terms_len; i++) {
|
||||||
|
FieldT coeff = b_terms[i].coeff;
|
||||||
|
size_t index = b_terms[i].index;
|
||||||
|
|
||||||
|
b.push_back(linear_term<FieldT>(variable<FieldT>(index), coeff));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < c_terms_len; i++) {
|
||||||
|
FieldT coeff = c_terms[i].coeff;
|
||||||
|
size_t index = c_terms[i].index;
|
||||||
|
|
||||||
|
c.push_back(linear_term<FieldT>(variable<FieldT>(index), coeff));
|
||||||
|
}
|
||||||
|
|
||||||
|
linear_combination<FieldT> a_lc(a);
|
||||||
|
linear_combination<FieldT> b_lc(b);
|
||||||
|
linear_combination<FieldT> c_lc(c);
|
||||||
|
|
||||||
|
r1cs_constraint<FieldT> constraint(a_lc, b_lc, c_lc);
|
||||||
|
|
||||||
|
cs->add_constraint(constraint);
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" FieldT tinysnark_fieldt_mul(FieldT a, FieldT b) {
|
extern "C" FieldT tinysnark_fieldt_mul(FieldT a, FieldT b) {
|
||||||
return a * b;
|
return a * b;
|
||||||
}
|
}
|
||||||
@ -52,27 +172,3 @@ extern "C" void tinysnark_init_public_params() {
|
|||||||
assert(sizeof(p) == 32);
|
assert(sizeof(p) == 32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void tinysnark_test() {
|
|
||||||
protoboard<FieldT> pb;
|
|
||||||
|
|
||||||
linear_combination<FieldT> sum;
|
|
||||||
|
|
||||||
sum = sum + 1;
|
|
||||||
|
|
||||||
pb.add_r1cs_constraint(r1cs_constraint<FieldT>(1, sum, 1), "testing");
|
|
||||||
|
|
||||||
assert(pb.is_satisfied());
|
|
||||||
|
|
||||||
const r1cs_constraint_system<FieldT> constraint_system = pb.get_constraint_system();
|
|
||||||
|
|
||||||
cout << "Number of R1CS constraints: " << constraint_system.num_constraints() << endl;
|
|
||||||
|
|
||||||
auto keypair = r1cs_ppzksnark_generator<default_r1cs_ppzksnark_pp>(constraint_system);
|
|
||||||
|
|
||||||
auto proof = r1cs_ppzksnark_prover<default_r1cs_ppzksnark_pp>(keypair.pk, pb.primary_input(), pb.auxiliary_input());
|
|
||||||
|
|
||||||
r1cs_primary_input<FieldT> input;
|
|
||||||
|
|
||||||
assert(r1cs_ppzksnark_verifier_strong_IC<default_r1cs_ppzksnark_pp>(keypair.vk, input, proof));
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user