pub mod babybear;
pub mod fixed;
pub mod goldilocks;
pub mod mersenne31;
pub mod poseidon2;
pub mod proof;
pub use babybear::BabyBear;
pub use goldilocks::Goldilocks;
pub use mersenne31::Mersenne31;
pub trait PrimeField: Copy + Clone + Eq + PartialEq + Ord + PartialOrd + std::fmt::Debug {
const MODULUS: u128;
const BITS: u32;
const ZERO: Self;
const ONE: Self;
fn from_u64(v: u64) -> Self;
fn to_u64(self) -> u64;
fn add(self, rhs: Self) -> Self;
fn sub(self, rhs: Self) -> Self;
fn mul(self, rhs: Self) -> Self;
fn neg(self) -> Self;
fn inv(self) -> Option<Self> {
if self == Self::ZERO {
return None;
}
let exp = Self::MODULUS - 2;
Some(self.pow_u128(exp))
}
fn pow(self, mut exp: u64) -> Self {
let mut base = self;
let mut acc = Self::ONE;
while exp > 0 {
if exp & 1 == 1 {
acc = acc.mul(base);
}
base = base.mul(base);
exp >>= 1;
}
acc
}
fn pow_u128(self, mut exp: u128) -> Self {
let mut base = self;
let mut acc = Self::ONE;
while exp > 0 {
if exp & 1 == 1 {
acc = acc.mul(base);
}
base = base.mul(base);
exp >>= 1;
}
acc
}
}
#[cfg(test)]
mod tests {
use super::*;
fn test_field_laws<F: PrimeField>() {
let zero = F::ZERO;
let one = F::ONE;
let a = F::from_u64(42);
let b = F::from_u64(1337);
assert_eq!(a.add(zero), a);
assert_eq!(zero.add(a), a);
assert_eq!(a.mul(one), a);
assert_eq!(one.mul(a), a);
assert_eq!(a.mul(zero), zero);
assert_eq!(a.add(b), b.add(a));
assert_eq!(a.mul(b), b.mul(a));
assert_eq!(a.add(a.neg()), zero);
assert_eq!(zero.neg(), zero);
assert_eq!(a.sub(b), a.add(b.neg()));
if let Some(inv_a) = a.inv() {
assert_eq!(a.mul(inv_a), one);
}
assert!(zero.inv().is_none());
assert_eq!(a.pow(0), one);
assert_eq!(a.pow(1), a);
assert_eq!(a.pow(3), a.mul(a).mul(a));
let neg_one = one.neg();
assert_eq!(neg_one.mul(neg_one), one);
}
#[test]
fn goldilocks_field_laws() {
test_field_laws::<Goldilocks>();
}
#[test]
fn babybear_field_laws() {
test_field_laws::<BabyBear>();
}
#[test]
fn mersenne31_field_laws() {
test_field_laws::<Mersenne31>();
}
fn test_field_edge_cases<F: PrimeField>() {
let zero = F::ZERO;
let one = F::ONE;
let p_minus_1 = F::from_u64((F::MODULUS - 1) as u64);
assert_eq!(p_minus_1.add(one), zero);
let p_minus_2 = F::from_u64((F::MODULUS - 2) as u64);
assert_eq!(p_minus_1.add(p_minus_1), p_minus_2);
assert_eq!(zero.sub(one), p_minus_1);
assert_eq!(p_minus_1.mul(p_minus_1), one);
let p_as_u64 = F::MODULUS as u64;
assert_eq!(F::from_u64(p_as_u64), zero);
assert_eq!(F::from_u64(p_as_u64 + 1), one);
assert_eq!(p_minus_1.inv(), Some(p_minus_1));
assert_eq!(one.inv(), Some(one));
assert_eq!(p_minus_1.pow(2), one);
}
#[test]
fn goldilocks_edge_cases() {
test_field_edge_cases::<Goldilocks>();
let large = Goldilocks::from_u64(u64::MAX);
let result = large.mul(large);
assert!(result.to_u64() < goldilocks::MODULUS);
}
#[test]
fn babybear_edge_cases() {
test_field_edge_cases::<BabyBear>();
}
#[test]
fn mersenne31_edge_cases() {
test_field_edge_cases::<Mersenne31>();
}
}