Added r1cs ppzksnark proving scheme and some tests.

This commit is contained in:
Sean Bowe 2015-12-25 05:52:14 -07:00
parent a66c21fe11
commit fc1bdf2148
5 changed files with 317 additions and 31 deletions

@ -8,6 +8,9 @@ name = "bellman"
repository = "https://github.com/ebfull/bellman"
version = "0.0.1"
[dependencies]
rand = "0.3.12"
[dependencies.tinysnark]
path = "tinysnark"
version = "0.0.1"

@ -1,7 +1,16 @@
extern crate tinysnark;
extern crate rand;
use tinysnark::{Proof, Keypair, FieldT, LinearTerm, ConstraintSystem};
fn main() {
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)]
#![allow(improper_ctypes)]
//#![cfg_attr(test, feature(test))]
extern crate libc;
mod arith;
mod r1cs;
pub use self::arith::*;
pub use self::r1cs::*;
use std::sync::{Once, ONCE_INIT};
@ -13,7 +16,6 @@ static mut INITIALIZED: bool = false;
extern "C" {
fn tinysnark_init_public_params();
fn tinysnark_test();
}
pub fn init() {
@ -27,16 +29,48 @@ pub fn is_initialized() -> bool {
unsafe { INITIALIZED }
}
pub fn test() {
unsafe { tinysnark_test(); }
}
#[cfg(test)]
mod tests {
//extern crate test;
use super::{init, FieldT};
use super::{init, FieldT, Proof, Keypair, LinearTerm, ConstraintSystem};
//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]
fn test_one() {
init();

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;
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) {
return a * b;
}
@ -52,27 +172,3 @@ extern "C" void tinysnark_init_public_params() {
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));
}