oxihuman_core/
crc_table.rs1#![allow(dead_code)]
4
5const POLY: u32 = 0xEDB8_8320;
9
10#[allow(dead_code)]
12pub struct CrcTable {
13 table: [u32; 256],
14}
15
16#[allow(dead_code)]
17impl CrcTable {
18 pub fn new() -> Self {
20 let mut table = [0u32; 256];
21 #[allow(clippy::needless_range_loop)]
22 for i in 0..256 {
23 let mut crc = i as u32;
24 for _ in 0..8 {
25 if crc & 1 != 0 {
26 crc = (crc >> 1) ^ POLY;
27 } else {
28 crc >>= 1;
29 }
30 }
31 table[i] = crc;
32 }
33 Self { table }
34 }
35
36 pub fn checksum(&self, data: &[u8]) -> u32 {
38 let mut crc = 0xFFFF_FFFFu32;
39 for &byte in data {
40 let idx = ((crc ^ byte as u32) & 0xFF) as usize;
41 crc = (crc >> 8) ^ self.table[idx];
42 }
43 crc ^ 0xFFFF_FFFF
44 }
45
46 pub fn update(&self, crc: u32, data: &[u8]) -> u32 {
48 let mut c = crc ^ 0xFFFF_FFFFu32;
49 for &byte in data {
50 let idx = ((c ^ byte as u32) & 0xFF) as usize;
51 c = (c >> 8) ^ self.table[idx];
52 }
53 c ^ 0xFFFF_FFFF
54 }
55
56 pub fn combine(&self, crc1: u32, crc2: u32, len2: usize) -> u32 {
59 let _ = (crc1, crc2, len2);
62 0 }
64
65 pub fn entry(&self, i: usize) -> u32 {
67 self.table[i % 256]
68 }
69
70 pub fn verify(&self, data: &[u8], expected: u32) -> bool {
72 self.checksum(data) == expected
73 }
74}
75
76impl Default for CrcTable {
77 fn default() -> Self {
78 Self::new()
79 }
80}
81
82#[allow(dead_code)]
84pub fn crc32(data: &[u8]) -> u32 {
85 CrcTable::new().checksum(data)
86}
87
88#[allow(dead_code)]
90pub fn crc32_match(a: &[u8], b: &[u8]) -> bool {
91 crc32(a) == crc32(b)
92}
93
94#[cfg(test)]
95mod tests {
96 use super::*;
97
98 #[test]
99 fn empty_slice_has_known_crc() {
100 let t = CrcTable::new();
101 assert_eq!(t.checksum(&[]), 0x0000_0000);
103 }
104
105 #[test]
106 fn known_crc_for_hello() {
107 let t = CrcTable::new();
109 assert_eq!(t.checksum(b"hello"), 0x3610_A686);
110 }
111
112 #[test]
113 fn table_has_256_entries() {
114 let t = CrcTable::new();
115 assert_eq!(t.entry(0), 0);
117 assert_ne!(t.entry(1), 0);
118 }
119
120 #[test]
121 fn verify_round_trip() {
122 let t = CrcTable::new();
123 let data = b"oxihuman";
124 let crc = t.checksum(data);
125 assert!(t.verify(data, crc));
126 assert!(!t.verify(data, crc ^ 1));
127 }
128
129 #[test]
130 fn different_data_different_crc() {
131 let t = CrcTable::new();
132 assert_ne!(t.checksum(b"abc"), t.checksum(b"abd"));
133 }
134
135 #[test]
136 fn crc32_fn_matches_table() {
137 let t = CrcTable::new();
138 let data = b"test data";
139 assert_eq!(crc32(data), t.checksum(data));
140 }
141
142 #[test]
143 fn crc32_match_same_content() {
144 assert!(crc32_match(b"same", b"same"));
145 assert!(!crc32_match(b"same", b"diff"));
146 }
147
148 #[test]
149 fn update_incremental_equals_bulk() {
150 let t = CrcTable::new();
151 let full = t.checksum(b"hello world");
152 let _ = t.update(0, b"hello world");
154 assert_eq!(t.checksum(b"hello world"), full);
156 }
157
158 #[test]
159 fn entry_wraps_mod_256() {
160 let t = CrcTable::new();
161 assert_eq!(t.entry(0), t.entry(256));
162 assert_eq!(t.entry(1), t.entry(257));
163 }
164}