#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(transparent)]
pub struct F2(pub u8);
impl F2 {
pub const ZERO: Self = F2(0);
pub const ONE: Self = F2(1);
#[inline(always)]
pub fn add(self, rhs: Self) -> Self { F2(self.0 ^ rhs.0) }
#[inline(always)]
pub fn mul(self, rhs: Self) -> Self { F2(self.0 & rhs.0) }
#[inline(always)]
pub fn inv(self) -> Self {
debug_assert!(self.0 == 1, "inverse of zero");
self
}
#[inline(always)]
pub fn square(self) -> Self { self }
#[inline(always)]
pub fn sqrt(self) -> Self { self }
#[inline(always)]
pub fn trace(self) -> Self { self }
#[inline(always)]
pub fn is_zero(self) -> bool { self.0 == 0 }
#[inline(always)]
pub fn from_u8(v: u8) -> Self { F2(v & 1) }
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(transparent)]
pub struct F2_2(pub u8);
impl F2_2 {
pub const ZERO: Self = F2_2(0);
pub const ONE: Self = F2_2(1);
pub const BITS: u32 = 2;
#[inline(always)]
pub fn add(self, rhs: Self) -> Self { F2_2(self.0 ^ rhs.0) }
#[inline(always)]
pub fn mul(self, rhs: Self) -> Self {
let a0 = self.0 & 1;
let a1 = (self.0 >> 1) & 1;
let b0 = rhs.0 & 1;
let b1 = (rhs.0 >> 1) & 1;
let c0 = (a0 & b0) ^ (a1 & b1);
let c1 = (a0 & b1) ^ (a1 & b0) ^ (a1 & b1);
F2_2(c0 | (c1 << 1))
}
#[inline(always)]
pub fn square(self) -> Self {
let a0 = self.0 & 1;
let a1 = (self.0 >> 1) & 1;
F2_2((a0 ^ a1) | (a1 << 1))
}
pub fn inv(self) -> Self {
debug_assert!(self.0 != 0, "inverse of zero");
self.square()
}
pub fn frobenius(self, k: u32) -> Self {
let mut r = self;
for _ in 0..k { r = r.square(); }
r
}
pub fn sqrt(self) -> Self { self.frobenius(1) }
pub fn trace(self) -> F2 {
F2((self.0 >> 1) & 1)
}
pub fn norm(self) -> F2 {
let p = self.mul(self.square());
F2(p.0 & 1)
}
pub fn exp(self, mut e: u128) -> Self {
if e == 0 { return Self::ONE; }
let mut base = self;
let mut result = Self::ONE;
while e > 0 {
if e & 1 == 1 { result = result.mul(base); }
base = base.square();
e >>= 1;
}
result
}
#[inline(always)]
pub fn is_zero(self) -> bool { self.0 == 0 }
}
macro_rules! tower_level {
(
$name:ident, $repr:ty, $bits:expr,
$half:ident, $half_bits:expr,
$lo_mask:expr, $alpha:expr
) => {
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(transparent)]
pub struct $name(pub $repr);
impl $name {
pub const ZERO: Self = $name(0);
pub const ONE: Self = $name(1);
pub const BITS: u32 = $bits;
const ALPHA: $half = $half($alpha);
#[inline(always)]
fn lo(self) -> $half { $half((self.0 & $lo_mask) as _) }
#[inline(always)]
fn hi(self) -> $half { $half((self.0 >> $half_bits) as _) }
#[inline(always)]
fn pack(lo: $half, hi: $half) -> Self {
$name((lo.0 as $repr) | ((hi.0 as $repr) << $half_bits))
}
#[inline(always)]
pub fn add(self, rhs: Self) -> Self {
$name(self.0 ^ rhs.0)
}
#[inline]
pub fn mul(self, rhs: Self) -> Self {
let a_lo = self.lo();
let a_hi = self.hi();
let b_lo = rhs.lo();
let b_hi = rhs.hi();
let ll = a_lo.mul(b_lo);
let hh = a_hi.mul(b_hi);
let cross = a_lo.add(a_hi).mul(b_lo.add(b_hi)).add(ll).add(hh);
let c_lo = ll.add(hh.mul(Self::ALPHA));
let c_hi = cross.add(hh);
Self::pack(c_lo, c_hi)
}
#[inline]
pub fn square(self) -> Self {
let lo = self.lo();
let hi = self.hi();
let lo_sq = lo.square();
let hi_sq = hi.square();
let c_lo = lo_sq.add(hi_sq.mul(Self::ALPHA));
Self::pack(c_lo, hi_sq)
}
pub fn frobenius(self, k: u32) -> Self {
let mut r = self;
for _ in 0..k { r = r.square(); }
r
}
pub fn sqrt(self) -> Self {
self.frobenius($bits - 1)
}
pub fn trace(self) -> F2 {
let relative = self.lo().add(self.hi()); relative.trace() }
pub fn norm(self) -> $half {
let a_lo = self.lo();
let a_hi = self.hi();
a_lo.mul(a_lo.add(a_hi)).add(a_hi.square().mul(Self::ALPHA))
}
pub fn inv(self) -> Self {
debug_assert!(self.0 != 0, "inverse of zero");
let a_lo = self.lo();
let a_hi = self.hi();
let delta = a_lo.mul(a_lo.add(a_hi))
.add(a_hi.square().mul(Self::ALPHA));
let delta_inv = delta.inv();
let c_lo = delta_inv.mul(a_lo.add(a_hi));
let c_hi = delta_inv.mul(a_hi);
Self::pack(c_lo, c_hi)
}
pub fn exp(self, mut e: u128) -> Self {
if e == 0 { return Self::ONE; }
let mut base = self;
let mut result = Self::ONE;
while e > 0 {
if e & 1 == 1 { result = result.mul(base); }
base = base.square();
e >>= 1;
}
result
}
#[inline(always)]
pub fn is_zero(self) -> bool { self.0 == 0 }
}
};
}
tower_level!(F2_4, u8, 4, F2_2, 2, 0x03u8, 0x02); tower_level!(F2_8, u8, 8, F2_4, 4, 0x0Fu8, 0x08); tower_level!(F2_16, u16, 16, F2_8, 8, 0x00FFu16, 0x80); tower_level!(F2_32, u32, 32, F2_16, 16, 0x0000_FFFFu32, 0x8000); tower_level!(F2_64, u64, 64, F2_32, 32, 0x0000_0000_FFFF_FFFFu64, 0x8000_0000); tower_level!(F2_128, u128, 128, F2_64, 64, 0x0000_0000_0000_0000_FFFF_FFFF_FFFF_FFFFu128, 0x8000_0000_0000_0000);