diff --git a/snark/src/lib.rs b/snark/src/lib.rs index b217939..68a0a2b 100644 --- a/snark/src/lib.rs +++ b/snark/src/lib.rs @@ -34,8 +34,31 @@ pub fn initialize() { } } -pub fn pairing(p: &G1, q: &G2) -> Gt { - unsafe { libsnarkwrap_pairing(p, q) } +pub trait Pairing { + fn g1<'a>(&'a self, other: &'a Other) -> &'a G1; + fn g2<'a>(&'a self, other: &'a Other) -> &'a G2; +} + +impl Pairing 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 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(p: &Ga, q: &Gb) -> Gt where Ga: Pairing { + unsafe { libsnarkwrap_pairing(p.g1(q), p.g2(q)) } } pub trait Group: Sized + @@ -45,7 +68,8 @@ pub trait Group: Sized + Add + Sub + Neg + - PartialEq { + PartialEq + + 'static { fn zero() -> Self; fn one() -> Self; fn random() -> Self; @@ -73,6 +97,20 @@ fn pairing_test() { } } +#[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}; diff --git a/src/main.rs b/src/main.rs index cd4b9c0..e2e81f9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,12 @@ extern crate snark; +mod randompowers; +mod util; + use snark::*; fn main() { - initialize(); + initialize(); + + } diff --git a/src/randompowers.rs b/src/randompowers.rs new file mode 100644 index 0000000..510b95a --- /dev/null +++ b/src/randompowers.rs @@ -0,0 +1,196 @@ +use snark::*; +use util::Sequences; + +struct Spair { + p: G, + q: G +} + +impl Spair { + fn random(s: &Fr) -> Self { + let mut p = G::zero(); + + while p.is_zero() { + p = G::random(); + } + + Spair { + p: p, + q: p * (*s) + } + } + + fn new(p: &G, q: &G) -> Self { + if p.is_zero() { + panic!("tried to initialize spair with zero base") + } + + Spair { + p: *p, + q: *q + } + } +} + +fn same_power(a: &Spair, b: &Spair) -> bool +where Group1: Pairing { + pairing(&a.p, &b.q) == pairing(&a.q, &b.p) +} + +fn check<'a, + Group1: Group, + Group2: Group, + I: IntoIterator> + (i: I, a: &Spair) -> bool +where Group1: Pairing +{ + let mut p = Group1::zero(); + let mut q = Group1::zero(); + + for v in i { + let alpha = Fr::random(); + p = p + *v.0 * alpha; + q = q + *v.1 * alpha; + } + + if p.is_zero() { return false; } + + same_power(&Spair::new(&p, &q), &a) +} + +fn checkvec<'a, + Group1: Group, + Group2: Group, + I: IntoIterator>> + (i: I, a: &Spair) -> bool +where Group1: Pairing +{ + check(i.into_iter().map(|s| (&s.p, &s.q)), a) +} + +fn checkseq<'a, + Group1: Group, + Group2: Group, + I: Iterator> + (i: I, a: &Spair) -> bool +where Group1: Pairing +{ + check(Sequences::new(i), a) +} + +#[test] +fn samepower_seq() { + initialize(); + + fn general_seq_test() + where Group1: Pairing + { + // Test working + { + let s = Fr::random(); + let p = Spair::::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::::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::(); + general_seq_test::(); +} + +#[test] +fn samepower_vec() { + initialize(); + + fn samepower_general_test(i: usize, f: usize) + where Group1: Pairing + { + // Test working + { + let s = Fr::random(); + let p = Spair::::random(&s); + + let a: Vec> = (0..i).map(|_| Spair::random(&s)).collect(); + + assert!(checkvec(&a, &p)); + } + + // Test different scalar + { + let s = Fr::random(); + let p = Spair::::random(&Fr::random()); + + let a: Vec> = (0..i).map(|_| Spair::random(&s)).collect(); + + assert!(!checkvec(&a, &p)); + } + + // Test incorrect spair + { + let s = Fr::random(); + let p = Spair::::random(&s); + + let a: Vec> = (0..i).map(|i| { + if i == f { + Spair::random(&Fr::random()) + } else { + Spair::random(&s) + } + }).collect(); + + assert!(!checkvec(&a, &p)); + } + } + + fn samepower_test_each_group(i: usize, f: usize) + { + samepower_general_test::(i, f); + samepower_general_test::(i, f); + } + + samepower_test_each_group(1, 0); + samepower_test_each_group(10, 5); + samepower_test_each_group(100, 50); +} + +#[test] +fn trivial_samepower() { + initialize(); + + let f = Fr::random(); + let a = Spair::::random(&f); + let b = Spair::::random(&f); + let c = Spair::::random(&Fr::random()); + + assert!(same_power(&a, &b)); + assert!(same_power(&b, &a)); + assert!(!same_power(&b, &c)); +} diff --git a/src/util.rs b/src/util.rs new file mode 100644 index 0000000..5eb483c --- /dev/null +++ b/src/util.rs @@ -0,0 +1,28 @@ +pub struct Sequences<'a, T: 'a, I: Iterator> { + v: I, + last: Option<&'a T> +} + +impl<'a, T: 'a, I: Iterator> Sequences<'a, T, I> { + pub fn new(v: I) -> Self { + Sequences { v: v, last: None } + } +} + +impl<'a, T: 'a, I: Iterator> Iterator for Sequences<'a, T, I> { + type Item = (&'a T, &'a T); + + fn next(&mut self) -> Option<(&'a T, &'a T)> { + match (self.last, self.v.next()) { + (Some(a), Some(b)) => { + self.last = Some(b); + Some((a, b)) + }, + (None, Some(b)) => { + self.last = Some(b); + self.next() + }, + _ => None + } + } +}