Arithmetic in Fp

This commit is contained in:
Sean Bowe 2016-06-29 22:00:22 -06:00
parent 7f515bbe1c
commit eaa0de2964
No known key found for this signature in database
GPG Key ID: 95684257D8F8B031
2 changed files with 261 additions and 14 deletions

273
src/fp.rs
View File

@ -1,12 +1,15 @@
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> {
@ -14,20 +17,112 @@ pub struct Fp<P: PrimeFieldParams> {
_marker: PhantomData<P>
}
impl<P: PrimeFieldParams> Fp<P> {
pub fn zero() -> Self { unimplemented!() }
pub fn one() -> Self { unimplemented!() }
pub fn random<R: Rng>(rng: &mut R) -> Self { unimplemented!() }
impl<P: PrimeFieldParams> fmt::Debug for Fp<P> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}({})", P::name(), self.value)
}
}
pub fn is_zero(&self) -> bool { unimplemented!() }
pub fn inverse(&self) -> Self { unimplemented!() }
pub fn squared(&self) -> Self { unimplemented!() }
pub fn pow<P2: PrimeFieldParams>(&self, exp: &Fp<P2>) -> Self { unimplemented!() }
pub fn test_bit(&self, bit: usize) -> bool { unimplemented!() }
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 { unimplemented!() }
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> {
@ -37,25 +132,66 @@ impl<P: PrimeFieldParams> Clone for Fp<P> {
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> { unimplemented!() }
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> { unimplemented!() }
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> { unimplemented!() }
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> { unimplemented!() }
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> {
@ -66,4 +202,113 @@ impl<P: PrimeFieldParams> Neg for Fp<P> {
}
}
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 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 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);
}
}
}
}

View File

@ -8,6 +8,7 @@ impl PrimeFieldParams for FrParams {
BigUint::from_str_radix("21888242871839275222246405745257275088548364400416034343698204186575808495617", 10).unwrap()
}
fn bits() -> usize { 254 }
fn name() -> &'static str { "Fr" }
}
pub struct FqParams;
@ -17,4 +18,5 @@ impl PrimeFieldParams for FqParams {
BigUint::from_str_radix("21888242871839275222246405745257275088696311157297823662689037894645226208583", 10).unwrap()
}
fn bits() -> usize { 254 }
fn name() -> &'static str { "Fq" }
}