const CRC32_POLYNOMIAL: u32 = 0xEDB8_8320;
const CRC32_TABLE: [u32; 256] = build_crc32_table();
const fn build_crc32_table() -> [u32; 256] {
let mut table = [0u32; 256];
let mut byte = 0;
while byte < 256 {
let mut crc = byte as u32;
let mut bit = 0;
while bit < 8 {
crc = if crc & 1 != 0 { CRC32_POLYNOMIAL ^ (crc >> 1) } else { crc >> 1 };
bit += 1;
}
table[byte] = crc;
byte += 1;
}
table
}
pub fn crc32(bytes: &[u8]) -> u32 {
let mut crc = Crc32::new();
crc.update(bytes);
crc.finish()
}
#[derive(Debug, Clone)]
pub struct Crc32 {
state: u32,
}
impl Default for Crc32 {
fn default() -> Self {
Self::new()
}
}
impl Crc32 {
pub fn new() -> Self {
Self { state: 0xFFFF_FFFF }
}
pub fn update(&mut self, bytes: &[u8]) {
let mut crc = self.state;
for &byte in bytes {
crc = CRC32_TABLE[((crc ^ u32::from(byte)) & 0xFF) as usize] ^ (crc >> 8);
}
self.state = crc;
}
pub fn finish(&self) -> u32 {
!self.state
}
}
const ADLER_MODULUS: u32 = 65_521;
const ADLER_CHUNK: usize = 5552;
pub fn adler32(bytes: &[u8]) -> u32 {
let mut adler = Adler32::new();
adler.update(bytes);
adler.finish()
}
#[derive(Debug, Clone)]
pub struct Adler32 {
a: u32,
b: u32,
}
impl Default for Adler32 {
fn default() -> Self {
Self::new()
}
}
impl Adler32 {
pub fn new() -> Self {
Self { a: 1, b: 0 }
}
pub fn update(&mut self, bytes: &[u8]) {
for chunk in bytes.chunks(ADLER_CHUNK) {
for &byte in chunk {
self.a += u32::from(byte);
self.b += self.a;
}
self.a %= ADLER_MODULUS;
self.b %= ADLER_MODULUS;
}
}
pub fn finish(&self) -> u32 {
(self.b << 16) | self.a
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn crc32_check_value() {
assert_eq!(crc32(b"123456789"), 0xCBF4_3926);
}
#[test]
fn crc32_of_nothing_is_zero() {
assert_eq!(crc32(b""), 0);
}
#[test]
fn crc32_incremental_matches_one_shot() {
let data: Vec<u8> = (0..10_000u32).map(|i| (i * 7 % 251) as u8).collect();
let mut crc = Crc32::new();
for piece in data.chunks(333) {
crc.update(piece);
}
assert_eq!(crc.finish(), crc32(&data));
}
#[test]
fn adler32_check_value() {
assert_eq!(adler32(b"Wikipedia"), 0x11E6_0398);
}
#[test]
fn adler32_of_nothing_is_one() {
assert_eq!(adler32(b""), 1);
}
#[test]
fn adler32_incremental_matches_one_shot_across_chunk_boundary() {
let data: Vec<u8> = (0..30_000u32).map(|i| (i.wrapping_mul(2654435761) >> 24) as u8).collect();
let mut adler = Adler32::new();
for piece in data.chunks(1234) {
adler.update(piece);
}
assert_eq!(adler.finish(), adler32(&data));
let ones = vec![0xFFu8; 3 * ADLER_CHUNK + 17];
let mut adler = Adler32::new();
adler.update(&ones[..100]);
adler.update(&ones[100..]);
assert_eq!(adler.finish(), adler32(&ones));
}
}