Abstract away field operations into `Field` trait
This commit is contained in:
parent
391fa61173
commit
4b32ed6585
|
@ -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<P: PrimeFieldParams> {
|
||||
value: BigUint,
|
||||
_marker: PhantomData<P>
|
||||
}
|
||||
|
||||
impl<P: PrimeFieldParams> fmt::Debug for Fp<P> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}({})", P::name(), self.value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: PrimeFieldParams> Field for Fp<P> {
|
||||
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<R: Rng>(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<P2: PrimeFieldParams>(&self, exp: &Fp<P2>) -> 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<P: PrimeFieldParams> Fp<P> {
|
||||
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<P> {
|
||||
fn from(s: &'a str) -> Self {
|
||||
Fp {
|
||||
value: BigUint::from_str_radix(s, 10).unwrap() % P::modulus(),
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: PrimeFieldParams> Clone for Fp<P> {
|
||||
fn clone(&self) -> Self { unimplemented!() }
|
||||
}
|
||||
|
||||
forward_ops_to_field_ops!(impl(P: PrimeFieldParams) Fp<P>);
|
|
@ -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<R: Rng>(rng: &mut R) -> Self;
|
||||
fn is_zero(&self) -> bool;
|
||||
fn inverse(&self) -> Self;
|
||||
fn squared(&self) -> Self {
|
||||
self.mul(self)
|
||||
}
|
||||
fn pow<P: PrimeFieldParams>(&self, exp: &Fp<P>) -> 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;
|
||||
}
|
|
@ -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<Large>;
|
||||
|
||||
#[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<bool> = [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<bool> = [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<Small>;
|
||||
|
||||
#[test]
|
||||
fn field_ops() {
|
||||
fn test_field_operation<C: Fn(&Ft, &Ft) -> 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<F: Field>() {
|
||||
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<F: Field, R: Rng>(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<F: Field, R: Rng>(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<F: Field, R: Rng>(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<F: Field, R: Rng>(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<F: Field>() {
|
||||
can_invert::<F>();
|
||||
|
||||
let seed: [usize; 4] = [103245, 191922, 1293, 192103];
|
||||
let mut rng = StdRng::from_seed(&seed);
|
||||
|
||||
rand_element_squaring::<F, StdRng>(&mut rng);
|
||||
rand_element_addition_and_negation::<F, StdRng>(&mut rng);
|
||||
rand_element_multiplication::<F, StdRng>(&mut rng);
|
||||
rand_element_inverse::<F, StdRng>(&mut rng);
|
||||
}
|
||||
|
||||
|
374
src/fp.rs
374
src/fp.rs
|
@ -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<P: PrimeFieldParams> {
|
||||
value: BigUint,
|
||||
_marker: PhantomData<P>
|
||||
}
|
||||
|
||||
impl<P: PrimeFieldParams> fmt::Debug for Fp<P> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}({})", P::name(), self.value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: PrimeFieldParams> Fp<P> {
|
||||
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<R: Rng>(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<P2: PrimeFieldParams>(&self, exp: &Fp<P2>) -> 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<P> {
|
||||
fn from(s: &'a str) -> Self {
|
||||
Fp {
|
||||
value: BigUint::from_str_radix(s, 10).unwrap() % P::modulus(),
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: PrimeFieldParams> Clone for Fp<P> {
|
||||
fn clone(&self) -> Self { unimplemented!() }
|
||||
}
|
||||
|
||||
impl<'a, 'b, P: PrimeFieldParams> Add<&'b Fp<P>> for &'a Fp<P> {
|
||||
type Output = Fp<P>;
|
||||
|
||||
fn add(self, other: &Fp<P>) -> Fp<P> {
|
||||
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<P>> for &'a Fp<P> {
|
||||
type Output = Fp<P>;
|
||||
|
||||
fn sub(self, other: &Fp<P>) -> Fp<P> {
|
||||
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<P>> for &'a Fp<P> {
|
||||
type Output = Fp<P>;
|
||||
|
||||
fn mul(self, other: &Fp<P>) -> Fp<P> {
|
||||
Fp {
|
||||
value: (&self.value * &other.value) % &P::modulus(),
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, P: PrimeFieldParams> Neg for &'a Fp<P> {
|
||||
type Output = Fp<P>;
|
||||
|
||||
fn neg(self) -> Fp<P> {
|
||||
use num::Zero;
|
||||
|
||||
Fp {
|
||||
value: if self.value.is_zero() {
|
||||
self.value.clone()
|
||||
} else {
|
||||
P::modulus() - &self.value
|
||||
},
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: PrimeFieldParams> Neg for Fp<P> {
|
||||
type Output = Fp<P>;
|
||||
|
||||
fn neg(self) -> Fp<P> {
|
||||
-(&self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: PrimeFieldParams> PartialEq for Fp<P> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.value == other.value
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: PrimeFieldParams> Eq for Fp<P> {}
|
||||
|
||||
forward_all_binop_to_ref_ref!(impl(P: PrimeFieldParams) Mul for Fp<P>, 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<Small>;
|
||||
|
||||
#[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<bool> = [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<bool> = [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<Small>;
|
||||
|
||||
#[test]
|
||||
fn field_ops() {
|
||||
fn test_field_operation<C: Fn(&Ft, &Ft) -> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,5 +3,5 @@ extern crate rand;
|
|||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
mod fp;
|
||||
mod fields;
|
||||
mod params;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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::<fields::fp::Fp<FrParams>>();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq() {
|
||||
use fields;
|
||||
|
||||
fields::tests::field_trials::<fields::fp::Fp<FqParams>>();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue