use std::iter;
use std::convert::TryFrom;
use ::gf256::traits::FromLossy;
use ::gf256::*;
const POLYNOMIAL: p64 = p64(0x104c11db7);
pub fn naive_crc(data: &[u8]) -> u32 {
let mut crc = p64(0);
for b in
data.iter().copied()
.chain(iter::repeat(0x00).take(4))
.zip(iter::repeat(0xff).take(4).chain(iter::repeat(0x00)))
.map(|(m, b)| m ^ b)
{
crc = (crc << 8) | p64::from(b.reverse_bits());
crc = crc % POLYNOMIAL;
}
u32::try_from(crc).unwrap().reverse_bits() ^ 0xffffffff
}
pub fn less_naive_crc(data: &[u8]) -> u32 {
let mut crc = p32(0xffffffff);
for b in data {
crc = crc + (p32::from(b.reverse_bits()) << 24);
crc = p32::try_from((p64::from(crc) << 8) % POLYNOMIAL).unwrap();
}
u32::from(crc).reverse_bits() ^ 0xffffffff
}
pub fn word_less_naive_crc(data: &[u8]) -> u32 {
let mut crc = p32(0xffffffff);
let mut words = data.chunks_exact(4);
for word in &mut words {
let word = <[u8; 4]>::try_from(word).unwrap();
crc = crc + p32::from_le_bytes(word).reverse_bits();
crc = p32::try_from((p64::from(crc) << 32) % POLYNOMIAL).unwrap();
}
for b in words.remainder() {
crc = crc + (p32::from(b.reverse_bits()) << 24);
crc = p32::try_from((p64::from(crc) << 8) % POLYNOMIAL).unwrap();
}
u32::from(crc).reverse_bits() ^ 0xffffffff
}
pub fn table_crc(data: &[u8]) -> u32 {
const CRC_TABLE: [u32; 256] = {
let mut table = [0; 256];
let mut i = 0;
while i < table.len() {
let x = (i as u32).reverse_bits();
let x = p64((x as u64) << 8).naive_rem(POLYNOMIAL).0 as u32;
table[i] = x.reverse_bits();
i += 1;
}
table
};
let mut crc = 0xffffffff;
for b in data {
crc = (crc >> 8) ^ CRC_TABLE[usize::from((crc as u8) ^ b)];
}
crc ^ 0xffffffff
}
pub fn small_table_crc(data: &[u8]) -> u32 {
const CRC_SMALL_TABLE: [u32; 16] = {
let mut table = [0; 16];
let mut i = 0;
while i < table.len() {
let x = (i as u32).reverse_bits();
let x = p64((x as u64) << 4).naive_rem(POLYNOMIAL).0 as u32;
table[i] = x.reverse_bits();
i += 1;
}
table
};
let mut crc = 0xffffffff;
for b in data {
crc = (crc >> 4) ^ CRC_SMALL_TABLE[usize::from(((crc as u8) ^ (b >> 0)) & 0xf)];
crc = (crc >> 4) ^ CRC_SMALL_TABLE[usize::from(((crc as u8) ^ (b >> 4)) & 0xf)];
}
crc ^ 0xffffffff
}
pub fn barret_crc(data: &[u8]) -> u32 {
const BARRET_CONSTANT: p32 = {
p32(p64(POLYNOMIAL.0 << 32).naive_div(POLYNOMIAL).0 as u32)
};
let mut crc = p32(0xffffffff);
for b in data {
crc = crc ^ (p32::from(b.reverse_bits()) << 24);
crc = (crc << 8)
+ ((crc >> 24u32).widening_mul(BARRET_CONSTANT).1 + (crc >> 24u32))
.wrapping_mul(p32::from_lossy(POLYNOMIAL));
}
u32::from(crc).reverse_bits() ^ 0xffffffff
}
pub fn word_barret_crc(data: &[u8]) -> u32 {
const BARRET_CONSTANT: p32 = {
p32(p64(POLYNOMIAL.0 << 32).naive_div(POLYNOMIAL).0 as u32)
};
let mut crc = p32(0xffffffff);
let mut words = data.chunks_exact(4);
for word in &mut words {
let word = <[u8; 4]>::try_from(word).unwrap();
crc = crc ^ p32::from_le_bytes(word).reverse_bits();
crc = (crc.widening_mul(BARRET_CONSTANT).1 + crc)
.wrapping_mul(p32::from_lossy(POLYNOMIAL));
}
for b in words.remainder() {
crc = crc ^ (p32::from(b.reverse_bits()) << 24);
crc = (crc << 8)
+ ((crc >> 24u32).widening_mul(BARRET_CONSTANT).1 + (crc >> 24u32))
.wrapping_mul(p32::from_lossy(POLYNOMIAL));
}
u32::from(crc).reverse_bits() ^ 0xffffffff
}
pub fn reversed_barret_crc(data: &[u8]) -> u32 {
const BARRET_CONSTANT: p32 = {
p32(p64(POLYNOMIAL.0 << 32).naive_div(POLYNOMIAL).0 as u32)
};
const POLYNOMIAL_REV: p32 = p32(POLYNOMIAL.0 as u32).reverse_bits();
const BARRET_CONSTANT_REV: p32 = BARRET_CONSTANT.reverse_bits();
let mut crc = p32(0xffffffff);
for b in data {
crc = crc ^ p32::from(*b);
let (lo, _) = (crc << 24u32).widening_mul(BARRET_CONSTANT_REV);
let (lo, hi) = ((lo << 1u32) + (crc << 24u32)).widening_mul(POLYNOMIAL_REV);
crc = (crc >> 8u32) + ((hi << 1u32) | (lo >> 31u32));
}
u32::from(crc) ^ 0xffffffff
}
pub fn word_reversed_barret_crc(data: &[u8]) -> u32 {
const BARRET_CONSTANT: p32 = {
p32(p64(POLYNOMIAL.0 << 32).naive_div(POLYNOMIAL).0 as u32)
};
const POLYNOMIAL_REV: p32 = p32(POLYNOMIAL.0 as u32).reverse_bits();
const BARRET_CONSTANT_REV: p32 = BARRET_CONSTANT.reverse_bits();
let mut crc = p32(0xffffffff);
let mut words = data.chunks_exact(4);
for word in &mut words {
let word = <[u8; 4]>::try_from(word).unwrap();
crc = crc ^ p32::from_le_bytes(word);
let (lo, _) = crc.widening_mul(BARRET_CONSTANT_REV);
let (lo, hi) = ((lo << 1u32) + crc).widening_mul(POLYNOMIAL_REV);
crc = (hi << 1u32) | (lo >> 31u32);
}
for b in words.remainder() {
crc = crc ^ p32::from(*b);
let (lo, _) = (crc << 24u32).widening_mul(BARRET_CONSTANT_REV);
let (lo, hi) = ((lo << 1u32) + (crc << 24u32)).widening_mul(POLYNOMIAL_REV);
crc = (crc >> 8u32) + ((hi << 1u32) | (lo >> 31u32));
}
u32::from(crc) ^ 0xffffffff
}
fn main() {
let input = b"Hello World!";
let expected = 0x1c291ca3;
println!();
println!("testing crc({:?})", String::from_utf8_lossy(input));
let output = naive_crc(input);
println!("{:<24} => 0x{:08x}", "naive_crc", output);
assert_eq!(output, expected);
let output = less_naive_crc(input);
println!("{:<24} => 0x{:08x}", "less_naive_crc", output);
assert_eq!(output, expected);
let output = word_less_naive_crc(input);
println!("{:<24} => 0x{:08x}", "word_less_naive_crc", output);
assert_eq!(output, expected);
let output = table_crc(input);
println!("{:<24} => 0x{:08x}", "table_crc", output);
assert_eq!(output, expected);
let output = small_table_crc(input);
println!("{:<24} => 0x{:08x}", "small_table_crc", output);
assert_eq!(output, expected);
let output = barret_crc(input);
println!("{:<24} => 0x{:08x}", "barret_crc", output);
assert_eq!(output, expected);
let output = word_barret_crc(input);
println!("{:<24} => 0x{:08x}", "word_barret_crc", output);
assert_eq!(output, expected);
let output = reversed_barret_crc(input);
println!("{:<24} => 0x{:08x}", "reversed_barret_crc", output);
assert_eq!(output, expected);
let output = word_reversed_barret_crc(input);
println!("{:<24} => 0x{:08x}", "word_reversed_barret_crc", output);
assert_eq!(output, expected);
println!();
}