From 4b32ed6585a8e441980f0d654c8a2dacc844d2b0 Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Fri, 1 Jul 2016 13:50:55 -0600 Subject: [PATCH] Abstract away field operations into `Field` trait --- src/fields/fp.rs | 187 ++++++++++++++++++++++ src/fields/mod.rs | 28 ++++ src/fields/tests.rs | 203 ++++++++++++++++++++++++ src/fp.rs | 374 -------------------------------------------- src/lib.rs | 2 +- src/macros.rs | 61 ++++++++ src/params.rs | 16 +- 7 files changed, 495 insertions(+), 376 deletions(-) create mode 100644 src/fields/fp.rs create mode 100644 src/fields/mod.rs create mode 100644 src/fields/tests.rs delete mode 100644 src/fp.rs diff --git a/src/fields/fp.rs b/src/fields/fp.rs new file mode 100644 index 0000000..8b97bbd --- /dev/null +++ b/src/fields/fp.rs @@ -0,0 +1,187 @@ +use rand::Rng; +use num::{BigUint, Num}; +use std::ops::{Mul,Add,Sub,Neg}; +use std::cmp::{PartialEq, Eq}; +use std::convert::From; +use std::fmt; +use std::marker::PhantomData; +use super::Field; + +pub trait PrimeFieldParams { + fn modulus() -> BigUint; + fn bits() -> usize; + fn name() -> &'static str; +} + +pub struct Fp { + value: BigUint, + _marker: PhantomData

+} + +impl fmt::Debug for Fp

{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}({})", P::name(), self.value) + } +} + +impl Field for Fp

{ + fn zero() -> Self { + use num::Zero; + + Fp { + value: BigUint::zero(), + _marker: PhantomData + } + } + fn one() -> Self { + use num::One; + + Fp { + value: BigUint::one(), + _marker: PhantomData + } + } + fn random(rng: &mut R) -> Self { + use num::num_bigint::RandBigInt; + use num::Zero; + + Fp { + value: rng.gen_biguint_range(&BigUint::zero(), &P::modulus()), + _marker: PhantomData + } + } + + 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 + panic!("cannot get the multiplicative inverse of zero") + } else { + let mut res = Self::one(); + + let mut found_one = false; + + let exp = Self::zero() - Self::one() - Self::one(); + + for i in (0..P::bits()).rev() { + if found_one { + res = res.squared(); + } + + if exp.test_bit(i) { + found_one = true; + res = self * &res; + } + } + + res + } + } + + fn pow(&self, exp: &Fp) -> Self { + let mut res = Self::one(); + + let mut found_one = false; + + for i in (0..P2::bits()).rev() { + if found_one { + res = res.squared(); + } + + if exp.test_bit(i) { + found_one = true; + res = res * self; + } + } + + res + } + + fn neg(&self) -> Self { + use num::Zero; + + Fp { + value: if self.value.is_zero() { + self.value.clone() + } else { + P::modulus() - &self.value + }, + _marker: PhantomData + } + } + + fn mul(&self, other: &Self) -> Self { + Fp { + value: (&self.value * &other.value) % &P::modulus(), + _marker: PhantomData + } + } + + fn sub(&self, other: &Self) -> Self { + if other.value > self.value { + Fp { + value: (&self.value + P::modulus()) - &other.value, + _marker: PhantomData + } + } else { + Fp { + value: &self.value - &other.value, + _marker: PhantomData + } + } + } + + fn add(&self, other: &Self) -> Self { + let tmp = &self.value + &other.value; + if tmp >= P::modulus() { + Fp { + value: tmp - P::modulus(), + _marker: PhantomData + } + } else { + Fp { + value: tmp, + _marker: PhantomData + } + } + } + + fn eq(&self, other: &Self) -> bool { + self.value == other.value + } +} + +impl Fp

