#![forbid(unsafe_code)]
use fgf::poly::{AES, RS};
use fgf::{Binary, Elem, Embedding, EmbeddingError, Polynomial};
type Gf1 = fgf::Binary<1, fgf::Polynomial<3>>;
type Gf16 = fgf::Binary<16, fgf::Tower<fgf::Rijndael16>>;
type Gf64 = fgf::Binary<64, fgf::Tower<fgf::Rijndael64>>;
type FanPaar16Field = fgf::Binary<16, fgf::Tower<fgf::FanPaar16>>;
type Aes = Binary<8, Polynomial<AES>>;
type Nibble = Binary<4, Polynomial<0x13>>;
fn main() {
let small = Embedding::<Nibble, Aes>::new().unwrap();
let x = Elem::<Nibble>::from_raw(2);
let image = small.embed(x);
assert_eq!(image, Elem::<Aes>::from_raw(0x5C));
assert!(small.contains(image));
assert_eq!(small.restrict(image), Some(x));
assert_eq!(small.restrict(Elem::<Aes>::from_raw(2)), None);
println!("GF(16) x embeds into AES as {image}; the literal byte 2 is outside the image.");
let involution =
Embedding::<Binary<8, Polynomial<AES>>, Binary<8, Polynomial<RS>>>::new().unwrap();
let (a, b) = (Elem::<Aes>::from_raw(0x53), Elem::<Aes>::from_raw(0xca));
assert_eq!(
involution.embed(Elem::<Aes>::ONE),
Elem::<Binary<8, Polynomial<RS>>>::ONE
);
assert_eq!(
involution.embed(a * b),
involution.embed(a) * involution.embed(b)
);
assert_eq!(involution.restrict(involution.embed(a)), Some(a));
println!(
"AES {a} * {b} = {} maps to {} in the Reed-Solomon basis.",
a * b,
involution.embed(a * b)
);
let tower = Embedding::<Aes, Gf16>::new().unwrap();
let (lo, hi) = (Elem::<Aes>::from_raw(0x53), Elem::<Aes>::from_raw(0xca));
let z = Elem::<Gf16>::from_components(lo, hi);
assert_eq!(
tower.embed(lo),
Elem::<Gf16>::from_components(lo, Elem::<Aes>::ZERO)
);
assert_eq!(
tower.frobenius(z),
Elem::<Gf16>::from_components(lo + hi, hi)
);
assert_eq!(tower.trace(z), hi);
assert_eq!(
tower.norm(z),
lo.square() + lo * hi + Elem::<Aes>::from_raw(0x20) * hi.square()
);
let indeterminate = Elem::<Gf16>::from_raw(0x0100);
assert!(!tower.contains(indeterminate));
assert_eq!(tower.restrict(indeterminate), None);
println!(
"Gf16 z={z} has relative trace {hi} and norm {}.",
tower.norm(z)
);
let cross = Embedding::<FanPaar16Field, Gf16>::new().unwrap();
let (p, q) = (
Elem::<FanPaar16Field>::from_raw(0x35C2),
Elem::<FanPaar16Field>::from_raw(0x1234),
);
assert_eq!(cross.restrict(cross.embed(p * q)), Some(p * q));
assert_ne!(cross.embed(p).to_raw(), p.to_raw());
println!(
"Fan-Paar {p} maps to {} in the Rijndael basis.",
cross.embed(p)
);
let wide = Embedding::<Gf16, Gf64>::new().unwrap();
let lifted = wide.embed(z);
assert!(wide.contains(lifted));
assert_eq!(wide.restrict(lifted), Some(z));
assert_eq!(
wide.embed(tower.embed(lo)),
Embedding::<Aes, Gf64>::new().unwrap().embed(lo)
);
let mut frobenius = lifted;
for _ in 0..4 {
frobenius = wide.frobenius(frobenius);
}
assert_eq!(frobenius, lifted);
println!("Gf16 z={z} lifts into GF(2^64) as {lifted}; four Frobenius steps return it.");
let absolute = Embedding::<Gf1, Gf16>::new().unwrap();
let mut conjugate_sum = Elem::<Gf16>::ZERO;
let mut power = z;
for _ in 0..16 {
conjugate_sum += power;
power = power.square();
}
assert_eq!(absolute.restrict(conjugate_sum), Some(absolute.trace(z)));
println!(
"Absolute trace of z is {}.",
u8::from(absolute.trace(z).is_one())
);
assert_eq!(
Embedding::<Gf16, Aes>::new().unwrap_err(),
EmbeddingError::IncompatibleDegree {
source: 16,
target: 8
}
);
println!("GF(2^16) into GF(2^8) is rejected: source degree does not divide target degree.");
}