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"
|
||||
version = "0.0.1"
|
||||
|
||||
[dependencies]
|
||||
rand = "0.3.12"
|
||||
|
||||
[dependencies.tinysnark]
|
||||
path = "tinysnark"
|
||||
version = "0.0.1"
|
||||
|
11
src/main.rs
11
src/main.rs
@ -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
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));
|
||||
}
|
Loading…
Reference in New Issue
Block a user