{ + pub fn test_bit(&self, bit: usize) -> bool { + // TODO: This is a naive approach. + use num::{One, Zero}; + + let mut b = BigUint::one(); + let two = &b + &b; + for _ in 0..bit { + b = &b + &b; + } + + (&self.value / b) % two != BigUint::zero() + } +} + +impl<'a, P: PrimeFieldParams> From<&'a str> for Fp

{ + fn from(s: &'a str) -> Self { + Fp { + value: BigUint::from_str_radix(s, 10).unwrap() % P::modulus(), + _marker: PhantomData + } + } +} + +impl Clone for Fp

{ + fn clone(&self) -> Self { unimplemented!() } +} + +forward_ops_to_field_ops!(impl(P: PrimeFieldParams) Fp

); diff --git a/src/fields/mod.rs b/src/fields/mod.rs new file mode 100644 index 0000000..0d286a0 --- /dev/null +++ b/src/fields/mod.rs @@ -0,0 +1,28 @@ +pub mod fp; + +#[cfg(test)] +pub mod tests; + +use rand::Rng; +use self::fp::{Fp, PrimeFieldParams}; + +pub trait Field: Sized + Clone { + fn zero() -> Self; + fn one() -> Self; + fn random(rng: &mut R) -> Self; + fn is_zero(&self) -> bool; + fn inverse(&self) -> Self; + fn squared(&self) -> Self { + self.mul(self) + } + fn pow(&self, exp: &Fp

) -> Self; + fn eq(&self, other: &Self) -> bool; + fn ne(&self, other: &Self) -> bool { + !self.eq(other) + } + + fn neg(&self) -> Self; + fn mul(&self, other: &Self) -> Self; + fn sub(&self, other: &Self) -> Self; + fn add(&self, other: &Self) -> Self; +} diff --git a/src/fields/tests.rs b/src/fields/tests.rs new file mode 100644 index 0000000..82f48ea --- /dev/null +++ b/src/fields/tests.rs @@ -0,0 +1,203 @@ +use rand::{Rng,SeedableRng,StdRng}; +use fields::Field; + +mod large_field { + use fields::fp::*; + use num::{BigUint, Num}; + + struct Large; + + impl PrimeFieldParams for Large { + fn modulus() -> BigUint { + BigUint::from_str_radix("21888242871839275222246405745257275088696311157297823662689037894645226208583", 10).unwrap() + } + + fn bits() -> usize { 254 } + fn name() -> &'static str { "Large" } + } + + type Ft = Fp; + + #[test] + fn bit_testing() { + let a = Ft::from("13"); + assert!(a.test_bit(0) == true); + assert!(a.test_bit(1) == false); + assert!(a.test_bit(2) == true); + assert!(a.test_bit(3) == true); + + let expected: Vec = [1,1,0,1,1,0,0,0,0,1,0,0,1,1,1,0,0,0,0,0,1,1,0,0,1,0,0,1,1] + .iter().map(|a| *a == 1).rev().collect(); + + let a = Ft::from("453624211"); + + for (i, b) in expected.into_iter().enumerate() { + assert!(a.test_bit(i) == b); + } + + let expected: Vec = [1,1,1,1,0,1,0,1,1,0,1,0,0,0,1,1,1,0,1,1,1,1,0,0,0,0,1,1,0,1,1,0,1,0,0,1,1,0,1,1,0,0,1,1,0,0,1,1,1,1,0,1,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,0,0,0,1,1,1,0,1,1,1,1,0,0,0,1,1,1,0,0,1,0,1,0,0,0,0,1,1,0,0,1,1,1,1,0,1,1,1,1,0,0,0,1,1,0,0,1,1,1,0,1,1,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,1,0,1,0,1,0,0,0,1,1,0,1,1,0,0,1,0,1,1,1,1,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,1,0,1,1,0,1,0,1,1,0,1,0,0,0,1,0,0,1,0,1,1,1,0,1,1,0,0,0,0,0,1,1,0,0,0,1,1,1,1,1,1,0,0,0,0,1,0,1,1,1,0,1,1,0,1,1,0,0,0,0,1,1,1,1,1,0,0,1,1,1,1,1,1,0,1,0,0,1,0,1,1,0,0] + .iter().map(|a| *a == 1).rev().collect(); + let a = Ft::from("13888242871869275222244405745257275088696211157297823662689037894645226208556"); + + for (i, b) in expected.into_iter().enumerate() { + assert!(a.test_bit(i) == b); + } + } +} + +mod small_field { + use fields::fp::*; + use fields::Field; + use num::{BigUint, Num}; + + struct Small; + + impl PrimeFieldParams for Small { + fn modulus() -> BigUint { + BigUint::from_str_radix("13", 10).unwrap() + } + + fn bits() -> usize { 6 } + fn name() -> &'static str { "Small" } + } + + type Ft = Fp; + + #[test] + fn field_ops() { + fn test_field_operation Ft>(a: u64, b: u64, f: C, expected: u64) { + let af = Ft::from(format!("{}", a).as_ref()); + let bf = Ft::from(format!("{}", b).as_ref()); + let expectedf = Ft::from(format!("{}", expected).as_ref()); + + let res = f(&af, &bf); + + if res != expectedf { + panic!("res={:?} != expectedf={:?} (a={}, b={}, expected={})", res, expectedf, a, b, expected); + } + } + + const MODULO: u64 = 13; + + for a in 0..13u64 { + for b in 0..13u64 { + test_field_operation(a, b, |a,b| {a * b}, (a*b)%MODULO); + test_field_operation(a, b, |a,b| {a + b}, (a+b)%MODULO); + test_field_operation(a, b, |a,b| {a - b}, { + let mut tmp = (a as i64) - (b as i64); + if tmp < 0 { + tmp += MODULO as i64; + } + + tmp as u64 + }); + test_field_operation(a, b, |a,b| {a.pow(b)}, (a.pow(b as u32))%MODULO); + } + test_field_operation(a, 0, |a,_| {-a}, if a == 0 { 0 } else { MODULO - a }); + if a > 0 { + test_field_operation(a, 0, |a,_| {&a.inverse() * a}, 1); + } + } + } +} + + +fn can_invert() { + let mut a = F::one(); + for _ in 0..1000 { + assert!(a.ne(&F::zero())); + + let inv = a.inverse(); + + assert!(a.mul(&inv).eq(&F::one())); + + a = a.add(&F::one()); + } +} + + +fn rand_element_squaring(rng: &mut R) { + for _ in 0..100 { + let a = F::random(rng); + + let mul = a.mul(&a); + let sq = a.squared(); + + assert!(sq.eq(&mul)); + } + + let mut cur = F::zero(); + for _ in 0..100 { + let mul = cur.mul(&cur); + let sq = cur.squared(); + + assert!(sq.eq(&mul)); + + cur = cur.add(&F::one()); + } +} + +fn rand_element_addition_and_negation(rng: &mut R) { + for _ in 0..10 { + let mut a = F::random(rng); + let r = F::random(rng); + let mut b = a.add(&r); + + for _ in 0..10 { + let r = F::random(rng); + a = a.add(&r); + b = b.add(&r); + + let r = F::random(rng); + a = a.sub(&r); + b = b.sub(&r); + + let r = F::random(rng); + a = a.add(&r); + b = b.add(&r); + } + + b = b.sub(&r); + assert!(a.eq(&b)); + } +} + +fn rand_element_inverse(rng: &mut R) { + for _ in 0..100 { + let mut n = F::random(rng); + n = n.inverse().mul(&n); + assert!(n.eq(&F::one())); + } + for _ in 0..100 { + let a = F::random(rng); + let b = F::random(rng); + assert!(a.mul(&b).mul(&a.inverse()).eq(&b)); + } +} + +fn rand_element_multiplication(rng: &mut R) { + // If field is not associative under multiplication, 1/8 of all triplets a, b, c + // will fail the test (a*b)*c = a*(b*c). + + for _ in 0..250 { + let a = F::random(rng); + let b = F::random(rng); + let c = F::random(rng); + + assert!(a.mul(&b).mul(&c).eq(&b.mul(&c).mul(&a))); + } +} + +pub fn field_trials() { + can_invert::(); + + let seed: [usize; 4] = [103245, 191922, 1293, 192103]; + let mut rng = StdRng::from_seed(&seed); + + rand_element_squaring::(&mut rng); + rand_element_addition_and_negation::(&mut rng); + rand_element_multiplication::(&mut rng); + rand_element_inverse::(&mut rng); +} + + diff --git a/src/fp.rs b/src/fp.rs deleted file mode 100644 index ca1c067..0000000 --- a/src/fp.rs +++ /dev/null @@ -1,374 +0,0 @@ -use rand::Rng; -use num::{BigUint, Num}; -use std::ops::{Mul,Add,Sub,Neg}; -use std::cmp::{PartialEq, Eq}; -use std::convert::From; -use std::fmt; -use std::marker::PhantomData; - -pub trait PrimeFieldParams { - fn modulus() -> BigUint; - fn bits() -> usize; - fn name() -> &'static str; -} - -pub struct Fp { - value: BigUint, - _marker: PhantomData

-} - -impl fmt::Debug for Fp

{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}({})", P::name(), self.value) - } -} - -impl Fp

{ - pub fn zero() -> Self { - use num::Zero; - - Fp { - value: BigUint::zero(), - _marker: PhantomData - } - } - pub fn one() -> Self { - use num::One; - - Fp { - value: BigUint::one(), - _marker: PhantomData - } - } - pub fn random(rng: &mut R) -> Self { - use num::num_bigint::RandBigInt; - use num::Zero; - - Fp { - value: rng.gen_biguint_range(&BigUint::zero(), &P::modulus()), - _marker: PhantomData - } - } - - pub fn is_zero(&self) -> bool { - use num::Zero; - - self.value == BigUint::zero() - } - - pub fn inverse(&self) -> Self { - if self.is_zero() { - // TODO: this should likely bleed through the abstraction layers - panic!("cannot get the multiplicative inverse of zero") - } else { - let mut res = Self::one(); - - let mut found_one = false; - - let exp = Self::zero() - Self::one() - Self::one(); - - for i in (0..P::bits()).rev() { - if found_one { - res = res.squared(); - } - - if exp.test_bit(i) { - found_one = true; - res = self * &res; - } - } - - res - } - } - pub fn squared(&self) -> Self { - self * self - } - pub fn pow(&self, exp: &Fp) -> Self { - let mut res = Self::one(); - - let mut found_one = false; - - for i in (0..P2::bits()).rev() { - if found_one { - res = res.squared(); - } - - if exp.test_bit(i) { - found_one = true; - res = res * self; - } - } - - res - } - pub fn test_bit(&self, bit: usize) -> bool { - // TODO: This is a naive approach. - use num::{One, Zero}; - - let mut b = BigUint::one(); - let two = &b + &b; - for _ in 0..bit { - b = &b + &b; - } - - (&self.value / b) % two != BigUint::zero() - } -} - -impl<'a, P: PrimeFieldParams> From<&'a str> for Fp

{ - fn from(s: &'a str) -> Self { - Fp { - value: BigUint::from_str_radix(s, 10).unwrap() % P::modulus(), - _marker: PhantomData - } - } -} - -impl Clone for Fp

{ - fn clone(&self) -> Self { unimplemented!() } -} - -impl<'a, 'b, P: PrimeFieldParams> Add<&'b Fp

> for &'a Fp

{ - type Output = Fp

; - - fn add(self, other: &Fp

) -> Fp

{ - let tmp = &self.value + &other.value; - if tmp >= P::modulus() { - Fp { - value: tmp - P::modulus(), - _marker: PhantomData - } - } else { - Fp { - value: tmp, - _marker: PhantomData - } - } - } -} - -impl<'a, 'b, P: PrimeFieldParams> Sub<&'b Fp

> for &'a Fp

{ - type Output = Fp

; - - fn sub(self, other: &Fp

) -> Fp

{ - if other.value > self.value { - Fp { - value: (&self.value + P::modulus()) - &other.value, - _marker: PhantomData - } - } else { - Fp { - value: &self.value - &other.value, - _marker: PhantomData - } - } - } -} - -impl<'a, 'b, P: PrimeFieldParams> Mul<&'b Fp

> for &'a Fp

{ - type Output = Fp

; - - fn mul(self, other: &Fp

) -> Fp

{ - Fp { - value: (&self.value * &other.value) % &P::modulus(), - _marker: PhantomData - } - } -} - -impl<'a, P: PrimeFieldParams> Neg for &'a Fp

{ - type Output = Fp

; - - fn neg(self) -> Fp

{ - use num::Zero; - - Fp { - value: if self.value.is_zero() { - self.value.clone() - } else { - P::modulus() - &self.value - }, - _marker: PhantomData - } - } -} - -impl Neg for Fp

{ - type Output = Fp

; - - fn neg(self) -> Fp

{ - -(&self) - } -} - -impl PartialEq for Fp

{ - fn eq(&self, other: &Self) -> bool { - self.value == other.value - } -} - -impl Eq for Fp

{} - -forward_all_binop_to_ref_ref!(impl(P: PrimeFieldParams) Mul for Fp

, mul); - -#[cfg(test)] -mod large_field_tests { - use super::*; - use rand::{Rng,SeedableRng,StdRng}; - use num::{BigUint, Num}; - - struct Small; - - impl PrimeFieldParams for Small { - fn modulus() -> BigUint { - BigUint::from_str_radix("21888242871839275222246405745257275088696311157297823662689037894645226208583", 10).unwrap() - } - - fn bits() -> usize { 254 } - fn name() -> &'static str { "Small" } - } - - type Ft = Fp; - - #[test] - fn rand_element_squaring() { - let seed: [usize; 4] = [0, 0, 0, 0]; - let rng = &mut StdRng::from_seed(&seed); - - for _ in 0..100 { - let a = Ft::random(rng); - - let mul = &a * &a; - let sq = a.squared(); - - assert!(sq == mul); - } - - let mut cur = Ft::zero(); - for _ in 0..100 { - let mul = &cur * &cur; - let sq = cur.squared(); - - assert!(sq == mul); - - cur = &cur + &Ft::one(); - } - } - - #[test] - fn rand_element_multiplication() { - // If field is not associative under multiplication, 1/8 of all triplets a, b, c - // will fail the test (a*b)*c = a*(b*c). - - let seed: [usize; 4] = [0, 0, 0, 0]; - let rng = &mut StdRng::from_seed(&seed); - - for _ in 0..250 { - let a = &Ft::random(rng); - let b = &Ft::random(rng); - let c = &Ft::random(rng); - - assert!((a * b) * c == (b * c) * a); - } - } - - #[test] - fn rand_element_inverse() { - let seed: [usize; 4] = [0, 0, 0, 0]; - let rng = &mut StdRng::from_seed(&seed); - - for _ in 0..100 { - let mut n = Ft::random(rng); - n = n.inverse() * n; - assert_eq!(n, Ft::one()); - } - for _ in 0..100 { - let a = Ft::random(rng); - let b = Ft::random(rng); - assert_eq!(&a * &b * (a.inverse()), b); - } - } - - #[test] - fn bit_testing() { - let a = Ft::from("13"); - assert!(a.test_bit(0) == true); - assert!(a.test_bit(1) == false); - assert!(a.test_bit(2) == true); - assert!(a.test_bit(3) == true); - - let expected: Vec = [1,1,0,1,1,0,0,0,0,1,0,0,1,1,1,0,0,0,0,0,1,1,0,0,1,0,0,1,1] - .iter().map(|a| *a == 1).rev().collect(); - - let a = Ft::from("453624211"); - - for (i, b) in expected.into_iter().enumerate() { - assert!(a.test_bit(i) == b); - } - - let expected: Vec = [1,1,1,1,0,1,0,1,1,0,1,0,0,0,1,1,1,0,1,1,1,1,0,0,0,0,1,1,0,1,1,0,1,0,0,1,1,0,1,1,0,0,1,1,0,0,1,1,1,1,0,1,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,0,0,0,1,1,1,0,1,1,1,1,0,0,0,1,1,1,0,0,1,0,1,0,0,0,0,1,1,0,0,1,1,1,1,0,1,1,1,1,0,0,0,1,1,0,0,1,1,1,0,1,1,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,1,0,1,0,1,0,0,0,1,1,0,1,1,0,0,1,0,1,1,1,1,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,1,0,1,1,0,1,0,1,1,0,1,0,0,0,1,0,0,1,0,1,1,1,0,1,1,0,0,0,0,0,1,1,0,0,0,1,1,1,1,1,1,0,0,0,0,1,0,1,1,1,0,1,1,0,1,1,0,0,0,0,1,1,1,1,1,0,0,1,1,1,1,1,1,0,1,0,0,1,0,1,1,0,0] - .iter().map(|a| *a == 1).rev().collect(); - let a = Ft::from("13888242871869275222244405745257275088696211157297823662689037894645226208556"); - - for (i, b) in expected.into_iter().enumerate() { - assert!(a.test_bit(i) == b); - } - } -} - -#[cfg(test)] -mod small_field_tests { - use super::*; - use num::{BigUint, Num}; - - struct Small; - - impl PrimeFieldParams for Small { - fn modulus() -> BigUint { - BigUint::from_str_radix("13", 10).unwrap() - } - - fn bits() -> usize { 6 } - fn name() -> &'static str { "Small" } - } - - type Ft = Fp; - - #[test] - fn field_ops() { - fn test_field_operation Ft>(a: u64, b: u64, f: C, expected: u64) { - let af = Ft::from(format!("{}", a).as_ref()); - let bf = Ft::from(format!("{}", b).as_ref()); - let expectedf = Ft::from(format!("{}", expected).as_ref()); - - let res = f(&af, &bf); - - if res != expectedf { - panic!("res={:?} != expectedf={:?} (a={}, b={}, expected={})", res, expectedf, a, b, expected); - } - } - - const MODULO: u64 = 13; - - for a in 0..13u64 { - for b in 0..13u64 { - test_field_operation(a, b, |a,b| {a * b}, (a*b)%MODULO); - test_field_operation(a, b, |a,b| {a + b}, (a+b)%MODULO); - test_field_operation(a, b, |a,b| {a - b}, { - let mut tmp = (a as i64) - (b as i64); - if tmp < 0 { - tmp += MODULO as i64; - } - - tmp as u64 - }); - test_field_operation(a, b, |a,b| {a.pow(b)}, (a.pow(b as u32))%MODULO); - } - test_field_operation(a, 0, |a,_| {-a}, if a == 0 { 0 } else { MODULO - a }); - if a > 0 { - test_field_operation(a, 0, |a,_| {&a.inverse() * a}, 1); - } - } - } -} diff --git a/src/lib.rs b/src/lib.rs index 2af944f..886d1d7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,5 +3,5 @@ extern crate rand; #[macro_use] mod macros; -mod fp; +mod fields; mod params; diff --git a/src/macros.rs b/src/macros.rs index 1633dde..00cc91f 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -44,3 +44,64 @@ macro_rules! forward_all_binop_to_ref_ref { forward_val_ref_binop!(impl($($t: $p),*) $imp for $res, $method); }; } + +macro_rules! forward_ops_to_field_ops { + (impl($($t:ident: $p:ident),*) $res:ty) => { + impl<'a, 'b, $($t: $p),*> Add<&'a $res> for &'b $res { + type Output = $res; + + #[inline] + fn add(self, other: &'a $res) -> $res { + Field::add(self, other) + } + } + + impl<'a, 'b, $($t: $p),*> Sub<&'a $res> for &'b $res { + type Output = $res; + + #[inline] + fn sub(self, other: &'a $res) -> $res { + Field::sub(self, other) + } + } + + impl<'a, 'b, $($t: $p),*> Mul<&'a $res> for &'b $res { + type Output = $res; + + #[inline] + fn mul(self, other: &'a $res) -> $res { + Field::mul(self, other) + } + } + + impl<'a, $($t: $p),*> Neg for &'a $res { + type Output = $res; + + #[inline] + fn neg(self) -> $res { + Field::neg(self) + } + } + + impl<$($t: $p),*> Neg for $res { + type Output = $res; + + #[inline] + fn neg(self) -> $res { + Field::neg(&self) + } + } + + impl<$($t: $p),*> PartialEq for $res { + fn eq(&self, other: &Self) -> bool { + Field::eq(self, other) + } + } + + impl<$($t: $p),*> Eq for $res {} + + forward_all_binop_to_ref_ref!(impl($($t: $p),*) Add for $res, add); + forward_all_binop_to_ref_ref!(impl($($t: $p),*) Sub for $res, sub); + forward_all_binop_to_ref_ref!(impl($($t: $p),*) Mul for $res, mul); + } +} diff --git a/src/params.rs b/src/params.rs index cec7007..2bbfdc5 100644 --- a/src/params.rs +++ b/src/params.rs @@ -1,5 +1,5 @@ use num::{Num,BigUint}; -use fp::PrimeFieldParams; +use fields::fp::PrimeFieldParams; pub struct FrParams; @@ -20,3 +20,17 @@ impl PrimeFieldParams for FqParams { fn bits() -> usize { 254 } fn name() -> &'static str { "Fq" } } + +#[test] +fn test_fr() { + use fields; + + fields::tests::field_trials::>(); +} + +#[test] +fn test_fq() { + use fields; + + fields::tests::field_trials::>(); +}