Switch to using BN crate and refactor implementation.

This commit is contained in:
Sean Bowe 2016-09-12 16:32:36 -06:00
parent 5e6e1f7f7d
commit 96989f61ac
No known key found for this signature in database
GPG Key ID: 95684257D8F8B031
16 changed files with 1002 additions and 1472 deletions

32
Cargo.lock generated
View File

@ -2,10 +2,28 @@
name = "mpc"
version = "0.0.1"
dependencies = [
"bn 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"snark 0.0.1",
]
[[package]]
name = "bn"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "byteorder"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "crossbeam"
version = "0.2.9"
@ -26,10 +44,24 @@ name = "libc"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rand"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-serialize"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "snark"
version = "0.0.1"
dependencies = [
"bn 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@ -11,4 +11,7 @@ readme = "README.md"
[dependencies]
snark = { path = "./snark/" }
bn = "0.2.2"
crossbeam = "0.2.9"
rand = "0.3.14"
rustc-serialize = "~0.3.19"

View File

@ -16,3 +16,4 @@ gcc = "0.3.*"
[dependencies]
libc = "0.2.*"
lazy_static = "0.1.*"
bn = "0.2.2"

View File

@ -1,158 +0,0 @@
use std::ops::{Add,Sub,Mul,Neg};
use libc::{c_char,uint64_t};
use std::ffi::CString;
/// The scalar field for the curve construction we use.
#[derive(Copy, Clone, Eq, PartialEq)]
#[repr(C)]
pub struct Fr([u64; 4]);
extern "C" {
fn libsnarkwrap_Fr_random() -> Fr;
fn libsnarkwrap_Fr_zero() -> Fr;
fn libsnarkwrap_Fr_one() -> Fr;
fn libsnarkwrap_Fr_from(s: *const c_char) -> Fr;
fn libsnarkwrap_Fr_exp(a: *const Fr, b: uint64_t) -> Fr;
fn libsnarkwrap_Fr_add(a: *const Fr, b: *const Fr) -> Fr;
fn libsnarkwrap_Fr_mul(a: *const Fr, b: *const Fr) -> Fr;
fn libsnarkwrap_Fr_sub(a: *const Fr, b: *const Fr) -> Fr;
fn libsnarkwrap_Fr_neg(a: *const Fr) -> Fr;
fn libsnarkwrap_Fr_inverse(a: *const Fr) -> Fr;
fn libsnarkwrap_Fr_is_zero(a: *const Fr) -> bool;
}
impl Fr {
pub fn zero() -> Self {
unsafe { libsnarkwrap_Fr_zero() }
}
pub fn one() -> Self {
unsafe { libsnarkwrap_Fr_one() }
}
pub fn random() -> Self {
unsafe { libsnarkwrap_Fr_random() }
}
pub fn inverse(&self) -> Self {
unsafe { libsnarkwrap_Fr_inverse(self) }
}
pub fn is_zero(&self) -> bool {
unsafe { libsnarkwrap_Fr_is_zero(self) }
}
pub fn exp(&self, e: u64) -> Self {
unsafe { libsnarkwrap_Fr_exp(self, e) }
}
pub fn random_nonzero() -> Self {
let mut tmp = Self::random();
while tmp.is_zero() {
tmp = Self::random();
}
return tmp;
}
pub fn from_str(s: &str) -> Self {
for c in s.chars() {
if c != '0' &&
c != '1' &&
c != '2' &&
c != '3' &&
c != '4' &&
c != '5' &&
c != '6' &&
c != '7' &&
c != '8' &&
c != '9' {
panic!("character out of range")
}
}
let s = CString::new(s).unwrap();
unsafe { libsnarkwrap_Fr_from(s.as_ptr()) }
}
}
impl Add for Fr {
type Output = Fr;
fn add(self, other: Fr) -> Fr {
unsafe { libsnarkwrap_Fr_add(&self, &other) }
}
}
impl Mul for Fr {
type Output = Fr;
fn mul(self, other: Fr) -> Fr {
unsafe { libsnarkwrap_Fr_mul(&self, &other) }
}
}
impl Sub for Fr {
type Output = Fr;
fn sub(self, other: Fr) -> Fr {
unsafe { libsnarkwrap_Fr_sub(&self, &other) }
}
}
impl Neg for Fr {
type Output = Fr;
fn neg(self) -> Fr {
unsafe { libsnarkwrap_Fr_neg(&self) }
}
}
#[test]
fn test_inverses() {
super::initialize();
for _ in 0..50 {
let a = Fr::random();
assert!(a != Fr::zero());
let b = a.inverse();
assert!(a * b == Fr::one());
}
}
#[test]
fn test_basic_arith() {
super::initialize();
let a = Fr::from_str("34563126457335463");
let b = Fr::from_str("23463856875665981");
let ab = Fr::from_str("810984252370463483215040853984203");
let aplusb = Fr::from_str("58026983333001444");
let aminusb = Fr::from_str("11099269581669482");
let aneg = Fr::from_str("21888242871839275222246405745257275088548364400416034343698169623449351160154");
let a50 = Fr::from_str("18657215030604597165059661904200246872501020503322948614804364624353607925980");
assert!(ab == (a * b));
assert!(aplusb == (a + b));
assert!(aminusb == (a - b));
assert!(aneg == (-a));
assert!(a50 == a.exp(50));
}
#[test]
fn test_primitives() {
super::initialize();
let a = Fr::from_str("0");
assert!(a.is_zero());
let a = Fr::from_str("1");
assert!(!a.is_zero());
let a = Fr::zero();
assert!(a.is_zero());
let a = Fr::one();
assert!(!a.is_zero());
}

View File

@ -1,80 +0,0 @@
use std::ops::{Add,Sub,Mul,Neg};
use super::{Fr,Group};
#[derive(Copy, Clone)]
#[repr(C)]
pub struct G1 {
x: [u64; 4],
y: [u64; 4],
z: [u64; 4]
}
extern "C" {
fn libsnarkwrap_G1_zero() -> G1;
fn libsnarkwrap_G1_one() -> G1;
fn libsnarkwrap_G1_random() -> G1;
fn libsnarkwrap_G1_is_zero(p: *const G1) -> bool;
fn libsnarkwrap_G1_is_equal(p: *const G1, q: *const G1) -> bool;
fn libsnarkwrap_G1_add(p: *const G1, q: *const G1) -> G1;
fn libsnarkwrap_G1_sub(p: *const G1, q: *const G1) -> G1;
fn libsnarkwrap_G1_neg(p: *const G1) -> G1;
fn libsnarkwrap_G1_scalarmul(p: *const G1, s: *const Fr) -> G1;
}
impl PartialEq for G1 {
fn eq(&self, other: &G1) -> bool {
unsafe { libsnarkwrap_G1_is_equal(self, other) }
}
}
impl Group for G1 {
fn zero() -> G1 {
unsafe { libsnarkwrap_G1_zero() }
}
fn one() -> G1 {
unsafe { libsnarkwrap_G1_one() }
}
fn random() -> G1 {
unsafe { libsnarkwrap_G1_random() }
}
fn is_zero(&self) -> bool {
unsafe { libsnarkwrap_G1_is_zero(self) }
}
}
impl Add for G1 {
type Output = G1;
fn add(self, other: G1) -> G1 {
unsafe { libsnarkwrap_G1_add(&self, &other) }
}
}
impl Mul<Fr> for G1 {
type Output = G1;
fn mul(self, other: Fr) -> G1 {
unsafe { libsnarkwrap_G1_scalarmul(&self, &other) }
}
}
impl Sub for G1 {
type Output = G1;
fn sub(self, other: G1) -> G1 {
unsafe { libsnarkwrap_G1_sub(&self, &other) }
}
}
impl Neg for G1 {
type Output = G1;
fn neg(self) -> G1 {
unsafe { libsnarkwrap_G1_neg(&self) }
}
}

View File

@ -1,80 +0,0 @@
use std::ops::{Add,Sub,Mul,Neg};
use super::{Fr,Group};
#[derive(Copy, Clone)]
#[repr(C)]
pub struct G2 {
x: [u64; 4 * 2],
y: [u64; 4 * 2],
z: [u64; 4 * 2]
}
extern "C" {
fn libsnarkwrap_G2_zero() -> G2;
fn libsnarkwrap_G2_one() -> G2;
fn libsnarkwrap_G2_random() -> G2;
fn libsnarkwrap_G2_is_zero(p: *const G2) -> bool;
fn libsnarkwrap_G2_is_equal(p: *const G2, q: *const G2) -> bool;
fn libsnarkwrap_G2_add(p: *const G2, q: *const G2) -> G2;
fn libsnarkwrap_G2_sub(p: *const G2, q: *const G2) -> G2;
fn libsnarkwrap_G2_neg(p: *const G2) -> G2;
fn libsnarkwrap_G2_scalarmul(p: *const G2, s: *const Fr) -> G2;
}
impl PartialEq for G2 {
fn eq(&self, other: &G2) -> bool {
unsafe { libsnarkwrap_G2_is_equal(self, other) }
}
}
impl Group for G2 {
fn zero() -> G2 {
unsafe { libsnarkwrap_G2_zero() }
}
fn one() -> G2 {
unsafe { libsnarkwrap_G2_one() }
}
fn random() -> G2 {
unsafe { libsnarkwrap_G2_random() }
}
fn is_zero(&self) -> bool {
unsafe { libsnarkwrap_G2_is_zero(self) }
}
}
impl Add for G2 {
type Output = G2;
fn add(self, other: G2) -> G2 {
unsafe { libsnarkwrap_G2_add(&self, &other) }
}
}
impl Mul<Fr> for G2 {
type Output = G2;
fn mul(self, other: Fr) -> G2 {
unsafe { libsnarkwrap_G2_scalarmul(&self, &other) }
}
}
impl Sub for G2 {
type Output = G2;
fn sub(self, other: G2) -> G2 {
unsafe { libsnarkwrap_G2_sub(&self, &other) }
}
}
impl Neg for G2 {
type Output = G2;
fn neg(self) -> G2 {
unsafe { libsnarkwrap_G2_neg(&self) }
}
}

View File

@ -1,21 +0,0 @@
use std::ops::Mul;
use super::Fr;
#[derive(Copy, Clone, Eq, PartialEq)]
#[repr(C)]
pub struct Gt {
a: [u64; 4 * 6],
b: [u64; 4 * 6]
}
extern "C" {
fn libsnarkwrap_gt_exp(p: *const Gt, s: *const Fr) -> Gt;
}
impl Mul<Fr> for Gt {
type Output = Gt;
fn mul(self, other: Fr) -> Gt {
unsafe { libsnarkwrap_gt_exp(&self, &other) }
}
}

View File

@ -1,23 +1,14 @@
extern crate bn;
extern crate libc;
#[macro_use]
extern crate lazy_static;
use std::ops::{Add,Sub,Mul,Neg};
use std::sync::Mutex;
mod fr;
mod g1;
mod g2;
mod gt;
pub use self::fr::Fr;
pub use self::gt::Gt;
pub use self::g1::G1;
pub use self::g2::G2;
use bn::*;
extern "C" {
fn libsnarkwrap_init();
fn libsnarkwrap_pairing(p: *const G1, q: *const G2) -> Gt;
fn libsnarkwrap_getcs(d: *mut libc::uint64_t, vars: *mut libc::uint64_t, inputs: *mut libc::uint64_t, omega: *mut Fr) -> *mut libc::c_void;
fn libsnarkwrap_dropcs(cs: *mut libc::c_void);
fn libsnarkwrap_dropkeypair(kp: *mut libc::c_void);
@ -89,7 +80,7 @@ lazy_static! {
}
/// This must be called before anything in this module is used.
pub fn initialize() {
fn initialize() {
use std::mem::align_of;
let mut l = INIT_LOCK.lock().unwrap();
@ -118,9 +109,11 @@ pub struct Keypair {
impl PartialEq for Keypair {
fn eq(&self, other: &Keypair) -> bool {
unsafe { libsnarkwrap_keypair_eq(
self.ptr, other.ptr
) }
initialize();
unsafe {
libsnarkwrap_keypair_eq(self.ptr, other.ptr)
}
}
}
@ -144,6 +137,8 @@ impl Keypair {
vk_z: &G2
) -> Keypair
{
initialize();
assert_eq!(pk_a.len(), pk_a_prime.len());
assert_eq!(pk_a.len(), pk_b.len());
assert_eq!(pk_a.len(), pk_b_prime.len());
@ -188,6 +183,8 @@ impl Keypair {
beta: &Fr,
gamma: &Fr
) -> Keypair {
initialize();
unsafe {
Keypair {
ptr: libsnarkwrap_test_keygen(
@ -200,6 +197,8 @@ impl Keypair {
impl CS {
pub fn dummy() -> Self {
initialize();
let mut d = 0;
let mut vars = 0;
let mut num_inputs = 0;
@ -217,11 +216,15 @@ impl CS {
}
pub fn test_compare_tau(&self, v1: &[G1], v2: &[G2], tau: &Fr) -> bool {
initialize();
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 {
initialize();
assert_eq!(at.len(), bt1.len());
assert_eq!(bt1.len(), bt2.len());
assert_eq!(bt2.len(), ct.len());
@ -237,13 +240,18 @@ impl CS {
}
}
pub fn eval(&self,
lt1: &[G1],
lt2: &[G2],
at: &mut [G1],
bt1: &mut [G1],
bt2: &mut [G2],
ct: &mut [G1]) {
pub fn eval(
&self,
lt1: &[G1],
lt2: &[G2],
at: &mut [G1],
bt1: &mut [G1],
bt2: &mut [G2],
ct: &mut [G1]
)
{
initialize();
assert_eq!(lt1.len(), lt2.len());
assert_eq!(at.len(), bt1.len());
assert_eq!(bt1.len(), bt2.len());
@ -265,186 +273,16 @@ impl CS {
impl Drop for CS {
fn drop(&mut self) {
initialize();
unsafe { libsnarkwrap_dropcs(self.ptr) }
}
}
impl Drop for Keypair {
fn drop(&mut self) {
initialize();
unsafe { libsnarkwrap_dropkeypair(self.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;
}
impl Pairing<G2> for G1 {
fn g1<'a>(&'a self, _: &'a G2) -> &'a G1 {
self
}
fn g2<'a>(&'a self, other: &'a G2) -> &'a G2 {
other
}
}
impl Pairing<G1> for G2 {
fn g1<'a>(&'a self, other: &'a G1) -> &'a G1 {
other
}
fn g2<'a>(&'a self, _: &'a G1) -> &'a G2 {
self
}
}
pub fn pairing<Ga: Group, Gb: Group>(p: &Ga, q: &Gb) -> Gt where Ga: Pairing<Gb> {
unsafe { libsnarkwrap_pairing(p.g1(q), p.g2(q)) }
}
pub trait Group: Sized + Send +
Copy +
Clone +
Mul<Fr, Output=Self> +
Add<Output=Self> +
Sub<Output=Self> +
Neg<Output=Self> +
PartialEq +
'static {
fn zero() -> Self;
fn one() -> Self;
fn random() -> Self;
fn random_nonzero() -> Self {
let mut tmp = Self::random();
while tmp.is_zero() {
tmp = Self::random();
}
tmp
}
fn is_zero(&self) -> bool;
}
#[test]
fn pairing_test() {
initialize();
for _ in 0..50 {
let p = G1::random();
let q = G2::random();
let s = Fr::random();
let sp = p * s;
let sq = q * s;
let a = pairing(&p, &q) * s;
let b = pairing(&sp, &q);
let c = pairing(&p, &sq);
assert!(a == b);
assert!(b == c);
}
}
#[test]
fn pairing_ordering_irrelevant() {
initialize();
let p = G1::random();
let q = G2::random();
let a = pairing(&p, &q);
let b = pairing(&q, &p);
assert!(a == b);
}
#[cfg(test)]
mod test_groups {
use super::{Fr, G1, G2, initialize, Group};
fn test_associative<G: Group>() {
for _ in 0..50 {
let a = G::random();
let b = G::random();
let c = G::random();
let x = (a + b) + c;
let y = (a + c) + b;
assert!(x == y);
}
}
fn test_primitives<G: Group>() {
let a = G::zero();
let b = G::one();
assert_eq!(a.is_zero(), true);
assert_eq!(b.is_zero(), false);
}
fn test_scalar_mul<G: Group>() {
let r = G::random();
let res = r * Fr::from_str("16");
let mut acc = G::zero();
for _ in 0..16 {
acc = acc + r;
}
assert!(acc == res);
}
fn test_addition<G: Group>() {
{
let a = G::random();
let b = -(a);
let c = a + b;
assert!(c.is_zero());
}
{
let a = G::random();
let b = -(a);
let c = a - b;
let d = a * Fr::from_str("2");
assert!(c == d);
}
}
fn test_allocations_and_moves<G: Group>() {
let a: Vec<G> = (0..100)
.map(|i| (G::one() * Fr::from_str(&format!("{}", i))))
.collect();
let b = a.iter().fold(G::zero(), |a, b| a + *b);
assert!(b == G::one() * Fr::from_str("4950"));
}
fn test_group_ops<G: Group>() {
test_associative::<G>();
test_primitives::<G>();
test_scalar_mul::<G>();
test_addition::<G>();
test_allocations_and_moves::<G>();
}
#[test]
fn test_g1() {
initialize();
test_group_ops::<G1>();
}
#[test]
fn test_g2() {
initialize();
test_group_ops::<G2>();
}
}

View File

@ -37,138 +37,6 @@ extern "C" void libsnarkwrap_init() {
assert(alignof(curve_GT) == alignof(uint64_t));
}
// Fr
extern "C" curve_Fr libsnarkwrap_Fr_random() {
return curve_Fr::random_element();
}
extern "C" curve_Fr libsnarkwrap_Fr_zero() {
return curve_Fr::zero();
}
extern "C" curve_Fr libsnarkwrap_Fr_one() {
return curve_Fr::one();
}
extern "C" curve_Fr libsnarkwrap_Fr_from(const char *a) {
return curve_Fr(a);
}
extern "C" curve_Fr libsnarkwrap_Fr_exp(const curve_Fr *a, uint64_t b) {
return (*a) ^ b;
}
extern "C" curve_Fr libsnarkwrap_Fr_add(const curve_Fr *a, const curve_Fr *b) {
return *a + *b;
}
extern "C" curve_Fr libsnarkwrap_Fr_sub(const curve_Fr *a, const curve_Fr *b) {
return *a - *b;
}
extern "C" curve_Fr libsnarkwrap_Fr_mul(const curve_Fr *a, const curve_Fr *b) {
return *a * *b;
}
extern "C" curve_Fr libsnarkwrap_Fr_neg(const curve_Fr *a) {
return -(*a);
}
extern "C" curve_Fr libsnarkwrap_Fr_inverse(const curve_Fr *a) {
return a->inverse();
}
extern "C" bool libsnarkwrap_Fr_is_zero(const curve_Fr *a) {
return a->is_zero();
}
// G1
extern "C" curve_G1 libsnarkwrap_G1_zero() {
return curve_G1::zero();
}
extern "C" curve_G1 libsnarkwrap_G1_one() {
return curve_G1::one();
}
extern "C" curve_G1 libsnarkwrap_G1_random() {
return curve_G1::random_element();
}
extern "C" bool libsnarkwrap_G1_is_zero(const curve_G1 *p) {
return p->is_zero();
}
extern "C" bool libsnarkwrap_G1_is_equal(const curve_G1 *p, const curve_G1 *q) {
return *p == *q;
}
extern "C" curve_G1 libsnarkwrap_G1_add(const curve_G1 *p, const curve_G1 *q) {
return *p + *q;
}
extern "C" curve_G1 libsnarkwrap_G1_sub(const curve_G1 *p, const curve_G1 *q) {
return *p - *q;
}
extern "C" curve_G1 libsnarkwrap_G1_neg(const curve_G1 *p) {
return -(*p);
}
extern "C" curve_G1 libsnarkwrap_G1_scalarmul(const curve_G1 *p, const curve_Fr *q) {
return (*q) * (*p);
}
// G2
extern "C" curve_G2 libsnarkwrap_G2_zero() {
return curve_G2::zero();
}
extern "C" curve_G2 libsnarkwrap_G2_one() {
return curve_G2::one();
}
extern "C" curve_G2 libsnarkwrap_G2_random() {
return curve_G2::random_element();
}
extern "C" bool libsnarkwrap_G2_is_zero(const curve_G2 *p) {
return p->is_zero();
}
extern "C" bool libsnarkwrap_G2_is_equal(const curve_G2 *p, const curve_G2 *q) {
return *p == *q;
}
extern "C" curve_G2 libsnarkwrap_G2_add(const curve_G2 *p, const curve_G2 *q) {
return *p + *q;
}
extern "C" curve_G2 libsnarkwrap_G2_sub(const curve_G2 *p, const curve_G2 *q) {
return *p - *q;
}
extern "C" curve_G2 libsnarkwrap_G2_neg(const curve_G2 *p) {
return -(*p);
}
extern "C" curve_G2 libsnarkwrap_G2_scalarmul(const curve_G2 *p, const curve_Fr *q) {
return (*q) * (*p);
}
// Pairing
extern "C" curve_GT libsnarkwrap_gt_exp(const curve_GT *p, const curve_Fr *s) {
return (*p) ^ (*s);
}
extern "C" curve_GT libsnarkwrap_pairing(const curve_G1 *p, const curve_G2 *q) {
return curve_pp::reduced_pairing(*p, *q);
}
// QAP
extern "C" void* libsnarkwrap_getcs(uint64_t *d, uint64_t *vars, uint64_t *num_inputs, curve_Fr *omega)

View File

@ -1,14 +1,15 @@
extern crate bn;
extern crate rand;
extern crate snark;
extern crate crossbeam;
extern crate rustc_serialize;
mod taupowers;
mod sequences;
mod qap;
mod protocol;
mod spair;
mod spairs;
mod transcript;
fn main() {
snark::initialize();
}

View File

@ -1,613 +0,0 @@
use snark::*;
use spair::*;
use taupowers::*;
use qap::*;
use std::collections::HashMap;
fn mul_all_by<G: Group>(v: &[G], c: Fr) -> Vec<G> {
v.iter().map(|g| *g * c).collect()
}
#[derive(Clone)]
struct Secrets {
tau: Fr,
rho_a: Fr,
rho_b: Fr,
alpha_a: Fr,
alpha_b: Fr,
alpha_c: Fr,
beta: Fr,
gamma: Fr
}
type BlakeHash = [u8; 1];
#[derive(Clone)]
struct Spairs {
tau: Spair<G2>,
f1: G2, // f1
f1pA: G2, // f1 * rho_a
f1pAaA: G2, // f1 * rho_a * alpha_a
f1pApB: G2, // f1 * rho_a * rho_b
f1pApBaC: G2, // f1 * rho_a * rho_b * alpha_c
f1pApBaB: G2, // f1 * rho_a * rho_b * alpha_b
f2: G2, // f2
f2beta: G2, // f2 * beta
f2betagamma: G2, // f2 * beta * gamma
aA: Spair<G1>, // (f3, f3 * alpha_a)
aC: Spair<G1>, // (f4, f4 * alpha_c)
pB: Spair<G1>, // (f5, f5 * rho_b)
pApB: Spair<G1>, // (f6, f6 * rho_a)
gamma: Spair<G1> // (f7, f7 * gamma)
}
impl Spairs {
fn is_valid(&self) -> bool {
!self.f1.is_zero() &&
!self.f1pA.is_zero() &&
!self.f1pAaA.is_zero() &&
!self.f1pApB.is_zero() &&
!self.f1pApBaC.is_zero() &&
!self.f1pApBaB.is_zero() &&
!self.f2.is_zero() &&
!self.f2beta.is_zero() &&
!self.f2betagamma.is_zero() &&
same_power(&self.aA, &Spair::new(&self.f1pA, &self.f1pAaA).unwrap()) &&
same_power(&self.aC, &Spair::new(&self.f1pApB, &self.f1pApBaC).unwrap()) &&
same_power(&self.pB, &Spair::new(&self.f1pA, &self.f1pApB).unwrap()) &&
same_power(&self.pApB, &Spair::new(&self.f1, &self.f1pApB).unwrap()) &&
same_power(&self.gamma, &Spair::new(&self.f2beta, &self.f2betagamma).unwrap())
}
fn alpha_b(&self) -> Spair<G2> {
Spair::new(&self.f1pApB, &self.f1pApBaB).unwrap()
}
fn rho_a(&self) -> Spair<G2> {
Spair::new(&self.f1, &self.f1pA).unwrap()
}
fn rho_b(&self) -> Spair<G2> {
Spair::new(&self.f1pA, &self.f1pApB).unwrap()
}
fn alpha_a_rho_a(&self) -> Spair<G2> {
Spair::new(&self.f1, &self.f1pAaA).unwrap()
}
fn alpha_b_rho_b(&self) -> Spair<G2> {
Spair::new(&self.f1pA, &self.f1pApBaB).unwrap()
}
fn rho_a_rho_b(&self) -> Spair<G2> {
Spair::new(&self.f1, &self.f1pApB).unwrap()
}
fn alpha_c_rho_a_rho_b(&self) -> Spair<G2> {
Spair::new(&self.f1, &self.f1pApBaC).unwrap()
}
fn beta(&self) -> Spair<G2> {
Spair::new(&self.f2, &self.f2beta).unwrap()
}
fn beta_gamma(&self) -> Spair<G2> {
Spair::new(&self.f2, &self.f2betagamma).unwrap()
}
}
impl Secrets {
#[cfg(test)]
fn new_blank() -> Secrets {
Secrets {
tau: Fr::one(),
rho_a: Fr::one(),
rho_b: Fr::one(),
alpha_a: Fr::one(),
alpha_b: Fr::one(),
alpha_c: Fr::one(),
beta: Fr::one(),
gamma: Fr::one()
}
}
fn new() -> Secrets {
Secrets {
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()
}
}
fn spairs(&self) -> Spairs {
let f1 = G2::random_nonzero();
let f1pA = f1 * self.rho_a;
let f1pAaA = f1pA * self.alpha_a;
let f1pApB = f1pA * self.rho_b;
let f1pApBaC = f1pApB * self.alpha_c;
let f1pApBaB = f1pApB * self.alpha_b;
let f2 = G2::random_nonzero();
let f2beta = f2 * self.beta;
let f2betagamma = f2beta * self.gamma;
let tmp = Spairs {
tau: Spair::random(&self.tau),
f1: f1,
f1pA: f1pA,
f1pAaA: f1pAaA,
f1pApB: f1pApB,
f1pApBaC: f1pApBaC,
f1pApBaB: f1pApBaB,
f2: f2,
f2beta: f2beta,
f2betagamma: f2betagamma,
aA: Spair::random(&self.alpha_a),
aC: Spair::random(&self.alpha_c),
pB: Spair::random(&self.rho_b),
pApB: Spair::random(&(self.rho_a * self.rho_b)),
gamma: Spair::random(&self.gamma)
};
assert!(tmp.is_valid());
tmp
}
fn keypair(&self, cs: &CS) -> Keypair {
Keypair::generate(
cs,
&self.tau,
&self.alpha_a,
&self.alpha_b,
&self.alpha_c,
&self.rho_a,
&self.rho_b,
&self.beta,
&self.gamma
)
}
}
struct Player {
secrets: Secrets,
spairs: Spairs
}
fn blake2s(s: &Spairs) -> BlakeHash {
// TODO
[0]
}
impl Player {
fn new() -> Player {
let secrets = Secrets::new();
let spairs = secrets.spairs();
Player {
secrets: secrets,
spairs: spairs
}
}
#[cfg(test)]
fn test_multiply_secrets(&self, acc: &mut Secrets) {
acc.tau = acc.tau * self.secrets.tau;
acc.alpha_a = acc.alpha_a * self.secrets.alpha_a;
acc.alpha_b = acc.alpha_b * self.secrets.alpha_b;
acc.alpha_c = acc.alpha_c * self.secrets.alpha_c;
acc.rho_a = acc.rho_a * self.secrets.rho_a;
acc.rho_b = acc.rho_b * self.secrets.rho_b;
acc.beta = acc.beta * self.secrets.beta;
acc.gamma = acc.gamma * self.secrets.gamma;
}
fn spairs_commitment(&self) -> BlakeHash {
blake2s(&self.spairs)
}
fn exponentiate_with_tau(
&self,
prev_g1: &[G1],
prev_g2: &[G2]) -> (Vec<G1>, Vec<G2>)
{
assert_eq!(prev_g1.len(), prev_g2.len());
let mut new_g1 = Vec::with_capacity(prev_g1.len());
let mut new_g2 = Vec::with_capacity(prev_g2.len());
for ((&g1, &g2), tp) in prev_g1.iter().zip(prev_g2.iter()).zip(TauPowers::new(self.secrets.tau)) {
new_g1.push(g1 * tp);
new_g2.push(g2 * tp);
}
assert_eq!(new_g1.len(), prev_g1.len());
assert_eq!(new_g2.len(), prev_g2.len());
(new_g1, new_g2)
}
fn random_coeffs_part_one(
&self,
vk_A: &G2,
vk_B: &G1,
vk_C: &G2,
vk_Z: &G2,
pk_A: &[G1],
pk_A_prime: &[G1],
pk_B: &[G2],
pk_B_temp: &[G1],
pk_B_prime: &[G1],
pk_C: &[G1],
pk_C_prime: &[G1]) -> (G2, G1, G2, G2, Vec<G1>, Vec<G1>, Vec<G2>, Vec<G1>, Vec<G1>, Vec<G1>, Vec<G1>)
{
(
*vk_A * self.secrets.alpha_a,
*vk_B * self.secrets.alpha_b,
*vk_C * self.secrets.alpha_c,
*vk_Z * (self.secrets.rho_a * self.secrets.rho_b),
mul_all_by(pk_A, self.secrets.rho_a),
mul_all_by(pk_A_prime, (self.secrets.rho_a * self.secrets.alpha_a)),
mul_all_by(pk_B, self.secrets.rho_b),
mul_all_by(pk_B_temp, self.secrets.rho_b),
mul_all_by(pk_B_prime, (self.secrets.rho_b * self.secrets.alpha_b)),
mul_all_by(pk_C, (self.secrets.rho_a * self.secrets.rho_b)),
mul_all_by(pk_C_prime, (self.secrets.rho_a * self.secrets.rho_b * self.secrets.alpha_c))
)
}
fn random_coeffs_part_two(
&self,
vk_gamma: &G2,
vk_beta_gamma_one: &G1,
vk_beta_gamma_two: &G2,
pk_K: &[G1]) -> (G2, G1, G2, Vec<G1>)
{
(
*vk_gamma * self.secrets.gamma,
*vk_beta_gamma_one * (self.secrets.beta * self.secrets.gamma),
*vk_beta_gamma_two * (self.secrets.beta * self.secrets.gamma),
mul_all_by(pk_K, self.secrets.beta)
)
}
}
struct Coordinator {
commitments: Vec<BlakeHash>,
spairs: HashMap<usize, Spairs>
}
impl Coordinator {
fn new() -> Self {
Coordinator { commitments: vec![], spairs: HashMap::new() }
}
fn receive_commitment(&mut self, h: BlakeHash)
{
self.commitments.push(h);
}
fn check_commitment(&mut self, i: usize, spairs: Spairs) -> bool
{
self.spairs.insert(i, spairs.clone());
spairs.is_valid() && blake2s(&spairs) == self.commitments[i]
}
fn check_taupowers(
&self,
prev_g1: &[G1],
prev_g2: &[G2],
cur_g1: &[G1],
cur_g2: &[G2],
player: usize) -> bool
{
prev_g1.len() >= 2 &&
prev_g1.len() == prev_g2.len() &&
prev_g2.len() == cur_g1.len() &&
cur_g1.len() == cur_g2.len() &&
prev_g1[0] == G1::one() &&
prev_g2[0] == G2::one() &&
cur_g1[0] == G1::one() &&
cur_g2[0] == G2::one() &&
prev_g1[1] != G1::zero() &&
cur_g1[1] != G1::zero() &&
prev_g2[1] != G2::zero() &&
cur_g2[1] != G2::zero() &&
// Check that we've exponentiated on top of the previous player correctly
same_power(&Spair::new(&prev_g1[1], &cur_g1[1]).unwrap(), &self.spairs[&player].tau) &&
// Check that all G1 elements are exponentiated correctly
checkseq(cur_g1.iter(), &Spair::new(&cur_g2[0], &cur_g2[1]).unwrap()) &&
// Check that all G2 elements are exponentiated correctly
checkseq(cur_g2.iter(), &Spair::new(&cur_g1[0], &cur_g1[1]).unwrap())
}
fn check_random_coeffs_part_one(
&self,
player: usize,
prev_vk_A: &G2,
prev_vk_B: &G1,
prev_vk_C: &G2,
prev_vk_Z: &G2,
prev_pk_A: &[G1],
prev_pk_A_prime: &[G1],
prev_pk_B: &[G2],
prev_pk_B_temp: &[G1],
prev_pk_B_prime: &[G1],
prev_pk_C: &[G1],
prev_pk_C_prime: &[G1],
cur_vk_A: &G2,
cur_vk_B: &G1,
cur_vk_C: &G2,
cur_vk_Z: &G2,
cur_pk_A: &[G1],
cur_pk_A_prime: &[G1],
cur_pk_B: &[G2],
cur_pk_B_temp: &[G1],
cur_pk_B_prime: &[G1],
cur_pk_C: &[G1],
cur_pk_C_prime: &[G1]
) -> bool
{
!prev_vk_A.is_zero() && !cur_vk_A.is_zero() &&
!prev_vk_B.is_zero() && !cur_vk_B.is_zero() &&
!prev_vk_C.is_zero() && !cur_vk_C.is_zero() &&
!prev_vk_Z.is_zero() && !cur_vk_Z.is_zero() &&
prev_pk_A.len() == cur_pk_A.len() &&
prev_pk_A_prime.len() == cur_pk_A_prime.len() &&
prev_pk_B.len() == cur_pk_B.len() &&
prev_pk_B_temp.len() == cur_pk_B_temp.len() &&
prev_pk_B_prime.len() == cur_pk_B_prime.len() &&
prev_pk_C.len() == cur_pk_C.len() &&
prev_pk_C_prime.len() == cur_pk_C_prime.len() &&
same_power(&Spair::new(prev_vk_A, cur_vk_A).unwrap(), &self.spairs[&player].aA) &&
same_power(&Spair::new(prev_vk_B, cur_vk_B).unwrap(), &self.spairs[&player].alpha_b()) &&
same_power(&Spair::new(prev_vk_C, cur_vk_C).unwrap(), &self.spairs[&player].aC) &&
same_power(&Spair::new(prev_vk_Z, cur_vk_Z).unwrap(), &self.spairs[&player].pApB) &&
check(prev_pk_A.iter().zip(cur_pk_A.iter()), &self.spairs[&player].rho_a()) &&
check(prev_pk_A_prime.iter().zip(cur_pk_A_prime.iter()), &self.spairs[&player].alpha_a_rho_a()) &&
check(prev_pk_B.iter().zip(cur_pk_B.iter()), &self.spairs[&player].pB) &&
check(prev_pk_B_temp.iter().zip(cur_pk_B_temp.iter()), &self.spairs[&player].rho_b()) &&
check(prev_pk_B_prime.iter().zip(cur_pk_B_prime.iter()), &self.spairs[&player].alpha_b_rho_b()) &&
check(prev_pk_C.iter().zip(cur_pk_C.iter()), &self.spairs[&player].rho_a_rho_b()) &&
check(prev_pk_C_prime.iter().zip(cur_pk_C_prime.iter()), &self.spairs[&player].alpha_c_rho_a_rho_b())
}
fn check_random_coeffs_part_two(
&self,
player: usize,
prev_vk_gamma: &G2,
prev_vk_beta_gamma_one: &G1,
prev_vk_beta_gamma_two: &G2,
prev_pk_K: &[G1],
cur_vk_gamma: &G2,
cur_vk_beta_gamma_one: &G1,
cur_vk_beta_gamma_two: &G2,
cur_pk_K: &[G1]
) -> bool
{
!prev_vk_gamma.is_zero() && !cur_vk_gamma.is_zero() &&
!prev_vk_beta_gamma_one.is_zero() && !cur_vk_beta_gamma_one.is_zero() &&
!prev_vk_beta_gamma_two.is_zero() && !cur_vk_beta_gamma_two.is_zero() &&
prev_pk_K.len() == cur_pk_K.len() &&
same_power(&Spair::new(prev_vk_gamma, cur_vk_gamma).unwrap(), &self.spairs[&player].gamma) &&
same_power(&Spair::new(prev_vk_beta_gamma_one, cur_vk_beta_gamma_one).unwrap(), &self.spairs[&player].beta_gamma()) &&
same_power(&Spair::new(prev_vk_beta_gamma_two, cur_vk_beta_gamma_two).unwrap(), &Spair::new(prev_vk_beta_gamma_one, cur_vk_beta_gamma_one).unwrap()) &&
check(prev_pk_K.iter().zip(cur_pk_K.iter()), &self.spairs[&player].beta())
}
}
#[test]
fn implthing() {
initialize();
let cs = CS::dummy();
// Each player initializes
const NUM_PARTIES: usize = 15;
let players = (0..NUM_PARTIES).map(|_| Player::new()).collect::<Vec<_>>();
// Coordinator initializes
let mut coordinator = Coordinator::new();
// Phase 1: Commitments
for player in &players {
coordinator.receive_commitment(player.spairs_commitment());
}
// Phase 2: Random powers protocol
// Each player needs to output spairs
// Each player needs to output powers of tau in G1/G2
let mut powers_of_tau_g1: Vec<G1> = (0..cs.d+1).map(|_| G1::one()).collect::<Vec<_>>();
let mut powers_of_tau_g2: Vec<G2> = (0..cs.d+1).map(|_| G2::one()).collect::<Vec<_>>();
for (i, player) in players.iter().enumerate() {
// Players reveal their spairs, which we check against their commitments
assert!(coordinator.check_commitment(i, player.spairs.clone()));
// Players compute the powers of tau given the previous player
let (new_g1, new_g2) = player.exponentiate_with_tau(
&powers_of_tau_g1, &powers_of_tau_g2
);
// Coordinator checks the powers of tau were computed correctly.
assert!(coordinator.check_taupowers(&powers_of_tau_g1, &powers_of_tau_g2, &new_g1, &new_g2, i));
powers_of_tau_g1 = new_g1;
powers_of_tau_g2 = new_g2;
}
// Phase 3: Remote computation
// The coordinator performs an FFT and evaluates the QAP,
// also performing Z extention.
let (at, bt1, bt2, ct) = evaluate_qap(&powers_of_tau_g1, &powers_of_tau_g2, &cs);
// Phase 4: Random Coefficients, part I
let mut vk_A = G2::one();
let mut vk_B = G1::one();
let mut vk_C = G2::one();
let mut vk_Z = bt2[bt2.len() - 1]; // last value is Z(tau) in G2
let mut pk_A = at.clone();
let mut pk_A_prime = at.clone();
let mut pk_B = bt2.clone();
let mut pk_B_temp = bt1.clone(); // Compute pk_B in G1 although not part of the key to use for pk_K later
let mut pk_B_prime = bt1.clone();
let mut pk_C = ct.clone();
let mut pk_C_prime = ct.clone();
for (i, player) in players.iter().enumerate() {
let (
new_vk_A,
new_vk_B,
new_vk_C,
new_vk_Z,
new_pk_A,
new_pk_A_prime,
new_pk_B,
new_pk_B_temp,
new_pk_B_prime,
new_pk_C,
new_pk_C_prime
) = player.random_coeffs_part_one(
&vk_A,
&vk_B,
&vk_C,
&vk_Z,
&pk_A,
&pk_A_prime,
&pk_B,
&pk_B_temp,
&pk_B_prime,
&pk_C,
&pk_C_prime
);
assert!(coordinator.check_random_coeffs_part_one(
i,
&vk_A,
&vk_B,
&vk_C,
&vk_Z,
&pk_A,
&pk_A_prime,
&pk_B,
&pk_B_temp,
&pk_B_prime,
&pk_C,
&pk_C_prime,
&new_vk_A,
&new_vk_B,
&new_vk_C,
&new_vk_Z,
&new_pk_A,
&new_pk_A_prime,
&new_pk_B,
&new_pk_B_temp,
&new_pk_B_prime,
&new_pk_C,
&new_pk_C_prime
));
vk_A = new_vk_A;
vk_B = new_vk_B;
vk_C = new_vk_C;
vk_Z = new_vk_Z;
pk_A = new_pk_A;
pk_A_prime = new_pk_A_prime;
pk_B = new_pk_B;
pk_B_temp = new_pk_B_temp;
pk_B_prime = new_pk_B_prime;
pk_C = new_pk_C;
pk_C_prime = new_pk_C_prime;
}
// Phase 5: Random Coefficients, part II
let mut vk_gamma = G2::one();
let mut vk_beta_gamma_one = G1::one();
let mut vk_beta_gamma_two = G2::one();
// Initializing pk_K as pk_A + pk _B + pk_C
let mut pk_K = Vec::with_capacity(pk_A.len());
for ((&a, &b), &c) in pk_A.iter().take(pk_A.len() - 1)
.zip(pk_B_temp.iter().take(pk_B.len() - 1))
.zip(pk_C.iter().take(pk_C.len() - 1))
{
pk_K.push(a + b + c);
}
// Perform Z extention as libsnark does.
pk_K.push(pk_A[pk_A.len() - 1]);
pk_K.push(pk_B_temp[pk_B_temp.len() - 1]);
pk_K.push(pk_C[pk_C.len() - 1]);
for (i, player) in players.iter().enumerate() {
let (
new_vk_gamma,
new_vk_beta_gamma_one,
new_vk_beta_gamma_two,
new_pk_K
) = player.random_coeffs_part_two(
&vk_gamma,
&vk_beta_gamma_one,
&vk_beta_gamma_two,
&pk_K
);
assert!(coordinator.check_random_coeffs_part_two(
i,
&vk_gamma,
&vk_beta_gamma_one,
&vk_beta_gamma_two,
&pk_K,
&new_vk_gamma,
&new_vk_beta_gamma_one,
&new_vk_beta_gamma_two,
&new_pk_K
));
vk_gamma = new_vk_gamma;
vk_beta_gamma_one = new_vk_beta_gamma_one;
vk_beta_gamma_two = new_vk_beta_gamma_two;
pk_K = new_pk_K;
}
let produced_kp = Keypair::from(
&cs,
&pk_A,
&pk_A_prime,
&pk_B,
&pk_B_prime,
&pk_C,
&pk_C_prime,
&pk_K,
&powers_of_tau_g1,
&vk_A,
&vk_B,
&vk_C,
&vk_gamma,
&vk_beta_gamma_one,
&vk_beta_gamma_two,
&vk_Z
);
// Compare against libsnark:
{
let mut shared_secrets = Secrets::new_blank();
for player in &players {
player.test_multiply_secrets(&mut shared_secrets);
}
let target_kp = shared_secrets.keypair(&cs);
assert!(produced_kp == target_kp);
}
}

View File

@ -1,3 +1,4 @@
use bn::*;
use snark::*;
use crossbeam;
@ -6,7 +7,7 @@ use crossbeam;
/// Extends with Z(tau) as (effectively) done in libsnark.
pub fn evaluate_qap(g1_powers: &[G1], g2_powers: &[G2], cs: &CS) -> (Vec<G1>, Vec<G1>, Vec<G2>, Vec<G1>)
{
assert_eq!(g1_powers.len(), g2_powers.len());
assert_eq!(g1_powers.len(), cs.d+1);
assert_eq!(g2_powers.len(), cs.d+1);
let lc1 = lagrange_coeffs(&g1_powers[0..cs.d], cs.omega);
@ -25,7 +26,7 @@ pub fn evaluate_qap(g1_powers: &[G1], g2_powers: &[G2], cs: &CS) -> (Vec<G1>, Ve
fn evaluate_qap_polynomials(lc1: &[G1], lc2: &[G2], cs: &CS) -> (Vec<G1>, Vec<G1>, Vec<G2>, Vec<G1>)
{
assert_eq!(lc1.len(), lc2.len());
assert_eq!(lc1.len(), cs.d);
assert_eq!(lc2.len(), cs.d);
let mut at = (0..cs.num_vars).map(|_| G1::zero()).collect::<Vec<_>>();
@ -40,10 +41,11 @@ fn evaluate_qap_polynomials(lc1: &[G1], lc2: &[G2], cs: &CS) -> (Vec<G1>, Vec<G1
fn lagrange_coeffs<G: Group>(v: &[G], omega: Fr) -> Vec<G>
{
assert!(v.len() >= 2);
assert_eq!((v.len() / 2) * 2, v.len());
const THREADS: usize = 8;
let overd = Fr::from_str(&format!("{}", v.len())).inverse();
let overd = Fr::from_str(&format!("{}", v.len())).unwrap().inverse().unwrap();
let mut tmp = fft(v, omega, THREADS);
tmp.reverse(); // coefficients are in reverse
@ -112,57 +114,52 @@ fn fft<G: Group>(v: &[G], omega: Fr, threads: usize) -> Vec<G>
}
}
#[cfg(test)]
mod test {
use super::{lagrange_coeffs, evaluate_qap_polynomials};
use snark::*;
#[test]
fn compare_to_libsnark() {
use taupowers::*;
#[test]
fn compare_to_libsnark() {
initialize();
let rng = &mut ::rand::thread_rng();
// Get the QAP degree and omega (for FFT evaluation)
let cs = CS::dummy();
// Get the QAP degree and omega (for FFT evaluation)
let cs = CS::dummy();
// Sample a random tau
let tau = Fr::random();
// Sample a random tau
let tau = Fr::random(rng);
// Generate powers of tau in G1, from 0 to d exclusive of d
let powers_of_tau_g1 = TauPowers::new(tau).take(cs.d).map(|e| G1::one() * e).collect::<Vec<_>>();
// Generate powers of tau in G2, from 0 to d exclusive of d
let powers_of_tau_g2 = TauPowers::new(tau).take(cs.d).map(|e| G2::one() * e).collect::<Vec<_>>();
// Generate powers of tau in G1, from 0 to d exclusive of d
let powers_of_tau_g1 = TauPowers::new(tau).take(cs.d).map(|e| G1::one() * e).collect::<Vec<_>>();
// Generate powers of tau in G2, from 0 to d exclusive of d
let powers_of_tau_g2 = TauPowers::new(tau).take(cs.d).map(|e| G2::one() * e).collect::<Vec<_>>();
// Perform FFT to compute lagrange coeffs in G1/G2
let lc1 = lagrange_coeffs(&powers_of_tau_g1, cs.omega);
let lc2 = lagrange_coeffs(&powers_of_tau_g2, cs.omega);
// Perform FFT to compute lagrange coeffs in G1/G2
let lc1 = lagrange_coeffs(&powers_of_tau_g1, cs.omega);
let lc2 = lagrange_coeffs(&powers_of_tau_g2, cs.omega);
{
// Perform G1 FFT with wrong omega
let lc1 = lagrange_coeffs(&powers_of_tau_g1, Fr::random());
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!(!cs.test_compare_tau(&lc1, &lc2, &tau));
}
// Compare against libsnark
assert!(cs.test_compare_tau(&lc1, &lc2, &tau));
// Wrong tau
assert!(!cs.test_compare_tau(&lc1, &lc2, &Fr::random()));
let (at, bt1, bt2, ct) = evaluate_qap_polynomials(&lc1, &lc2, &cs);
// Compare evaluation with libsnark
assert!(cs.test_eval(&tau, &at, &bt1, &bt2, &ct));
// Wrong tau
assert!(!cs.test_eval(&Fr::random(), &at, &bt1, &bt2, &ct));
// Wrong polynomials
assert!(!cs.test_eval(&Fr::random(), &bt1, &bt1, &bt2, &ct));
{
// Perform G1 FFT with wrong omega
let lc1 = lagrange_coeffs(&powers_of_tau_g1, Fr::random(rng));
assert!(!cs.test_compare_tau(&lc1, &lc2, &tau));
}
{
// Perform G2 FFT with wrong omega
let lc2 = lagrange_coeffs(&powers_of_tau_g2, Fr::random(rng));
assert!(!cs.test_compare_tau(&lc1, &lc2, &tau));
}
// Compare against libsnark
assert!(cs.test_compare_tau(&lc1, &lc2, &tau));
// Wrong tau
assert!(!cs.test_compare_tau(&lc1, &lc2, &Fr::random(rng)));
let (at, bt1, bt2, ct) = evaluate_qap_polynomials(&lc1, &lc2, &cs);
// Compare evaluation with libsnark
assert!(cs.test_eval(&tau, &at, &bt1, &bt2, &ct));
// Wrong tau
assert!(!cs.test_eval(&Fr::random(rng), &at, &bt1, &bt2, &ct));
// Wrong polynomials
assert!(!cs.test_eval(&Fr::random(rng), &bt1, &bt1, &bt2, &ct));
}

View File

@ -1,130 +0,0 @@
use snark::*;
use sequences::*;
#[derive(Clone)]
pub struct Spair<G: Group> {
p: G,
q: G
}
impl<G: Group> Spair<G> {
pub fn random(s: &Fr) -> Self {
let p = G::random_nonzero();
Spair {
p: p,
q: p * (*s)
}
}
pub fn new(p: &G, q: &G) -> Option<Self> {
if p.is_zero() || q.is_zero() {
None
} else {
Some(Spair {
p: *p,
q: *q
})
}
}
}
pub fn same_power<Group1: Group, Group2: Group>(a: &Spair<Group1>, b: &Spair<Group2>) -> bool
where Group1: Pairing<Group2> {
pairing(&a.p, &b.q) == pairing(&a.q, &b.p)
}
/// This performs a check to see if a large number of (p,q) pairs in G
/// have the same power, with only one pairing.
pub fn check<'a,
Group1: Group,
Group2: Group,
I: IntoIterator<Item=(&'a Group1, &'a Group1)>>
(i: I, a: &Spair<Group2>) -> bool
where Group1: Pairing<Group2>
{
let mut p = Group1::zero();
let mut q = Group1::zero();
for v in i {
let alpha = Fr::random_nonzero();
p = p + *v.0 * alpha;
q = q + *v.1 * alpha;
}
if p.is_zero() || q.is_zero() { return false; }
same_power(&Spair::new(&p, &q).unwrap(), &a)
}
pub fn checkseq<'a,
Group1: Group,
Group2: Group,
I: Iterator<Item=&'a Group1>>
(i: I, a: &Spair<Group2>) -> bool
where Group1: Pairing<Group2>
{
check(Sequences::new(i), a)
}
#[test]
fn trivial_samepower() {
initialize();
let f = Fr::random();
let a = Spair::<G1>::random(&f);
let b = Spair::<G2>::random(&f);
let c = Spair::<G1>::random(&Fr::random());
assert!(same_power(&a, &b));
assert!(same_power(&b, &a));
assert!(!same_power(&b, &c));
}
#[test]
fn samepower_seq() {
initialize();
fn general_seq_test<Group1: Group, Group2: Group>()
where Group1: Pairing<Group2>
{
// Test working
{
let s = Fr::random();
let p = Spair::<Group2>::random(&s);
let mut a = vec![];
a.push(Group1::random());
for _ in 0..50 {
let n = *a.last().unwrap() * s;
a.push(n);
}
assert!(checkseq(a.iter(), &p));
}
// Test not working.
{
let s = Fr::random();
let p = Spair::<Group2>::random(&s);
let mut a = vec![];
a.push(Group1::random());
for i in 0..50 {
if i == 10 {
a.push(Group1::random());
} else {
let n = *a.last().unwrap() * s;
a.push(n);
}
}
assert!(!checkseq(a.iter(), &p));
}
}
general_seq_test::<G1, G2>();
general_seq_test::<G2, G1>();
}

359
src/spairs.rs Normal file
View File

@ -0,0 +1,359 @@
use bn::*;
use rand::Rng;
use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
use sequences::*;
pub type BlakeHash = [u8; 32];
#[derive(Clone, PartialEq, Eq)]
pub struct Spair<G: Group> {
f: G,
fs: G
}
impl<G: Group> Encodable for Spair<G> {
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
try!(self.f.encode(s));
try!(self.fs.encode(s));
Ok(())
}
}
impl<G: Group> Decodable for Spair<G> {
fn decode<S: Decoder>(s: &mut S) -> Result<Spair<G>, S::Error> {
let f = try!(G::decode(s));
let fs = try!(G::decode(s));
Spair::new(f, fs).ok_or_else(|| s.error("invalid s-pair"))
}
}
impl<G: Group> Spair<G> {
pub fn new(f: G, fs: G) -> Option<Self> {
if f.is_zero() || fs.is_zero() {
None
} else {
Some(Spair {
f: f,
fs: fs
})
}
}
pub fn random<R: Rng>(rng: &mut R, s: Fr) -> Option<Self> {
let f = G::random(rng);
Spair::new(f, f * s)
}
}
pub struct Secrets {
pub tau: Fr,
pub rho_a: Fr,
pub rho_b: Fr,
pub alpha_a: Fr,
pub alpha_b: Fr,
pub alpha_c: Fr,
pub beta: Fr,
pub gamma: Fr
}
impl Secrets {
pub fn new<R: Rng>(rng: &mut R) -> Secrets {
Secrets {
tau: Fr::random(rng),
rho_a: Fr::random(rng),
rho_b: Fr::random(rng),
alpha_a: Fr::random(rng),
alpha_b: Fr::random(rng),
alpha_c: Fr::random(rng),
beta: Fr::random(rng),
gamma: Fr::random(rng)
}
}
pub fn spairs<R: Rng>(&self, rng: &mut R) -> Spairs {
let f1 = G2::random(rng);
let f1pA = f1 * self.rho_a;
let f1pAaA = f1pA * self.alpha_a;
let f1pApB = f1pA * self.rho_b;
let f1pApBaC = f1pApB * self.alpha_c;
let f1pApBaB = f1pApB * self.alpha_b;
let f2 = G2::random(rng);
let f2beta = f2 * self.beta;
let f2betagamma = f2beta * self.gamma;
let tmp = Spairs {
tau: Spair::random(rng, self.tau).unwrap(),
f1: f1,
f1pA: f1pA,
f1pAaA: f1pAaA,
f1pApB: f1pApB,
f1pApBaC: f1pApBaC,
f1pApBaB: f1pApBaB,
f2: f2,
f2beta: f2beta,
f2betagamma: f2betagamma,
aA: Spair::random(rng, self.alpha_a).unwrap(),
aC: Spair::random(rng, self.alpha_c).unwrap(),
pB: Spair::random(rng, self.rho_b).unwrap(),
pApB: Spair::random(rng, self.rho_a * self.rho_b).unwrap(),
gamma: Spair::random(rng, self.gamma).unwrap()
};
assert!(tmp.is_valid());
tmp
}
}
#[derive(Clone, PartialEq, Eq)]
pub struct Spairs {
// TODO: use a getter for some of this stuff
pub tau: Spair<G2>,
f1: G2, // f1
f1pA: G2, // f1 * rho_a
f1pAaA: G2, // f1 * rho_a * alpha_a
f1pApB: G2, // f1 * rho_a * rho_b
f1pApBaC: G2, // f1 * rho_a * rho_b * alpha_c
f1pApBaB: G2, // f1 * rho_a * rho_b * alpha_b
f2: G2, // f2
f2beta: G2, // f2 * beta
f2betagamma: G2, // f2 * beta * gamma
pub aA: Spair<G1>, // (f3, f3 * alpha_a)
pub aC: Spair<G1>, // (f4, f4 * alpha_c)
pub pB: Spair<G1>, // (f5, f5 * rho_b)
pub pApB: Spair<G1>, // (f6, f6 * rho_a)
pub gamma: Spair<G1> // (f7, f7 * gamma)
}
impl Encodable for Spairs {
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
try!(self.tau.encode(s));
try!(self.f1.encode(s));
try!(self.f1pA.encode(s));
try!(self.f1pAaA.encode(s));
try!(self.f1pApB.encode(s));
try!(self.f1pApBaC.encode(s));
try!(self.f1pApBaB.encode(s));
try!(self.f2.encode(s));
try!(self.f2beta.encode(s));
try!(self.f2betagamma.encode(s));
try!(self.aA.encode(s));
try!(self.aC.encode(s));
try!(self.pB.encode(s));
try!(self.pApB.encode(s));
try!(self.gamma.encode(s));
Ok(())
}
}
impl Decodable for Spairs {
fn decode<S: Decoder>(s: &mut S) -> Result<Spairs, S::Error> {
let perhaps_valid = Spairs {
tau: try!(Spair::decode(s)),
f1: try!(G2::decode(s)),
f1pA: try!(G2::decode(s)),
f1pAaA: try!(G2::decode(s)),
f1pApB: try!(G2::decode(s)),
f1pApBaC: try!(G2::decode(s)),
f1pApBaB: try!(G2::decode(s)),
f2: try!(G2::decode(s)),
f2beta: try!(G2::decode(s)),
f2betagamma: try!(G2::decode(s)),
aA: try!(Spair::decode(s)),
aC: try!(Spair::decode(s)),
pB: try!(Spair::decode(s)),
pApB: try!(Spair::decode(s)),
gamma: try!(Spair::decode(s))
};
if perhaps_valid.is_valid() {
Ok(perhaps_valid)
} else {
Err(s.error("invalid spairs"))
}
}
}
impl Spairs {
pub fn hash(&self) -> BlakeHash {
// TODO
[0; 32]
}
fn is_valid(&self) -> bool {
!self.f1.is_zero() &&
!self.f1pA.is_zero() &&
!self.f1pAaA.is_zero() &&
!self.f1pApB.is_zero() &&
!self.f1pApBaC.is_zero() &&
!self.f1pApBaB.is_zero() &&
!self.f2.is_zero() &&
!self.f2beta.is_zero() &&
!self.f2betagamma.is_zero() &&
same_power(&self.aA, &Spair::new(self.f1pA, self.f1pAaA).unwrap()) &&
same_power(&self.aC, &Spair::new(self.f1pApB, self.f1pApBaC).unwrap()) &&
same_power(&self.pB, &Spair::new(self.f1pA, self.f1pApB).unwrap()) &&
same_power(&self.pApB, &Spair::new(self.f1, self.f1pApB).unwrap()) &&
same_power(&self.gamma, &Spair::new(self.f2beta, self.f2betagamma).unwrap())
}
pub fn alpha_b(&self) -> Spair<G2> {
Spair::new(self.f1pApB, self.f1pApBaB).unwrap()
}
pub fn rho_a(&self) -> Spair<G2> {
Spair::new(self.f1, self.f1pA).unwrap()
}
pub fn rho_b(&self) -> Spair<G2> {
Spair::new(self.f1pA, self.f1pApB).unwrap()
}
pub fn alpha_a_rho_a(&self) -> Spair<G2> {
Spair::new(self.f1, self.f1pAaA).unwrap()
}
pub fn alpha_b_rho_b(&self) -> Spair<G2> {
Spair::new(self.f1pA, self.f1pApBaB).unwrap()
}
pub fn rho_a_rho_b(&self) -> Spair<G2> {
Spair::new(self.f1, self.f1pApB).unwrap()
}
pub fn alpha_c_rho_a_rho_b(&self) -> Spair<G2> {
Spair::new(self.f1, self.f1pApBaC).unwrap()
}
pub fn beta(&self) -> Spair<G2> {
Spair::new(self.f2, self.f2beta).unwrap()
}
pub fn beta_gamma(&self) -> Spair<G2> {
Spair::new(self.f2, self.f2betagamma).unwrap()
}
}
pub trait Pairing<G: Group>: Group {
fn pairing(self, other: G) -> Gt;
}
impl Pairing<G2> for G1 {
fn pairing(self, other: G2) -> Gt {
pairing(self, other)
}
}
impl Pairing<G1> for G2 {
fn pairing(self, other: G1) -> Gt {
pairing(other, self)
}
}
pub fn same_power<Group1: Group, Group2: Group>(a: &Spair<Group1>, b: &Spair<Group2>) -> bool
where Group1: Pairing<Group2> {
a.f.pairing(b.fs) == a.fs.pairing(b.f)
}
/// This performs a check to see if a large number of (p,q) pairs in G
/// have the same power, with only one pairing.
pub fn check<'a,
R: Rng,
Group1: Group,
Group2: Group,
I: IntoIterator<Item=(&'a Group1, &'a Group1)>>
(rng: &mut R, i: I, a: &Spair<Group2>) -> bool
where Group1: Pairing<Group2>
{
let mut p = Group1::zero();
let mut q = Group1::zero();
for v in i {
let alpha = Fr::random(rng);
p = p + *v.0 * alpha;
q = q + *v.1 * alpha;
}
if p.is_zero() || q.is_zero() { return false; }
same_power(&Spair::new(p, q).unwrap(), &a)
}
pub fn checkseq<'a,
R: Rng,
Group1: Group,
Group2: Group,
I: Iterator<Item=&'a Group1>>
(rng: &mut R, i: I, a: &Spair<Group2>) -> bool
where Group1: Pairing<Group2>
{
check(rng, Sequences::new(i), a)
}
#[test]
fn trivial_samepower() {
let rng = &mut ::rand::thread_rng();
let f = Fr::random(rng);
let e = Fr::random(rng);
let a = Spair::<G1>::random(rng, f).unwrap();
let b = Spair::<G2>::random(rng, f).unwrap();
let c = Spair::<G1>::random(rng, e).unwrap();
assert!(same_power(&a, &b));
assert!(same_power(&b, &a));
assert!(!same_power(&b, &c));
}
#[test]
fn samepower_seq() {
fn general_seq_test<Group1: Group, Group2: Group>()
where Group1: Pairing<Group2>
{
let rng = &mut ::rand::thread_rng();
// Test working
{
let s = Fr::random(rng);
let p = Spair::<Group2>::random(rng, s).unwrap();
let mut a = vec![];
a.push(Group1::random(rng));
for _ in 0..50 {
let n = *a.last().unwrap() * s;
a.push(n);
}
assert!(checkseq(rng, a.iter(), &p));
}
// Test not working.
{
let s = Fr::random(rng);
let p = Spair::<Group2>::random(rng, s).unwrap();
let mut a = vec![];
a.push(Group1::random(rng));
for i in 0..50 {
if i == 10 {
a.push(Group1::random(rng));
} else {
let n = *a.last().unwrap() * s;
a.push(n);
}
}
assert!(!checkseq(rng, a.iter(), &p));
}
}
general_seq_test::<G1, G2>();
general_seq_test::<G2, G1>();
}

View File

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

512
src/transcript.rs Normal file
View File

@ -0,0 +1,512 @@
use bn::*;
use spairs::*;
use snark::*;
use taupowers::*;
use qap::*;
use rand::Rng;
trait State {
type Metadata;
}
/// We're currently receiving commitments.
struct ReceivingCommitments;
/// We're performing the powers of tau.
struct PowersOfTau {
commitments: Box<Iterator<Item=BlakeHash>>,
spairs: Vec<Spairs>,
prev_g1: Vec<G1>,
prev_g2: Vec<G2>
}
/// We're performing the first round of random coefficients.
struct RandomCoeffStage1 {
spairs: Vec<Spairs>,
powers_of_tau_g1: Vec<G1>,
at: Vec<G1>,
bt1: Vec<G1>,
bt2: Vec<G2>,
ct: Vec<G1>,
values: Stage1Values,
curplayer: usize
}
/// We're performing the second round of random coefficients.
struct RandomCoeffStage2 {
spairs: Vec<Spairs>,
powers_of_tau_g1: Vec<G1>,
coeffs_1: Stage1Values,
values: Stage2Values,
curplayer: usize
}
#[derive(Clone)]
struct Stage1Values {
vk_a: G2,
vk_b: G1,
vk_c: G2,
vk_z: G2,
pk_a: Vec<G1>,
pk_a_prime: Vec<G1>,
pk_b: Vec<G2>,
pk_b_temp: Vec<G1>, // compute pk_B in G1 for K query
pk_b_prime: Vec<G1>,
pk_c: Vec<G1>,
pk_c_prime: Vec<G1>
}
#[derive(Clone)]
struct Stage2Values {
vk_gamma: G2,
vk_beta_gamma_one: G1,
vk_beta_gamma_two: G2,
pk_k: Vec<G1>
}
impl Stage1Values {
fn new(at: &Vec<G1>, bt1: &Vec<G1>, bt2: &Vec<G2>, ct: &Vec<G1>) -> Self {
Stage1Values {
vk_a: G2::one(),
vk_b: G1::one(),
vk_c: G2::one(),
vk_z: bt2[bt2.len() - 1],
pk_a: at.clone(),
pk_a_prime: at.clone(),
pk_b: bt2.clone(),
pk_b_temp: bt1.clone(),
pk_b_prime: bt1.clone(),
pk_c: ct.clone(),
pk_c_prime: ct.clone()
}
}
}
impl State for ReceivingCommitments {
type Metadata = Vec<BlakeHash>;
}
impl State for PowersOfTau {
type Metadata = Self;
}
impl State for RandomCoeffStage1 {
type Metadata = Self;
}
impl State for RandomCoeffStage2 {
type Metadata = Self;
}
struct Transcript<'a, R: Rng, S: State> {
meta: S::Metadata,
cs: &'a CS,
rng: R
}
impl<'a, R: Rng> Transcript<'a, R, ReceivingCommitments> {
fn new(rng: R, cs: &'a CS) -> Self {
Transcript {
meta: vec![],
cs: cs,
rng: rng
}
}
fn take(&mut self, h: BlakeHash) {
self.meta.push(h);
}
fn next(self) -> Transcript<'a, R, PowersOfTau> {
Transcript {
meta: PowersOfTau {
commitments: Box::new(self.meta.into_iter()) as Box<Iterator<Item=BlakeHash>>,
spairs: vec![],
prev_g1: (0..self.cs.d+1).map(|_| G1::one()).collect(),
prev_g2: (0..self.cs.d+1).map(|_| G2::one()).collect()
},
cs: self.cs,
rng: self.rng
}
}
}
impl<'a, R: Rng> Transcript<'a, R, PowersOfTau> {
fn current(&self) -> (Vec<G1>, Vec<G2>) {
(self.meta.prev_g1.clone(), self.meta.prev_g2.clone())
}
fn take(
&mut self,
spairs: Spairs,
g1: Vec<G1>,
g2: Vec<G2>
) -> bool
{
if
g1.len() == self.meta.prev_g1.len() &&
g2.len() == self.meta.prev_g2.len() &&
g1[0] == G1::one() &&
g2[0] == G2::one() &&
!g1[1].is_zero() &&
!g2[1].is_zero() &&
// The player is supposed to multiply the i'th element
// by tau^i. Let's check one non-degenerate case in G1.
same_power(
&Spair::new(self.meta.prev_g1[1], g1[1]).unwrap(),
&spairs.tau
) &&
// Check that all G1 elements are exponentiated the same as G2 elements
checkseq(&mut self.rng, g1.iter(), &Spair::new(g2[0], g2[1]).unwrap()) &&
// Check that all G2 elements are exponentiated the same as G1 elements
checkseq(&mut self.rng, g2.iter(), &Spair::new(g1[0], g1[1]).unwrap())
{
self.meta.prev_g1 = g1;
self.meta.prev_g2 = g2;
// Check that the commitment is correct.
match self.meta.commitments.next() {
Some(commitment) => {
if spairs.hash() != commitment {
false
} else {
self.meta.spairs.push(spairs.clone());
true
}
},
None => false
}
} else {
false
}
}
fn next(self) -> Transcript<'a, R, RandomCoeffStage1> {
// evaluate QAP for the next round
let (at, bt1, bt2, ct) = evaluate_qap(&self.meta.prev_g1, &self.meta.prev_g2, &self.cs);
// initialize pieces of the params for the next round
let values = Stage1Values::new(&at, &bt1, &bt2, &ct);
Transcript {
meta: RandomCoeffStage1 {
spairs: self.meta.spairs,
powers_of_tau_g1: self.meta.prev_g1,
at: at,
bt1: bt1,
bt2: bt2,
ct: ct,
values: values,
curplayer: 0
},
cs: self.cs,
rng: self.rng
}
}
}
impl<'a, R: Rng> Transcript<'a, R, RandomCoeffStage1> {
fn current(&self) -> Stage1Values {
self.meta.values.clone()
}
fn take(
&mut self,
new_values: Stage1Values
) -> bool
{
if
new_values.vk_a.is_zero() ||
new_values.vk_b.is_zero() ||
new_values.vk_c.is_zero() ||
new_values.vk_z.is_zero() ||
// Sizes need to match up
new_values.pk_a.len() != self.meta.values.pk_a.len() ||
new_values.pk_a_prime.len() != self.meta.values.pk_a_prime.len() ||
new_values.pk_b.len() != self.meta.values.pk_b.len() ||
new_values.pk_b_temp.len() != self.meta.values.pk_b_temp.len() ||
new_values.pk_b_prime.len() != self.meta.values.pk_b_prime.len() ||
new_values.pk_c.len() != self.meta.values.pk_c.len() ||
new_values.pk_c_prime.len() != self.meta.values.pk_c_prime.len() ||
// Check parts of the verification key
!same_power(
&Spair::new(self.meta.values.vk_a, new_values.vk_a).unwrap(),
&self.meta.spairs[self.meta.curplayer].aA
) ||
!same_power(
&Spair::new(self.meta.values.vk_b, new_values.vk_b).unwrap(),
&self.meta.spairs[self.meta.curplayer].alpha_b()
) ||
!same_power(
&Spair::new(self.meta.values.vk_c, new_values.vk_c).unwrap(),
&self.meta.spairs[self.meta.curplayer].aC
) ||
!same_power(
&Spair::new(self.meta.values.vk_z, new_values.vk_z).unwrap(),
&self.meta.spairs[self.meta.curplayer].pApB
) ||
// Check parts of the proving key
!check(
&mut self.rng,
self.meta.values.pk_a.iter().zip(new_values.pk_a.iter()),
&self.meta.spairs[self.meta.curplayer].rho_a()
) ||
!check(
&mut self.rng,
self.meta.values.pk_a_prime.iter().zip(new_values.pk_a_prime.iter()),
&self.meta.spairs[self.meta.curplayer].alpha_a_rho_a()
) ||
!check(
&mut self.rng,
self.meta.values.pk_b.iter().zip(new_values.pk_b.iter()),
&self.meta.spairs[self.meta.curplayer].pB
) ||
!check(
&mut self.rng,
self.meta.values.pk_b_temp.iter().zip(new_values.pk_b_temp.iter()),
&self.meta.spairs[self.meta.curplayer].rho_b()
) ||
!check(
&mut self.rng,
self.meta.values.pk_b_prime.iter().zip(new_values.pk_b_prime.iter()),
&self.meta.spairs[self.meta.curplayer].alpha_b_rho_b()
) ||
!check(
&mut self.rng,
self.meta.values.pk_c.iter().zip(new_values.pk_c.iter()),
&self.meta.spairs[self.meta.curplayer].rho_a_rho_b()
) ||
!check(
&mut self.rng,
self.meta.values.pk_c_prime.iter().zip(new_values.pk_c_prime.iter()),
&self.meta.spairs[self.meta.curplayer].alpha_c_rho_a_rho_b()
)
{
self.meta.curplayer += 1;
return false;
} else {
self.meta.values = new_values;
self.meta.curplayer += 1;
return true;
}
}
fn next(self) -> Transcript<'a, R, RandomCoeffStage2> {
let mut pk_k = Vec::with_capacity(self.meta.values.pk_a.len()+3);
for ((&a, &b), &c) in self.meta.values.pk_a.iter().take(self.meta.values.pk_a.len() - 1)
.zip(self.meta.values.pk_b_temp.iter().take(self.meta.values.pk_b_temp.len() - 1))
.zip(self.meta.values.pk_c.iter().take(self.meta.values.pk_c.len() - 1))
{
pk_k.push(a + b + c);
}
// Perform Z extention as libsnark does.
pk_k.push(self.meta.values.pk_a[self.meta.values.pk_a.len() - 1]);
pk_k.push(self.meta.values.pk_b_temp[self.meta.values.pk_b_temp.len() - 1]);
pk_k.push(self.meta.values.pk_c[self.meta.values.pk_c.len() - 1]);
Transcript {
meta: RandomCoeffStage2 {
spairs: self.meta.spairs,
powers_of_tau_g1: self.meta.powers_of_tau_g1,
coeffs_1: self.meta.values,
values: Stage2Values {
vk_gamma: G2::one(),
vk_beta_gamma_one: G1::one(),
vk_beta_gamma_two: G2::one(),
pk_k: pk_k
},
curplayer: 0
},
cs: self.cs,
rng: self.rng
}
}
}
impl<'a, R: Rng> Transcript<'a, R, RandomCoeffStage2> {
fn current(&self) -> Stage2Values {
self.meta.values.clone()
}
fn take(
&mut self,
new_values: Stage2Values
) -> bool
{
if
new_values.vk_gamma.is_zero() ||
new_values.vk_beta_gamma_one.is_zero() ||
new_values.vk_beta_gamma_two.is_zero() ||
new_values.pk_k.len() != self.meta.values.pk_k.len() ||
!same_power(
&Spair::new(self.meta.values.vk_gamma, new_values.vk_gamma).unwrap(),
&self.meta.spairs[self.meta.curplayer].gamma
) ||
!same_power(
&Spair::new(self.meta.values.vk_beta_gamma_one, new_values.vk_beta_gamma_one).unwrap(),
&self.meta.spairs[self.meta.curplayer].beta_gamma()
) ||
!same_power(
&Spair::new(self.meta.values.vk_beta_gamma_two, new_values.vk_beta_gamma_two).unwrap(),
&Spair::new(self.meta.values.vk_beta_gamma_one, new_values.vk_beta_gamma_one).unwrap()
) ||
!check(
&mut self.rng,
self.meta.values.pk_k.iter().zip(new_values.pk_k.iter()),
&self.meta.spairs[self.meta.curplayer].beta()
)
{
self.meta.curplayer += 1;
return false;
} else {
self.meta.values = new_values;
self.meta.curplayer += 1;
return true;
}
}
fn keypair(&self) -> Keypair {
Keypair::from(
&self.cs,
&self.meta.coeffs_1.pk_a,
&self.meta.coeffs_1.pk_a_prime,
&self.meta.coeffs_1.pk_b,
&self.meta.coeffs_1.pk_b_prime,
&self.meta.coeffs_1.pk_c,
&self.meta.coeffs_1.pk_c_prime,
&self.meta.values.pk_k,
&self.meta.powers_of_tau_g1,
&self.meta.coeffs_1.vk_a,
&self.meta.coeffs_1.vk_b,
&self.meta.coeffs_1.vk_c,
&self.meta.values.vk_gamma,
&self.meta.values.vk_beta_gamma_one,
&self.meta.values.vk_beta_gamma_two,
&self.meta.coeffs_1.vk_z
)
}
}
#[test]
fn mpc_simulation() {
fn mul_all_by<G: Group>(v: &mut [G], c: Fr) {
for g in v {
*g = *g * c;
}
}
let cs = CS::dummy();
let rng = &mut ::rand::thread_rng();
const PARTIES: usize = 3;
let secrets = (0..PARTIES).map(|_| Secrets::new(rng)).collect::<Vec<_>>();
let spairs = secrets.iter().map(|s| s.spairs(rng)).collect::<Vec<_>>();
let commitments = spairs.iter().map(|s| s.hash()).collect::<Vec<_>>();
let mut transcript = Transcript::new(rng, &cs);
for i in &commitments {
transcript.take(*i);
}
let mut transcript = transcript.next();
// Random powers protocol
{
let (mut cur_g1, mut cur_g2) = transcript.current();
for (secrets, spairs) in secrets.iter().zip(spairs.iter()) {
for ((g1, g2), tp) in cur_g1.iter_mut().zip(cur_g2.iter_mut()).zip(TauPowers::new(secrets.tau)) {
*g1 = *g1 * tp;
*g2 = *g2 * tp;
}
assert!(transcript.take(spairs.clone(), cur_g1.clone(), cur_g2.clone()));
}
}
let mut transcript = transcript.next();
// Random coeff stage 1
{
let mut cur_values = transcript.current();
for secrets in secrets.iter() {
// Contribute to verification key
cur_values.vk_a = cur_values.vk_a * secrets.alpha_a;
cur_values.vk_b = cur_values.vk_b * secrets.alpha_b;
cur_values.vk_c = cur_values.vk_c * secrets.alpha_c;
cur_values.vk_z = cur_values.vk_z * (secrets.rho_a * secrets.rho_b);
// Contribute to proving key
mul_all_by(&mut cur_values.pk_a, secrets.rho_a);
mul_all_by(&mut cur_values.pk_a_prime, (secrets.rho_a * secrets.alpha_a));
mul_all_by(&mut cur_values.pk_b, secrets.rho_b);
mul_all_by(&mut cur_values.pk_b_temp, secrets.rho_b);
mul_all_by(&mut cur_values.pk_b_prime, (secrets.rho_b * secrets.alpha_b));
mul_all_by(&mut cur_values.pk_c, (secrets.rho_a * secrets.rho_b));
mul_all_by(&mut cur_values.pk_c_prime, (secrets.rho_a * secrets.rho_b * secrets.alpha_c));
assert!(transcript.take(cur_values.clone()));
}
}
let mut transcript = transcript.next();
// Random coeff stage 2
{
let mut cur_values = transcript.current();
for secrets in secrets.iter() {
let betagamma = secrets.beta * secrets.gamma;
cur_values.vk_gamma = cur_values.vk_gamma * secrets.gamma;
cur_values.vk_beta_gamma_one = cur_values.vk_beta_gamma_one * betagamma;
cur_values.vk_beta_gamma_two = cur_values.vk_beta_gamma_two * betagamma;
mul_all_by(&mut cur_values.pk_k, secrets.beta);
assert!(transcript.take(cur_values.clone()));
}
}
// Construct the final keypair:
let keypair = transcript.keypair();
{
// Compare with libsnark
let mut tau = Fr::one();
let mut alpha_a = Fr::one();
let mut alpha_b = Fr::one();
let mut alpha_c = Fr::one();
let mut rho_a = Fr::one();
let mut rho_b = Fr::one();
let mut beta = Fr::one();
let mut gamma = Fr::one();
for s in secrets {
tau = tau * s.tau;
alpha_a = alpha_a * s.alpha_a;
alpha_b = alpha_b * s.alpha_b;
alpha_c = alpha_c * s.alpha_c;
rho_a = rho_a * s.rho_a;
rho_b = rho_b * s.rho_b;
beta = beta * s.beta;
gamma = gamma * s.gamma;
}
let expected_keypair = Keypair::generate(
&cs,
&tau,
&alpha_a,
&alpha_b,
&alpha_c,
&rho_a,
&rho_b,
&beta,
&gamma
);
assert!(expected_keypair == keypair);
}
}