use std::fmt;
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
#[derive(Copy, Clone)]
pub struct Tables {
pub exp: [u8; 255],
pub log: [u8; 256],
}
impl PartialEq for Tables {
fn eq(&self, other: &Tables) -> bool {
for i in 0..255 {
if self.exp[i] != other.exp[i] {
return false;
}
if self.log[i] != other.log[i] {
return false;
}
}
true
}
}
impl fmt::Debug for Tables {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let _ = writeln!(f, "exp: (");
for i in 0..255 {
let _ = write!(f, "{}, ", self.exp[i]);
}
let _ = writeln!(f, ")");
let _ = writeln!(f, "log: (");
for i in 0..256 {
let _ = write!(f, "{}, ", self.log[i]);
}
writeln!(f, ")")
}
}
impl Tables {
pub fn generate() -> Tables {
let mut tabs = Tables {
exp: [0; 255],
log: [0; 256],
};
let mut tmp: u16 = 1;
for power in 0..255usize {
tabs.exp[power] = tmp as u8;
tabs.log[tmp as usize] = power as u8;
tmp = (tmp << 1) ^ tmp;
if (tmp & 0x100) > 0 {
tmp ^= 0x11B;
}
}
tabs
}
}
lazy_static! {
pub static ref TABLES: Tables = { Tables::generate() };
}
fn get_tables() -> &'static Tables {
&TABLES
}
#[derive(Copy, Debug, Clone, PartialEq, Eq)]
pub struct Gf256 {
pub poly: u8,
}
impl Gf256 {
#[inline]
pub fn zero() -> Gf256 {
Gf256 { poly: 0 }
}
#[inline]
pub fn one() -> Gf256 {
Gf256 { poly: 1 }
}
#[inline]
pub fn from_byte(b: u8) -> Gf256 {
Gf256 { poly: b }
}
#[inline]
pub fn to_byte(self) -> u8 {
self.poly
}
pub fn exp(power: u8) -> Gf256 {
let tabs = get_tables();
Gf256::from_byte(tabs.exp[power as usize])
}
pub fn log(self) -> Option<u8> {
if self.poly == 0 {
None
} else {
let tabs = get_tables();
Some(tabs.log[self.poly as usize])
}
}
pub fn pow(mut self, mut exp: u8) -> Gf256 {
let mut acc = Self::one();
while exp > 1 {
if (exp & 1) == 1 {
acc *= self;
}
exp /= 2;
self *= self;
}
if exp == 1 {
acc *= self;
}
acc
}
}
impl Add<Gf256> for Gf256 {
type Output = Gf256;
#[inline]
#[allow(clippy::suspicious_arithmetic_impl)]
fn add(self, rhs: Gf256) -> Gf256 {
Gf256::from_byte(self.poly ^ rhs.poly)
}
}
impl AddAssign<Gf256> for Gf256 {
#[inline]
fn add_assign(&mut self, rhs: Gf256) {
*self = *self + rhs;
}
}
impl Sub<Gf256> for Gf256 {
type Output = Gf256;
#[inline]
#[allow(clippy::suspicious_arithmetic_impl)]
fn sub(self, rhs: Gf256) -> Gf256 {
Gf256::from_byte(self.poly ^ rhs.poly)
}
}
impl SubAssign<Gf256> for Gf256 {
#[inline]
fn sub_assign(&mut self, rhs: Gf256) {
*self = *self - rhs;
}
}
impl Mul<Gf256> for Gf256 {
type Output = Gf256;
fn mul(self, rhs: Gf256) -> Gf256 {
if let (Some(l1), Some(l2)) = (self.log(), rhs.log()) {
let tmp = (u16::from(l1) + u16::from(l2)) % 255;
Gf256::exp(tmp as u8)
} else {
Gf256 { poly: 0 }
}
}
}
impl MulAssign<Gf256> for Gf256 {
fn mul_assign(&mut self, rhs: Gf256) {
*self = *self * rhs;
}
}
impl Div<Gf256> for Gf256 {
type Output = Gf256;
fn div(self, rhs: Gf256) -> Gf256 {
let l2 = rhs.log().expect("division by zero");
if let Some(l1) = self.log() {
let tmp = (u16::from(l1) + 255 - u16::from(l2)) % 255;
Gf256::exp(tmp as u8)
} else {
Gf256 { poly: 0 }
}
}
}
impl DivAssign<Gf256> for Gf256 {
fn div_assign(&mut self, rhs: Gf256) {
*self = *self / rhs;
}
}
impl Neg for Gf256 {
type Output = Gf256;
fn neg(self) -> Gf256 {
Gf256::zero() - self
}
}
#[macro_export]
#[doc(hidden)]
macro_rules! gf256 {
($e:expr) => {
Gf256::from_byte($e)
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! gf256_vec {
( $( ($x:expr, $y:expr) ),* ) => {
{
let mut temp_vec = Vec::new();
$(
temp_vec.push((Gf256::from_byte($x), Gf256::from_byte($y)));
)*
temp_vec
}
};
( $( $x:expr ),* ) => {
{
let mut temp_vec = Vec::new();
$(
temp_vec.push(Gf256::from_byte($x));
)*
temp_vec
}
};
}
#[cfg(test)]
#[allow(trivial_casts)]
mod tests {
use super::*;
use quickcheck::*;
mod vectors {
use super::*;
use flate2::read::GzDecoder;
use itertools::Itertools;
use std::fs::File;
use std::io::{BufRead, BufReader};
macro_rules! mk_test {
($id:ident, $op:expr, $val:expr) => {
mk_test!($id, $op, $val, 0);
};
($id:ident, $op:expr, $val:expr, $y:expr) => {
#[test]
fn $id() {
let results = (0..256).cartesian_product($y..256).map(|(i, j)| {
let (i, j) = (Gf256::from_byte(i as u8), Gf256::from_byte(j as u8));
(i.to_byte(), j.to_byte(), $val(i, j).to_byte())
});
let ref_path = format!("tests/fixtures/gf256/gf256_{}.txt.gz", stringify!($id));
let reference =
BufReader::new(GzDecoder::new(File::open(ref_path).unwrap()).unwrap());
for ((i, j, k), line) in results.zip(reference.lines()) {
let left = format!("{} {} {} = {}", i, $op, j, k);
let right = line.unwrap();
assert_eq!(left, right);
}
}
};
}
mk_test!(add, "+", |i: Gf256, j: Gf256| i + j);
mk_test!(sub, "-", |i: Gf256, j: Gf256| i - j);
mk_test!(mul, "*", |i: Gf256, j: Gf256| i * j);
mk_test!(div, "/", |i: Gf256, j: Gf256| i.div(j), 1);
mk_test!(pow, "^", |i: Gf256, j: Gf256| i.pow(j.to_byte()));
}
impl Arbitrary for Gf256 {
fn arbitrary<G: Gen>(gen: &mut G) -> Gf256 {
Gf256::from_byte(u8::arbitrary(gen))
}
}
mod addition {
use super::*;
quickcheck! {
fn law_associativity(a: Gf256, b: Gf256, c: Gf256) -> bool {
(a + b) + c == a + (b + c)
}
fn law_commutativity(a: Gf256, b: Gf256) -> bool {
let x = a + b;
let y = b + a;
x == y
}
fn law_distributivity(a: Gf256, b: Gf256, c: Gf256) -> bool {
a * (b + c) == a * b + a * c
}
fn law_identity(a: Gf256) -> bool {
a + Gf256::zero() == a && Gf256::zero() + a == a
}
fn law_inverses(a: Gf256) -> bool {
a + (-a) == Gf256::zero() && (-a) + a == Gf256::zero()
}
}
}
mod multiplication {
use super::*;
quickcheck! {
fn law_associativity(a: Gf256, b: Gf256, c: Gf256) -> bool {
(a * b) * c == a * (b * c)
}
fn law_commutativity(a: Gf256, b: Gf256) -> bool {
let x = a * b;
let y = b * a;
x == y
}
fn law_distributivity(a: Gf256, b: Gf256, c: Gf256) -> bool {
(a + b) * c == a * c + b * c
}
fn law_identity(a: Gf256) -> bool {
a * Gf256::one() == a && Gf256::one() * a == a
}
fn law_inverses(a: Gf256) -> TestResult {
if a == Gf256::zero() {
return TestResult::discard();
}
let left = a * (Gf256::one() / a) == Gf256::one();
let right = (Gf256::one() / a) * a == Gf256::one();
TestResult::from_bool(left && right)
}
}
}
}
#[cfg(test)]
mod additional_tests {
use super::*;
const REFERENCE_TABLE: Tables = Tables {
exp: [
1, 3, 5, 15, 17, 51, 85, 255, 26, 46, 114, 150, 161, 248, 19, 53, 95, 225, 56, 72, 216,
115, 149, 164, 247, 2, 6, 10, 30, 34, 102, 170, 229, 52, 92, 228, 55, 89, 235, 38, 106,
190, 217, 112, 144, 171, 230, 49, 83, 245, 4, 12, 20, 60, 68, 204, 79, 209, 104, 184,
211, 110, 178, 205, 76, 212, 103, 169, 224, 59, 77, 215, 98, 166, 241, 8, 24, 40, 120,
136, 131, 158, 185, 208, 107, 189, 220, 127, 129, 152, 179, 206, 73, 219, 118, 154,
181, 196, 87, 249, 16, 48, 80, 240, 11, 29, 39, 105, 187, 214, 97, 163, 254, 25, 43,
125, 135, 146, 173, 236, 47, 113, 147, 174, 233, 32, 96, 160, 251, 22, 58, 78, 210,
109, 183, 194, 93, 231, 50, 86, 250, 21, 63, 65, 195, 94, 226, 61, 71, 201, 64, 192,
91, 237, 44, 116, 156, 191, 218, 117, 159, 186, 213, 100, 172, 239, 42, 126, 130, 157,
188, 223, 122, 142, 137, 128, 155, 182, 193, 88, 232, 35, 101, 175, 234, 37, 111, 177,
200, 67, 197, 84, 252, 31, 33, 99, 165, 244, 7, 9, 27, 45, 119, 153, 176, 203, 70, 202,
69, 207, 74, 222, 121, 139, 134, 145, 168, 227, 62, 66, 198, 81, 243, 14, 18, 54, 90,
238, 41, 123, 141, 140, 143, 138, 133, 148, 167, 242, 13, 23, 57, 75, 221, 124, 132,
151, 162, 253, 28, 36, 108, 180, 199, 82, 246,
],
log: [
0, 0, 25, 1, 50, 2, 26, 198, 75, 199, 27, 104, 51, 238, 223, 3, 100, 4, 224, 14, 52,
141, 129, 239, 76, 113, 8, 200, 248, 105, 28, 193, 125, 194, 29, 181, 249, 185, 39,
106, 77, 228, 166, 114, 154, 201, 9, 120, 101, 47, 138, 5, 33, 15, 225, 36, 18, 240,
130, 69, 53, 147, 218, 142, 150, 143, 219, 189, 54, 208, 206, 148, 19, 92, 210, 241,
64, 70, 131, 56, 102, 221, 253, 48, 191, 6, 139, 98, 179, 37, 226, 152, 34, 136, 145,
16, 126, 110, 72, 195, 163, 182, 30, 66, 58, 107, 40, 84, 250, 133, 61, 186, 43, 121,
10, 21, 155, 159, 94, 202, 78, 212, 172, 229, 243, 115, 167, 87, 175, 88, 168, 80, 244,
234, 214, 116, 79, 174, 233, 213, 231, 230, 173, 232, 44, 215, 117, 122, 235, 22, 11,
245, 89, 203, 95, 176, 156, 169, 81, 160, 127, 12, 246, 111, 23, 196, 73, 236, 216, 67,
31, 45, 164, 118, 123, 183, 204, 187, 62, 90, 251, 96, 177, 134, 59, 82, 161, 108, 170,
85, 41, 157, 151, 178, 135, 144, 97, 190, 220, 252, 188, 149, 207, 205, 55, 63, 91,
209, 83, 57, 132, 60, 65, 162, 109, 71, 20, 42, 158, 93, 86, 242, 211, 171, 68, 17,
146, 217, 35, 32, 46, 137, 180, 124, 184, 38, 119, 153, 227, 165, 103, 74, 237, 222,
197, 49, 254, 24, 13, 99, 140, 128, 192, 247, 112, 7,
],
};
#[test]
fn reference_table_gen() {
println!("REFERENCE TABLES");
println!("{:?}", REFERENCE_TABLE);
println!("GENERATED TABLES");
println!("{:?}", get_tables());
assert!(get_tables() == &REFERENCE_TABLE);
}
}