pub mod binary;
pub mod goldilocks;
pub mod mersenne31;
pub mod quad_mersenne31;
pub use binary::cantor;
pub use binary::description;
pub use binary::embedding;
pub use binary::normal;
pub use binary::poly;
pub use binary::tower;
pub use binary::tower::{
FanPaar2, FanPaar4, FanPaar8, FanPaar16, FanPaar32, FanPaar64, Rijndael16, Rijndael32,
Rijndael64, Tower, TowerGeneratorSpec, TowerSpec,
};
pub use binary::{
AES, Binary, BinaryDegree, BinaryDescription, BinaryField, BinaryRepr, ByteLogExp, Cantor,
Embedding, EmbeddingError, Normal, Polynomial, RS,
};
pub use goldilocks::Goldilocks;
pub use mersenne31::Mersenne31;
pub use quad_mersenne31::QuadMersenne31;
mod private {
pub trait Sealed {}
}
mod element_private {
pub trait Sealed {}
}
#[allow(clippy::cast_possible_truncation, clippy::cast_lossless)]
pub(crate) const fn powmod(mut base: u64, mut exponent: u64, modulus: u64) -> u64 {
let mut result = 1 % modulus;
base %= modulus;
while exponent > 0 {
if exponent & 1 == 1 {
result = ((result as u128 * base as u128) % modulus as u128) as u64;
}
base = ((base as u128 * base as u128) % modulus as u128) as u64;
exponent >>= 1;
}
result
}
#[must_use]
#[allow(clippy::cast_possible_truncation, clippy::cast_lossless)]
pub const fn is_prime(candidate: u64) -> bool {
const SMALL: [u64; 12] = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37];
const WITNESSES: [u64; 7] = [2, 325, 9375, 28_178, 450_775, 9_780_504, 1_795_265_022];
if candidate < 2 {
return false;
}
let mut i = 0;
while i < SMALL.len() {
let prime = SMALL[i];
if candidate == prime {
return true;
}
if candidate.is_multiple_of(prime) {
return false;
}
i += 1;
}
let mut odd = candidate - 1;
let mut shifts = 0u32;
while odd.is_multiple_of(2) {
odd /= 2;
shifts += 1;
}
let mut i = 0;
while i < WITNESSES.len() {
let residue = WITNESSES[i] % candidate;
i += 1;
if residue == 0 {
continue;
}
let mut trial = powmod(residue, odd, candidate);
if trial == 1 || trial == candidate - 1 {
continue;
}
let mut round = 1;
let mut composite = true;
while round < shifts {
trial = ((trial as u128 * trial as u128) % candidate as u128) as u64;
if trial == candidate - 1 {
composite = false;
break;
}
round += 1;
}
if composite {
return false;
}
}
true
}
pub trait PrimeIdentity: private::Sealed + Copy + 'static {
const CHARACTERISTIC: u64;
const VALID: ();
}
#[derive(Clone, Copy, Debug)]
pub struct PrimeCharacteristic<const P: u64>;
impl<const P: u64> private::Sealed for PrimeCharacteristic<P> {}
impl<const P: u64> PrimeIdentity for PrimeCharacteristic<P> {
const CHARACTERISTIC: u64 = {
assert!(is_prime(P), "characteristic is not prime");
P
};
const VALID: () = assert!(is_prime(P), "characteristic is not prime");
}
pub trait Field: Copy + core::fmt::Debug + 'static {
type Raw: Copy + Eq + Ord + core::hash::Hash + core::fmt::Debug;
type Characteristic: PrimeIdentity;
const NAME: &'static str;
const DEGREE: u32;
const ORDER: u128;
const ZERO_RAW: Self::Raw;
const ONE_RAW: Self::Raw;
const VALID: ();
fn canonical_raw(raw: Self::Raw) -> Self::Raw;
fn add_raw(left: Self::Raw, right: Self::Raw) -> Self::Raw;
fn sub_raw(left: Self::Raw, right: Self::Raw) -> Self::Raw;
fn neg_raw(value: Self::Raw) -> Self::Raw;
fn mul_raw(left: Self::Raw, right: Self::Raw) -> Self::Raw;
fn inv_raw(value: Self::Raw) -> Self::Raw;
}
pub(crate) struct Validate<F>(core::marker::PhantomData<F>);
impl<F: Field> Validate<F> {
pub(crate) const OK: () = {
let characteristic = <F::Characteristic as PrimeIdentity>::CHARACTERISTIC;
assert!(F::DEGREE > 0, "field degree must be positive");
assert!(
characteristic != 2 || F::DEGREE <= 64,
"binary field degree exceeds 64"
);
let mut order: u128 = 1;
let mut i = 0;
while i < F::DEGREE {
order = match order.checked_mul(characteristic as u128) {
Some(value) => value,
None => panic!("field order overflows u128"),
};
i += 1;
}
assert!(order == F::ORDER, "ORDER is not CHARACTERISTIC^DEGREE");
let () = F::VALID;
};
}
pub struct Elem<F: Field> {
pub(crate) raw: F::Raw,
}
#[allow(clippy::expl_impl_clone_on_copy)]
impl<F: Field> Clone for Elem<F> {
#[inline]
fn clone(&self) -> Self {
*self
}
}
impl<F: Field> Copy for Elem<F> {}
impl<F: Field> PartialEq for Elem<F> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.raw == other.raw
}
}
impl<F: Field> Eq for Elem<F> {}
impl<F: Field> core::hash::Hash for Elem<F> {
#[inline]
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.raw.hash(state);
}
}
impl<F: Field> PartialOrd for Elem<F> {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<F: Field> Ord for Elem<F> {
#[inline]
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.raw.cmp(&other.raw)
}
}
impl<F: Field> core::fmt::Debug for Elem<F> {
fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(formatter, "{}({:?})", F::NAME, self.raw)
}
}
impl<F: Field> Default for Elem<F> {
#[inline]
fn default() -> Self {
Self::ZERO
}
}
impl<F: Field> Elem<F> {
pub const ZERO: Self = {
let () = Validate::<F>::OK;
Elem { raw: F::ZERO_RAW }
};
pub const ONE: Self = {
let () = Validate::<F>::OK;
Elem { raw: F::ONE_RAW }
};
#[inline]
#[must_use]
pub const fn to_raw(self) -> F::Raw {
self.raw
}
}
pub trait HasGenerator: Field {
const GENERATOR_RAW: Self::Raw;
}
impl<F: HasGenerator> Elem<F> {
pub const GENERATOR: Self = {
let () = Validate::<F>::OK;
Elem {
raw: F::GENERATOR_RAW,
}
};
}
#[allow(private_bounds)]
pub trait FieldElem:
element_private::Sealed + Copy + Eq + core::fmt::Debug + core::hash::Hash + Default + 'static
{
type Field: Field;
fn from_raw(raw: <Self::Field as Field>::Raw) -> Self;
const ZERO: Self;
const ONE: Self;
#[must_use]
fn add(self, rhs: Self) -> Self;
#[must_use]
fn sub(self, rhs: Self) -> Self;
#[must_use]
fn neg(self) -> Self;
#[must_use]
fn mul(self, rhs: Self) -> Self;
#[must_use]
fn inv(self) -> Self;
#[must_use]
fn div(self, rhs: Self) -> Self;
#[must_use]
fn square(self) -> Self;
#[must_use]
fn pow(self, exponent: u128) -> Self;
fn is_zero(self) -> bool;
fn is_one(self) -> bool;
}
impl<F: Field> element_private::Sealed for Elem<F> {}
impl<F: Field> FieldElem for Elem<F> {
type Field = F;
#[inline]
fn from_raw(raw: F::Raw) -> Self {
let () = Validate::<F>::OK;
Elem {
raw: F::canonical_raw(raw),
}
}
const ZERO: Self = Self::ZERO;
const ONE: Self = Self::ONE;
#[inline]
fn add(self, rhs: Self) -> Self {
Elem {
raw: F::add_raw(self.raw, rhs.raw),
}
}
#[inline]
fn sub(self, rhs: Self) -> Self {
Elem {
raw: F::sub_raw(self.raw, rhs.raw),
}
}
#[inline]
fn neg(self) -> Self {
Elem {
raw: F::neg_raw(self.raw),
}
}
#[inline]
fn mul(self, rhs: Self) -> Self {
Elem {
raw: F::mul_raw(self.raw, rhs.raw),
}
}
#[inline]
fn inv(self) -> Self {
Elem {
raw: F::inv_raw(self.raw),
}
}
#[inline]
fn div(self, rhs: Self) -> Self {
if rhs.raw == F::ZERO_RAW {
Self::ZERO
} else {
Elem {
raw: F::mul_raw(self.raw, F::inv_raw(rhs.raw)),
}
}
}
#[inline]
fn square(self) -> Self {
Elem {
raw: F::mul_raw(self.raw, self.raw),
}
}
#[inline]
fn pow(self, mut exponent: u128) -> Self {
let mut base = self.raw;
let mut result = F::ONE_RAW;
while exponent != 0 {
if exponent & 1 != 0 {
result = F::mul_raw(result, base);
}
base = F::mul_raw(base, base);
exponent >>= 1;
}
Elem { raw: result }
}
#[inline]
fn is_zero(self) -> bool {
self.raw == F::ZERO_RAW
}
#[inline]
fn is_one(self) -> bool {
self.raw == F::ONE_RAW
}
}
impl<F: Field> core::ops::Add for Elem<F> {
type Output = Self;
#[inline]
fn add(self, rhs: Self) -> Self {
Elem {
raw: F::add_raw(self.raw, rhs.raw),
}
}
}
impl<F: Field> core::ops::Sub for Elem<F> {
type Output = Self;
#[inline]
fn sub(self, rhs: Self) -> Self {
Elem {
raw: F::sub_raw(self.raw, rhs.raw),
}
}
}
impl<F: Field> core::ops::Neg for Elem<F> {
type Output = Self;
#[inline]
fn neg(self) -> Self {
Elem {
raw: F::neg_raw(self.raw),
}
}
}
impl<F: Field> core::ops::Mul for Elem<F> {
type Output = Self;
#[inline]
fn mul(self, rhs: Self) -> Self {
Elem {
raw: F::mul_raw(self.raw, rhs.raw),
}
}
}
impl<F: Field> core::ops::Div for Elem<F> {
type Output = Self;
#[inline]
fn div(self, rhs: Self) -> Self {
<Self as FieldElem>::div(self, rhs)
}
}
impl<F: Field> core::ops::AddAssign for Elem<F> {
#[inline]
fn add_assign(&mut self, rhs: Self) {
*self = *self + rhs;
}
}
impl<F: Field> core::ops::SubAssign for Elem<F> {
#[inline]
fn sub_assign(&mut self, rhs: Self) {
*self = *self - rhs;
}
}
impl<F: Field> core::ops::MulAssign for Elem<F> {
#[inline]
fn mul_assign(&mut self, rhs: Self) {
*self = *self * rhs;
}
}
impl<F: Field> core::ops::DivAssign for Elem<F> {
#[inline]
fn div_assign(&mut self, rhs: Self) {
*self = *self / rhs;
}
}
impl<F: Field> core::iter::Sum for Elem<F> {
#[inline]
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(Self::ZERO, |left, right| left + right)
}
}
impl<'a, F: Field> core::iter::Sum<&'a Elem<F>> for Elem<F> {
#[inline]
fn sum<I: Iterator<Item = &'a Elem<F>>>(iter: I) -> Self {
iter.fold(Self::ZERO, |left, &right| left + right)
}
}
impl<F: Field> core::iter::Product for Elem<F> {
#[inline]
fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(Self::ONE, |left, right| left * right)
}
}
impl<'a, F: Field> core::iter::Product<&'a Elem<F>> for Elem<F> {
#[inline]
fn product<I: Iterator<Item = &'a Elem<F>>>(iter: I) -> Self {
iter.fold(Self::ONE, |left, &right| left * right)
}
}
pub trait FieldBuffer: Field {
const BYTES: usize;
const STORAGE_BITS: u32;
fn decode(bytes: &[u8]) -> Elem<Self>;
fn encode(bytes: &mut [u8], value: Elem<Self>);
}