mirror of https://github.com/zcash/mpc.git
Implementation cleanup and reorganization.
This commit is contained in:
parent
15d017ab56
commit
5e838fe2b4
|
@ -26,18 +26,18 @@ extern "C" {
|
|||
lc2: *const G2,
|
||||
d: libc::uint64_t,
|
||||
vars: libc::uint64_t,
|
||||
At: *mut G1,
|
||||
Bt1: *mut G1,
|
||||
Bt2: *mut G2,
|
||||
Ct: *mut G1);
|
||||
at: *mut G1,
|
||||
bt1: *mut G1,
|
||||
bt2: *mut G2,
|
||||
ct: *mut G1);
|
||||
fn libsnarkwrap_test_eval(
|
||||
cs: *const libc::c_void,
|
||||
tau: *const Fr,
|
||||
vars: libc::uint64_t,
|
||||
At: *const G1,
|
||||
Bt1: *const G1,
|
||||
Bt2: *const G2,
|
||||
Ct: *const G1) -> bool;
|
||||
at: *const G1,
|
||||
bt1: *const G1,
|
||||
bt2: *const G2,
|
||||
ct: *const G1) -> bool;
|
||||
fn libsnarkwrap_test_compare_tau(
|
||||
i1: *const G1,
|
||||
i2: *const G2,
|
||||
|
@ -68,44 +68,49 @@ pub struct CS {
|
|||
}
|
||||
|
||||
impl CS {
|
||||
pub fn test_eval(&self, tau: &Fr, At: &[G1], Bt1: &[G1], Bt2: &[G2], Ct: &[G1]) -> bool {
|
||||
assert_eq!(At.len(), Bt1.len());
|
||||
assert_eq!(Bt1.len(), Bt2.len());
|
||||
assert_eq!(Bt2.len(), Ct.len());
|
||||
pub fn test_compare_tau(&self, v1: &[G1], v2: &[G2], tau: &Fr) -> bool {
|
||||
assert_eq!(v1.len(), v2.len());
|
||||
unsafe { libsnarkwrap_test_compare_tau(&v1[0], &v2[0], tau, v1.len() as u64, self.ptr) }
|
||||
}
|
||||
|
||||
pub fn test_eval(&self, tau: &Fr, at: &[G1], bt1: &[G1], bt2: &[G2], ct: &[G1]) -> bool {
|
||||
assert_eq!(at.len(), bt1.len());
|
||||
assert_eq!(bt1.len(), bt2.len());
|
||||
assert_eq!(bt2.len(), ct.len());
|
||||
|
||||
unsafe {
|
||||
libsnarkwrap_test_eval(self.ptr,
|
||||
tau,
|
||||
At.len() as u64,
|
||||
&At[0],
|
||||
&Bt1[0],
|
||||
&Bt2[0],
|
||||
&Ct[0])
|
||||
at.len() as u64,
|
||||
&at[0],
|
||||
&bt1[0],
|
||||
&bt2[0],
|
||||
&ct[0])
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eval(&self,
|
||||
Lt1: &[G1],
|
||||
Lt2: &[G2],
|
||||
At: &mut [G1],
|
||||
Bt1: &mut [G1],
|
||||
Bt2: &mut [G2],
|
||||
Ct: &mut [G1]) {
|
||||
assert_eq!(Lt1.len(), Lt2.len());
|
||||
assert_eq!(At.len(), Bt1.len());
|
||||
assert_eq!(Bt1.len(), Bt2.len());
|
||||
assert_eq!(Bt2.len(), Ct.len());
|
||||
lt1: &[G1],
|
||||
lt2: &[G2],
|
||||
at: &mut [G1],
|
||||
bt1: &mut [G1],
|
||||
bt2: &mut [G2],
|
||||
ct: &mut [G1]) {
|
||||
assert_eq!(lt1.len(), lt2.len());
|
||||
assert_eq!(at.len(), bt1.len());
|
||||
assert_eq!(bt1.len(), bt2.len());
|
||||
assert_eq!(bt2.len(), ct.len());
|
||||
|
||||
unsafe {
|
||||
libsnarkwrap_eval(self.ptr,
|
||||
&Lt1[0],
|
||||
&Lt2[0],
|
||||
Lt1.len() as u64,
|
||||
At.len() as u64,
|
||||
&mut At[0],
|
||||
&mut Bt1[0],
|
||||
&mut Bt2[0],
|
||||
&mut Ct[0]);
|
||||
<1[0],
|
||||
<2[0],
|
||||
lt1.len() as u64,
|
||||
at.len() as u64,
|
||||
&mut at[0],
|
||||
&mut bt1[0],
|
||||
&mut bt2[0],
|
||||
&mut ct[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -132,13 +137,6 @@ pub fn getcs() -> CS {
|
|||
}
|
||||
}
|
||||
|
||||
/// Check that the lagrange coefficients computed by tau over
|
||||
/// G1 equal the expected vector.
|
||||
pub fn compare_tau(v1: &[G1], v2: &[G2], tau: &Fr, cs: &CS) -> bool {
|
||||
assert_eq!(v1.len(), v2.len());
|
||||
unsafe { libsnarkwrap_test_compare_tau(&v1[0], &v2[0], tau, v1.len() as u64, cs.ptr) }
|
||||
}
|
||||
|
||||
pub trait Pairing<Other: Group> {
|
||||
fn g1<'a>(&'a self, other: &'a Other) -> &'a G1;
|
||||
fn g2<'a>(&'a self, other: &'a Other) -> &'a G2;
|
||||
|
|
|
@ -207,28 +207,6 @@ extern "C" void libsnarkwrap_dropcs(r1cs_constraint_system<curve_Fr> *cs)
|
|||
delete cs;
|
||||
}
|
||||
|
||||
extern "C" bool libsnarkwrap_test_compare_tau(
|
||||
const curve_G1 *inputs1,
|
||||
const curve_G2 *inputs2,
|
||||
const curve_Fr *tau,
|
||||
uint64_t d,
|
||||
const r1cs_constraint_system<curve_Fr> *cs
|
||||
)
|
||||
{
|
||||
auto qap = r1cs_to_qap_instance_map(*cs);
|
||||
auto coeffs = qap.domain->lagrange_coeffs(*tau);
|
||||
assert(coeffs.size() == d);
|
||||
assert(qap.degree() == d);
|
||||
|
||||
bool res = true;
|
||||
for (size_t i = 0; i < d; i++) {
|
||||
res &= (coeffs[i] * curve_G1::one()) == inputs1[i];
|
||||
res &= (coeffs[i] * curve_G2::one()) == inputs2[i];
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
extern "C" void libsnarkwrap_eval(
|
||||
const r1cs_constraint_system<curve_Fr> *cs,
|
||||
const curve_G1 *lc1,
|
||||
|
@ -266,6 +244,30 @@ extern "C" void libsnarkwrap_eval(
|
|||
}
|
||||
}
|
||||
|
||||
// Comparison tests
|
||||
|
||||
extern "C" bool libsnarkwrap_test_compare_tau(
|
||||
const curve_G1 *inputs1,
|
||||
const curve_G2 *inputs2,
|
||||
const curve_Fr *tau,
|
||||
uint64_t d,
|
||||
const r1cs_constraint_system<curve_Fr> *cs
|
||||
)
|
||||
{
|
||||
auto qap = r1cs_to_qap_instance_map(*cs);
|
||||
auto coeffs = qap.domain->lagrange_coeffs(*tau);
|
||||
assert(coeffs.size() == d);
|
||||
assert(qap.degree() == d);
|
||||
|
||||
bool res = true;
|
||||
for (size_t i = 0; i < d; i++) {
|
||||
res &= (coeffs[i] * curve_G1::one()) == inputs1[i];
|
||||
res &= (coeffs[i] * curve_G2::one()) == inputs2[i];
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
extern "C" bool libsnarkwrap_test_eval(
|
||||
const r1cs_constraint_system<curve_Fr> *cs,
|
||||
const curve_Fr *tau,
|
||||
|
|
|
@ -79,7 +79,7 @@ fn fft<G: Group>(v: &[G], omega: Fr, threads: usize) -> Vec<G>
|
|||
mod test {
|
||||
use super::lagrange_coeffs;
|
||||
use snark::*;
|
||||
use util::*;
|
||||
use taupowers::*;
|
||||
|
||||
#[test]
|
||||
fn compare_to_libsnark() {
|
||||
|
@ -103,35 +103,35 @@ mod test {
|
|||
{
|
||||
// Perform G1 FFT with wrong omega
|
||||
let lc1 = lagrange_coeffs(&powers_of_tau_g1, Fr::random());
|
||||
assert!(!compare_tau(&lc1, &lc2, &tau, &cs));
|
||||
assert!(!cs.test_compare_tau(&lc1, &lc2, &tau));
|
||||
}
|
||||
{
|
||||
// Perform G2 FFT with wrong omega
|
||||
let lc2 = lagrange_coeffs(&powers_of_tau_g2, Fr::random());
|
||||
assert!(!compare_tau(&lc1, &lc2, &tau, &cs));
|
||||
assert!(!cs.test_compare_tau(&lc1, &lc2, &tau));
|
||||
}
|
||||
|
||||
// Compare against libsnark
|
||||
assert!(compare_tau(&lc1, &lc2, &tau, &cs));
|
||||
assert!(cs.test_compare_tau(&lc1, &lc2, &tau));
|
||||
|
||||
// Wrong tau
|
||||
assert!(!compare_tau(&lc1, &lc2, &Fr::random(), &cs));
|
||||
assert!(!cs.test_compare_tau(&lc1, &lc2, &Fr::random()));
|
||||
|
||||
// Evaluate At, Ct in G1 and Bt in G1/G2
|
||||
let mut At = (0..cs.num_vars).map(|_| G1::zero()).collect::<Vec<_>>();
|
||||
let mut Bt1 = (0..cs.num_vars).map(|_| G1::zero()).collect::<Vec<_>>();
|
||||
let mut Bt2 = (0..cs.num_vars).map(|_| G2::zero()).collect::<Vec<_>>();
|
||||
let mut Ct = (0..cs.num_vars).map(|_| G1::zero()).collect::<Vec<_>>();
|
||||
let mut at = (0..cs.num_vars).map(|_| G1::zero()).collect::<Vec<_>>();
|
||||
let mut bt1 = (0..cs.num_vars).map(|_| G1::zero()).collect::<Vec<_>>();
|
||||
let mut bt2 = (0..cs.num_vars).map(|_| G2::zero()).collect::<Vec<_>>();
|
||||
let mut ct = (0..cs.num_vars).map(|_| G1::zero()).collect::<Vec<_>>();
|
||||
|
||||
cs.eval(&lc1, &lc2, &mut At, &mut Bt1, &mut Bt2, &mut Ct);
|
||||
cs.eval(&lc1, &lc2, &mut at, &mut bt1, &mut bt2, &mut ct);
|
||||
|
||||
// Compare evaluation with libsnark
|
||||
assert!(cs.test_eval(&tau, &At, &Bt1, &Bt2, &Ct));
|
||||
assert!(cs.test_eval(&tau, &at, &bt1, &bt2, &ct));
|
||||
|
||||
// Wrong tau
|
||||
assert!(!cs.test_eval(&Fr::random(), &At, &Bt1, &Bt2, &Ct));
|
||||
assert!(!cs.test_eval(&Fr::random(), &at, &bt1, &bt2, &ct));
|
||||
|
||||
// Wrong polynomials
|
||||
assert!(!cs.test_eval(&Fr::random(), &Bt1, &Bt1, &Bt2, &Ct));
|
||||
assert!(!cs.test_eval(&Fr::random(), &bt1, &bt1, &bt2, &ct));
|
||||
}
|
||||
}
|
||||
|
|
40
src/main.rs
40
src/main.rs
|
@ -1,48 +1,14 @@
|
|||
extern crate snark;
|
||||
extern crate crossbeam;
|
||||
|
||||
mod util;
|
||||
mod taupowers;
|
||||
mod sequences;
|
||||
mod lagrange;
|
||||
mod protocol;
|
||||
mod spair;
|
||||
|
||||
use snark::*;
|
||||
use protocol::*;
|
||||
use lagrange::*;
|
||||
|
||||
fn main() {
|
||||
initialize();
|
||||
|
||||
// Get the constraint system
|
||||
let cs = getcs();
|
||||
|
||||
// Initialize the players
|
||||
const NUM_PLAYERS: usize = 3;
|
||||
let players = (0..NUM_PLAYERS).map(|_| Player::new(&cs)).collect::<Vec<_>>();
|
||||
|
||||
// Phase 1 & 2 produces s-pairs for each player
|
||||
let spairs = players.iter().map(|p| p.spairs()).collect::<Vec<_>>();
|
||||
|
||||
// Phase 3 produces random powers of tau in G1/G2
|
||||
let (taupowers_g1, taupowers_g2) = {
|
||||
let mut transcript = vec![];
|
||||
|
||||
for (i, p) in players.iter().enumerate() {
|
||||
if i == 0 {
|
||||
transcript.push(p.randompowers_start().unwrap());
|
||||
} else {
|
||||
let v = p.randompowers(&transcript[i-1].0, &transcript[i-1].1).unwrap();
|
||||
transcript.push(v);
|
||||
}
|
||||
|
||||
// Verification
|
||||
assert!(verify_randompowers(&transcript[i],
|
||||
if i == 0 { None } else { Some(&transcript[i-1]) },
|
||||
&spairs[i]));
|
||||
}
|
||||
|
||||
transcript[NUM_PLAYERS-1].clone()
|
||||
};
|
||||
snark::initialize();
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,149 +0,0 @@
|
|||
use snark::*;
|
||||
use util::*;
|
||||
use lagrange::*;
|
||||
use spair::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ProtocolError {
|
||||
InvalidTauPowersSize
|
||||
}
|
||||
|
||||
pub struct Samples<T> {
|
||||
tau: T,
|
||||
rho_a: T,
|
||||
rho_b: T,
|
||||
alpha_a: T,
|
||||
alpha_b: T,
|
||||
alpha_c: T,
|
||||
beta: T,
|
||||
gamma: T
|
||||
}
|
||||
|
||||
pub struct Player<'a> {
|
||||
secrets: Samples<Fr>,
|
||||
cs: &'a CS
|
||||
}
|
||||
|
||||
impl<'a> Player<'a> {
|
||||
pub fn new(cs: &'a CS) -> Player {
|
||||
Player {
|
||||
secrets: Samples {
|
||||
tau: Fr::random_nonzero(),
|
||||
rho_a: Fr::random_nonzero(),
|
||||
rho_b: Fr::random_nonzero(),
|
||||
alpha_a: Fr::random_nonzero(),
|
||||
alpha_b: Fr::random_nonzero(),
|
||||
alpha_c: Fr::random_nonzero(),
|
||||
beta: Fr::random_nonzero(),
|
||||
gamma: Fr::random_nonzero()
|
||||
},
|
||||
cs: cs
|
||||
}
|
||||
}
|
||||
|
||||
pub fn spairs<G: Group>(&self) -> Samples<Spair<G>> {
|
||||
Samples {
|
||||
tau: Spair::random(&self.secrets.tau),
|
||||
rho_a: Spair::random(&self.secrets.rho_a),
|
||||
rho_b: Spair::random(&self.secrets.rho_b),
|
||||
alpha_a: Spair::random(&self.secrets.alpha_a),
|
||||
alpha_b: Spair::random(&self.secrets.alpha_b),
|
||||
alpha_c: Spair::random(&self.secrets.alpha_c),
|
||||
beta: Spair::random(&self.secrets.beta),
|
||||
gamma: Spair::random(&self.secrets.gamma)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn randompowers_start(&self) -> Result<(Vec<G1>, Vec<G2>), ProtocolError> {
|
||||
use std::iter::repeat;
|
||||
|
||||
let v1 = repeat(G1::one()).take(self.cs.d + 1).collect::<Vec<_>>();
|
||||
let v2 = repeat(G2::one()).take(self.cs.d + 1).collect::<Vec<_>>();
|
||||
|
||||
self.randompowers(&v1, &v2)
|
||||
}
|
||||
|
||||
pub fn randompowers(&self, v1: &[G1], v2: &[G2]) -> Result<(Vec<G1>, Vec<G2>), ProtocolError> {
|
||||
if (v1.len() != v2.len()) || (v1.len() != self.cs.d + 1) {
|
||||
return Err(ProtocolError::InvalidTauPowersSize)
|
||||
}
|
||||
|
||||
let mut t1 = Vec::with_capacity(self.cs.d + 1);
|
||||
let mut t2 = Vec::with_capacity(self.cs.d + 1);
|
||||
|
||||
for (i, tp) in TauPowers::new(self.secrets.tau).take(self.cs.d+1).enumerate() {
|
||||
t1.push(v1[i] * tp);
|
||||
t2.push(v2[i] * tp);
|
||||
}
|
||||
|
||||
Ok((t1, t2))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn verify_randompowers(
|
||||
current: &(Vec<G1>, Vec<G2>),
|
||||
last: Option<&(Vec<G1>, Vec<G2>)>,
|
||||
spair: &Samples<Spair<G2>>
|
||||
) -> bool {
|
||||
current.0[0] == G1::one() &&
|
||||
current.1[0] == G2::one() &&
|
||||
match last {
|
||||
Some(last) => {
|
||||
checkseq(current.0.iter(), &Spair::new(¤t.1[0], ¤t.1[1])) &&
|
||||
checkseq(current.1.iter(), &Spair::new(¤t.0[0], ¤t.0[1])) &&
|
||||
same_power(&Spair::new(&last.0[1], ¤t.0[1]), &spair.tau)
|
||||
},
|
||||
None => {
|
||||
checkseq(current.0.iter(), &spair.tau) &&
|
||||
checkseq(current.1.iter(), &Spair::new(¤t.0[0], ¤t.0[1]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn randompowers_test() {
|
||||
initialize();
|
||||
|
||||
const NUM_PARTIES: usize = 3;
|
||||
|
||||
let cs = getcs();
|
||||
|
||||
// All parties should initialize with their secret randomness
|
||||
let parties: Vec<Player> = (0..NUM_PARTIES).map(|_| Player::new(&cs)).collect();
|
||||
// All parties should reveal their s-pairs
|
||||
let spairs: Vec<Samples<Spair<G2>>> = parties.iter().map(|p| p.spairs()).collect();
|
||||
|
||||
let mut transcript = vec![];
|
||||
|
||||
for (i, p) in parties.iter().enumerate() {
|
||||
if i == 0 {
|
||||
transcript.push(p.randompowers_start().unwrap());
|
||||
} else {
|
||||
let v = p.randompowers(&transcript[i-1].0, &transcript[i-1].1).unwrap();
|
||||
transcript.push(v);
|
||||
}
|
||||
}
|
||||
|
||||
// Verification
|
||||
let mut last = None;
|
||||
for i in 0..NUM_PARTIES {
|
||||
// Wrong tau s-pair should fail
|
||||
assert!(!verify_randompowers(&transcript[i],
|
||||
last,
|
||||
&spairs[(i+1)%NUM_PARTIES]));
|
||||
|
||||
if last.is_some() {
|
||||
// Verifying against wrong last transcript should fail
|
||||
assert!(!verify_randompowers(&transcript[i],
|
||||
Some(&transcript[i]),
|
||||
&spairs[i]));
|
||||
}
|
||||
|
||||
// Correct check
|
||||
assert!(verify_randompowers(&transcript[i],
|
||||
last,
|
||||
&spairs[i]));
|
||||
|
||||
last = Some(&transcript[i]);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,3 @@
|
|||
use snark::Fr;
|
||||
|
||||
pub struct Sequences<'a, T: 'a, I: Iterator<Item=&'a T>> {
|
||||
v: I,
|
||||
last: Option<&'a T>
|
||||
|
@ -36,26 +34,3 @@ fn test_sequences() {
|
|||
let expected = vec![(&a[0], &a[1]), (&a[1], &a[2]), (&a[2], &a[3])];
|
||||
assert_eq!(b, expected);
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub struct TauPowers {
|
||||
acc: Fr,
|
||||
tau: Fr
|
||||
}
|
||||
|
||||
impl TauPowers {
|
||||
pub fn new(tau: Fr) -> TauPowers {
|
||||
TauPowers { acc: Fr::one(), tau: tau }
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for TauPowers {
|
||||
type Item = Fr;
|
||||
|
||||
fn next(&mut self) -> Option<Fr> {
|
||||
let tmp = self.acc;
|
||||
self.acc = tmp * self.tau;
|
||||
Some(tmp)
|
||||
}
|
||||
}
|
19
src/spair.rs
19
src/spair.rs
|
@ -1,5 +1,5 @@
|
|||
use snark::*;
|
||||
use util::*;
|
||||
use sequences::*;
|
||||
|
||||
pub struct Spair<G: Group> {
|
||||
p: G,
|
||||
|
@ -8,7 +8,7 @@ pub struct Spair<G: Group> {
|
|||
|
||||
impl<G: Group> Spair<G> {
|
||||
pub fn random(s: &Fr) -> Self {
|
||||
let mut p = G::zero();
|
||||
let mut p = G::random();
|
||||
|
||||
while p.is_zero() {
|
||||
p = G::random();
|
||||
|
@ -20,14 +20,14 @@ impl<G: Group> Spair<G> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn new(p: &G, q: &G) -> Self {
|
||||
pub fn new(p: &G, q: &G) -> Option<Self> {
|
||||
if p.is_zero() {
|
||||
panic!("tried to initialize spair with zero base")
|
||||
}
|
||||
|
||||
Spair {
|
||||
None
|
||||
} else {
|
||||
Some(Spair {
|
||||
p: *p,
|
||||
q: *q
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ where Group1: Pairing<Group2>
|
|||
|
||||
if p.is_zero() { return false; }
|
||||
|
||||
same_power(&Spair::new(&p, &q), &a)
|
||||
same_power(&Spair::new(&p, &q).unwrap(), &a)
|
||||
}
|
||||
|
||||
pub fn checkseq<'a,
|
||||
|
@ -132,8 +132,6 @@ fn samepower_seq() {
|
|||
general_seq_test::<G2, G1>();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
fn checkvec<'a,
|
||||
Group1: Group,
|
||||
Group2: Group,
|
||||
|
@ -198,4 +196,3 @@ fn samepower_vec() {
|
|||
samepower_test_each_group(10, 5);
|
||||
samepower_test_each_group(100, 50);
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
use snark;
|
||||
|
||||
pub struct TauPowers {
|
||||
acc: snark::Fr,
|
||||
tau: snark::Fr
|
||||
}
|
||||
|
||||
impl TauPowers {
|
||||
pub fn new(tau: snark::Fr) -> TauPowers {
|
||||
TauPowers { acc: snark::Fr::one(), tau: tau }
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for TauPowers {
|
||||
type Item = snark::Fr;
|
||||
|
||||
fn next(&mut self) -> Option<snark::Fr> {
|
||||
let tmp = self.acc;
|
||||
self.acc = tmp * self.tau;
|
||||
Some(tmp)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tau_powers() {
|
||||
snark::initialize();
|
||||
|
||||
let tau = snark::Fr::random();
|
||||
let mut taupowers = TauPowers::new(tau);
|
||||
assert!(taupowers.next() == Some(snark::Fr::one()));
|
||||
assert!(taupowers.next() == Some(tau));
|
||||
assert!(taupowers.next() == Some(tau * tau));
|
||||
assert!(taupowers.next() == Some(tau * tau * tau));
|
||||
}
|
Loading…
Reference in New Issue