use crc32c::crc32c_append; /// CRC32C checksum implementation for iSCSI pub struct Crc32c { value: u32, } impl Crc32c { /// Create new CRC32C calculator pub fn new() -> Self { Self { value: 0 } } /// Initialize with existing value pub fn with_value(value: u32) -> Self { Self { value } } /// Append data to CRC calculation pub fn append(&mut self, data: &[u8]) { self.value = crc32c_append(self.value, data); } /// Get final CRC value pub fn finalize(&self) -> u32 { self.value } /// Calculate CRC32C for entire buffer pub fn calculate(data: &[u8]) -> u32 { crc32c::crc32c(data) } /// Verify CRC32C checksum pub fn verify(data: &[u8], expected: u32) -> bool { Self::calculate(data) == expected } /// Convert to 4-byte array (little-endian) pub fn to_bytes(&self) -> [u8; 4] { self.value.to_le_bytes() } /// Convert to 4-byte array (big-endian, iSCSI standard) pub fn to_bytes_be(&self) -> [u8; 4] { self.value.to_be_bytes() } /// Parse from 4-byte array (big-endian) pub fn from_bytes_be(bytes: [u8; 4]) -> Self { Self { value: u32::from_be_bytes(bytes), } } } impl Default for Crc32c { fn default() -> Self { Self::new() } } #[cfg(test)] mod tests { use super::*; #[test] fn test_crc32c_basic() { let data = b"Hello, World!"; let crc = Crc32c::calculate(data); // Should match known CRC32C value assert!(crc != 0); } #[test] fn test_crc32c_append() { let mut crc = Crc32c::new(); crc.append(b"Hello"); crc.append(b"World"); let final_crc = crc.finalize(); let direct_crc = Crc32c::calculate(b"HelloWorld"); assert_eq!(final_crc, direct_crc); } #[test] fn test_crc32c_verify() { let data = b"test data"; let crc = Crc32c::calculate(data); assert!(Crc32c::verify(data, crc)); assert!(!Crc32c::verify(data, crc + 1)); } #[test] fn test_crc32c_bytes() { let crc = Crc32c::with_value(0x12345678); let bytes_be = crc.to_bytes_be(); assert_eq!(bytes_be, [0x12, 0x34, 0x56, 0x78]); let parsed = Crc32c::from_bytes_be(bytes_be); assert_eq!(parsed.value, 0x12345678); } }