#![forbid(unsafe_code)]
use fgf::Field;
use fgf::{Binary, Elem, Mersenne31, Polynomial, QuadMersenne31};
use fgf::poly::AES;
type Gf16 = fgf::Binary<16, fgf::Tower<fgf::Rijndael16>>;
type FanPaar8Field = fgf::Binary<8, fgf::Tower<fgf::FanPaar8>>;
type FanPaar16Field = fgf::Binary<16, fgf::Tower<fgf::FanPaar16>>;
fn main() {
let a = Elem::<Binary<8, Polynomial<AES>>>::from_raw(0x53);
let b = Elem::<Binary<8, Polynomial<AES>>>::from_raw(0xca);
let x = Elem::<Gf16>::from_components(a, b);
let conjugate = x.pow(Binary::<8, Polynomial<AES>>::ORDER);
assert_eq!(conjugate, Elem::<Gf16>::from_components(a + b, b));
assert_eq!(conjugate.pow(Binary::<8, Polynomial<AES>>::ORDER), x);
assert_eq!(x.pow(Gf16::ORDER), x);
let trace = x + conjugate;
let norm = x * conjugate;
assert_eq!(
trace,
Elem::<Gf16>::from_components(b, Elem::<Binary<8, Polynomial<AES>>>::ZERO)
);
let (norm_base, norm_extension) = norm.to_components();
assert_eq!(norm_extension, Elem::<Binary<8, Polynomial<AES>>>::ZERO);
assert_eq!(
norm_base,
a.square() + a * b + Elem::<Binary<8, Polynomial<AES>>>::from_raw(0x20) * b.square()
);
assert_eq!(x * x.inv(), Elem::<Gf16>::ONE);
assert_eq!(x.to_bytes(), [a.to_raw(), b.to_raw()]);
println!("AES-rooted tower: x={x}, conjugate={conjugate}, trace={trace}, norm={norm_base}");
let c = Elem::<FanPaar8Field>::from_raw(0x53);
let d = Elem::<FanPaar8Field>::from_raw(0xca);
let embedded_c = Elem::<FanPaar16Field>::from_components(c, Elem::<FanPaar8Field>::ZERO);
let embedded_d = Elem::<FanPaar16Field>::from_components(d, Elem::<FanPaar8Field>::ZERO);
assert_eq!(
embedded_c * embedded_d,
Elem::<FanPaar16Field>::from_components(c * d, Elem::<FanPaar8Field>::ZERO)
);
let y = Elem::<FanPaar16Field>::from_components(c, d);
assert_eq!(y.mul_alpha(), y * Elem::<FanPaar16Field>::from_raw(0x0100));
let y_conjugate = y.pow(256);
assert_eq!(
(y + y_conjugate).to_components().1,
Elem::<FanPaar8Field>::ZERO
);
assert_eq!(
(y * y_conjugate).to_components().1,
Elem::<FanPaar8Field>::ZERO
);
println!(
"Fan–Paar tower: y={y}, y * tower generator={}",
y.mul_alpha()
);
let re = Elem::<Mersenne31>::from_raw(7);
let im = Elem::<Mersenne31>::from_raw(11);
let z = Elem::<QuadMersenne31>::from_components(re, im);
assert_eq!(
Elem::<QuadMersenne31>::I.square(),
-Elem::<QuadMersenne31>::ONE
);
assert_eq!(z.pow(Mersenne31::ORDER), z.conjugate());
assert_eq!(z.norm(), re.square() + im.square());
assert_eq!(
z * z.conjugate(),
Elem::<QuadMersenne31>::from_components(z.norm(), Elem::<Mersenne31>::ZERO)
);
assert_eq!(z * z.inv(), Elem::<QuadMersenne31>::ONE);
println!(
"QuadMersenne31: z={z}, conjugate={}, norm={}",
z.conjugate(),
z.norm()
);
}