#![forbid(unsafe_code)]
use fgf::Field;
use fgf::{Elem, FiniteField, Mersenne31, Polynomial, QuadMersenne31};
use fgf::poly::AES;
type Gf16 = fgf::FiniteField<2, 16, fgf::Extension<fgf::Rijndael16, 2>>;
type FanPaar8Field = fgf::FiniteField<2, 8, fgf::Extension<fgf::FanPaar8, 2>>;
type FanPaar16Field = fgf::FiniteField<2, 16, fgf::Extension<fgf::FanPaar16, 2>>;
fn main() {
let a = Elem::<FiniteField<2, 8, Polynomial<AES>>>::from_raw(0x53);
let b = Elem::<FiniteField<2, 8, Polynomial<AES>>>::from_raw(0xca);
let x = Elem::<Gf16>::from_components([a, b]);
let conjugate = x.pow(FiniteField::<2, 8, Polynomial<AES>>::ORDER);
assert_eq!(conjugate, Elem::<Gf16>::from_components([a + b, b]));
assert_eq!(
conjugate.pow(FiniteField::<2, 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::<FiniteField<2, 8, Polynomial<AES>>>::ZERO])
);
let [norm_base, norm_extension] = norm.to_components();
assert_eq!(
norm_extension,
Elem::<FiniteField<2, 8, Polynomial<AES>>>::ZERO
);
assert_eq!(
norm_base,
a.square()
+ a * b
+ Elem::<FiniteField<2, 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()]);
assert_eq!(Elem::<Gf16>::ZERO.inv(), Elem::<Gf16>::ZERO);
assert_eq!(x.div(Elem::<Gf16>::ZERO), Elem::<Gf16>::ZERO);
assert_eq!(Elem::<Gf16>::ZERO.pow(0), Elem::<Gf16>::ONE);
assert_eq!(
Elem::<FanPaar16Field>::GENERATOR.pow(65_535),
Elem::<FanPaar16Field>::ONE
);
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()
);
}