macro_rules! quad_tower {
(
$marker:ident, $raw:ty, $base:ty, $base_raw:ty, $shift:literal,
$delta:literal, $generator:literal, $root:literal, $name:literal,
$bits:literal, $bytes:literal, $order:expr,
$debug_fmt:literal, $display_fmt:literal $(,)?
) => {
use core::fmt;
type Base = $base;
use crate::field::{Elem as ElemTrait, Field};
#[doc = concat!("Constant term of the irreducible tower polynomial `", $root, "^2 + ", $root, " + DELTA`.")]
pub const DELTA: Base = Base::from_raw($delta);
pub const GENERATOR: Elem = Elem($generator);
#[doc = concat!("Marker type for ", $name, ".")]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default, PartialOrd, Ord)]
pub struct $marker;
#[doc = concat!("An element of ", $name, ", stored as `a + b*", $root, "` with `a` in the low half.")]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Default, PartialOrd, Ord)]
pub struct Elem(pub(crate) $raw);
impl Elem {
pub const ZERO: Self = Self(0);
pub const ONE: Self = Self(1);
#[doc = concat!("Construct `a + b*", $root, "` from its two base-field components.")]
#[inline]
#[must_use]
pub const fn from_components(a: Base, b: Base) -> Self {
Self((a.to_raw() as $raw) | ((b.to_raw() as $raw) << $shift))
}
#[doc = concat!("Return the `(a, b)` components of `a + b*", $root, "`.")]
#[inline]
#[must_use]
#[allow(clippy::cast_possible_truncation)]
pub const fn to_components(self) -> (Base, Base) {
(
Base::from_raw(self.0 as $base_raw),
Base::from_raw((self.0 >> $shift) as $base_raw),
)
}
#[inline]
#[must_use]
pub const fn from_bytes(bytes: [u8; $bytes]) -> Self {
Self(<$raw>::from_le_bytes(bytes))
}
#[inline]
#[must_use]
pub const fn to_bytes(self) -> [u8; $bytes] {
self.0.to_le_bytes()
}
#[inline]
#[must_use]
pub const fn from_raw(value: $raw) -> Self {
Self(value)
}
#[inline]
#[must_use]
pub const fn to_raw(self) -> $raw {
self.0
}
#[inline]
#[must_use]
pub const fn add(self, rhs: Self) -> Self {
Self(self.0 ^ rhs.0)
}
#[inline]
#[must_use]
pub const fn sub(self, rhs: Self) -> Self {
self.add(rhs)
}
#[inline]
#[must_use]
pub const fn neg(self) -> Self {
self
}
#[doc = concat!("Karatsuba multiplication followed by `", $root, "^2 = ", $root, " + DELTA` reduction.")]
#[inline]
#[must_use]
pub const fn mul(self, rhs: Self) -> Self {
let (a, b) = self.to_components();
let (c, d) = rhs.to_components();
let ac = a.mul(c);
let bd = b.mul(d);
let constant = ac.add(DELTA.mul(bd));
let extension = a.add(b).mul(c.add(d)).add(ac);
Self::from_components(constant, extension)
}
#[inline]
#[must_use]
pub const fn square(self) -> Self {
let (a, b) = self.to_components();
let a2 = a.square();
let b2 = b.square();
Self::from_components(a2.add(DELTA.mul(b2)), b2)
}
#[doc = concat!("`conj(a + b*", $root, ") = (a + b) + b*", $root, "` and `norm = a^2 + a*b + DELTA*b^2`,")]
#[inline]
#[must_use]
pub const fn inv(self) -> Self {
let (a, b) = self.to_components();
if a.to_raw() == 0 && b.to_raw() == 0 {
return Self::ZERO;
}
let norm = a.square().add(a.mul(b)).add(DELTA.mul(b.square()));
let norm_inv = norm.inv();
Self::from_components(a.add(b).mul(norm_inv), b.mul(norm_inv))
}
#[must_use]
pub const fn div(self, rhs: Self) -> Self {
if self.0 == 0 || rhs.0 == 0 {
return Self::ZERO;
}
self.mul(rhs.inv())
}
#[must_use]
pub const fn pow(self, mut exponent: u64) -> 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
}
}
impl ElemTrait for Elem {
const ZERO: Self = Self::ZERO;
const ONE: Self = Self::ONE;
#[inline]
fn add(self, rhs: Self) -> Self {
Elem::add(self, rhs)
}
#[inline]
fn sub(self, rhs: Self) -> Self {
Elem::sub(self, rhs)
}
#[inline]
fn mul(self, rhs: Self) -> Self {
Elem::mul(self, rhs)
}
#[inline]
fn square(self) -> Self {
Elem::square(self)
}
#[inline]
fn inv(self) -> Self {
Elem::inv(self)
}
#[inline]
fn div(self, rhs: Self) -> Self {
Elem::div(self, rhs)
}
#[inline]
fn pow(self, exponent: u64) -> Self {
Elem::pow(self, exponent)
}
}
impl Field for $marker {
type Elem = Elem;
const NAME: &'static str = $name;
const BITS: u32 = $bits;
const BYTES: usize = $bytes;
const ORDER: u128 = $order;
const CHARACTERISTIC: u64 = 2;
const GENERATOR: Elem = GENERATOR;
#[inline]
fn decode(bytes: &[u8]) -> Elem {
let bytes: [u8; $bytes] = bytes
.try_into()
.expect(concat!($name, " element has the wrong byte width"));
Elem::from_bytes(bytes)
}
#[inline]
fn encode(bytes: &mut [u8], value: Elem) {
assert_eq!(
bytes.len(),
$bytes,
concat!($name, " element has the wrong byte width")
);
bytes.copy_from_slice(&value.to_bytes());
}
}
impl fmt::Debug for Elem {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let (a, b) = self.to_components();
write!(f, $debug_fmt, a.to_raw(), b.to_raw())
}
}
impl fmt::Display for Elem {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, $display_fmt, self.0)
}
}
impl core::ops::Add for Elem {
type Output = Self;
#[inline]
fn add(self, rhs: Self) -> Self {
Elem::add(self, rhs)
}
}
impl core::ops::Sub for Elem {
type Output = Self;
#[inline]
fn sub(self, rhs: Self) -> Self {
Elem::sub(self, rhs)
}
}
impl core::ops::Neg for Elem {
type Output = Self;
#[inline]
fn neg(self) -> Self {
Elem::neg(self)
}
}
impl core::ops::Mul for Elem {
type Output = Self;
#[inline]
fn mul(self, rhs: Self) -> Self {
Elem::mul(self, rhs)
}
}
impl core::ops::Div for Elem {
type Output = Self;
#[inline]
fn div(self, rhs: Self) -> Self {
Elem::div(self, rhs)
}
}
impl core::ops::AddAssign for Elem {
#[inline]
fn add_assign(&mut self, rhs: Self) {
*self = Elem::add(*self, rhs);
}
}
impl core::ops::SubAssign for Elem {
#[inline]
fn sub_assign(&mut self, rhs: Self) {
*self = Elem::sub(*self, rhs);
}
}
impl core::ops::MulAssign for Elem {
#[inline]
fn mul_assign(&mut self, rhs: Self) {
*self = Elem::mul(*self, rhs);
}
}
impl core::ops::DivAssign for Elem {
#[inline]
fn div_assign(&mut self, rhs: Self) {
*self = Elem::div(*self, rhs);
}
}
impl core::iter::Sum for Elem {
#[inline]
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(Self::ZERO, Elem::add)
}
}
impl<'a> core::iter::Sum<&'a Elem> for Elem {
#[inline]
fn sum<I: Iterator<Item = &'a Elem>>(iter: I) -> Self {
iter.fold(Self::ZERO, |acc, &x| Elem::add(acc, x))
}
}
impl core::iter::Product for Elem {
#[inline]
fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(Self::ONE, Elem::mul)
}
}
impl<'a> core::iter::Product<&'a Elem> for Elem {
#[inline]
fn product<I: Iterator<Item = &'a Elem>>(iter: I) -> Self {
iter.fold(Self::ONE, |acc, &x| Elem::mul(acc, x))
}
}
};
}
pub mod gf16 {
quad_tower!(
Gf16,
u16,
crate::field::gf8b::Elem,
u8,
8,
0x20,
0x0108,
"u",
"GF(2^16)",
16,
2,
65_536,
"Gf16({:#04x}+{:#04x}u)",
"{:04x}",
);
}
pub mod gf32 {
quad_tower!(
Gf32,
u32,
super::gf16::Elem,
u16,
16,
0x2000,
0x0001_0002,
"v",
"GF(2^32)",
32,
4,
1u128 << 32,
"Gf32({:#06x}+{:#06x}v)",
"{:08x}",
);
}
pub mod gf64 {
quad_tower!(
Gf64,
u64,
super::gf32::Elem,
u32,
32,
0x2000_0000,
0x0000_0001_0000_0004,
"w",
"GF(2^64)",
64,
8,
1u128 << 64,
"Gf64({:#010x}+{:#010x}w)",
"{:016x}",
);
}