mirror of https://github.com/zcash/mpc.git
Switch to using BN crate and refactor implementation.
This commit is contained in:
parent
5e6e1f7f7d
commit
96989f61ac
|
@ -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)",
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -16,3 +16,4 @@ gcc = "0.3.*"
|
|||
[dependencies]
|
||||
libc = "0.2.*"
|
||||
lazy_static = "0.1.*"
|
||||
bn = "0.2.2"
|
||||
|
|
158
snark/src/fr.rs
158
snark/src/fr.rs
|
@ -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());
|
||||
}
|
|
@ -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) }
|
||||
}
|
||||
}
|
|
@ -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) }
|
||||
}
|
||||
}
|
|
@ -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) }
|
||||
}
|
||||
}
|
230
snark/src/lib.rs
230
snark/src/lib.rs
|
@ -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>();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
||||
}
|
||||
|
|
613
src/protocol.rs
613
src/protocol.rs
|
@ -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);
|
||||
}
|
||||
}
|
93
src/qap.rs
93
src/qap.rs
|
@ -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));
|
||||
}
|
||||
|
|
130
src/spair.rs
130
src/spair.rs
|
@ -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>();
|
||||
}
|
|
@ -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>();
|
||||
}
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue