Implementation cleanup and reorganization.

This commit is contained in:
Sean Bowe 2016-08-08 22:54:30 -06:00
parent 15d017ab56
commit 5e838fe2b4
No known key found for this signature in database
GPG Key ID: 95684257D8F8B031
9 changed files with 125 additions and 302 deletions

View File

@ -26,18 +26,18 @@ extern "C" {
lc2: *const G2,
d: libc::uint64_t,
vars: libc::uint64_t,
At: *mut G1,
Bt1: *mut G1,
Bt2: *mut G2,
Ct: *mut G1);
at: *mut G1,
bt1: *mut G1,
bt2: *mut G2,
ct: *mut G1);
fn libsnarkwrap_test_eval(
cs: *const libc::c_void,
tau: *const Fr,
vars: libc::uint64_t,
At: *const G1,
Bt1: *const G1,
Bt2: *const G2,
Ct: *const G1) -> bool;
at: *const G1,
bt1: *const G1,
bt2: *const G2,
ct: *const G1) -> bool;
fn libsnarkwrap_test_compare_tau(
i1: *const G1,
i2: *const G2,
@ -68,44 +68,49 @@ pub struct CS {
}
impl CS {
pub fn test_eval(&self, tau: &Fr, At: &[G1], Bt1: &[G1], Bt2: &[G2], Ct: &[G1]) -> bool {
assert_eq!(At.len(), Bt1.len());
assert_eq!(Bt1.len(), Bt2.len());
assert_eq!(Bt2.len(), Ct.len());
pub fn test_compare_tau(&self, v1: &[G1], v2: &[G2], tau: &Fr) -> bool {
assert_eq!(v1.len(), v2.len());
unsafe { libsnarkwrap_test_compare_tau(&v1[0], &v2[0], tau, v1.len() as u64, self.ptr) }
}
pub fn test_eval(&self, tau: &Fr, at: &[G1], bt1: &[G1], bt2: &[G2], ct: &[G1]) -> bool {
assert_eq!(at.len(), bt1.len());
assert_eq!(bt1.len(), bt2.len());
assert_eq!(bt2.len(), ct.len());
unsafe {
libsnarkwrap_test_eval(self.ptr,
tau,
At.len() as u64,
&At[0],
&Bt1[0],
&Bt2[0],
&Ct[0])
at.len() as u64,
&at[0],
&bt1[0],
&bt2[0],
&ct[0])
}
}
pub fn eval(&self,
Lt1: &[G1],
Lt2: &[G2],
At: &mut [G1],
Bt1: &mut [G1],
Bt2: &mut [G2],
Ct: &mut [G1]) {
assert_eq!(Lt1.len(), Lt2.len());
assert_eq!(At.len(), Bt1.len());
assert_eq!(Bt1.len(), Bt2.len());
assert_eq!(Bt2.len(), Ct.len());
lt1: &[G1],
lt2: &[G2],
at: &mut [G1],
bt1: &mut [G1],
bt2: &mut [G2],
ct: &mut [G1]) {
assert_eq!(lt1.len(), lt2.len());
assert_eq!(at.len(), bt1.len());
assert_eq!(bt1.len(), bt2.len());
assert_eq!(bt2.len(), ct.len());
unsafe {
libsnarkwrap_eval(self.ptr,
&Lt1[0],
&Lt2[0],
Lt1.len() as u64,
At.len() as u64,
&mut At[0],
&mut Bt1[0],
&mut Bt2[0],
&mut Ct[0]);
&lt1[0],
&lt2[0],
lt1.len() as u64,
at.len() as u64,
&mut at[0],
&mut bt1[0],
&mut bt2[0],
&mut ct[0]);
}
}
}
@ -132,13 +137,6 @@ pub fn getcs() -> CS {
}
}
/// Check that the lagrange coefficients computed by tau over
/// G1 equal the expected vector.
pub fn compare_tau(v1: &[G1], v2: &[G2], tau: &Fr, cs: &CS) -> bool {
assert_eq!(v1.len(), v2.len());
unsafe { libsnarkwrap_test_compare_tau(&v1[0], &v2[0], tau, v1.len() as u64, cs.ptr) }
}
pub trait Pairing<Other: Group> {
fn g1<'a>(&'a self, other: &'a Other) -> &'a G1;
fn g2<'a>(&'a self, other: &'a Other) -> &'a G2;

View File

@ -207,28 +207,6 @@ extern "C" void libsnarkwrap_dropcs(r1cs_constraint_system<curve_Fr> *cs)
delete cs;
}
extern "C" bool libsnarkwrap_test_compare_tau(
const curve_G1 *inputs1,
const curve_G2 *inputs2,
const curve_Fr *tau,
uint64_t d,
const r1cs_constraint_system<curve_Fr> *cs
)
{
auto qap = r1cs_to_qap_instance_map(*cs);
auto coeffs = qap.domain->lagrange_coeffs(*tau);
assert(coeffs.size() == d);
assert(qap.degree() == d);
bool res = true;
for (size_t i = 0; i < d; i++) {
res &= (coeffs[i] * curve_G1::one()) == inputs1[i];
res &= (coeffs[i] * curve_G2::one()) == inputs2[i];
}
return res;
}
extern "C" void libsnarkwrap_eval(
const r1cs_constraint_system<curve_Fr> *cs,
const curve_G1 *lc1,
@ -266,6 +244,30 @@ extern "C" void libsnarkwrap_eval(
}
}
// Comparison tests
extern "C" bool libsnarkwrap_test_compare_tau(
const curve_G1 *inputs1,
const curve_G2 *inputs2,
const curve_Fr *tau,
uint64_t d,
const r1cs_constraint_system<curve_Fr> *cs
)
{
auto qap = r1cs_to_qap_instance_map(*cs);
auto coeffs = qap.domain->lagrange_coeffs(*tau);
assert(coeffs.size() == d);
assert(qap.degree() == d);
bool res = true;
for (size_t i = 0; i < d; i++) {
res &= (coeffs[i] * curve_G1::one()) == inputs1[i];
res &= (coeffs[i] * curve_G2::one()) == inputs2[i];
}
return res;
}
extern "C" bool libsnarkwrap_test_eval(
const r1cs_constraint_system<curve_Fr> *cs,
const curve_Fr *tau,

View File

@ -79,7 +79,7 @@ fn fft<G: Group>(v: &[G], omega: Fr, threads: usize) -> Vec<G>
mod test {
use super::lagrange_coeffs;
use snark::*;
use util::*;
use taupowers::*;
#[test]
fn compare_to_libsnark() {
@ -103,35 +103,35 @@ mod test {
{
// Perform G1 FFT with wrong omega
let lc1 = lagrange_coeffs(&powers_of_tau_g1, Fr::random());
assert!(!compare_tau(&lc1, &lc2, &tau, &cs));
assert!(!cs.test_compare_tau(&lc1, &lc2, &tau));
}
{
// Perform G2 FFT with wrong omega
let lc2 = lagrange_coeffs(&powers_of_tau_g2, Fr::random());
assert!(!compare_tau(&lc1, &lc2, &tau, &cs));
assert!(!cs.test_compare_tau(&lc1, &lc2, &tau));
}
// Compare against libsnark
assert!(compare_tau(&lc1, &lc2, &tau, &cs));
assert!(cs.test_compare_tau(&lc1, &lc2, &tau));
// Wrong tau
assert!(!compare_tau(&lc1, &lc2, &Fr::random(), &cs));
assert!(!cs.test_compare_tau(&lc1, &lc2, &Fr::random()));
// Evaluate At, Ct in G1 and Bt in G1/G2
let mut At = (0..cs.num_vars).map(|_| G1::zero()).collect::<Vec<_>>();
let mut Bt1 = (0..cs.num_vars).map(|_| G1::zero()).collect::<Vec<_>>();
let mut Bt2 = (0..cs.num_vars).map(|_| G2::zero()).collect::<Vec<_>>();
let mut Ct = (0..cs.num_vars).map(|_| G1::zero()).collect::<Vec<_>>();
let mut at = (0..cs.num_vars).map(|_| G1::zero()).collect::<Vec<_>>();
let mut bt1 = (0..cs.num_vars).map(|_| G1::zero()).collect::<Vec<_>>();
let mut bt2 = (0..cs.num_vars).map(|_| G2::zero()).collect::<Vec<_>>();
let mut ct = (0..cs.num_vars).map(|_| G1::zero()).collect::<Vec<_>>();
cs.eval(&lc1, &lc2, &mut At, &mut Bt1, &mut Bt2, &mut Ct);
cs.eval(&lc1, &lc2, &mut at, &mut bt1, &mut bt2, &mut ct);
// Compare evaluation with libsnark
assert!(cs.test_eval(&tau, &At, &Bt1, &Bt2, &Ct));
assert!(cs.test_eval(&tau, &at, &bt1, &bt2, &ct));
// Wrong tau
assert!(!cs.test_eval(&Fr::random(), &At, &Bt1, &Bt2, &Ct));
assert!(!cs.test_eval(&Fr::random(), &at, &bt1, &bt2, &ct));
// Wrong polynomials
assert!(!cs.test_eval(&Fr::random(), &Bt1, &Bt1, &Bt2, &Ct));
assert!(!cs.test_eval(&Fr::random(), &bt1, &bt1, &bt2, &ct));
}
}

View File

@ -1,48 +1,14 @@
extern crate snark;
extern crate crossbeam;
mod util;
mod taupowers;
mod sequences;
mod lagrange;
mod protocol;
mod spair;
use snark::*;
use protocol::*;
use lagrange::*;
fn main() {
initialize();
// Get the constraint system
let cs = getcs();
// Initialize the players
const NUM_PLAYERS: usize = 3;
let players = (0..NUM_PLAYERS).map(|_| Player::new(&cs)).collect::<Vec<_>>();
// Phase 1 & 2 produces s-pairs for each player
let spairs = players.iter().map(|p| p.spairs()).collect::<Vec<_>>();
// Phase 3 produces random powers of tau in G1/G2
let (taupowers_g1, taupowers_g2) = {
let mut transcript = vec![];
for (i, p) in players.iter().enumerate() {
if i == 0 {
transcript.push(p.randompowers_start().unwrap());
} else {
let v = p.randompowers(&transcript[i-1].0, &transcript[i-1].1).unwrap();
transcript.push(v);
}
// Verification
assert!(verify_randompowers(&transcript[i],
if i == 0 { None } else { Some(&transcript[i-1]) },
&spairs[i]));
}
transcript[NUM_PLAYERS-1].clone()
};
snark::initialize();
}

0
src/protocol.rs Normal file
View File

View File

@ -1,149 +0,0 @@
use snark::*;
use util::*;
use lagrange::*;
use spair::*;
#[derive(Debug)]
pub enum ProtocolError {
InvalidTauPowersSize
}
pub struct Samples<T> {
tau: T,
rho_a: T,
rho_b: T,
alpha_a: T,
alpha_b: T,
alpha_c: T,
beta: T,
gamma: T
}
pub struct Player<'a> {
secrets: Samples<Fr>,
cs: &'a CS
}
impl<'a> Player<'a> {
pub fn new(cs: &'a CS) -> Player {
Player {
secrets: Samples {
tau: Fr::random_nonzero(),
rho_a: Fr::random_nonzero(),
rho_b: Fr::random_nonzero(),
alpha_a: Fr::random_nonzero(),
alpha_b: Fr::random_nonzero(),
alpha_c: Fr::random_nonzero(),
beta: Fr::random_nonzero(),
gamma: Fr::random_nonzero()
},
cs: cs
}
}
pub fn spairs<G: Group>(&self) -> Samples<Spair<G>> {
Samples {
tau: Spair::random(&self.secrets.tau),
rho_a: Spair::random(&self.secrets.rho_a),
rho_b: Spair::random(&self.secrets.rho_b),
alpha_a: Spair::random(&self.secrets.alpha_a),
alpha_b: Spair::random(&self.secrets.alpha_b),
alpha_c: Spair::random(&self.secrets.alpha_c),
beta: Spair::random(&self.secrets.beta),
gamma: Spair::random(&self.secrets.gamma)
}
}
pub fn randompowers_start(&self) -> Result<(Vec<G1>, Vec<G2>), ProtocolError> {
use std::iter::repeat;
let v1 = repeat(G1::one()).take(self.cs.d + 1).collect::<Vec<_>>();
let v2 = repeat(G2::one()).take(self.cs.d + 1).collect::<Vec<_>>();
self.randompowers(&v1, &v2)
}
pub fn randompowers(&self, v1: &[G1], v2: &[G2]) -> Result<(Vec<G1>, Vec<G2>), ProtocolError> {
if (v1.len() != v2.len()) || (v1.len() != self.cs.d + 1) {
return Err(ProtocolError::InvalidTauPowersSize)
}
let mut t1 = Vec::with_capacity(self.cs.d + 1);
let mut t2 = Vec::with_capacity(self.cs.d + 1);
for (i, tp) in TauPowers::new(self.secrets.tau).take(self.cs.d+1).enumerate() {
t1.push(v1[i] * tp);
t2.push(v2[i] * tp);
}
Ok((t1, t2))
}
}
pub fn verify_randompowers(
current: &(Vec<G1>, Vec<G2>),
last: Option<&(Vec<G1>, Vec<G2>)>,
spair: &Samples<Spair<G2>>
) -> bool {
current.0[0] == G1::one() &&
current.1[0] == G2::one() &&
match last {
Some(last) => {
checkseq(current.0.iter(), &Spair::new(&current.1[0], &current.1[1])) &&
checkseq(current.1.iter(), &Spair::new(&current.0[0], &current.0[1])) &&
same_power(&Spair::new(&last.0[1], &current.0[1]), &spair.tau)
},
None => {
checkseq(current.0.iter(), &spair.tau) &&
checkseq(current.1.iter(), &Spair::new(&current.0[0], &current.0[1]))
}
}
}
#[test]
fn randompowers_test() {
initialize();
const NUM_PARTIES: usize = 3;
let cs = getcs();
// All parties should initialize with their secret randomness
let parties: Vec<Player> = (0..NUM_PARTIES).map(|_| Player::new(&cs)).collect();
// All parties should reveal their s-pairs
let spairs: Vec<Samples<Spair<G2>>> = parties.iter().map(|p| p.spairs()).collect();
let mut transcript = vec![];
for (i, p) in parties.iter().enumerate() {
if i == 0 {
transcript.push(p.randompowers_start().unwrap());
} else {
let v = p.randompowers(&transcript[i-1].0, &transcript[i-1].1).unwrap();
transcript.push(v);
}
}
// Verification
let mut last = None;
for i in 0..NUM_PARTIES {
// Wrong tau s-pair should fail
assert!(!verify_randompowers(&transcript[i],
last,
&spairs[(i+1)%NUM_PARTIES]));
if last.is_some() {
// Verifying against wrong last transcript should fail
assert!(!verify_randompowers(&transcript[i],
Some(&transcript[i]),
&spairs[i]));
}
// Correct check
assert!(verify_randompowers(&transcript[i],
last,
&spairs[i]));
last = Some(&transcript[i]);
}
}

View File

@ -1,5 +1,3 @@
use snark::Fr;
pub struct Sequences<'a, T: 'a, I: Iterator<Item=&'a T>> {
v: I,
last: Option<&'a T>
@ -36,26 +34,3 @@ fn test_sequences() {
let expected = vec![(&a[0], &a[1]), (&a[1], &a[2]), (&a[2], &a[3])];
assert_eq!(b, expected);
}
pub struct TauPowers {
acc: Fr,
tau: Fr
}
impl TauPowers {
pub fn new(tau: Fr) -> TauPowers {
TauPowers { acc: Fr::one(), tau: tau }
}
}
impl Iterator for TauPowers {
type Item = Fr;
fn next(&mut self) -> Option<Fr> {
let tmp = self.acc;
self.acc = tmp * self.tau;
Some(tmp)
}
}

View File

@ -1,5 +1,5 @@
use snark::*;
use util::*;
use sequences::*;
pub struct Spair<G: Group> {
p: G,
@ -8,7 +8,7 @@ pub struct Spair<G: Group> {
impl<G: Group> Spair<G> {
pub fn random(s: &Fr) -> Self {
let mut p = G::zero();
let mut p = G::random();
while p.is_zero() {
p = G::random();
@ -20,14 +20,14 @@ impl<G: Group> Spair<G> {
}
}
pub fn new(p: &G, q: &G) -> Self {
pub fn new(p: &G, q: &G) -> Option<Self> {
if p.is_zero() {
panic!("tried to initialize spair with zero base")
}
Spair {
None
} else {
Some(Spair {
p: *p,
q: *q
})
}
}
}
@ -57,7 +57,7 @@ where Group1: Pairing<Group2>
if p.is_zero() { return false; }
same_power(&Spair::new(&p, &q), &a)
same_power(&Spair::new(&p, &q).unwrap(), &a)
}
pub fn checkseq<'a,
@ -132,8 +132,6 @@ fn samepower_seq() {
general_seq_test::<G2, G1>();
}
/*
fn checkvec<'a,
Group1: Group,
Group2: Group,
@ -198,4 +196,3 @@ fn samepower_vec() {
samepower_test_each_group(10, 5);
samepower_test_each_group(100, 50);
}
*/

34
src/taupowers.rs Normal file
View File

@ -0,0 +1,34 @@
use snark;
pub struct TauPowers {
acc: snark::Fr,
tau: snark::Fr
}
impl TauPowers {
pub fn new(tau: snark::Fr) -> TauPowers {
TauPowers { acc: snark::Fr::one(), tau: tau }
}
}
impl Iterator for TauPowers {
type Item = snark::Fr;
fn next(&mut self) -> Option<snark::Fr> {
let tmp = self.acc;
self.acc = tmp * self.tau;
Some(tmp)
}
}
#[test]
fn test_tau_powers() {
snark::initialize();
let tau = snark::Fr::random();
let mut taupowers = TauPowers::new(tau);
assert!(taupowers.next() == Some(snark::Fr::one()));
assert!(taupowers.next() == Some(tau));
assert!(taupowers.next() == Some(tau * tau));
assert!(taupowers.next() == Some(tau * tau * tau));
}