diff --git a/src/fields/fp.rs b/src/fields/fp.rs index 3773bc1..5ab6ca2 100644 --- a/src/fields/fp.rs +++ b/src/fields/fp.rs @@ -51,12 +51,6 @@ impl Field for Fp

{ } } - fn is_zero(&self) -> bool { - use num::Zero; - - self.value == BigUint::zero() - } - fn inverse(&self) -> Self { if self.is_zero() { // TODO: this should likely bleed through the abstraction layers diff --git a/src/fields/fp12.rs b/src/fields/fp12.rs new file mode 100644 index 0000000..434d85d --- /dev/null +++ b/src/fields/fp12.rs @@ -0,0 +1,127 @@ +use ::Fq2; +use ::Fq6; +use rand::Rng; +use fields::Field; +use std::ops::{Mul,Add,Sub,Neg}; +use std::cmp::{PartialEq, Eq}; +use std::marker::PhantomData; +use std::fmt; + +pub trait Fp12Params { + fn non_residue() -> Fq2; + fn name() -> &'static str; +} + +pub struct Fp12 { + a: Fq6, + b: Fq6, + _marker: PhantomData

+} + +impl Fp12

{ + pub fn new(a: Fq6, b: Fq6) -> Self { + Fp12 { + a: a, + b: b, + _marker: PhantomData + } + } +} + +impl fmt::Debug for Fp12

{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}({:?}, {:?})", P::name(), self.a, self.b) + } +} + +impl Clone for Fp12

{ + fn clone(&self) -> Self { + Fp12 { + a: self.a.clone(), + b: self.b.clone(), + _marker: PhantomData + } + } +} + +impl Field for Fp12

{ + fn zero() -> Self { + Fp12 { + a: Fq6::zero(), + b: Fq6::zero(), + _marker: PhantomData + } + } + fn one() -> Self { + Fp12 { + a: Fq6::one(), + b: Fq6::zero(), + _marker: PhantomData + } + } + fn random(rng: &mut R) -> Self { + Fp12 { + a: Fq6::random(rng), + b: Fq6::random(rng), + _marker: PhantomData + } + } + + fn inverse(&self) -> Self { + let t = (self.a.squared() - (self.b.squared().mul_by_nonresidue(&P::non_residue()))).inverse(); + + Fp12 { + a: &self.a * &t, + b: -(&self.b * &t), + _marker: PhantomData + } + } + + fn squared(&self) -> Self { + let a = &self.a; let b = &self.b; + let ab = &(a * b); + + Fp12 { + a: (b.mul_by_nonresidue(&P::non_residue()) + a) * (a + b) - ab - ab.mul_by_nonresidue(&P::non_residue()), + b: ab + ab, + _marker: PhantomData + } + } + + fn eq(&self, other: &Self) -> bool { + self.a == other.a && self.b == other.b + } + fn neg(&self) -> Self { + Fp12 { + a: -(&self.a), + b: -(&self.b), + _marker: PhantomData + } + } + fn mul(&self, other: &Self) -> Self { + let a_a = &(&self.a * &other.a); + let b_b = &(&self.b * &other.b); + + Fp12 { + a: b_b.mul_by_nonresidue(&P::non_residue()) + a_a, + b: (&self.a + &self.b) * (&other.a + &other.b) - a_a - b_b, + _marker: PhantomData + } + } + fn sub(&self, other: &Self) -> Self { + Fp12 { + a: &self.a - &other.a, + b: &self.b - &other.b, + _marker: PhantomData + } + } + fn add(&self, other: &Self) -> Self { + Fp12 { + a: &self.a + &other.a, + b: &self.b + &other.b, + _marker: PhantomData + } + } +} + +forward_ops_to_field_ops!(impl(P: Fp12Params) Fp12

); diff --git a/src/fields/fp2.rs b/src/fields/fp2.rs index a28d234..c885e42 100644 --- a/src/fields/fp2.rs +++ b/src/fields/fp2.rs @@ -1,6 +1,5 @@ use ::Fq; use rand::Rng; -use fields::fp::PrimeFieldParams; use fields::Field; use std::ops::{Mul,Add,Sub,Neg}; use std::cmp::{PartialEq, Eq}; @@ -66,9 +65,7 @@ impl Field for Fp2

{ _marker: PhantomData } } - fn is_zero(&self) -> bool { - self == &Self::zero() - } + fn inverse(&self) -> Self { let t = (self.a.squared() - (self.b.squared() * P::non_residue())).inverse(); diff --git a/src/fields/fp6.rs b/src/fields/fp6.rs new file mode 100644 index 0000000..1d88aba --- /dev/null +++ b/src/fields/fp6.rs @@ -0,0 +1,147 @@ +use ::Fq2; +use rand::Rng; +use fields::Field; +use std::ops::{Mul,Add,Sub,Neg}; +use std::cmp::{PartialEq, Eq}; +use std::marker::PhantomData; +use std::fmt; + +pub trait Fp6Params { + fn non_residue() -> Fq2; + fn name() -> &'static str; +} + +pub struct Fp6 { + a: Fq2, + b: Fq2, + c: Fq2, + _marker: PhantomData

+} + +impl Fp6

{ + pub fn new(a: Fq2, b: Fq2, c: Fq2) -> Self { + Fp6 { + a: a, + b: b, + c: c, + _marker: PhantomData + } + } +} + +impl fmt::Debug for Fp6

{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}({:?}, {:?}, {:?})", P::name(), self.a, self.b, self.c) + } +} + +impl Clone for Fp6

{ + fn clone(&self) -> Self { + Fp6 { + a: self.a.clone(), + b: self.b.clone(), + c: self.c.clone(), + _marker: PhantomData + } + } +} + +impl Field for Fp6

{ + fn zero() -> Self { + Fp6 { + a: Fq2::zero(), + b: Fq2::zero(), + c: Fq2::zero(), + _marker: PhantomData + } + } + + fn one() -> Self { + Fp6 { + a: Fq2::one(), + b: Fq2::zero(), + c: Fq2::zero(), + _marker: PhantomData + } + } + + fn random(rng: &mut R) -> Self { + Fp6 { + a: Fq2::random(rng), + b: Fq2::random(rng), + c: Fq2::random(rng), + _marker: PhantomData + } + } + + fn inverse(&self) -> Self { + let c0 = self.a.squared() - &self.b * &self.c * P::non_residue(); + let c1 = self.c.squared() * P::non_residue() - &self.a * &self.b; + let c2 = self.b.squared() - &self.a * &self.c; + let t = ((&self.c * &c1 + &self.b * &c2) * P::non_residue() + &self.a * &c0).inverse(); + + Fp6 { + a: &t * &c0, + b: &t * &c1, + c: &t * &c2, + _marker: PhantomData + } + } + + fn eq(&self, other: &Self) -> bool { + self.a == other.a && self.b == other.b && self.c == other.c + } + + fn neg(&self) -> Self { + Fp6 { + a: -(&self.a), + b: -(&self.b), + c: -(&self.c), + _marker: PhantomData + } + } + + fn mul(&self, other: &Self) -> Self { + let a_a = &self.a * &other.a; + let b_b = &self.b * &other.b; + let c_c = &self.c * &other.c; + + Fp6 { + a: ((&self.b + &self.c) * (&other.b + &other.c) - &b_b - &c_c) * P::non_residue() + &a_a, + b: (&self.a + &self.b) * (&other.a + &other.b) - &a_a - &b_b + &c_c * P::non_residue(), + c: (&self.a + &self.c) * (&other.a + &other.c) - &a_a + &b_b - &c_c, + _marker: PhantomData + } + } + + fn sub(&self, other: &Self) -> Self { + Fp6 { + a: &self.a - &other.a, + b: &self.b - &other.b, + c: &self.c - &other.c, + _marker: PhantomData + } + } + + fn add(&self, other: &Self) -> Self { + Fp6 { + a: &self.a + &other.a, + b: &self.b + &other.b, + c: &self.c + &other.c, + _marker: PhantomData + } + } +} + +impl Fp6

{ + pub fn mul_by_nonresidue(&self, other: &Fq2) -> Fp6

{ + Fp6 { + a: &self.c * other, + b: self.a.clone(), + c: self.b.clone(), + _marker: PhantomData + } + } +} + +forward_ops_to_field_ops!(impl(P: Fp6Params) Fp6

); diff --git a/src/fields/mod.rs b/src/fields/mod.rs index bfb5610..0c24f0e 100644 --- a/src/fields/mod.rs +++ b/src/fields/mod.rs @@ -3,6 +3,8 @@ mod macros; pub mod fp; pub mod fp2; +pub mod fp6; +pub mod fp12; #[cfg(test)] pub mod tests; @@ -15,7 +17,9 @@ pub trait Field: Sized + Clone + Debug { fn zero() -> Self; fn one() -> Self; fn random(rng: &mut R) -> Self; - fn is_zero(&self) -> bool; + fn is_zero(&self) -> bool { + self.eq(&Self::zero()) + } fn inverse(&self) -> Self; fn squared(&self) -> Self { self.mul(self) diff --git a/src/lib.rs b/src/lib.rs index 219db22..e0c205d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,13 +8,17 @@ mod groups; pub use fields::fp::Fp; pub use fields::fp2::Fp2; -pub use params::{FrParams,FqParams,Fq2Params,G1Params,G2Params}; +pub use fields::fp6::Fp6; +pub use fields::fp12::Fp12; +pub use params::{FrParams,FqParams,Fq2Params,G1Params,G2Params,Fq6Params,Fq12Params}; pub use fields::Field; pub use groups::Jacobian; pub type Fr = Fp; pub type Fq = Fp; pub type Fq2 = Fp2; +pub type Fq6 = Fp6; +pub type Fq12 = Fp12; pub type Scalar = Fr; pub type G1 = Jacobian; diff --git a/src/params.rs b/src/params.rs index 567f783..397508d 100644 --- a/src/params.rs +++ b/src/params.rs @@ -2,7 +2,9 @@ use num::{Num,BigUint}; use fields::Field; use fields::fp::PrimeFieldParams; use fields::fp2::Fp2Params; -use super::{Fr,Fq,Fq2,G1,G2}; +use fields::fp6::Fp6Params; +use fields::fp12::Fp12Params; +use super::{Fr,Fq,Fq2,Fq6,Fq12,G1,G2}; use groups::*; pub struct FrParams; @@ -166,3 +168,127 @@ fn g2_test_vector() { assert_eq!(expect, e); } + +pub struct Fq6Params; + +impl Fp6Params for Fq6Params { + fn non_residue() -> Fq2 { + Fq2::new(Fq::from("9"), Fq::from("1")) + } + fn name() -> &'static str { + "Fq6" + } +} + +#[test] +fn test_fq6() { + use fields; + + fields::tests::field_trials::(); +} + +pub struct Fq12Params; + +impl Fp12Params for Fq12Params { + fn non_residue() -> Fq2 { + Fq2::new(Fq::from("9"), Fq::from("1")) + } + fn name() -> &'static str { + "Fq12" + } +} + +#[test] +fn test_fq12() { + use fields; + + fields::tests::field_trials::(); +} + +#[test] +fn fq12_test_vector() { + let start = Fq12::new( + Fq6::new( + Fq2::new( + Fq::from("19797905000333868150253315089095386158892526856493194078073564469188852136946"), + Fq::from("10509658143212501778222314067134547632307419253211327938344904628569123178733") + ), + Fq2::new( + Fq::from("208316612133170645758860571704540129781090973693601051684061348604461399206"), + Fq::from("12617661120538088237397060591907161689901553895660355849494983891299803248390") + ), + Fq2::new( + Fq::from("2897490589776053688661991433341220818937967872052418196321943489809183508515"), + Fq::from("2730506433347642574983433139433778984782882168213690554721050571242082865799") + ) + ), + Fq6::new( + Fq2::new( + Fq::from("17870056122431653936196746815433147921488990391314067765563891966783088591110"), + Fq::from("14314041658607615069703576372547568077123863812415914883625850585470406221594") + ), + Fq2::new( + Fq::from("10123533891707846623287020000407963680629966110211808794181173248765209982878"), + Fq::from("5062091880848845693514855272640141851746424235009114332841857306926659567101") + ), + Fq2::new( + Fq::from("9839781502639936537333620974973645053542086898304697594692219798017709586567"), + Fq::from("1583892292110602864638265389721494775152090720173641072176370350017825640703") + ) + ) + ); + + // Do a bunch of arbitrary stuff to the element + + let mut next = start.clone(); + for _ in 0..100 { + next = &next * &start; + } + + let mut cpy = next.clone(); + + for _ in 0..10 { + next = next.squared(); + } + + for _ in 0..10 { + next = &next + &start; + next = &next - &cpy; + next = -&next; + } + + next = next.squared(); + + let finally = Fq12::new( + Fq6::new( + Fq2::new( + Fq::from("18388750939593263065521177085001223024106699964957029146547831509155008229833"), + Fq::from("18370529854582635460997127698388761779167953912610241447912705473964014492243") + ), + Fq2::new( + Fq::from("3691824277096717481466579496401243638295254271265821828017111951446539785268"), + Fq::from("20513494218085713799072115076991457239411567892860153903443302793553884247235") + ), + Fq2::new( + Fq::from("12214155472433286415803224222551966441740960297013786627326456052558698216399"), + Fq::from("10987494248070743195602580056085773610850106455323751205990078881956262496575") + ) + ), + Fq6::new( + Fq2::new( + Fq::from("5134522153456102954632718911439874984161223687865160221119284322136466794876"), + Fq::from("20119236909927036376726859192821071338930785378711977469360149362002019539920") + ), + Fq2::new( + Fq::from("8839766648621210419302228913265679710586991805716981851373026244791934012854"), + Fq::from("9103032146464138788288547957401673544458789595252696070370942789051858719203") + ), + Fq2::new( + Fq::from("10378379548636866240502412547812481928323945124508039853766409196375806029865"), + Fq::from("9021627154807648093720460686924074684389554332435186899318369174351765754041") + ) + ) + ); + + assert_eq!(finally, next); +}