pub mod cantor;
pub mod description;
pub mod normal;
pub mod poly;
pub mod tower;
pub use cantor::Cantor;
pub use description::{BinaryDescription, ByteLogExp};
pub use normal::Normal;
pub use poly::{AES, Polynomial, RS};
use core::fmt;
use super::finite_field::{FiniteField, FiniteFieldRepr, checked_order};
use super::{Elem, Field, FieldBuffer, PrimeCharacteristic, RangeError, Validate};
pub(crate) mod binary_private {
pub trait Sealed {}
}
pub trait BinaryRepr<const N: u32>: FiniteFieldRepr<2, N> {
const DESCRIPTION: &'static BinaryDescription;
const LOG_EXP: Option<&'static ByteLogExp>;
}
#[allow(private_bounds)]
pub trait BinaryField:
Field<Characteristic = PrimeCharacteristic<2>> + binary_private::Sealed
{
const DESCRIPTION: &'static BinaryDescription;
}
pub trait BinaryDegree<const N: u32>: BinaryField {}
#[allow(clippy::cast_possible_truncation)]
pub(crate) const fn residue_row_raw<R: BinaryRepr<1>>(value: u64) -> u8 {
let () = Validate::<FiniteField<2, 1, R>>::OK;
if value.is_multiple_of(2) {
0
} else {
R::DESCRIPTION.one() as u8
}
}
#[allow(clippy::cast_possible_truncation)]
pub(crate) const fn residue_row_value<R: BinaryRepr<1>>(raw: u8) -> Option<u64> {
let () = Validate::<FiniteField<2, 1, R>>::OK;
let one = R::DESCRIPTION.one() as u8;
if raw == 0 {
Some(0)
} else if raw == one {
Some(1)
} else {
None
}
}
macro_rules! prime_hooks {
(1) => {
fn from_prime(value: u64) -> <Self as Field>::Raw {
let () = Validate::<Self>::OK;
$crate::field::binary::residue_row_raw::<R>(value % 2)
}
fn to_prime(raw: <Self as Field>::Raw) -> Option<u64> {
let () = Validate::<Self>::OK;
$crate::field::binary::residue_row_value::<R>(<Self as Field>::canonical_raw(raw))
}
};
($n:literal) => {
fn from_prime(value: u64) -> <Self as Field>::Raw {
let () = Validate::<Self>::OK;
if value % 2 == 0 {
<Self as Field>::ZERO_RAW
} else {
<Self as Field>::ONE_RAW
}
}
fn to_prime(raw: <Self as Field>::Raw) -> Option<u64> {
let () = Validate::<Self>::OK;
let raw = <Self as Field>::canonical_raw(raw);
if raw == <Self as Field>::ZERO_RAW {
Some(0)
} else if raw == <Self as Field>::ONE_RAW {
Some(1)
} else {
None
}
}
};
}
macro_rules! degree_row {
($n:literal, $raw:ty, $mask:expr) => {
impl<R: BinaryRepr<$n>> $crate::field::binary::binary_private::Sealed
for FiniteField<2, $n, R>
{
}
impl<R: BinaryRepr<$n>> Field for FiniteField<2, $n, R> {
type Raw = $raw;
type Characteristic = PrimeCharacteristic<2>;
const NAME: &'static str = <R as FiniteFieldRepr<2, $n>>::NAME;
const DEGREE: u32 = $n;
const ORDER: u128 = checked_order::<2, $n>();
const ZERO_RAW: $raw = {
let () = <Self as Field>::VALID;
0
};
#[allow(clippy::cast_possible_truncation)]
const ONE_RAW: $raw = {
let () = <Self as Field>::VALID;
R::DESCRIPTION.one() as $raw
};
const VALID: () = {
checked_order::<2, $n>();
let () = <R as FiniteFieldRepr<2, $n>>::VALID;
};
#[inline]
fn canonical_raw(raw: $raw) -> $raw {
let () = Validate::<Self>::OK;
raw & $mask
}
#[inline]
fn add_raw(left: $raw, right: $raw) -> $raw {
let () = Validate::<Self>::OK;
left ^ right
}
#[inline]
fn sub_raw(left: $raw, right: $raw) -> $raw {
let () = Validate::<Self>::OK;
left ^ right
}
#[inline]
fn neg_raw(value: $raw) -> $raw {
let () = Validate::<Self>::OK;
value
}
#[inline]
fn mul_raw(left: $raw, right: $raw) -> $raw {
Elem::<Self>::from_raw(left)
.mul(Elem::<Self>::from_raw(right))
.to_raw()
}
#[inline]
fn inv_raw(value: $raw) -> $raw {
Elem::<Self>::from_raw(value).inv().to_raw()
}
}
impl<R: BinaryRepr<$n>> $crate::field::private::RowAccess for FiniteField<2, $n, R> {
const DESCRIPTOR: &'static $crate::field::extension::Descriptor =
R::DESCRIPTION.as_descriptor();
const BINARY_DESCRIPTION: Option<
&'static $crate::field::binary::description::BinaryDescription,
> = Some(R::DESCRIPTION);
fn prime_coordinates_into(dst: &mut [u64], raw: <Self as Field>::Raw) {
let () = Validate::<Self>::OK;
assert_eq!(
dst.len(),
$n,
"prime coordinate count differs from the field degree"
);
#[allow(clippy::cast_lossless)]
let word = <Self as Field>::canonical_raw(raw) as u64;
let mut i: u32 = 0;
while i < $n {
dst[i as usize] = (word >> i) & 1;
i += 1;
}
}
fn from_prime_coordinates(src: &[u64]) -> <Self as Field>::Raw {
let () = Validate::<Self>::OK;
assert_eq!(
src.len(),
$n,
"prime coordinate count differs from the field degree"
);
let mut word = 0u64;
let mut i: u32 = 0;
while i < $n {
let coordinate = src[i as usize];
assert!(
coordinate < 2,
"prime coordinate is not below the characteristic"
);
word |= coordinate << i;
i += 1;
}
#[allow(clippy::cast_possible_truncation)]
let raw = word as $raw;
raw
}
prime_hooks!($n);
}
impl<R: BinaryRepr<$n>> BinaryField for FiniteField<2, $n, R> {
const DESCRIPTION: &'static BinaryDescription = R::DESCRIPTION;
}
impl<R: BinaryRepr<$n>> BinaryDegree<$n> for FiniteField<2, $n, R> {}
};
}
macro_rules! small_row {
($n:literal, $mask:expr) => {
impl<R: BinaryRepr<$n>> Elem<FiniteField<2, $n, R>> {
#[allow(clippy::let_unit_value)]
#[allow(clippy::ignored_unit_patterns)]
#[inline]
#[must_use]
pub const fn from_raw(value: u8) -> Self {
let () = Validate::<FiniteField<2, $n, R>>::OK;
let () = R::VALID;
Elem { raw: value & $mask }
}
#[inline]
#[must_use]
pub const fn from_bytes(bytes: [u8; 1]) -> Self {
Self::from_raw(bytes[0])
}
#[inline]
#[must_use]
pub const fn to_bytes(self) -> [u8; 1] {
[self.raw]
}
#[inline]
#[must_use]
pub const fn add(self, rhs: Self) -> Self {
Elem {
raw: self.raw ^ rhs.raw,
}
}
#[inline]
#[must_use]
pub const fn sub(self, rhs: Self) -> Self {
self.add(rhs)
}
#[inline]
#[must_use]
pub const fn neg(self) -> Self {
self
}
#[inline]
#[must_use]
pub const fn mul(self, rhs: Self) -> Self {
match R::LOG_EXP {
Some(tables) => Elem {
raw: tables.mul(self.raw, rhs.raw),
},
None => {
#[allow(clippy::cast_possible_truncation, clippy::cast_lossless)]
let product = R::DESCRIPTION.mul(self.raw as u64, rhs.raw as u64) as u8;
Elem { raw: product }
}
}
}
#[inline]
#[must_use]
pub const fn square(self) -> Self {
self.mul(self)
}
#[inline]
#[must_use]
pub const fn inv(self) -> Self {
match R::LOG_EXP {
Some(tables) => Elem {
raw: tables.inv(self.raw),
},
None => {
#[allow(clippy::cast_possible_truncation, clippy::cast_lossless)]
let inverse = R::DESCRIPTION.inv(self.raw as u64) as u8;
Elem { raw: inverse }
}
}
}
#[inline]
#[must_use]
pub const fn div(self, rhs: Self) -> Self {
if self.raw == 0 || rhs.raw == 0 {
return Self::ZERO;
}
self.mul(rhs.inv())
}
#[must_use]
pub const fn pow(self, mut exponent: u128) -> Self {
let mut base = self;
let mut result = Self::ONE;
while exponent != 0 {
if exponent & 1 != 0 {
result = result.mul(base);
}
base = base.square();
exponent >>= 1;
}
result
}
#[inline]
#[must_use]
pub const fn canonical(self) -> Self {
self
}
#[inline]
#[must_use]
pub const fn is_zero(self) -> bool {
self.raw == 0
}
#[inline]
#[must_use]
pub const fn is_one(self) -> bool {
self.raw == Self::ONE.raw
}
}
};
}
degree_row!(1, u8, 0x1);
degree_row!(2, u8, 0x3);
degree_row!(4, u8, 0xF);
degree_row!(8, u8, 0xFF);
small_row!(1, 0x1);
small_row!(2, 0x3);
small_row!(4, 0xF);
small_row!(8, 0xFF);
impl<R: BinaryRepr<1>> Elem<FiniteField<2, 1, R>> {
#[inline]
pub const fn from_residue(value: u64) -> Result<Self, RangeError> {
match super::check_residue(value, 2) {
Ok(checked) => Ok(Elem {
raw: residue_row_raw::<R>(checked),
}),
Err(error) => Err(error),
}
}
#[inline]
#[must_use]
pub const fn to_residue(self) -> Option<u64> {
residue_row_value::<R>(self.raw)
}
}
impl<R: BinaryRepr<8>> FieldBuffer for FiniteField<2, 8, R> {
const BYTES: usize = 1;
const STORAGE_BITS: u32 = 8;
#[inline]
fn decode(bytes: &[u8]) -> Elem<Self> {
let bytes: [u8; 1] = bytes
.try_into()
.expect("GF(2^8) element has the wrong byte width");
Elem::<Self>::from_raw(bytes[0])
}
#[inline]
fn encode(bytes: &mut [u8], value: Elem<Self>) {
assert_eq!(bytes.len(), 1, "GF(2^8) element has the wrong byte width");
bytes.copy_from_slice(&value.to_bytes());
}
}
impl<R: BinaryRepr<8>> fmt::Display for Elem<FiniteField<2, 8, R>> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "{:02x}", self.raw)
}
}
impl<R: BinaryRepr<1>> fmt::Display for Elem<FiniteField<2, 1, R>> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "{}", self.raw)
}
}
impl<R: BinaryRepr<2>> fmt::Display for Elem<FiniteField<2, 2, R>> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "{:01x}", self.raw)
}
}
impl<R: BinaryRepr<4>> fmt::Display for Elem<FiniteField<2, 4, R>> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "{:01x}", self.raw)
}
}