diff --git a/src/fields/fp.rs b/src/fields/fp.rs index 8b97bbd..4bb3c62 100644 --- a/src/fields/fp.rs +++ b/src/fields/fp.rs @@ -181,7 +181,12 @@ impl<'a, P: PrimeFieldParams> From<&'a str> for Fp
{
}
impl {
- fn clone(&self) -> Self { unimplemented!() }
+ fn clone(&self) -> Self {
+ Fp {
+ value: self.value.clone(),
+ _marker: PhantomData
+ }
+ }
}
forward_ops_to_field_ops!(impl(P: PrimeFieldParams) Fp );
diff --git a/src/macros.rs b/src/fields/macros.rs
similarity index 100%
rename from src/macros.rs
rename to src/fields/macros.rs
diff --git a/src/fields/mod.rs b/src/fields/mod.rs
index 0d286a0..1bd6a67 100644
--- a/src/fields/mod.rs
+++ b/src/fields/mod.rs
@@ -1,3 +1,6 @@
+#[macro_use]
+mod macros;
+
pub mod fp;
#[cfg(test)]
@@ -5,8 +8,9 @@ pub mod tests;
use rand::Rng;
use self::fp::{Fp, PrimeFieldParams};
+use std::fmt::Debug;
-pub trait Field: Sized + Clone {
+pub trait Field: Sized + Clone + Debug {
fn zero() -> Self;
fn one() -> Self;
fn random {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{}({:?}, {:?}, {:?})", P::name(), self.x, self.y, self.z)
+ }
+}
+
+impl {
+ fn clone(&self) -> Self {
+ Jacobian {
+ x: self.x.clone(),
+ y: self.y.clone(),
+ z: self.z.clone()
+ }
+ }
+}
+pub enum Affine {
+ fn clone(&self) -> Self {
+ match *self {
+ Affine::Zero => Affine::Zero,
+ Affine::Point{ref x, ref y} => Affine::Point{x: x.clone(), y: y.clone()}
+ }
+ }
+}
+
+impl {
+/*
+ fn to_jacobian(self) -> Jacobian {
+ match self {
+ Affine::Zero => P::zero(),
+ Affine::Point{x, y} => Jacobian {
+ x: x,
+ y: y,
+ z: P::Base::one()
+ }
+ }
+ }
+*/
+}
+
+impl {
+ pub fn new(x: P::Base, y: P::Base, z: P::Base) -> Option {
+ if self.is_zero() {
+ Affine::Zero
+ } else {
+ let z_inv = self.z.inverse();
+ let z2_inv = z_inv.squared();
+ let z3_inv = z2_inv.mul(&z_inv);
+
+ Affine::Point {
+ x: self.x.mul(&z2_inv),
+ y: self.y.mul(&z3_inv)
+ }
+ }
+ }
+
+ pub fn zero() -> Self {
+ P::zero()
+ }
+
+ pub fn one() -> Self {
+ P::one()
+ }
+
+ pub fn add(&self, other: &Self) -> Self {
+ if self.is_zero() {
+ return other.clone()
+ }
+
+ if other.is_zero() {
+ return self.clone()
+ }
+
+ let z1_squared = self.z.squared();
+ let z2_squared = other.z.squared();
+ let u1 = self.x.mul(&z2_squared);
+ let u2 = other.x.mul(&z1_squared);
+ let z1_cubed = self.z.mul(&z1_squared);
+ let z2_cubed = other.z.mul(&z2_squared);
+ let s1 = self.y.mul(&z2_cubed);
+ let s2 = other.y.mul(&z1_cubed);
+
+ if u1.eq(&u2) && s1.eq(&s2) {
+ self.double()
+ } else {
+ let h = u2.sub(&u1);
+ let s2_minus_s1 = s2.sub(&s1);
+ let i = h.add(&h).squared();
+ let j = h.mul(&i);
+ let r = s2_minus_s1.add(&s2_minus_s1);
+ let v = u1.mul(&i);
+ let s1_j = s1.mul(&j);
+ let x3 = r.squared().sub(&j).sub(&v.add(&v));
+ let y3 = r.mul(&v.sub(&x3)).sub(&s1_j.add(&s1_j));
+
+ Jacobian {
+ x: x3,
+ y: y3,
+ z: self.z.add(&other.z).squared().sub(&z1_squared).sub(&z2_squared).mul(&h)
+ }
+ }
+ }
+
+ pub fn double(&self) -> Self {
+ let a = self.x.squared();
+ let b = self.y.squared();
+ let c = b.squared();
+ let mut d = self.x.add(&b).squared().sub(&a).sub(&c);
+ d = d.add(&d);
+ let e = a.add(&a).add(&a);
+ let f = e.squared();
+ let x3 = f.sub(&d.add(&d));
+ let mut eight_c = c.add(&c);
+ eight_c = eight_c.add(&eight_c);
+ eight_c = eight_c.add(&eight_c);
+ let y3 = e.mul(&d.sub(&x3)).sub(&eight_c);
+ let y1z1 = self.y.mul(&self.z);
+ let z3 = y1z1.add(&y1z1);
+
+ Jacobian {
+ x: x3,
+ y: y3,
+ z: z3
+ }
+ }
+
+ pub fn eq(&self, other: &Self) -> bool {
+ if self.is_zero() {
+ return other.is_zero()
+ }
+
+ if other.is_zero() {
+ return false;
+ }
+
+ let z1_squared = self.z.squared();
+ let z2_squared = other.z.squared();
+
+ if self.x.mul(&z2_squared).ne(&other.x.mul(&z1_squared)) {
+ return false;
+ }
+
+ let z1_cubed = self.z.mul(&z1_squared);
+ let z2_cubed = other.z.mul(&z2_squared);
+
+ if self.y.mul(&z2_cubed).ne(&other.y.mul(&z1_cubed)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ pub fn neg(&self) -> Self {
+ Jacobian {
+ x: self.x.clone(),
+ y: self.y.neg(),
+ z: self.z.clone()
+ }
+ }
+
+ #[inline]
+ pub fn is_zero(&self) -> bool {
+ self.z.is_zero()
+ }
+
+ pub fn mul {
+ let mut result = Jacobian:: ::zero();
+ let mut found_one = false;
+ for i in (0..S::bits()).rev() {
+ if found_one {
+ result = result.double();
+ }
+
+ if other.test_bit(i) {
+ found_one = true;
+ result = &result + self;
+ }
+ }
+
+ result
+ }
+
+ #[inline]
+ pub fn sub(&self, other: &Self) -> Jacobian {
+ self.add(&other.neg())
+ }
+}
+
+forward_ops_to_group_ops!(impl(P: GroupParams) Jacobian );
diff --git a/src/groups/tests.rs b/src/groups/tests.rs
new file mode 100644
index 0000000..1f3d267
--- /dev/null
+++ b/src/groups/tests.rs
@@ -0,0 +1,76 @@
+use super::*;
+use ::Fr;
+use fields::Field;
+
+use rand::Rng;
+
+pub fn group_trials = Jacobian ;
+
+ let one = G:: ::one();
+ let two = one.add(&one);
+ let three = two.add(&one);
+ let four = three.add(&one);
+
+ assert_eq!(one.double(), two);
+ assert_eq!(two.double(), four);
+ }
+
+ fn random_test_addition = Jacobian ;
+
+ for _ in 0..50 {
+ let r1 = &G:: ::random(rng);
+ let r2 = &G:: ::random(rng);
+ let r3 = &G:: ::random(rng);
+
+ let s1 = (r1 + r2) + r3;
+ let s2 = (r2 + r3) + r1;
+
+ assert_eq!(s1, s2);
+ }
+ }
+
+ fn random_test_doubling = Jacobian ;
+
+ for _ in 0..50 {
+ let r1 = &G:: ::random(rng);
+ let r2 = &G:: ::random(rng);
+
+ let a = (r1 + r2) + r1;
+ let b = r1.double() + r2;
+
+ assert!(a.eq(&b));
+ }
+ }
+
+ fn random_test_dh = Jacobian ;
+
+ for _ in 0..50 {
+ let alice_sk = Fr::random(rng);
+ let bob_sk = Fr::random(rng);
+
+ let alice_pk = G:: ::one() * &alice_sk;
+ let bob_pk = G:: ::one() * &bob_sk;
+
+ let alice_shared = &bob_pk * &alice_sk;
+ let bob_shared = &alice_pk * &bob_sk;
+
+ assert_eq!(alice_shared, bob_shared);
+ }
+ }
+
+ test_doubling:: ();
+
+ use rand::{SeedableRng,StdRng};
+ let seed: [usize; 4] = [103245, 191922, 1293, 192103];
+ let mut rng = StdRng::from_seed(&seed);
+
+ random_test_addition:: (&mut rng);
+ random_test_doubling:: (&mut rng);
+ random_test_dh:: (&mut rng);
+}
+
diff --git a/src/lib.rs b/src/lib.rs
index 886d1d7..2b273c3 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,7 +1,18 @@
extern crate num;
extern crate rand;
-#[macro_use]
-mod macros;
mod fields;
mod params;
+
+mod groups;
+
+pub use fields::fp::Fp;
+pub use params::{FrParams,FqParams,G1Params};
+pub use fields::Field;
+pub use groups::Jacobian;
+
+pub type Fr = Fp) -> Jacobian