From c05c8c0d90b06226e0decbe8f3931afbde5ad91a Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Tue, 2 Aug 2016 16:14:05 -0600 Subject: [PATCH] Randompowers subprotocol simulation --- README.md | 2 +- snark/src/fr.rs | 40 ++++++++++++++++++++++ snark/src/libsnarkwrap.cpp | 12 ++++--- src/randompowers.rs | 70 +++++++++++++++++++++++++++++++++++++- src/util.rs | 8 +++++ 5 files changed, 126 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 88df415..1b8fe4b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # mpc -This is a multi-party computation protocol for the key-generation step of Pinnochio zkSNARKs [[PGHR13]](https://eprint.iacr.org/2013/279) designed for use in the Zcash "Sprout" public parameter ceremony. +This is a multi-party computation protocol for the key-generation step of Pinocchio zkSNARKs [[PGHR13]](https://eprint.iacr.org/2013/279) designed for use in the Zcash "Sprout" public parameter ceremony. ## License diff --git a/snark/src/fr.rs b/snark/src/fr.rs index dd2ee0b..2a71374 100644 --- a/snark/src/fr.rs +++ b/snark/src/fr.rs @@ -14,6 +14,7 @@ extern "C" { 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_is_zero(a: *const Fr) -> bool; } impl Fr { @@ -21,6 +22,20 @@ impl Fr { unsafe { libsnarkwrap_Fr_random() } } + pub fn is_zero(&self) -> bool { + unsafe { libsnarkwrap_Fr_is_zero(self) } + } + + 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' && @@ -74,3 +89,28 @@ impl Neg for Fr { unsafe { libsnarkwrap_Fr_neg(&self) } } } + +#[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"); + + assert!(ab == (a * b)); + assert!(aplusb == (a + b)); + assert!(aminusb == (a - b)); + assert!(aneg == (-a)); +} + +#[test] +fn test_primitives() { + let a = Fr::from_str("0"); + assert!(a.is_zero()); + let a = Fr::from_str("1"); + assert!(!a.is_zero()); +} diff --git a/snark/src/libsnarkwrap.cpp b/snark/src/libsnarkwrap.cpp index 084a0a0..406330c 100644 --- a/snark/src/libsnarkwrap.cpp +++ b/snark/src/libsnarkwrap.cpp @@ -33,22 +33,26 @@ extern "C" FieldT libsnarkwrap_Fr_from(const char *a) { return FieldT(a); } -extern "C" FieldT libsnarkwrap_Fr_add(const char *a, const char *b) { +extern "C" FieldT libsnarkwrap_Fr_add(FieldT *a, FieldT *b) { return *a + *b; } -extern "C" FieldT libsnarkwrap_Fr_sub(const char *a, const char *b) { +extern "C" FieldT libsnarkwrap_Fr_sub(FieldT *a, FieldT *b) { return *a - *b; } -extern "C" FieldT libsnarkwrap_Fr_mul(const char *a, const char *b) { +extern "C" FieldT libsnarkwrap_Fr_mul(FieldT *a, FieldT *b) { return *a * *b; } -extern "C" FieldT libsnarkwrap_Fr_neg(const char *a) { +extern "C" FieldT libsnarkwrap_Fr_neg(FieldT *a) { return -(*a); } +extern "C" bool libsnarkwrap_Fr_is_zero(FieldT *a) { + return a->is_zero(); +} + // G1 extern "C" alt_bn128_G1 libsnarkwrap_G1_zero() { diff --git a/src/randompowers.rs b/src/randompowers.rs index 510b95a..6e6ee73 100644 --- a/src/randompowers.rs +++ b/src/randompowers.rs @@ -37,6 +37,8 @@ where Group1: Pairing { 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. fn check<'a, Group1: Group, Group2: Group, @@ -48,7 +50,7 @@ where Group1: Pairing let mut q = Group1::zero(); for v in i { - let alpha = Fr::random(); + let alpha = Fr::random_nonzero(); p = p + *v.0 * alpha; q = q + *v.1 * alpha; } @@ -78,6 +80,72 @@ where Group1: Pairing check(Sequences::new(i), a) } +struct TauPowers { + acc: Fr, + tau: Fr +} + +impl TauPowers { + fn new(tau: Fr) -> TauPowers { + TauPowers { acc: Fr::from_str("1"), tau: tau } + } +} + +impl Iterator for TauPowers { + type Item = Fr; + + fn next(&mut self) -> Option { + let tmp = self.acc; + self.acc = tmp * self.tau; + Some(tmp) + } +} + +#[test] +fn randompowers_simulation() { + initialize(); + + let parties = 3; + let d = 1024; + + let mut messages: Vec<(Spair, Vec, Vec)> = vec![]; + messages.reserve(parties); + + for i in 0..parties { + let tau = Fr::random_nonzero(); + let rp = Spair::random(&tau); + + if i == 0 { + messages.push(( + rp, + TauPowers::new(tau).map(|p| G1::one() * p).take(d).collect(), + TauPowers::new(tau).map(|p| G2::one() * p).take(d).collect() + )); + } else { + let v1 = messages[i-1].1.iter().zip(TauPowers::new(tau)).map(|(b, p)| *b * p).collect(); + let v2 = messages[i-1].2.iter().zip(TauPowers::new(tau)).map(|(b, p)| *b * p).collect(); + + messages.push(( + rp, + v1, + v2 + )); + } + } + + // Check validity + for i in 0..parties { + if i == 0 { + assert!(checkseq(messages[i].1.iter(), &messages[i].0)); + assert!(checkseq(messages[i].2.iter(), &Spair::new(&messages[i].1[0], &messages[i].1[1]))); + } else { + assert!(checkseq(messages[i].1.iter(), &Spair::new(&messages[i].2[0], &messages[i].2[1]))); + assert!(checkseq(messages[i].2.iter(), &Spair::new(&messages[i].1[0], &messages[i].1[1]))); + assert!(same_power(&Spair::new(&messages[i-1].1[1], &messages[i].1[1]), &messages[i].0)); + } + } +} + #[test] fn samepower_seq() { initialize(); diff --git a/src/util.rs b/src/util.rs index 5eb483c..eab9f2a 100644 --- a/src/util.rs +++ b/src/util.rs @@ -26,3 +26,11 @@ impl<'a, T: 'a, I: Iterator> Iterator for Sequences<'a, T, I> { } } } + +#[test] +fn test_sequences() { + let a = vec![10, 57, 34, 12]; + let b: Vec<(&usize, &usize)> = Sequences::new(a.iter()).collect(); + let expected = vec![(&a[0], &a[1]), (&a[1], &a[2]), (&a[2], &a[3])]; + assert_eq!(b, expected); +}